aboutsummaryrefslogtreecommitdiff
path: root/src/lj_gc.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lj_gc.c68
1 files changed, 32 insertions, 36 deletions
diff --git a/src/lj_gc.c b/src/lj_gc.c
index c5ff1f04..53f1d974 100644
--- a/src/lj_gc.c
+++ b/src/lj_gc.c
@@ -12,6 +12,7 @@
12#include "lj_obj.h" 12#include "lj_obj.h"
13#include "lj_gc.h" 13#include "lj_gc.h"
14#include "lj_err.h" 14#include "lj_err.h"
15#include "lj_buf.h"
15#include "lj_str.h" 16#include "lj_str.h"
16#include "lj_tab.h" 17#include "lj_tab.h"
17#include "lj_func.h" 18#include "lj_func.h"
@@ -68,7 +69,7 @@ static void gc_mark(global_State *g, GCobj *o)
68 gray2black(o); /* Closed upvalues are never gray. */ 69 gray2black(o); /* Closed upvalues are never gray. */
69 } else if (gct != ~LJ_TSTR && gct != ~LJ_TCDATA) { 70 } else if (gct != ~LJ_TSTR && gct != ~LJ_TCDATA) {
70 lua_assert(gct == ~LJ_TFUNC || gct == ~LJ_TTAB || 71 lua_assert(gct == ~LJ_TFUNC || gct == ~LJ_TTAB ||
71 gct == ~LJ_TTHREAD || gct == ~LJ_TPROTO); 72 gct == ~LJ_TTHREAD || gct == ~LJ_TPROTO || gct == ~LJ_TTRACE);
72 setgcrefr(o->gch.gclist, g->gc.gray); 73 setgcrefr(o->gch.gclist, g->gc.gray);
73 setgcref(g->gc.gray, o); 74 setgcref(g->gc.gray, o);
74 } 75 }
@@ -267,12 +268,12 @@ static MSize gc_traverse_frames(global_State *g, lua_State *th)
267{ 268{
268 TValue *frame, *top = th->top-1, *bot = tvref(th->stack); 269 TValue *frame, *top = th->top-1, *bot = tvref(th->stack);
269 /* Note: extra vararg frame not skipped, marks function twice (harmless). */ 270 /* Note: extra vararg frame not skipped, marks function twice (harmless). */
270 for (frame = th->base-1; frame > bot; frame = frame_prev(frame)) { 271 for (frame = th->base-1; frame > bot+LJ_FR2; frame = frame_prev(frame)) {
271 GCfunc *fn = frame_func(frame); 272 GCfunc *fn = frame_func(frame);
272 TValue *ftop = frame; 273 TValue *ftop = frame;
273 if (isluafunc(fn)) ftop += funcproto(fn)->framesize; 274 if (isluafunc(fn)) ftop += funcproto(fn)->framesize;
274 if (ftop > top) top = ftop; 275 if (ftop > top) top = ftop;
275 gc_markobj(g, fn); /* Need to mark hidden function (or L). */ 276 if (!LJ_FR2) gc_markobj(g, fn); /* Need to mark hidden function (or L). */
276 } 277 }
277 top++; /* Correct bias of -1 (frame == base-1). */ 278 top++; /* Correct bias of -1 (frame == base-1). */
278 if (top > tvref(th->maxstack)) top = tvref(th->maxstack); 279 if (top > tvref(th->maxstack)) top = tvref(th->maxstack);
@@ -283,7 +284,7 @@ static MSize gc_traverse_frames(global_State *g, lua_State *th)
283static void gc_traverse_thread(global_State *g, lua_State *th) 284static void gc_traverse_thread(global_State *g, lua_State *th)
284{ 285{
285 TValue *o, *top = th->top; 286 TValue *o, *top = th->top;
286 for (o = tvref(th->stack)+1; o < top; o++) 287 for (o = tvref(th->stack)+1+LJ_FR2; o < top; o++)
287 gc_marktv(g, o); 288 gc_marktv(g, o);
288 if (g->gc.state == GCSatomic) { 289 if (g->gc.state == GCSatomic) {
289 top = tvref(th->stack) + th->stacksize; 290 top = tvref(th->stack) + th->stacksize;
@@ -348,15 +349,6 @@ static size_t gc_propagate_gray(global_State *g)
348 349
349/* -- Sweep phase --------------------------------------------------------- */ 350/* -- Sweep phase --------------------------------------------------------- */
350 351
351/* Try to shrink some common data structures. */
352static void gc_shrink(global_State *g, lua_State *L)
353{
354 if (g->strnum <= (g->strmask >> 2) && g->strmask > LJ_MIN_STRTAB*2-1)
355 lj_str_resize(L, g->strmask >> 1); /* Shrink string table. */
356 if (g->tmpbuf.sz > LJ_MIN_SBUF*2)
357 lj_str_resizebuf(L, &g->tmpbuf, g->tmpbuf.sz >> 1); /* Shrink temp buf. */
358}
359
360/* Type of GC free functions. */ 352/* Type of GC free functions. */
361typedef void (LJ_FASTCALL *GCFreeFunc)(global_State *g, GCobj *o); 353typedef void (LJ_FASTCALL *GCFreeFunc)(global_State *g, GCobj *o);
362 354
@@ -382,7 +374,7 @@ static const GCFreeFunc gc_freefunc[] = {
382}; 374};
383 375
384/* Full sweep of a GC list. */ 376/* Full sweep of a GC list. */
385#define gc_fullsweep(g, p) gc_sweep(g, (p), LJ_MAX_MEM) 377#define gc_fullsweep(g, p) gc_sweep(g, (p), ~(uint32_t)0)
386 378
387/* Partial sweep of a GC list. */ 379/* Partial sweep of a GC list. */
388static GCRef *gc_sweep(global_State *g, GCRef *p, uint32_t lim) 380static GCRef *gc_sweep(global_State *g, GCRef *p, uint32_t lim)
@@ -460,17 +452,18 @@ static void gc_call_finalizer(global_State *g, lua_State *L,
460{ 452{
461 /* Save and restore lots of state around the __gc callback. */ 453 /* Save and restore lots of state around the __gc callback. */
462 uint8_t oldh = hook_save(g); 454 uint8_t oldh = hook_save(g);
463 MSize oldt = g->gc.threshold; 455 GCSize oldt = g->gc.threshold;
464 int errcode; 456 int errcode;
465 TValue *top; 457 TValue *top;
466 lj_trace_abort(g); 458 lj_trace_abort(g);
467 top = L->top;
468 L->top = top+2;
469 hook_entergc(g); /* Disable hooks and new traces during __gc. */ 459 hook_entergc(g); /* Disable hooks and new traces during __gc. */
470 g->gc.threshold = LJ_MAX_MEM; /* Prevent GC steps. */ 460 g->gc.threshold = LJ_MAX_MEM; /* Prevent GC steps. */
471 copyTV(L, top, mo); 461 top = L->top;
472 setgcV(L, top+1, o, ~o->gch.gct); 462 copyTV(L, top++, mo);
473 errcode = lj_vm_pcall(L, top+1, 1+0, -1); /* Stack: |mo|o| -> | */ 463 if (LJ_FR2) setnilV(top++);
464 setgcV(L, top, o, ~o->gch.gct);
465 L->top = top+1;
466 errcode = lj_vm_pcall(L, top, 1+0, -1); /* Stack: |mo|o| -> | */
474 hook_restore(g, oldh); 467 hook_restore(g, oldh);
475 g->gc.threshold = oldt; /* Restore GC threshold. */ 468 g->gc.threshold = oldt; /* Restore GC threshold. */
476 if (errcode) 469 if (errcode)
@@ -483,7 +476,7 @@ static void gc_finalize(lua_State *L)
483 global_State *g = G(L); 476 global_State *g = G(L);
484 GCobj *o = gcnext(gcref(g->gc.mmudata)); 477 GCobj *o = gcnext(gcref(g->gc.mmudata));
485 cTValue *mo; 478 cTValue *mo;
486 lua_assert(gcref(g->jit_L) == NULL); /* Must not be called on trace. */ 479 lua_assert(tvref(g->jit_base) == NULL); /* Must not be called on trace. */
487 /* Unchain from list of userdata to be finalized. */ 480 /* Unchain from list of userdata to be finalized. */
488 if (o == gcref(g->gc.mmudata)) 481 if (o == gcref(g->gc.mmudata))
489 setgcrefnull(g->gc.mmudata); 482 setgcrefnull(g->gc.mmudata);
@@ -592,11 +585,13 @@ static void atomic(global_State *g, lua_State *L)
592 /* All marking done, clear weak tables. */ 585 /* All marking done, clear weak tables. */
593 gc_clearweak(gcref(g->gc.weak)); 586 gc_clearweak(gcref(g->gc.weak));
594 587
588 lj_buf_shrink(L, &g->tmpbuf); /* Shrink temp buffer. */
589
595 /* Prepare for sweep phase. */ 590 /* Prepare for sweep phase. */
596 g->gc.currentwhite = (uint8_t)otherwhite(g); /* Flip current white. */ 591 g->gc.currentwhite = (uint8_t)otherwhite(g); /* Flip current white. */
597 g->strempty.marked = g->gc.currentwhite; 592 g->strempty.marked = g->gc.currentwhite;
598 setmref(g->gc.sweep, &g->gc.root); 593 setmref(g->gc.sweep, &g->gc.root);
599 g->gc.estimate = g->gc.total - (MSize)udsize; /* Initial estimate. */ 594 g->gc.estimate = g->gc.total - (GCSize)udsize; /* Initial estimate. */
600} 595}
601 596
602/* GC state machine. Returns a cost estimate for each step performed. */ 597/* GC state machine. Returns a cost estimate for each step performed. */
@@ -613,14 +608,14 @@ static size_t gc_onestep(lua_State *L)
613 g->gc.state = GCSatomic; /* End of mark phase. */ 608 g->gc.state = GCSatomic; /* End of mark phase. */
614 return 0; 609 return 0;
615 case GCSatomic: 610 case GCSatomic:
616 if (gcref(g->jit_L)) /* Don't run atomic phase on trace. */ 611 if (tvref(g->jit_base)) /* Don't run atomic phase on trace. */
617 return LJ_MAX_MEM; 612 return LJ_MAX_MEM;
618 atomic(g, L); 613 atomic(g, L);
619 g->gc.state = GCSsweepstring; /* Start of sweep phase. */ 614 g->gc.state = GCSsweepstring; /* Start of sweep phase. */
620 g->gc.sweepstr = 0; 615 g->gc.sweepstr = 0;
621 return 0; 616 return 0;
622 case GCSsweepstring: { 617 case GCSsweepstring: {
623 MSize old = g->gc.total; 618 GCSize old = g->gc.total;
624 gc_fullsweep(g, &g->strhash[g->gc.sweepstr++]); /* Sweep one chain. */ 619 gc_fullsweep(g, &g->strhash[g->gc.sweepstr++]); /* Sweep one chain. */
625 if (g->gc.sweepstr > g->strmask) 620 if (g->gc.sweepstr > g->strmask)
626 g->gc.state = GCSsweep; /* All string hash chains sweeped. */ 621 g->gc.state = GCSsweep; /* All string hash chains sweeped. */
@@ -629,12 +624,13 @@ static size_t gc_onestep(lua_State *L)
629 return GCSWEEPCOST; 624 return GCSWEEPCOST;
630 } 625 }
631 case GCSsweep: { 626 case GCSsweep: {
632 MSize old = g->gc.total; 627 GCSize old = g->gc.total;
633 setmref(g->gc.sweep, gc_sweep(g, mref(g->gc.sweep, GCRef), GCSWEEPMAX)); 628 setmref(g->gc.sweep, gc_sweep(g, mref(g->gc.sweep, GCRef), GCSWEEPMAX));
634 lua_assert(old >= g->gc.total); 629 lua_assert(old >= g->gc.total);
635 g->gc.estimate -= old - g->gc.total; 630 g->gc.estimate -= old - g->gc.total;
636 if (gcref(*mref(g->gc.sweep, GCRef)) == NULL) { 631 if (gcref(*mref(g->gc.sweep, GCRef)) == NULL) {
637 gc_shrink(g, L); 632 if (g->strnum <= (g->strmask >> 2) && g->strmask > LJ_MIN_STRTAB*2-1)
633 lj_str_resize(L, g->strmask >> 1); /* Shrink string table. */
638 if (gcref(g->gc.mmudata)) { /* Need any finalizations? */ 634 if (gcref(g->gc.mmudata)) { /* Need any finalizations? */
639 g->gc.state = GCSfinalize; 635 g->gc.state = GCSfinalize;
640#if LJ_HASFFI 636#if LJ_HASFFI
@@ -649,7 +645,7 @@ static size_t gc_onestep(lua_State *L)
649 } 645 }
650 case GCSfinalize: 646 case GCSfinalize:
651 if (gcref(g->gc.mmudata) != NULL) { 647 if (gcref(g->gc.mmudata) != NULL) {
652 if (gcref(g->jit_L)) /* Don't call finalizers on trace. */ 648 if (tvref(g->jit_base)) /* Don't call finalizers on trace. */
653 return LJ_MAX_MEM; 649 return LJ_MAX_MEM;
654 gc_finalize(L); /* Finalize one userdata object. */ 650 gc_finalize(L); /* Finalize one userdata object. */
655 if (g->gc.estimate > GCFINALIZECOST) 651 if (g->gc.estimate > GCFINALIZECOST)
@@ -672,7 +668,7 @@ static size_t gc_onestep(lua_State *L)
672int LJ_FASTCALL lj_gc_step(lua_State *L) 668int LJ_FASTCALL lj_gc_step(lua_State *L)
673{ 669{
674 global_State *g = G(L); 670 global_State *g = G(L);
675 MSize lim; 671 GCSize lim;
676 int32_t ostate = g->vmstate; 672 int32_t ostate = g->vmstate;
677 setvmstate(g, GC); 673 setvmstate(g, GC);
678 lim = (GCSTEPSIZE/100) * g->gc.stepmul; 674 lim = (GCSTEPSIZE/100) * g->gc.stepmul;
@@ -681,13 +677,13 @@ int LJ_FASTCALL lj_gc_step(lua_State *L)
681 if (g->gc.total > g->gc.threshold) 677 if (g->gc.total > g->gc.threshold)
682 g->gc.debt += g->gc.total - g->gc.threshold; 678 g->gc.debt += g->gc.total - g->gc.threshold;
683 do { 679 do {
684 lim -= (MSize)gc_onestep(L); 680 lim -= (GCSize)gc_onestep(L);
685 if (g->gc.state == GCSpause) { 681 if (g->gc.state == GCSpause) {
686 g->gc.threshold = (g->gc.estimate/100) * g->gc.pause; 682 g->gc.threshold = (g->gc.estimate/100) * g->gc.pause;
687 g->vmstate = ostate; 683 g->vmstate = ostate;
688 return 1; /* Finished a GC cycle. */ 684 return 1; /* Finished a GC cycle. */
689 } 685 }
690 } while ((int32_t)lim > 0); 686 } while (sizeof(lim) == 8 ? ((int64_t)lim > 0) : ((int32_t)lim > 0));
691 if (g->gc.debt < GCSTEPSIZE) { 687 if (g->gc.debt < GCSTEPSIZE) {
692 g->gc.threshold = g->gc.total + GCSTEPSIZE; 688 g->gc.threshold = g->gc.total + GCSTEPSIZE;
693 g->vmstate = ostate; 689 g->vmstate = ostate;
@@ -711,8 +707,8 @@ void LJ_FASTCALL lj_gc_step_fixtop(lua_State *L)
711/* Perform multiple GC steps. Called from JIT-compiled code. */ 707/* Perform multiple GC steps. Called from JIT-compiled code. */
712int LJ_FASTCALL lj_gc_step_jit(global_State *g, MSize steps) 708int LJ_FASTCALL lj_gc_step_jit(global_State *g, MSize steps)
713{ 709{
714 lua_State *L = gco2th(gcref(g->jit_L)); 710 lua_State *L = gco2th(gcref(g->cur_L));
715 L->base = mref(G(L)->jit_base, TValue); 711 L->base = tvref(G(L)->jit_base);
716 L->top = curr_topL(L); 712 L->top = curr_topL(L);
717 while (steps-- > 0 && lj_gc_step(L) == 0) 713 while (steps-- > 0 && lj_gc_step(L) == 0)
718 ; 714 ;
@@ -806,7 +802,7 @@ void lj_gc_barriertrace(global_State *g, uint32_t traceno)
806/* -- Allocator ----------------------------------------------------------- */ 802/* -- Allocator ----------------------------------------------------------- */
807 803
808/* Call pluggable memory allocator to allocate or resize a fragment. */ 804/* Call pluggable memory allocator to allocate or resize a fragment. */
809void *lj_mem_realloc(lua_State *L, void *p, MSize osz, MSize nsz) 805void *lj_mem_realloc(lua_State *L, void *p, GCSize osz, GCSize nsz)
810{ 806{
811 global_State *g = G(L); 807 global_State *g = G(L);
812 lua_assert((osz == 0) == (p == NULL)); 808 lua_assert((osz == 0) == (p == NULL));
@@ -814,19 +810,19 @@ void *lj_mem_realloc(lua_State *L, void *p, MSize osz, MSize nsz)
814 if (p == NULL && nsz > 0) 810 if (p == NULL && nsz > 0)
815 lj_err_mem(L); 811 lj_err_mem(L);
816 lua_assert((nsz == 0) == (p == NULL)); 812 lua_assert((nsz == 0) == (p == NULL));
817 lua_assert(checkptr32(p)); 813 lua_assert(checkptrGC(p));
818 g->gc.total = (g->gc.total - osz) + nsz; 814 g->gc.total = (g->gc.total - osz) + nsz;
819 return p; 815 return p;
820} 816}
821 817
822/* Allocate new GC object and link it to the root set. */ 818/* Allocate new GC object and link it to the root set. */
823void * LJ_FASTCALL lj_mem_newgco(lua_State *L, MSize size) 819void * LJ_FASTCALL lj_mem_newgco(lua_State *L, GCSize size)
824{ 820{
825 global_State *g = G(L); 821 global_State *g = G(L);
826 GCobj *o = (GCobj *)g->allocf(g->allocd, NULL, 0, size); 822 GCobj *o = (GCobj *)g->allocf(g->allocd, NULL, 0, size);
827 if (o == NULL) 823 if (o == NULL)
828 lj_err_mem(L); 824 lj_err_mem(L);
829 lua_assert(checkptr32(o)); 825 lua_assert(checkptrGC(o));
830 g->gc.total += size; 826 g->gc.total += size;
831 setgcrefr(o->gch.nextgc, g->gc.root); 827 setgcrefr(o->gch.nextgc, g->gc.root);
832 setgcref(g->gc.root, o); 828 setgcref(g->gc.root, o);