aboutsummaryrefslogtreecommitdiff
path: root/src/lj_gc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_gc.c')
-rw-r--r--src/lj_gc.c73
1 files changed, 37 insertions, 36 deletions
diff --git a/src/lj_gc.c b/src/lj_gc.c
index 86fcd6eb..81439aab 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"
@@ -24,6 +25,7 @@
24#include "lj_cdata.h" 25#include "lj_cdata.h"
25#endif 26#endif
26#include "lj_trace.h" 27#include "lj_trace.h"
28#include "lj_dispatch.h"
27#include "lj_vm.h" 29#include "lj_vm.h"
28 30
29#define GCSTEPSIZE 1024u 31#define GCSTEPSIZE 1024u
@@ -68,7 +70,7 @@ static void gc_mark(global_State *g, GCobj *o)
68 gray2black(o); /* Closed upvalues are never gray. */ 70 gray2black(o); /* Closed upvalues are never gray. */
69 } else if (gct != ~LJ_TSTR && gct != ~LJ_TCDATA) { 71 } else if (gct != ~LJ_TSTR && gct != ~LJ_TCDATA) {
70 lua_assert(gct == ~LJ_TFUNC || gct == ~LJ_TTAB || 72 lua_assert(gct == ~LJ_TFUNC || gct == ~LJ_TTAB ||
71 gct == ~LJ_TTHREAD || gct == ~LJ_TPROTO); 73 gct == ~LJ_TTHREAD || gct == ~LJ_TPROTO || gct == ~LJ_TTRACE);
72 setgcrefr(o->gch.gclist, g->gc.gray); 74 setgcrefr(o->gch.gclist, g->gc.gray);
73 setgcref(g->gc.gray, o); 75 setgcref(g->gc.gray, o);
74 } 76 }
@@ -244,6 +246,8 @@ static void gc_traverse_trace(global_State *g, GCtrace *T)
244 IRIns *ir = &T->ir[ref]; 246 IRIns *ir = &T->ir[ref];
245 if (ir->o == IR_KGC) 247 if (ir->o == IR_KGC)
246 gc_markobj(g, ir_kgc(ir)); 248 gc_markobj(g, ir_kgc(ir));
249 if (irt_is64(ir->t) && ir->o != IR_KNULL)
250 ref++;
247 } 251 }
248 if (T->link) gc_marktrace(g, T->link); 252 if (T->link) gc_marktrace(g, T->link);
249 if (T->nextroot) gc_marktrace(g, T->nextroot); 253 if (T->nextroot) gc_marktrace(g, T->nextroot);
@@ -274,12 +278,12 @@ static MSize gc_traverse_frames(global_State *g, lua_State *th)
274{ 278{
275 TValue *frame, *top = th->top-1, *bot = tvref(th->stack); 279 TValue *frame, *top = th->top-1, *bot = tvref(th->stack);
276 /* Note: extra vararg frame not skipped, marks function twice (harmless). */ 280 /* Note: extra vararg frame not skipped, marks function twice (harmless). */
277 for (frame = th->base-1; frame > bot; frame = frame_prev(frame)) { 281 for (frame = th->base-1; frame > bot+LJ_FR2; frame = frame_prev(frame)) {
278 GCfunc *fn = frame_func(frame); 282 GCfunc *fn = frame_func(frame);
279 TValue *ftop = frame; 283 TValue *ftop = frame;
280 if (isluafunc(fn)) ftop += funcproto(fn)->framesize; 284 if (isluafunc(fn)) ftop += funcproto(fn)->framesize;
281 if (ftop > top) top = ftop; 285 if (ftop > top) top = ftop;
282 gc_markobj(g, fn); /* Need to mark hidden function (or L). */ 286 if (!LJ_FR2) gc_markobj(g, fn); /* Need to mark hidden function (or L). */
283 } 287 }
284 top++; /* Correct bias of -1 (frame == base-1). */ 288 top++; /* Correct bias of -1 (frame == base-1). */
285 if (top > tvref(th->maxstack)) top = tvref(th->maxstack); 289 if (top > tvref(th->maxstack)) top = tvref(th->maxstack);
@@ -290,7 +294,7 @@ static MSize gc_traverse_frames(global_State *g, lua_State *th)
290static void gc_traverse_thread(global_State *g, lua_State *th) 294static void gc_traverse_thread(global_State *g, lua_State *th)
291{ 295{
292 TValue *o, *top = th->top; 296 TValue *o, *top = th->top;
293 for (o = tvref(th->stack)+1; o < top; o++) 297 for (o = tvref(th->stack)+1+LJ_FR2; o < top; o++)
294 gc_marktv(g, o); 298 gc_marktv(g, o);
295 if (g->gc.state == GCSatomic) { 299 if (g->gc.state == GCSatomic) {
296 top = tvref(th->stack) + th->stacksize; 300 top = tvref(th->stack) + th->stacksize;
@@ -355,15 +359,6 @@ static size_t gc_propagate_gray(global_State *g)
355 359
356/* -- Sweep phase --------------------------------------------------------- */ 360/* -- Sweep phase --------------------------------------------------------- */
357 361
358/* Try to shrink some common data structures. */
359static void gc_shrink(global_State *g, lua_State *L)
360{
361 if (g->strnum <= (g->strmask >> 2) && g->strmask > LJ_MIN_STRTAB*2-1)
362 lj_str_resize(L, g->strmask >> 1); /* Shrink string table. */
363 if (g->tmpbuf.sz > LJ_MIN_SBUF*2)
364 lj_str_resizebuf(L, &g->tmpbuf, g->tmpbuf.sz >> 1); /* Shrink temp buf. */
365}
366
367/* Type of GC free functions. */ 362/* Type of GC free functions. */
368typedef void (LJ_FASTCALL *GCFreeFunc)(global_State *g, GCobj *o); 363typedef void (LJ_FASTCALL *GCFreeFunc)(global_State *g, GCobj *o);
369 364
@@ -389,7 +384,7 @@ static const GCFreeFunc gc_freefunc[] = {
389}; 384};
390 385
391/* Full sweep of a GC list. */ 386/* Full sweep of a GC list. */
392#define gc_fullsweep(g, p) gc_sweep(g, (p), LJ_MAX_MEM) 387#define gc_fullsweep(g, p) gc_sweep(g, (p), ~(uint32_t)0)
393 388
394/* Partial sweep of a GC list. */ 389/* Partial sweep of a GC list. */
395static GCRef *gc_sweep(global_State *g, GCRef *p, uint32_t lim) 390static GCRef *gc_sweep(global_State *g, GCRef *p, uint32_t lim)
@@ -467,18 +462,21 @@ static void gc_call_finalizer(global_State *g, lua_State *L,
467{ 462{
468 /* Save and restore lots of state around the __gc callback. */ 463 /* Save and restore lots of state around the __gc callback. */
469 uint8_t oldh = hook_save(g); 464 uint8_t oldh = hook_save(g);
470 MSize oldt = g->gc.threshold; 465 GCSize oldt = g->gc.threshold;
471 int errcode; 466 int errcode;
472 TValue *top; 467 TValue *top;
473 lj_trace_abort(g); 468 lj_trace_abort(g);
474 top = L->top;
475 L->top = top+2;
476 hook_entergc(g); /* Disable hooks and new traces during __gc. */ 469 hook_entergc(g); /* Disable hooks and new traces during __gc. */
470 if (LJ_HASPROFILE && (oldh & HOOK_PROFILE)) lj_dispatch_update(g);
477 g->gc.threshold = LJ_MAX_MEM; /* Prevent GC steps. */ 471 g->gc.threshold = LJ_MAX_MEM; /* Prevent GC steps. */
478 copyTV(L, top, mo); 472 top = L->top;
479 setgcV(L, top+1, o, ~o->gch.gct); 473 copyTV(L, top++, mo);
480 errcode = lj_vm_pcall(L, top+1, 1+0, -1); /* Stack: |mo|o| -> | */ 474 if (LJ_FR2) setnilV(top++);
475 setgcV(L, top, o, ~o->gch.gct);
476 L->top = top+1;
477 errcode = lj_vm_pcall(L, top, 1+0, -1); /* Stack: |mo|o| -> | */
481 hook_restore(g, oldh); 478 hook_restore(g, oldh);
479 if (LJ_HASPROFILE && (oldh & HOOK_PROFILE)) lj_dispatch_update(g);
482 g->gc.threshold = oldt; /* Restore GC threshold. */ 480 g->gc.threshold = oldt; /* Restore GC threshold. */
483 if (errcode) 481 if (errcode)
484 lj_err_throw(L, errcode); /* Propagate errors. */ 482 lj_err_throw(L, errcode); /* Propagate errors. */
@@ -490,7 +488,7 @@ static void gc_finalize(lua_State *L)
490 global_State *g = G(L); 488 global_State *g = G(L);
491 GCobj *o = gcnext(gcref(g->gc.mmudata)); 489 GCobj *o = gcnext(gcref(g->gc.mmudata));
492 cTValue *mo; 490 cTValue *mo;
493 lua_assert(gcref(g->jit_L) == NULL); /* Must not be called on trace. */ 491 lua_assert(tvref(g->jit_base) == NULL); /* Must not be called on trace. */
494 /* Unchain from list of userdata to be finalized. */ 492 /* Unchain from list of userdata to be finalized. */
495 if (o == gcref(g->gc.mmudata)) 493 if (o == gcref(g->gc.mmudata))
496 setgcrefnull(g->gc.mmudata); 494 setgcrefnull(g->gc.mmudata);
@@ -599,11 +597,13 @@ static void atomic(global_State *g, lua_State *L)
599 /* All marking done, clear weak tables. */ 597 /* All marking done, clear weak tables. */
600 gc_clearweak(gcref(g->gc.weak)); 598 gc_clearweak(gcref(g->gc.weak));
601 599
600 lj_buf_shrink(L, &g->tmpbuf); /* Shrink temp buffer. */
601
602 /* Prepare for sweep phase. */ 602 /* Prepare for sweep phase. */
603 g->gc.currentwhite = (uint8_t)otherwhite(g); /* Flip current white. */ 603 g->gc.currentwhite = (uint8_t)otherwhite(g); /* Flip current white. */
604 g->strempty.marked = g->gc.currentwhite; 604 g->strempty.marked = g->gc.currentwhite;
605 setmref(g->gc.sweep, &g->gc.root); 605 setmref(g->gc.sweep, &g->gc.root);
606 g->gc.estimate = g->gc.total - (MSize)udsize; /* Initial estimate. */ 606 g->gc.estimate = g->gc.total - (GCSize)udsize; /* Initial estimate. */
607} 607}
608 608
609/* GC state machine. Returns a cost estimate for each step performed. */ 609/* GC state machine. Returns a cost estimate for each step performed. */
@@ -620,14 +620,14 @@ static size_t gc_onestep(lua_State *L)
620 g->gc.state = GCSatomic; /* End of mark phase. */ 620 g->gc.state = GCSatomic; /* End of mark phase. */
621 return 0; 621 return 0;
622 case GCSatomic: 622 case GCSatomic:
623 if (gcref(g->jit_L)) /* Don't run atomic phase on trace. */ 623 if (tvref(g->jit_base)) /* Don't run atomic phase on trace. */
624 return LJ_MAX_MEM; 624 return LJ_MAX_MEM;
625 atomic(g, L); 625 atomic(g, L);
626 g->gc.state = GCSsweepstring; /* Start of sweep phase. */ 626 g->gc.state = GCSsweepstring; /* Start of sweep phase. */
627 g->gc.sweepstr = 0; 627 g->gc.sweepstr = 0;
628 return 0; 628 return 0;
629 case GCSsweepstring: { 629 case GCSsweepstring: {
630 MSize old = g->gc.total; 630 GCSize old = g->gc.total;
631 gc_fullsweep(g, &g->strhash[g->gc.sweepstr++]); /* Sweep one chain. */ 631 gc_fullsweep(g, &g->strhash[g->gc.sweepstr++]); /* Sweep one chain. */
632 if (g->gc.sweepstr > g->strmask) 632 if (g->gc.sweepstr > g->strmask)
633 g->gc.state = GCSsweep; /* All string hash chains sweeped. */ 633 g->gc.state = GCSsweep; /* All string hash chains sweeped. */
@@ -636,12 +636,13 @@ static size_t gc_onestep(lua_State *L)
636 return GCSWEEPCOST; 636 return GCSWEEPCOST;
637 } 637 }
638 case GCSsweep: { 638 case GCSsweep: {
639 MSize old = g->gc.total; 639 GCSize old = g->gc.total;
640 setmref(g->gc.sweep, gc_sweep(g, mref(g->gc.sweep, GCRef), GCSWEEPMAX)); 640 setmref(g->gc.sweep, gc_sweep(g, mref(g->gc.sweep, GCRef), GCSWEEPMAX));
641 lua_assert(old >= g->gc.total); 641 lua_assert(old >= g->gc.total);
642 g->gc.estimate -= old - g->gc.total; 642 g->gc.estimate -= old - g->gc.total;
643 if (gcref(*mref(g->gc.sweep, GCRef)) == NULL) { 643 if (gcref(*mref(g->gc.sweep, GCRef)) == NULL) {
644 gc_shrink(g, L); 644 if (g->strnum <= (g->strmask >> 2) && g->strmask > LJ_MIN_STRTAB*2-1)
645 lj_str_resize(L, g->strmask >> 1); /* Shrink string table. */
645 if (gcref(g->gc.mmudata)) { /* Need any finalizations? */ 646 if (gcref(g->gc.mmudata)) { /* Need any finalizations? */
646 g->gc.state = GCSfinalize; 647 g->gc.state = GCSfinalize;
647#if LJ_HASFFI 648#if LJ_HASFFI
@@ -656,7 +657,7 @@ static size_t gc_onestep(lua_State *L)
656 } 657 }
657 case GCSfinalize: 658 case GCSfinalize:
658 if (gcref(g->gc.mmudata) != NULL) { 659 if (gcref(g->gc.mmudata) != NULL) {
659 if (gcref(g->jit_L)) /* Don't call finalizers on trace. */ 660 if (tvref(g->jit_base)) /* Don't call finalizers on trace. */
660 return LJ_MAX_MEM; 661 return LJ_MAX_MEM;
661 gc_finalize(L); /* Finalize one userdata object. */ 662 gc_finalize(L); /* Finalize one userdata object. */
662 if (g->gc.estimate > GCFINALIZECOST) 663 if (g->gc.estimate > GCFINALIZECOST)
@@ -679,7 +680,7 @@ static size_t gc_onestep(lua_State *L)
679int LJ_FASTCALL lj_gc_step(lua_State *L) 680int LJ_FASTCALL lj_gc_step(lua_State *L)
680{ 681{
681 global_State *g = G(L); 682 global_State *g = G(L);
682 MSize lim; 683 GCSize lim;
683 int32_t ostate = g->vmstate; 684 int32_t ostate = g->vmstate;
684 setvmstate(g, GC); 685 setvmstate(g, GC);
685 lim = (GCSTEPSIZE/100) * g->gc.stepmul; 686 lim = (GCSTEPSIZE/100) * g->gc.stepmul;
@@ -688,13 +689,13 @@ int LJ_FASTCALL lj_gc_step(lua_State *L)
688 if (g->gc.total > g->gc.threshold) 689 if (g->gc.total > g->gc.threshold)
689 g->gc.debt += g->gc.total - g->gc.threshold; 690 g->gc.debt += g->gc.total - g->gc.threshold;
690 do { 691 do {
691 lim -= (MSize)gc_onestep(L); 692 lim -= (GCSize)gc_onestep(L);
692 if (g->gc.state == GCSpause) { 693 if (g->gc.state == GCSpause) {
693 g->gc.threshold = (g->gc.estimate/100) * g->gc.pause; 694 g->gc.threshold = (g->gc.estimate/100) * g->gc.pause;
694 g->vmstate = ostate; 695 g->vmstate = ostate;
695 return 1; /* Finished a GC cycle. */ 696 return 1; /* Finished a GC cycle. */
696 } 697 }
697 } while ((int32_t)lim > 0); 698 } while (sizeof(lim) == 8 ? ((int64_t)lim > 0) : ((int32_t)lim > 0));
698 if (g->gc.debt < GCSTEPSIZE) { 699 if (g->gc.debt < GCSTEPSIZE) {
699 g->gc.threshold = g->gc.total + GCSTEPSIZE; 700 g->gc.threshold = g->gc.total + GCSTEPSIZE;
700 g->vmstate = ostate; 701 g->vmstate = ostate;
@@ -718,8 +719,8 @@ void LJ_FASTCALL lj_gc_step_fixtop(lua_State *L)
718/* Perform multiple GC steps. Called from JIT-compiled code. */ 719/* Perform multiple GC steps. Called from JIT-compiled code. */
719int LJ_FASTCALL lj_gc_step_jit(global_State *g, MSize steps) 720int LJ_FASTCALL lj_gc_step_jit(global_State *g, MSize steps)
720{ 721{
721 lua_State *L = gco2th(gcref(g->jit_L)); 722 lua_State *L = gco2th(gcref(g->cur_L));
722 L->base = mref(G(L)->jit_base, TValue); 723 L->base = tvref(G(L)->jit_base);
723 L->top = curr_topL(L); 724 L->top = curr_topL(L);
724 while (steps-- > 0 && lj_gc_step(L) == 0) 725 while (steps-- > 0 && lj_gc_step(L) == 0)
725 ; 726 ;
@@ -813,7 +814,7 @@ void lj_gc_barriertrace(global_State *g, uint32_t traceno)
813/* -- Allocator ----------------------------------------------------------- */ 814/* -- Allocator ----------------------------------------------------------- */
814 815
815/* Call pluggable memory allocator to allocate or resize a fragment. */ 816/* Call pluggable memory allocator to allocate or resize a fragment. */
816void *lj_mem_realloc(lua_State *L, void *p, MSize osz, MSize nsz) 817void *lj_mem_realloc(lua_State *L, void *p, GCSize osz, GCSize nsz)
817{ 818{
818 global_State *g = G(L); 819 global_State *g = G(L);
819 lua_assert((osz == 0) == (p == NULL)); 820 lua_assert((osz == 0) == (p == NULL));
@@ -821,19 +822,19 @@ void *lj_mem_realloc(lua_State *L, void *p, MSize osz, MSize nsz)
821 if (p == NULL && nsz > 0) 822 if (p == NULL && nsz > 0)
822 lj_err_mem(L); 823 lj_err_mem(L);
823 lua_assert((nsz == 0) == (p == NULL)); 824 lua_assert((nsz == 0) == (p == NULL));
824 lua_assert(checkptr32(p)); 825 lua_assert(checkptrGC(p));
825 g->gc.total = (g->gc.total - osz) + nsz; 826 g->gc.total = (g->gc.total - osz) + nsz;
826 return p; 827 return p;
827} 828}
828 829
829/* Allocate new GC object and link it to the root set. */ 830/* Allocate new GC object and link it to the root set. */
830void * LJ_FASTCALL lj_mem_newgco(lua_State *L, MSize size) 831void * LJ_FASTCALL lj_mem_newgco(lua_State *L, GCSize size)
831{ 832{
832 global_State *g = G(L); 833 global_State *g = G(L);
833 GCobj *o = (GCobj *)g->allocf(g->allocd, NULL, 0, size); 834 GCobj *o = (GCobj *)g->allocf(g->allocd, NULL, 0, size);
834 if (o == NULL) 835 if (o == NULL)
835 lj_err_mem(L); 836 lj_err_mem(L);
836 lua_assert(checkptr32(o)); 837 lua_assert(checkptrGC(o));
837 g->gc.total += size; 838 g->gc.total += size;
838 setgcrefr(o->gch.nextgc, g->gc.root); 839 setgcrefr(o->gch.nextgc, g->gc.root);
839 setgcref(g->gc.root, o); 840 setgcref(g->gc.root, o);