diff options
Diffstat (limited to 'src/lj_gc.c')
-rw-r--r-- | src/lj_gc.c | 73 |
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) | |||
290 | static void gc_traverse_thread(global_State *g, lua_State *th) | 294 | static 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. */ | ||
359 | static 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. */ |
368 | typedef void (LJ_FASTCALL *GCFreeFunc)(global_State *g, GCobj *o); | 363 | typedef 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. */ |
395 | static GCRef *gc_sweep(global_State *g, GCRef *p, uint32_t lim) | 390 | static 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) | |||
679 | int LJ_FASTCALL lj_gc_step(lua_State *L) | 680 | int 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. */ |
719 | int LJ_FASTCALL lj_gc_step_jit(global_State *g, MSize steps) | 720 | int 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. */ |
816 | void *lj_mem_realloc(lua_State *L, void *p, MSize osz, MSize nsz) | 817 | void *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. */ |
830 | void * LJ_FASTCALL lj_mem_newgco(lua_State *L, MSize size) | 831 | void * 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); |