diff options
Diffstat (limited to '')
-rw-r--r-- | src/lj_gc.c | 72 |
1 files changed, 43 insertions, 29 deletions
diff --git a/src/lj_gc.c b/src/lj_gc.c index 81439aab..671b5983 100644 --- a/src/lj_gc.c +++ b/src/lj_gc.c | |||
@@ -42,7 +42,8 @@ | |||
42 | 42 | ||
43 | /* Mark a TValue (if needed). */ | 43 | /* Mark a TValue (if needed). */ |
44 | #define gc_marktv(g, tv) \ | 44 | #define gc_marktv(g, tv) \ |
45 | { lua_assert(!tvisgcv(tv) || (~itype(tv) == gcval(tv)->gch.gct)); \ | 45 | { lj_assertG(!tvisgcv(tv) || (~itype(tv) == gcval(tv)->gch.gct), \ |
46 | "TValue and GC type mismatch"); \ | ||
46 | if (tviswhite(tv)) gc_mark(g, gcV(tv)); } | 47 | if (tviswhite(tv)) gc_mark(g, gcV(tv)); } |
47 | 48 | ||
48 | /* Mark a GCobj (if needed). */ | 49 | /* Mark a GCobj (if needed). */ |
@@ -56,7 +57,8 @@ | |||
56 | static void gc_mark(global_State *g, GCobj *o) | 57 | static void gc_mark(global_State *g, GCobj *o) |
57 | { | 58 | { |
58 | int gct = o->gch.gct; | 59 | int gct = o->gch.gct; |
59 | lua_assert(iswhite(o) && !isdead(g, o)); | 60 | lj_assertG(iswhite(o), "mark of non-white object"); |
61 | lj_assertG(!isdead(g, o), "mark of dead object"); | ||
60 | white2gray(o); | 62 | white2gray(o); |
61 | if (LJ_UNLIKELY(gct == ~LJ_TUDATA)) { | 63 | if (LJ_UNLIKELY(gct == ~LJ_TUDATA)) { |
62 | GCtab *mt = tabref(gco2ud(o)->metatable); | 64 | GCtab *mt = tabref(gco2ud(o)->metatable); |
@@ -69,8 +71,9 @@ static void gc_mark(global_State *g, GCobj *o) | |||
69 | if (uv->closed) | 71 | if (uv->closed) |
70 | gray2black(o); /* Closed upvalues are never gray. */ | 72 | gray2black(o); /* Closed upvalues are never gray. */ |
71 | } else if (gct != ~LJ_TSTR && gct != ~LJ_TCDATA) { | 73 | } else if (gct != ~LJ_TSTR && gct != ~LJ_TCDATA) { |
72 | lua_assert(gct == ~LJ_TFUNC || gct == ~LJ_TTAB || | 74 | lj_assertG(gct == ~LJ_TFUNC || gct == ~LJ_TTAB || |
73 | gct == ~LJ_TTHREAD || gct == ~LJ_TPROTO || gct == ~LJ_TTRACE); | 75 | gct == ~LJ_TTHREAD || gct == ~LJ_TPROTO || gct == ~LJ_TTRACE, |
76 | "bad GC type %d", gct); | ||
74 | setgcrefr(o->gch.gclist, g->gc.gray); | 77 | setgcrefr(o->gch.gclist, g->gc.gray); |
75 | setgcref(g->gc.gray, o); | 78 | setgcref(g->gc.gray, o); |
76 | } | 79 | } |
@@ -103,7 +106,8 @@ static void gc_mark_uv(global_State *g) | |||
103 | { | 106 | { |
104 | GCupval *uv; | 107 | GCupval *uv; |
105 | for (uv = uvnext(&g->uvhead); uv != &g->uvhead; uv = uvnext(uv)) { | 108 | for (uv = uvnext(&g->uvhead); uv != &g->uvhead; uv = uvnext(uv)) { |
106 | lua_assert(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv); | 109 | lj_assertG(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv, |
110 | "broken upvalue chain"); | ||
107 | if (isgray(obj2gco(uv))) | 111 | if (isgray(obj2gco(uv))) |
108 | gc_marktv(g, uvval(uv)); | 112 | gc_marktv(g, uvval(uv)); |
109 | } | 113 | } |
@@ -198,7 +202,7 @@ static int gc_traverse_tab(global_State *g, GCtab *t) | |||
198 | for (i = 0; i <= hmask; i++) { | 202 | for (i = 0; i <= hmask; i++) { |
199 | Node *n = &node[i]; | 203 | Node *n = &node[i]; |
200 | if (!tvisnil(&n->val)) { /* Mark non-empty slot. */ | 204 | if (!tvisnil(&n->val)) { /* Mark non-empty slot. */ |
201 | lua_assert(!tvisnil(&n->key)); | 205 | lj_assertG(!tvisnil(&n->key), "mark of nil key in non-empty slot"); |
202 | if (!(weak & LJ_GC_WEAKKEY)) gc_marktv(g, &n->key); | 206 | if (!(weak & LJ_GC_WEAKKEY)) gc_marktv(g, &n->key); |
203 | if (!(weak & LJ_GC_WEAKVAL)) gc_marktv(g, &n->val); | 207 | if (!(weak & LJ_GC_WEAKVAL)) gc_marktv(g, &n->val); |
204 | } | 208 | } |
@@ -213,7 +217,8 @@ static void gc_traverse_func(global_State *g, GCfunc *fn) | |||
213 | gc_markobj(g, tabref(fn->c.env)); | 217 | gc_markobj(g, tabref(fn->c.env)); |
214 | if (isluafunc(fn)) { | 218 | if (isluafunc(fn)) { |
215 | uint32_t i; | 219 | uint32_t i; |
216 | lua_assert(fn->l.nupvalues <= funcproto(fn)->sizeuv); | 220 | lj_assertG(fn->l.nupvalues <= funcproto(fn)->sizeuv, |
221 | "function upvalues out of range"); | ||
217 | gc_markobj(g, funcproto(fn)); | 222 | gc_markobj(g, funcproto(fn)); |
218 | for (i = 0; i < fn->l.nupvalues; i++) /* Mark Lua function upvalues. */ | 223 | for (i = 0; i < fn->l.nupvalues; i++) /* Mark Lua function upvalues. */ |
219 | gc_markobj(g, &gcref(fn->l.uvptr[i])->uv); | 224 | gc_markobj(g, &gcref(fn->l.uvptr[i])->uv); |
@@ -229,7 +234,7 @@ static void gc_traverse_func(global_State *g, GCfunc *fn) | |||
229 | static void gc_marktrace(global_State *g, TraceNo traceno) | 234 | static void gc_marktrace(global_State *g, TraceNo traceno) |
230 | { | 235 | { |
231 | GCobj *o = obj2gco(traceref(G2J(g), traceno)); | 236 | GCobj *o = obj2gco(traceref(G2J(g), traceno)); |
232 | lua_assert(traceno != G2J(g)->cur.traceno); | 237 | lj_assertG(traceno != G2J(g)->cur.traceno, "active trace escaped"); |
233 | if (iswhite(o)) { | 238 | if (iswhite(o)) { |
234 | white2gray(o); | 239 | white2gray(o); |
235 | setgcrefr(o->gch.gclist, g->gc.gray); | 240 | setgcrefr(o->gch.gclist, g->gc.gray); |
@@ -310,7 +315,7 @@ static size_t propagatemark(global_State *g) | |||
310 | { | 315 | { |
311 | GCobj *o = gcref(g->gc.gray); | 316 | GCobj *o = gcref(g->gc.gray); |
312 | int gct = o->gch.gct; | 317 | int gct = o->gch.gct; |
313 | lua_assert(isgray(o)); | 318 | lj_assertG(isgray(o), "propagation of non-gray object"); |
314 | gray2black(o); | 319 | gray2black(o); |
315 | setgcrefr(g->gc.gray, o->gch.gclist); /* Remove from gray list. */ | 320 | setgcrefr(g->gc.gray, o->gch.gclist); /* Remove from gray list. */ |
316 | if (LJ_LIKELY(gct == ~LJ_TTAB)) { | 321 | if (LJ_LIKELY(gct == ~LJ_TTAB)) { |
@@ -342,7 +347,7 @@ static size_t propagatemark(global_State *g) | |||
342 | return ((sizeof(GCtrace)+7)&~7) + (T->nins-T->nk)*sizeof(IRIns) + | 347 | return ((sizeof(GCtrace)+7)&~7) + (T->nins-T->nk)*sizeof(IRIns) + |
343 | T->nsnap*sizeof(SnapShot) + T->nsnapmap*sizeof(SnapEntry); | 348 | T->nsnap*sizeof(SnapShot) + T->nsnapmap*sizeof(SnapEntry); |
344 | #else | 349 | #else |
345 | lua_assert(0); | 350 | lj_assertG(0, "bad GC type %d", gct); |
346 | return 0; | 351 | return 0; |
347 | #endif | 352 | #endif |
348 | } | 353 | } |
@@ -396,11 +401,13 @@ static GCRef *gc_sweep(global_State *g, GCRef *p, uint32_t lim) | |||
396 | if (o->gch.gct == ~LJ_TTHREAD) /* Need to sweep open upvalues, too. */ | 401 | if (o->gch.gct == ~LJ_TTHREAD) /* Need to sweep open upvalues, too. */ |
397 | gc_fullsweep(g, &gco2th(o)->openupval); | 402 | gc_fullsweep(g, &gco2th(o)->openupval); |
398 | if (((o->gch.marked ^ LJ_GC_WHITES) & ow)) { /* Black or current white? */ | 403 | if (((o->gch.marked ^ LJ_GC_WHITES) & ow)) { /* Black or current white? */ |
399 | lua_assert(!isdead(g, o) || (o->gch.marked & LJ_GC_FIXED)); | 404 | lj_assertG(!isdead(g, o) || (o->gch.marked & LJ_GC_FIXED), |
405 | "sweep of undead object"); | ||
400 | makewhite(g, o); /* Value is alive, change to the current white. */ | 406 | makewhite(g, o); /* Value is alive, change to the current white. */ |
401 | p = &o->gch.nextgc; | 407 | p = &o->gch.nextgc; |
402 | } else { /* Otherwise value is dead, free it. */ | 408 | } else { /* Otherwise value is dead, free it. */ |
403 | lua_assert(isdead(g, o) || ow == LJ_GC_SFIXED); | 409 | lj_assertG(isdead(g, o) || ow == LJ_GC_SFIXED, |
410 | "sweep of unlive object"); | ||
404 | setgcrefr(*p, o->gch.nextgc); | 411 | setgcrefr(*p, o->gch.nextgc); |
405 | if (o == gcref(g->gc.root)) | 412 | if (o == gcref(g->gc.root)) |
406 | setgcrefr(g->gc.root, o->gch.nextgc); /* Adjust list anchor. */ | 413 | setgcrefr(g->gc.root, o->gch.nextgc); /* Adjust list anchor. */ |
@@ -427,11 +434,12 @@ static int gc_mayclear(cTValue *o, int val) | |||
427 | } | 434 | } |
428 | 435 | ||
429 | /* Clear collected entries from weak tables. */ | 436 | /* Clear collected entries from weak tables. */ |
430 | static void gc_clearweak(GCobj *o) | 437 | static void gc_clearweak(global_State *g, GCobj *o) |
431 | { | 438 | { |
439 | UNUSED(g); | ||
432 | while (o) { | 440 | while (o) { |
433 | GCtab *t = gco2tab(o); | 441 | GCtab *t = gco2tab(o); |
434 | lua_assert((t->marked & LJ_GC_WEAK)); | 442 | lj_assertG((t->marked & LJ_GC_WEAK), "clear of non-weak table"); |
435 | if ((t->marked & LJ_GC_WEAKVAL)) { | 443 | if ((t->marked & LJ_GC_WEAKVAL)) { |
436 | MSize i, asize = t->asize; | 444 | MSize i, asize = t->asize; |
437 | for (i = 0; i < asize; i++) { | 445 | for (i = 0; i < asize; i++) { |
@@ -488,7 +496,7 @@ static void gc_finalize(lua_State *L) | |||
488 | global_State *g = G(L); | 496 | global_State *g = G(L); |
489 | GCobj *o = gcnext(gcref(g->gc.mmudata)); | 497 | GCobj *o = gcnext(gcref(g->gc.mmudata)); |
490 | cTValue *mo; | 498 | cTValue *mo; |
491 | lua_assert(tvref(g->jit_base) == NULL); /* Must not be called on trace. */ | 499 | lj_assertG(tvref(g->jit_base) == NULL, "finalizer called on trace"); |
492 | /* Unchain from list of userdata to be finalized. */ | 500 | /* Unchain from list of userdata to be finalized. */ |
493 | if (o == gcref(g->gc.mmudata)) | 501 | if (o == gcref(g->gc.mmudata)) |
494 | setgcrefnull(g->gc.mmudata); | 502 | setgcrefnull(g->gc.mmudata); |
@@ -580,7 +588,7 @@ static void atomic(global_State *g, lua_State *L) | |||
580 | 588 | ||
581 | setgcrefr(g->gc.gray, g->gc.weak); /* Empty the list of weak tables. */ | 589 | setgcrefr(g->gc.gray, g->gc.weak); /* Empty the list of weak tables. */ |
582 | setgcrefnull(g->gc.weak); | 590 | setgcrefnull(g->gc.weak); |
583 | lua_assert(!iswhite(obj2gco(mainthread(g)))); | 591 | lj_assertG(!iswhite(obj2gco(mainthread(g))), "main thread turned white"); |
584 | gc_markobj(g, L); /* Mark running thread. */ | 592 | gc_markobj(g, L); /* Mark running thread. */ |
585 | gc_traverse_curtrace(g); /* Traverse current trace. */ | 593 | gc_traverse_curtrace(g); /* Traverse current trace. */ |
586 | gc_mark_gcroot(g); /* Mark GC roots (again). */ | 594 | gc_mark_gcroot(g); /* Mark GC roots (again). */ |
@@ -595,7 +603,7 @@ static void atomic(global_State *g, lua_State *L) | |||
595 | udsize += gc_propagate_gray(g); /* And propagate the marks. */ | 603 | udsize += gc_propagate_gray(g); /* And propagate the marks. */ |
596 | 604 | ||
597 | /* All marking done, clear weak tables. */ | 605 | /* All marking done, clear weak tables. */ |
598 | gc_clearweak(gcref(g->gc.weak)); | 606 | gc_clearweak(g, gcref(g->gc.weak)); |
599 | 607 | ||
600 | lj_buf_shrink(L, &g->tmpbuf); /* Shrink temp buffer. */ | 608 | lj_buf_shrink(L, &g->tmpbuf); /* Shrink temp buffer. */ |
601 | 609 | ||
@@ -631,14 +639,14 @@ static size_t gc_onestep(lua_State *L) | |||
631 | gc_fullsweep(g, &g->strhash[g->gc.sweepstr++]); /* Sweep one chain. */ | 639 | gc_fullsweep(g, &g->strhash[g->gc.sweepstr++]); /* Sweep one chain. */ |
632 | if (g->gc.sweepstr > g->strmask) | 640 | if (g->gc.sweepstr > g->strmask) |
633 | g->gc.state = GCSsweep; /* All string hash chains sweeped. */ | 641 | g->gc.state = GCSsweep; /* All string hash chains sweeped. */ |
634 | lua_assert(old >= g->gc.total); | 642 | lj_assertG(old >= g->gc.total, "sweep increased memory"); |
635 | g->gc.estimate -= old - g->gc.total; | 643 | g->gc.estimate -= old - g->gc.total; |
636 | return GCSWEEPCOST; | 644 | return GCSWEEPCOST; |
637 | } | 645 | } |
638 | case GCSsweep: { | 646 | case GCSsweep: { |
639 | GCSize old = g->gc.total; | 647 | GCSize old = g->gc.total; |
640 | setmref(g->gc.sweep, gc_sweep(g, mref(g->gc.sweep, GCRef), GCSWEEPMAX)); | 648 | setmref(g->gc.sweep, gc_sweep(g, mref(g->gc.sweep, GCRef), GCSWEEPMAX)); |
641 | lua_assert(old >= g->gc.total); | 649 | lj_assertG(old >= g->gc.total, "sweep increased memory"); |
642 | g->gc.estimate -= old - g->gc.total; | 650 | g->gc.estimate -= old - g->gc.total; |
643 | if (gcref(*mref(g->gc.sweep, GCRef)) == NULL) { | 651 | if (gcref(*mref(g->gc.sweep, GCRef)) == NULL) { |
644 | if (g->strnum <= (g->strmask >> 2) && g->strmask > LJ_MIN_STRTAB*2-1) | 652 | if (g->strnum <= (g->strmask >> 2) && g->strmask > LJ_MIN_STRTAB*2-1) |
@@ -671,7 +679,7 @@ static size_t gc_onestep(lua_State *L) | |||
671 | g->gc.debt = 0; | 679 | g->gc.debt = 0; |
672 | return 0; | 680 | return 0; |
673 | default: | 681 | default: |
674 | lua_assert(0); | 682 | lj_assertG(0, "bad GC state"); |
675 | return 0; | 683 | return 0; |
676 | } | 684 | } |
677 | } | 685 | } |
@@ -745,7 +753,8 @@ void lj_gc_fullgc(lua_State *L) | |||
745 | } | 753 | } |
746 | while (g->gc.state == GCSsweepstring || g->gc.state == GCSsweep) | 754 | while (g->gc.state == GCSsweepstring || g->gc.state == GCSsweep) |
747 | gc_onestep(L); /* Finish sweep. */ | 755 | gc_onestep(L); /* Finish sweep. */ |
748 | lua_assert(g->gc.state == GCSfinalize || g->gc.state == GCSpause); | 756 | lj_assertG(g->gc.state == GCSfinalize || g->gc.state == GCSpause, |
757 | "bad GC state"); | ||
749 | /* Now perform a full GC. */ | 758 | /* Now perform a full GC. */ |
750 | g->gc.state = GCSpause; | 759 | g->gc.state = GCSpause; |
751 | do { gc_onestep(L); } while (g->gc.state != GCSpause); | 760 | do { gc_onestep(L); } while (g->gc.state != GCSpause); |
@@ -758,9 +767,11 @@ void lj_gc_fullgc(lua_State *L) | |||
758 | /* Move the GC propagation frontier forward. */ | 767 | /* Move the GC propagation frontier forward. */ |
759 | void lj_gc_barrierf(global_State *g, GCobj *o, GCobj *v) | 768 | void lj_gc_barrierf(global_State *g, GCobj *o, GCobj *v) |
760 | { | 769 | { |
761 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); | 770 | lj_assertG(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o), |
762 | lua_assert(g->gc.state != GCSfinalize && g->gc.state != GCSpause); | 771 | "bad object states for forward barrier"); |
763 | lua_assert(o->gch.gct != ~LJ_TTAB); | 772 | lj_assertG(g->gc.state != GCSfinalize && g->gc.state != GCSpause, |
773 | "bad GC state"); | ||
774 | lj_assertG(o->gch.gct != ~LJ_TTAB, "barrier object is not a table"); | ||
764 | /* Preserve invariant during propagation. Otherwise it doesn't matter. */ | 775 | /* Preserve invariant during propagation. Otherwise it doesn't matter. */ |
765 | if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic) | 776 | if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic) |
766 | gc_mark(g, v); /* Move frontier forward. */ | 777 | gc_mark(g, v); /* Move frontier forward. */ |
@@ -797,7 +808,8 @@ void lj_gc_closeuv(global_State *g, GCupval *uv) | |||
797 | lj_gc_barrierf(g, o, gcV(&uv->tv)); | 808 | lj_gc_barrierf(g, o, gcV(&uv->tv)); |
798 | } else { | 809 | } else { |
799 | makewhite(g, o); /* Make it white, i.e. sweep the upvalue. */ | 810 | makewhite(g, o); /* Make it white, i.e. sweep the upvalue. */ |
800 | lua_assert(g->gc.state != GCSfinalize && g->gc.state != GCSpause); | 811 | lj_assertG(g->gc.state != GCSfinalize && g->gc.state != GCSpause, |
812 | "bad GC state"); | ||
801 | } | 813 | } |
802 | } | 814 | } |
803 | } | 815 | } |
@@ -817,12 +829,13 @@ void lj_gc_barriertrace(global_State *g, uint32_t traceno) | |||
817 | void *lj_mem_realloc(lua_State *L, void *p, GCSize osz, GCSize nsz) | 829 | void *lj_mem_realloc(lua_State *L, void *p, GCSize osz, GCSize nsz) |
818 | { | 830 | { |
819 | global_State *g = G(L); | 831 | global_State *g = G(L); |
820 | lua_assert((osz == 0) == (p == NULL)); | 832 | lj_assertG((osz == 0) == (p == NULL), "realloc API violation"); |
821 | p = g->allocf(g->allocd, p, osz, nsz); | 833 | p = g->allocf(g->allocd, p, osz, nsz); |
822 | if (p == NULL && nsz > 0) | 834 | if (p == NULL && nsz > 0) |
823 | lj_err_mem(L); | 835 | lj_err_mem(L); |
824 | lua_assert((nsz == 0) == (p == NULL)); | 836 | lj_assertG((nsz == 0) == (p == NULL), "allocf API violation"); |
825 | lua_assert(checkptrGC(p)); | 837 | lj_assertG(checkptrGC(p), |
838 | "allocated memory address %p outside required range", p); | ||
826 | g->gc.total = (g->gc.total - osz) + nsz; | 839 | g->gc.total = (g->gc.total - osz) + nsz; |
827 | return p; | 840 | return p; |
828 | } | 841 | } |
@@ -834,7 +847,8 @@ void * LJ_FASTCALL lj_mem_newgco(lua_State *L, GCSize size) | |||
834 | GCobj *o = (GCobj *)g->allocf(g->allocd, NULL, 0, size); | 847 | GCobj *o = (GCobj *)g->allocf(g->allocd, NULL, 0, size); |
835 | if (o == NULL) | 848 | if (o == NULL) |
836 | lj_err_mem(L); | 849 | lj_err_mem(L); |
837 | lua_assert(checkptrGC(o)); | 850 | lj_assertG(checkptrGC(o), |
851 | "allocated memory address %p outside required range", o); | ||
838 | g->gc.total += size; | 852 | g->gc.total += size; |
839 | setgcrefr(o->gch.nextgc, g->gc.root); | 853 | setgcrefr(o->gch.nextgc, g->gc.root); |
840 | setgcref(g->gc.root, o); | 854 | setgcref(g->gc.root, o); |