diff options
Diffstat (limited to '')
-rw-r--r-- | src/lj_gc.c | 68 |
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) | |||
283 | static void gc_traverse_thread(global_State *g, lua_State *th) | 284 | static 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. */ | ||
352 | static 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. */ |
361 | typedef void (LJ_FASTCALL *GCFreeFunc)(global_State *g, GCobj *o); | 353 | typedef 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. */ |
388 | static GCRef *gc_sweep(global_State *g, GCRef *p, uint32_t lim) | 380 | static 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) | |||
672 | int LJ_FASTCALL lj_gc_step(lua_State *L) | 668 | int 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. */ |
712 | int LJ_FASTCALL lj_gc_step_jit(global_State *g, MSize steps) | 708 | int 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. */ |
809 | void *lj_mem_realloc(lua_State *L, void *p, MSize osz, MSize nsz) | 805 | void *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. */ |
823 | void * LJ_FASTCALL lj_mem_newgco(lua_State *L, MSize size) | 819 | void * 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); |