diff options
Diffstat (limited to 'src/lj_gc.c')
-rw-r--r-- | src/lj_gc.c | 193 |
1 files changed, 126 insertions, 67 deletions
diff --git a/src/lj_gc.c b/src/lj_gc.c index 06484f6f..c3a0c258 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,7 +25,9 @@ | |||
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" |
30 | #include "lj_vmevent.h" | ||
28 | 31 | ||
29 | #define GCSTEPSIZE 1024u | 32 | #define GCSTEPSIZE 1024u |
30 | #define GCSWEEPMAX 40 | 33 | #define GCSWEEPMAX 40 |
@@ -40,7 +43,8 @@ | |||
40 | 43 | ||
41 | /* Mark a TValue (if needed). */ | 44 | /* Mark a TValue (if needed). */ |
42 | #define gc_marktv(g, tv) \ | 45 | #define gc_marktv(g, tv) \ |
43 | { lua_assert(!tvisgcv(tv) || (~itype(tv) == gcval(tv)->gch.gct)); \ | 46 | { lj_assertG(!tvisgcv(tv) || (~itype(tv) == gcval(tv)->gch.gct), \ |
47 | "TValue and GC type mismatch"); \ | ||
44 | if (tviswhite(tv)) gc_mark(g, gcV(tv)); } | 48 | if (tviswhite(tv)) gc_mark(g, gcV(tv)); } |
45 | 49 | ||
46 | /* Mark a GCobj (if needed). */ | 50 | /* Mark a GCobj (if needed). */ |
@@ -54,21 +58,32 @@ | |||
54 | static void gc_mark(global_State *g, GCobj *o) | 58 | static void gc_mark(global_State *g, GCobj *o) |
55 | { | 59 | { |
56 | int gct = o->gch.gct; | 60 | int gct = o->gch.gct; |
57 | lua_assert(iswhite(o) && !isdead(g, o)); | 61 | lj_assertG(iswhite(o), "mark of non-white object"); |
62 | lj_assertG(!isdead(g, o), "mark of dead object"); | ||
58 | white2gray(o); | 63 | white2gray(o); |
59 | if (LJ_UNLIKELY(gct == ~LJ_TUDATA)) { | 64 | if (LJ_UNLIKELY(gct == ~LJ_TUDATA)) { |
60 | GCtab *mt = tabref(gco2ud(o)->metatable); | 65 | GCtab *mt = tabref(gco2ud(o)->metatable); |
61 | gray2black(o); /* Userdata are never gray. */ | 66 | gray2black(o); /* Userdata are never gray. */ |
62 | if (mt) gc_markobj(g, mt); | 67 | if (mt) gc_markobj(g, mt); |
63 | gc_markobj(g, tabref(gco2ud(o)->env)); | 68 | gc_markobj(g, tabref(gco2ud(o)->env)); |
69 | if (LJ_HASBUFFER && gco2ud(o)->udtype == UDTYPE_BUFFER) { | ||
70 | SBufExt *sbx = (SBufExt *)uddata(gco2ud(o)); | ||
71 | if (sbufiscow(sbx) && gcref(sbx->cowref)) | ||
72 | gc_markobj(g, gcref(sbx->cowref)); | ||
73 | if (gcref(sbx->dict_str)) | ||
74 | gc_markobj(g, gcref(sbx->dict_str)); | ||
75 | if (gcref(sbx->dict_mt)) | ||
76 | gc_markobj(g, gcref(sbx->dict_mt)); | ||
77 | } | ||
64 | } else if (LJ_UNLIKELY(gct == ~LJ_TUPVAL)) { | 78 | } else if (LJ_UNLIKELY(gct == ~LJ_TUPVAL)) { |
65 | GCupval *uv = gco2uv(o); | 79 | GCupval *uv = gco2uv(o); |
66 | gc_marktv(g, uvval(uv)); | 80 | gc_marktv(g, uvval(uv)); |
67 | if (uv->closed) | 81 | if (uv->closed) |
68 | gray2black(o); /* Closed upvalues are never gray. */ | 82 | gray2black(o); /* Closed upvalues are never gray. */ |
69 | } else if (gct != ~LJ_TSTR && gct != ~LJ_TCDATA) { | 83 | } else if (gct != ~LJ_TSTR && gct != ~LJ_TCDATA) { |
70 | lua_assert(gct == ~LJ_TFUNC || gct == ~LJ_TTAB || | 84 | lj_assertG(gct == ~LJ_TFUNC || gct == ~LJ_TTAB || |
71 | gct == ~LJ_TTHREAD || gct == ~LJ_TPROTO); | 85 | gct == ~LJ_TTHREAD || gct == ~LJ_TPROTO || gct == ~LJ_TTRACE, |
86 | "bad GC type %d", gct); | ||
72 | setgcrefr(o->gch.gclist, g->gc.gray); | 87 | setgcrefr(o->gch.gclist, g->gc.gray); |
73 | setgcref(g->gc.gray, o); | 88 | setgcref(g->gc.gray, o); |
74 | } | 89 | } |
@@ -101,7 +116,8 @@ static void gc_mark_uv(global_State *g) | |||
101 | { | 116 | { |
102 | GCupval *uv; | 117 | GCupval *uv; |
103 | for (uv = uvnext(&g->uvhead); uv != &g->uvhead; uv = uvnext(uv)) { | 118 | for (uv = uvnext(&g->uvhead); uv != &g->uvhead; uv = uvnext(uv)) { |
104 | lua_assert(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv); | 119 | lj_assertG(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv, |
120 | "broken upvalue chain"); | ||
105 | if (isgray(obj2gco(uv))) | 121 | if (isgray(obj2gco(uv))) |
106 | gc_marktv(g, uvval(uv)); | 122 | gc_marktv(g, uvval(uv)); |
107 | } | 123 | } |
@@ -196,7 +212,7 @@ static int gc_traverse_tab(global_State *g, GCtab *t) | |||
196 | for (i = 0; i <= hmask; i++) { | 212 | for (i = 0; i <= hmask; i++) { |
197 | Node *n = &node[i]; | 213 | Node *n = &node[i]; |
198 | if (!tvisnil(&n->val)) { /* Mark non-empty slot. */ | 214 | if (!tvisnil(&n->val)) { /* Mark non-empty slot. */ |
199 | lua_assert(!tvisnil(&n->key)); | 215 | lj_assertG(!tvisnil(&n->key), "mark of nil key in non-empty slot"); |
200 | if (!(weak & LJ_GC_WEAKKEY)) gc_marktv(g, &n->key); | 216 | if (!(weak & LJ_GC_WEAKKEY)) gc_marktv(g, &n->key); |
201 | if (!(weak & LJ_GC_WEAKVAL)) gc_marktv(g, &n->val); | 217 | if (!(weak & LJ_GC_WEAKVAL)) gc_marktv(g, &n->val); |
202 | } | 218 | } |
@@ -211,7 +227,8 @@ static void gc_traverse_func(global_State *g, GCfunc *fn) | |||
211 | gc_markobj(g, tabref(fn->c.env)); | 227 | gc_markobj(g, tabref(fn->c.env)); |
212 | if (isluafunc(fn)) { | 228 | if (isluafunc(fn)) { |
213 | uint32_t i; | 229 | uint32_t i; |
214 | lua_assert(fn->l.nupvalues <= funcproto(fn)->sizeuv); | 230 | lj_assertG(fn->l.nupvalues <= funcproto(fn)->sizeuv, |
231 | "function upvalues out of range"); | ||
215 | gc_markobj(g, funcproto(fn)); | 232 | gc_markobj(g, funcproto(fn)); |
216 | for (i = 0; i < fn->l.nupvalues; i++) /* Mark Lua function upvalues. */ | 233 | for (i = 0; i < fn->l.nupvalues; i++) /* Mark Lua function upvalues. */ |
217 | gc_markobj(g, &gcref(fn->l.uvptr[i])->uv); | 234 | gc_markobj(g, &gcref(fn->l.uvptr[i])->uv); |
@@ -227,7 +244,7 @@ static void gc_traverse_func(global_State *g, GCfunc *fn) | |||
227 | static void gc_marktrace(global_State *g, TraceNo traceno) | 244 | static void gc_marktrace(global_State *g, TraceNo traceno) |
228 | { | 245 | { |
229 | GCobj *o = obj2gco(traceref(G2J(g), traceno)); | 246 | GCobj *o = obj2gco(traceref(G2J(g), traceno)); |
230 | lua_assert(traceno != G2J(g)->cur.traceno); | 247 | lj_assertG(traceno != G2J(g)->cur.traceno, "active trace escaped"); |
231 | if (iswhite(o)) { | 248 | if (iswhite(o)) { |
232 | white2gray(o); | 249 | white2gray(o); |
233 | setgcrefr(o->gch.gclist, g->gc.gray); | 250 | setgcrefr(o->gch.gclist, g->gc.gray); |
@@ -244,6 +261,8 @@ static void gc_traverse_trace(global_State *g, GCtrace *T) | |||
244 | IRIns *ir = &T->ir[ref]; | 261 | IRIns *ir = &T->ir[ref]; |
245 | if (ir->o == IR_KGC) | 262 | if (ir->o == IR_KGC) |
246 | gc_markobj(g, ir_kgc(ir)); | 263 | gc_markobj(g, ir_kgc(ir)); |
264 | if (irt_is64(ir->t) && ir->o != IR_KNULL) | ||
265 | ref++; | ||
247 | } | 266 | } |
248 | if (T->link) gc_marktrace(g, T->link); | 267 | if (T->link) gc_marktrace(g, T->link); |
249 | if (T->nextroot) gc_marktrace(g, T->nextroot); | 268 | if (T->nextroot) gc_marktrace(g, T->nextroot); |
@@ -274,12 +293,12 @@ static MSize gc_traverse_frames(global_State *g, lua_State *th) | |||
274 | { | 293 | { |
275 | TValue *frame, *top = th->top-1, *bot = tvref(th->stack); | 294 | TValue *frame, *top = th->top-1, *bot = tvref(th->stack); |
276 | /* Note: extra vararg frame not skipped, marks function twice (harmless). */ | 295 | /* Note: extra vararg frame not skipped, marks function twice (harmless). */ |
277 | for (frame = th->base-1; frame > bot; frame = frame_prev(frame)) { | 296 | for (frame = th->base-1; frame > bot+LJ_FR2; frame = frame_prev(frame)) { |
278 | GCfunc *fn = frame_func(frame); | 297 | GCfunc *fn = frame_func(frame); |
279 | TValue *ftop = frame; | 298 | TValue *ftop = frame; |
280 | if (isluafunc(fn)) ftop += funcproto(fn)->framesize; | 299 | if (isluafunc(fn)) ftop += funcproto(fn)->framesize; |
281 | if (ftop > top) top = ftop; | 300 | if (ftop > top) top = ftop; |
282 | gc_markobj(g, fn); /* Need to mark hidden function (or L). */ | 301 | if (!LJ_FR2) gc_markobj(g, fn); /* Need to mark hidden function (or L). */ |
283 | } | 302 | } |
284 | top++; /* Correct bias of -1 (frame == base-1). */ | 303 | top++; /* Correct bias of -1 (frame == base-1). */ |
285 | if (top > tvref(th->maxstack)) top = tvref(th->maxstack); | 304 | if (top > tvref(th->maxstack)) top = tvref(th->maxstack); |
@@ -290,7 +309,7 @@ static MSize gc_traverse_frames(global_State *g, lua_State *th) | |||
290 | static void gc_traverse_thread(global_State *g, lua_State *th) | 309 | static void gc_traverse_thread(global_State *g, lua_State *th) |
291 | { | 310 | { |
292 | TValue *o, *top = th->top; | 311 | TValue *o, *top = th->top; |
293 | for (o = tvref(th->stack)+1; o < top; o++) | 312 | for (o = tvref(th->stack)+1+LJ_FR2; o < top; o++) |
294 | gc_marktv(g, o); | 313 | gc_marktv(g, o); |
295 | if (g->gc.state == GCSatomic) { | 314 | if (g->gc.state == GCSatomic) { |
296 | top = tvref(th->stack) + th->stacksize; | 315 | top = tvref(th->stack) + th->stacksize; |
@@ -306,7 +325,7 @@ static size_t propagatemark(global_State *g) | |||
306 | { | 325 | { |
307 | GCobj *o = gcref(g->gc.gray); | 326 | GCobj *o = gcref(g->gc.gray); |
308 | int gct = o->gch.gct; | 327 | int gct = o->gch.gct; |
309 | lua_assert(isgray(o)); | 328 | lj_assertG(isgray(o), "propagation of non-gray object"); |
310 | gray2black(o); | 329 | gray2black(o); |
311 | setgcrefr(g->gc.gray, o->gch.gclist); /* Remove from gray list. */ | 330 | setgcrefr(g->gc.gray, o->gch.gclist); /* Remove from gray list. */ |
312 | if (LJ_LIKELY(gct == ~LJ_TTAB)) { | 331 | if (LJ_LIKELY(gct == ~LJ_TTAB)) { |
@@ -338,7 +357,7 @@ static size_t propagatemark(global_State *g) | |||
338 | return ((sizeof(GCtrace)+7)&~7) + (T->nins-T->nk)*sizeof(IRIns) + | 357 | return ((sizeof(GCtrace)+7)&~7) + (T->nins-T->nk)*sizeof(IRIns) + |
339 | T->nsnap*sizeof(SnapShot) + T->nsnapmap*sizeof(SnapEntry); | 358 | T->nsnap*sizeof(SnapShot) + T->nsnapmap*sizeof(SnapEntry); |
340 | #else | 359 | #else |
341 | lua_assert(0); | 360 | lj_assertG(0, "bad GC type %d", gct); |
342 | return 0; | 361 | return 0; |
343 | #endif | 362 | #endif |
344 | } | 363 | } |
@@ -355,15 +374,6 @@ static size_t gc_propagate_gray(global_State *g) | |||
355 | 374 | ||
356 | /* -- Sweep phase --------------------------------------------------------- */ | 375 | /* -- Sweep phase --------------------------------------------------------- */ |
357 | 376 | ||
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. */ | 377 | /* Type of GC free functions. */ |
368 | typedef void (LJ_FASTCALL *GCFreeFunc)(global_State *g, GCobj *o); | 378 | typedef void (LJ_FASTCALL *GCFreeFunc)(global_State *g, GCobj *o); |
369 | 379 | ||
@@ -389,7 +399,7 @@ static const GCFreeFunc gc_freefunc[] = { | |||
389 | }; | 399 | }; |
390 | 400 | ||
391 | /* Full sweep of a GC list. */ | 401 | /* Full sweep of a GC list. */ |
392 | #define gc_fullsweep(g, p) gc_sweep(g, (p), LJ_MAX_MEM) | 402 | #define gc_fullsweep(g, p) gc_sweep(g, (p), ~(uint32_t)0) |
393 | 403 | ||
394 | /* Partial sweep of a GC list. */ | 404 | /* Partial sweep of a GC list. */ |
395 | static GCRef *gc_sweep(global_State *g, GCRef *p, uint32_t lim) | 405 | static GCRef *gc_sweep(global_State *g, GCRef *p, uint32_t lim) |
@@ -401,11 +411,13 @@ static GCRef *gc_sweep(global_State *g, GCRef *p, uint32_t lim) | |||
401 | if (o->gch.gct == ~LJ_TTHREAD) /* Need to sweep open upvalues, too. */ | 411 | if (o->gch.gct == ~LJ_TTHREAD) /* Need to sweep open upvalues, too. */ |
402 | gc_fullsweep(g, &gco2th(o)->openupval); | 412 | gc_fullsweep(g, &gco2th(o)->openupval); |
403 | if (((o->gch.marked ^ LJ_GC_WHITES) & ow)) { /* Black or current white? */ | 413 | if (((o->gch.marked ^ LJ_GC_WHITES) & ow)) { /* Black or current white? */ |
404 | lua_assert(!isdead(g, o) || (o->gch.marked & LJ_GC_FIXED)); | 414 | lj_assertG(!isdead(g, o) || (o->gch.marked & LJ_GC_FIXED), |
415 | "sweep of undead object"); | ||
405 | makewhite(g, o); /* Value is alive, change to the current white. */ | 416 | makewhite(g, o); /* Value is alive, change to the current white. */ |
406 | p = &o->gch.nextgc; | 417 | p = &o->gch.nextgc; |
407 | } else { /* Otherwise value is dead, free it. */ | 418 | } else { /* Otherwise value is dead, free it. */ |
408 | lua_assert(isdead(g, o) || ow == LJ_GC_SFIXED); | 419 | lj_assertG(isdead(g, o) || ow == LJ_GC_SFIXED, |
420 | "sweep of unlive object"); | ||
409 | setgcrefr(*p, o->gch.nextgc); | 421 | setgcrefr(*p, o->gch.nextgc); |
410 | if (o == gcref(g->gc.root)) | 422 | if (o == gcref(g->gc.root)) |
411 | setgcrefr(g->gc.root, o->gch.nextgc); /* Adjust list anchor. */ | 423 | setgcrefr(g->gc.root, o->gch.nextgc); /* Adjust list anchor. */ |
@@ -415,6 +427,32 @@ static GCRef *gc_sweep(global_State *g, GCRef *p, uint32_t lim) | |||
415 | return p; | 427 | return p; |
416 | } | 428 | } |
417 | 429 | ||
430 | /* Sweep one string interning table chain. Preserves hashalg bit. */ | ||
431 | static void gc_sweepstr(global_State *g, GCRef *chain) | ||
432 | { | ||
433 | /* Mask with other white and LJ_GC_FIXED. Or LJ_GC_SFIXED on shutdown. */ | ||
434 | int ow = otherwhite(g); | ||
435 | uintptr_t u = gcrefu(*chain); | ||
436 | GCRef q; | ||
437 | GCRef *p = &q; | ||
438 | GCobj *o; | ||
439 | setgcrefp(q, (u & ~(uintptr_t)1)); | ||
440 | while ((o = gcref(*p)) != NULL) { | ||
441 | if (((o->gch.marked ^ LJ_GC_WHITES) & ow)) { /* Black or current white? */ | ||
442 | lj_assertG(!isdead(g, o) || (o->gch.marked & LJ_GC_FIXED), | ||
443 | "sweep of undead string"); | ||
444 | makewhite(g, o); /* String is alive, change to the current white. */ | ||
445 | p = &o->gch.nextgc; | ||
446 | } else { /* Otherwise string is dead, free it. */ | ||
447 | lj_assertG(isdead(g, o) || ow == LJ_GC_SFIXED, | ||
448 | "sweep of unlive string"); | ||
449 | setgcrefr(*p, o->gch.nextgc); | ||
450 | lj_str_free(g, gco2str(o)); | ||
451 | } | ||
452 | } | ||
453 | setgcrefp(*chain, (gcrefu(q) | (u & 1))); | ||
454 | } | ||
455 | |||
418 | /* Check whether we can clear a key or a value slot from a table. */ | 456 | /* Check whether we can clear a key or a value slot from a table. */ |
419 | static int gc_mayclear(cTValue *o, int val) | 457 | static int gc_mayclear(cTValue *o, int val) |
420 | { | 458 | { |
@@ -432,11 +470,12 @@ static int gc_mayclear(cTValue *o, int val) | |||
432 | } | 470 | } |
433 | 471 | ||
434 | /* Clear collected entries from weak tables. */ | 472 | /* Clear collected entries from weak tables. */ |
435 | static void gc_clearweak(GCobj *o) | 473 | static void gc_clearweak(global_State *g, GCobj *o) |
436 | { | 474 | { |
475 | UNUSED(g); | ||
437 | while (o) { | 476 | while (o) { |
438 | GCtab *t = gco2tab(o); | 477 | GCtab *t = gco2tab(o); |
439 | lua_assert((t->marked & LJ_GC_WEAK)); | 478 | lj_assertG((t->marked & LJ_GC_WEAK), "clear of non-weak table"); |
440 | if ((t->marked & LJ_GC_WEAKVAL)) { | 479 | if ((t->marked & LJ_GC_WEAKVAL)) { |
441 | MSize i, asize = t->asize; | 480 | MSize i, asize = t->asize; |
442 | for (i = 0; i < asize; i++) { | 481 | for (i = 0; i < asize; i++) { |
@@ -467,21 +506,29 @@ static void gc_call_finalizer(global_State *g, lua_State *L, | |||
467 | { | 506 | { |
468 | /* Save and restore lots of state around the __gc callback. */ | 507 | /* Save and restore lots of state around the __gc callback. */ |
469 | uint8_t oldh = hook_save(g); | 508 | uint8_t oldh = hook_save(g); |
470 | MSize oldt = g->gc.threshold; | 509 | GCSize oldt = g->gc.threshold; |
471 | int errcode; | 510 | int errcode; |
472 | TValue *top; | 511 | TValue *top; |
473 | lj_trace_abort(g); | 512 | lj_trace_abort(g); |
474 | top = L->top; | ||
475 | L->top = top+2; | ||
476 | hook_entergc(g); /* Disable hooks and new traces during __gc. */ | 513 | hook_entergc(g); /* Disable hooks and new traces during __gc. */ |
514 | if (LJ_HASPROFILE && (oldh & HOOK_PROFILE)) lj_dispatch_update(g); | ||
477 | g->gc.threshold = LJ_MAX_MEM; /* Prevent GC steps. */ | 515 | g->gc.threshold = LJ_MAX_MEM; /* Prevent GC steps. */ |
478 | copyTV(L, top, mo); | 516 | top = L->top; |
479 | setgcV(L, top+1, o, ~o->gch.gct); | 517 | copyTV(L, top++, mo); |
480 | errcode = lj_vm_pcall(L, top+1, 1+0, -1); /* Stack: |mo|o| -> | */ | 518 | if (LJ_FR2) setnilV(top++); |
519 | setgcV(L, top, o, ~o->gch.gct); | ||
520 | L->top = top+1; | ||
521 | errcode = lj_vm_pcall(L, top, 1+0, -1); /* Stack: |mo|o| -> | */ | ||
481 | hook_restore(g, oldh); | 522 | hook_restore(g, oldh); |
523 | if (LJ_HASPROFILE && (oldh & HOOK_PROFILE)) lj_dispatch_update(g); | ||
482 | g->gc.threshold = oldt; /* Restore GC threshold. */ | 524 | g->gc.threshold = oldt; /* Restore GC threshold. */ |
483 | if (errcode) | 525 | if (errcode) { |
484 | lj_err_throw(L, errcode); /* Propagate errors. */ | 526 | ptrdiff_t errobj = savestack(L, L->top-1); /* Stack may be resized. */ |
527 | lj_vmevent_send(L, ERRFIN, | ||
528 | copyTV(L, L->top++, restorestack(L, errobj)); | ||
529 | ); | ||
530 | L->top--; | ||
531 | } | ||
485 | } | 532 | } |
486 | 533 | ||
487 | /* Finalize one userdata or cdata object from the mmudata list. */ | 534 | /* Finalize one userdata or cdata object from the mmudata list. */ |
@@ -490,7 +537,7 @@ static void gc_finalize(lua_State *L) | |||
490 | global_State *g = G(L); | 537 | global_State *g = G(L); |
491 | GCobj *o = gcnext(gcref(g->gc.mmudata)); | 538 | GCobj *o = gcnext(gcref(g->gc.mmudata)); |
492 | cTValue *mo; | 539 | cTValue *mo; |
493 | lua_assert(gcref(g->jit_L) == NULL); /* Must not be called on trace. */ | 540 | lj_assertG(tvref(g->jit_base) == NULL, "finalizer called on trace"); |
494 | /* Unchain from list of userdata to be finalized. */ | 541 | /* Unchain from list of userdata to be finalized. */ |
495 | if (o == gcref(g->gc.mmudata)) | 542 | if (o == gcref(g->gc.mmudata)) |
496 | setgcrefnull(g->gc.mmudata); | 543 | setgcrefnull(g->gc.mmudata); |
@@ -565,9 +612,9 @@ void lj_gc_freeall(global_State *g) | |||
565 | /* Free everything, except super-fixed objects (the main thread). */ | 612 | /* Free everything, except super-fixed objects (the main thread). */ |
566 | g->gc.currentwhite = LJ_GC_WHITES | LJ_GC_SFIXED; | 613 | g->gc.currentwhite = LJ_GC_WHITES | LJ_GC_SFIXED; |
567 | gc_fullsweep(g, &g->gc.root); | 614 | gc_fullsweep(g, &g->gc.root); |
568 | strmask = g->strmask; | 615 | strmask = g->str.mask; |
569 | for (i = 0; i <= strmask; i++) /* Free all string hash chains. */ | 616 | for (i = 0; i <= strmask; i++) /* Free all string hash chains. */ |
570 | gc_fullsweep(g, &g->strhash[i]); | 617 | gc_sweepstr(g, &g->str.tab[i]); |
571 | } | 618 | } |
572 | 619 | ||
573 | /* -- Collector ----------------------------------------------------------- */ | 620 | /* -- Collector ----------------------------------------------------------- */ |
@@ -582,7 +629,7 @@ static void atomic(global_State *g, lua_State *L) | |||
582 | 629 | ||
583 | setgcrefr(g->gc.gray, g->gc.weak); /* Empty the list of weak tables. */ | 630 | setgcrefr(g->gc.gray, g->gc.weak); /* Empty the list of weak tables. */ |
584 | setgcrefnull(g->gc.weak); | 631 | setgcrefnull(g->gc.weak); |
585 | lua_assert(!iswhite(obj2gco(mainthread(g)))); | 632 | lj_assertG(!iswhite(obj2gco(mainthread(g))), "main thread turned white"); |
586 | gc_markobj(g, L); /* Mark running thread. */ | 633 | gc_markobj(g, L); /* Mark running thread. */ |
587 | gc_traverse_curtrace(g); /* Traverse current trace. */ | 634 | gc_traverse_curtrace(g); /* Traverse current trace. */ |
588 | gc_mark_gcroot(g); /* Mark GC roots (again). */ | 635 | gc_mark_gcroot(g); /* Mark GC roots (again). */ |
@@ -597,13 +644,15 @@ static void atomic(global_State *g, lua_State *L) | |||
597 | udsize += gc_propagate_gray(g); /* And propagate the marks. */ | 644 | udsize += gc_propagate_gray(g); /* And propagate the marks. */ |
598 | 645 | ||
599 | /* All marking done, clear weak tables. */ | 646 | /* All marking done, clear weak tables. */ |
600 | gc_clearweak(gcref(g->gc.weak)); | 647 | gc_clearweak(g, gcref(g->gc.weak)); |
648 | |||
649 | lj_buf_shrink(L, &g->tmpbuf); /* Shrink temp buffer. */ | ||
601 | 650 | ||
602 | /* Prepare for sweep phase. */ | 651 | /* Prepare for sweep phase. */ |
603 | g->gc.currentwhite = (uint8_t)otherwhite(g); /* Flip current white. */ | 652 | g->gc.currentwhite = (uint8_t)otherwhite(g); /* Flip current white. */ |
604 | g->strempty.marked = g->gc.currentwhite; | 653 | g->strempty.marked = g->gc.currentwhite; |
605 | setmref(g->gc.sweep, &g->gc.root); | 654 | setmref(g->gc.sweep, &g->gc.root); |
606 | g->gc.estimate = g->gc.total - (MSize)udsize; /* Initial estimate. */ | 655 | g->gc.estimate = g->gc.total - (GCSize)udsize; /* Initial estimate. */ |
607 | } | 656 | } |
608 | 657 | ||
609 | /* GC state machine. Returns a cost estimate for each step performed. */ | 658 | /* GC state machine. Returns a cost estimate for each step performed. */ |
@@ -620,28 +669,29 @@ static size_t gc_onestep(lua_State *L) | |||
620 | g->gc.state = GCSatomic; /* End of mark phase. */ | 669 | g->gc.state = GCSatomic; /* End of mark phase. */ |
621 | return 0; | 670 | return 0; |
622 | case GCSatomic: | 671 | case GCSatomic: |
623 | if (gcref(g->jit_L)) /* Don't run atomic phase on trace. */ | 672 | if (tvref(g->jit_base)) /* Don't run atomic phase on trace. */ |
624 | return LJ_MAX_MEM; | 673 | return LJ_MAX_MEM; |
625 | atomic(g, L); | 674 | atomic(g, L); |
626 | g->gc.state = GCSsweepstring; /* Start of sweep phase. */ | 675 | g->gc.state = GCSsweepstring; /* Start of sweep phase. */ |
627 | g->gc.sweepstr = 0; | 676 | g->gc.sweepstr = 0; |
628 | return 0; | 677 | return 0; |
629 | case GCSsweepstring: { | 678 | case GCSsweepstring: { |
630 | MSize old = g->gc.total; | 679 | GCSize old = g->gc.total; |
631 | gc_fullsweep(g, &g->strhash[g->gc.sweepstr++]); /* Sweep one chain. */ | 680 | gc_sweepstr(g, &g->str.tab[g->gc.sweepstr++]); /* Sweep one chain. */ |
632 | if (g->gc.sweepstr > g->strmask) | 681 | if (g->gc.sweepstr > g->str.mask) |
633 | g->gc.state = GCSsweep; /* All string hash chains sweeped. */ | 682 | g->gc.state = GCSsweep; /* All string hash chains sweeped. */ |
634 | lua_assert(old >= g->gc.total); | 683 | lj_assertG(old >= g->gc.total, "sweep increased memory"); |
635 | g->gc.estimate -= old - g->gc.total; | 684 | g->gc.estimate -= old - g->gc.total; |
636 | return GCSWEEPCOST; | 685 | return GCSWEEPCOST; |
637 | } | 686 | } |
638 | case GCSsweep: { | 687 | case GCSsweep: { |
639 | MSize old = g->gc.total; | 688 | GCSize old = g->gc.total; |
640 | setmref(g->gc.sweep, gc_sweep(g, mref(g->gc.sweep, GCRef), GCSWEEPMAX)); | 689 | setmref(g->gc.sweep, gc_sweep(g, mref(g->gc.sweep, GCRef), GCSWEEPMAX)); |
641 | lua_assert(old >= g->gc.total); | 690 | lj_assertG(old >= g->gc.total, "sweep increased memory"); |
642 | g->gc.estimate -= old - g->gc.total; | 691 | g->gc.estimate -= old - g->gc.total; |
643 | if (gcref(*mref(g->gc.sweep, GCRef)) == NULL) { | 692 | if (gcref(*mref(g->gc.sweep, GCRef)) == NULL) { |
644 | gc_shrink(g, L); | 693 | if (g->str.num <= (g->str.mask >> 2) && g->str.mask > LJ_MIN_STRTAB*2-1) |
694 | lj_str_resize(L, g->str.mask >> 1); /* Shrink string table. */ | ||
645 | if (gcref(g->gc.mmudata)) { /* Need any finalizations? */ | 695 | if (gcref(g->gc.mmudata)) { /* Need any finalizations? */ |
646 | g->gc.state = GCSfinalize; | 696 | g->gc.state = GCSfinalize; |
647 | #if LJ_HASFFI | 697 | #if LJ_HASFFI |
@@ -656,9 +706,12 @@ static size_t gc_onestep(lua_State *L) | |||
656 | } | 706 | } |
657 | case GCSfinalize: | 707 | case GCSfinalize: |
658 | if (gcref(g->gc.mmudata) != NULL) { | 708 | if (gcref(g->gc.mmudata) != NULL) { |
659 | if (gcref(g->jit_L)) /* Don't call finalizers on trace. */ | 709 | GCSize old = g->gc.total; |
710 | if (tvref(g->jit_base)) /* Don't call finalizers on trace. */ | ||
660 | return LJ_MAX_MEM; | 711 | return LJ_MAX_MEM; |
661 | gc_finalize(L); /* Finalize one userdata object. */ | 712 | gc_finalize(L); /* Finalize one userdata object. */ |
713 | if (old >= g->gc.total && g->gc.estimate > old - g->gc.total) | ||
714 | g->gc.estimate -= old - g->gc.total; | ||
662 | if (g->gc.estimate > GCFINALIZECOST) | 715 | if (g->gc.estimate > GCFINALIZECOST) |
663 | g->gc.estimate -= GCFINALIZECOST; | 716 | g->gc.estimate -= GCFINALIZECOST; |
664 | return GCFINALIZECOST; | 717 | return GCFINALIZECOST; |
@@ -670,7 +723,7 @@ static size_t gc_onestep(lua_State *L) | |||
670 | g->gc.debt = 0; | 723 | g->gc.debt = 0; |
671 | return 0; | 724 | return 0; |
672 | default: | 725 | default: |
673 | lua_assert(0); | 726 | lj_assertG(0, "bad GC state"); |
674 | return 0; | 727 | return 0; |
675 | } | 728 | } |
676 | } | 729 | } |
@@ -679,7 +732,7 @@ static size_t gc_onestep(lua_State *L) | |||
679 | int LJ_FASTCALL lj_gc_step(lua_State *L) | 732 | int LJ_FASTCALL lj_gc_step(lua_State *L) |
680 | { | 733 | { |
681 | global_State *g = G(L); | 734 | global_State *g = G(L); |
682 | MSize lim; | 735 | GCSize lim; |
683 | int32_t ostate = g->vmstate; | 736 | int32_t ostate = g->vmstate; |
684 | setvmstate(g, GC); | 737 | setvmstate(g, GC); |
685 | lim = (GCSTEPSIZE/100) * g->gc.stepmul; | 738 | lim = (GCSTEPSIZE/100) * g->gc.stepmul; |
@@ -688,13 +741,13 @@ int LJ_FASTCALL lj_gc_step(lua_State *L) | |||
688 | if (g->gc.total > g->gc.threshold) | 741 | if (g->gc.total > g->gc.threshold) |
689 | g->gc.debt += g->gc.total - g->gc.threshold; | 742 | g->gc.debt += g->gc.total - g->gc.threshold; |
690 | do { | 743 | do { |
691 | lim -= (MSize)gc_onestep(L); | 744 | lim -= (GCSize)gc_onestep(L); |
692 | if (g->gc.state == GCSpause) { | 745 | if (g->gc.state == GCSpause) { |
693 | g->gc.threshold = (g->gc.estimate/100) * g->gc.pause; | 746 | g->gc.threshold = (g->gc.estimate/100) * g->gc.pause; |
694 | g->vmstate = ostate; | 747 | g->vmstate = ostate; |
695 | return 1; /* Finished a GC cycle. */ | 748 | return 1; /* Finished a GC cycle. */ |
696 | } | 749 | } |
697 | } while ((int32_t)lim > 0); | 750 | } while (sizeof(lim) == 8 ? ((int64_t)lim > 0) : ((int32_t)lim > 0)); |
698 | if (g->gc.debt < GCSTEPSIZE) { | 751 | if (g->gc.debt < GCSTEPSIZE) { |
699 | g->gc.threshold = g->gc.total + GCSTEPSIZE; | 752 | g->gc.threshold = g->gc.total + GCSTEPSIZE; |
700 | g->vmstate = ostate; | 753 | g->vmstate = ostate; |
@@ -718,8 +771,8 @@ void LJ_FASTCALL lj_gc_step_fixtop(lua_State *L) | |||
718 | /* Perform multiple GC steps. Called from JIT-compiled code. */ | 771 | /* Perform multiple GC steps. Called from JIT-compiled code. */ |
719 | int LJ_FASTCALL lj_gc_step_jit(global_State *g, MSize steps) | 772 | int LJ_FASTCALL lj_gc_step_jit(global_State *g, MSize steps) |
720 | { | 773 | { |
721 | lua_State *L = gco2th(gcref(g->jit_L)); | 774 | lua_State *L = gco2th(gcref(g->cur_L)); |
722 | L->base = mref(G(L)->jit_base, TValue); | 775 | L->base = tvref(G(L)->jit_base); |
723 | L->top = curr_topL(L); | 776 | L->top = curr_topL(L); |
724 | while (steps-- > 0 && lj_gc_step(L) == 0) | 777 | while (steps-- > 0 && lj_gc_step(L) == 0) |
725 | ; | 778 | ; |
@@ -744,7 +797,8 @@ void lj_gc_fullgc(lua_State *L) | |||
744 | } | 797 | } |
745 | while (g->gc.state == GCSsweepstring || g->gc.state == GCSsweep) | 798 | while (g->gc.state == GCSsweepstring || g->gc.state == GCSsweep) |
746 | gc_onestep(L); /* Finish sweep. */ | 799 | gc_onestep(L); /* Finish sweep. */ |
747 | lua_assert(g->gc.state == GCSfinalize || g->gc.state == GCSpause); | 800 | lj_assertG(g->gc.state == GCSfinalize || g->gc.state == GCSpause, |
801 | "bad GC state"); | ||
748 | /* Now perform a full GC. */ | 802 | /* Now perform a full GC. */ |
749 | g->gc.state = GCSpause; | 803 | g->gc.state = GCSpause; |
750 | do { gc_onestep(L); } while (g->gc.state != GCSpause); | 804 | do { gc_onestep(L); } while (g->gc.state != GCSpause); |
@@ -757,9 +811,11 @@ void lj_gc_fullgc(lua_State *L) | |||
757 | /* Move the GC propagation frontier forward. */ | 811 | /* Move the GC propagation frontier forward. */ |
758 | void lj_gc_barrierf(global_State *g, GCobj *o, GCobj *v) | 812 | void lj_gc_barrierf(global_State *g, GCobj *o, GCobj *v) |
759 | { | 813 | { |
760 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); | 814 | lj_assertG(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o), |
761 | lua_assert(g->gc.state != GCSfinalize && g->gc.state != GCSpause); | 815 | "bad object states for forward barrier"); |
762 | lua_assert(o->gch.gct != ~LJ_TTAB); | 816 | lj_assertG(g->gc.state != GCSfinalize && g->gc.state != GCSpause, |
817 | "bad GC state"); | ||
818 | lj_assertG(o->gch.gct != ~LJ_TTAB, "barrier object is not a table"); | ||
763 | /* Preserve invariant during propagation. Otherwise it doesn't matter. */ | 819 | /* Preserve invariant during propagation. Otherwise it doesn't matter. */ |
764 | if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic) | 820 | if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic) |
765 | gc_mark(g, v); /* Move frontier forward. */ | 821 | gc_mark(g, v); /* Move frontier forward. */ |
@@ -796,7 +852,8 @@ void lj_gc_closeuv(global_State *g, GCupval *uv) | |||
796 | lj_gc_barrierf(g, o, gcV(&uv->tv)); | 852 | lj_gc_barrierf(g, o, gcV(&uv->tv)); |
797 | } else { | 853 | } else { |
798 | makewhite(g, o); /* Make it white, i.e. sweep the upvalue. */ | 854 | makewhite(g, o); /* Make it white, i.e. sweep the upvalue. */ |
799 | lua_assert(g->gc.state != GCSfinalize && g->gc.state != GCSpause); | 855 | lj_assertG(g->gc.state != GCSfinalize && g->gc.state != GCSpause, |
856 | "bad GC state"); | ||
800 | } | 857 | } |
801 | } | 858 | } |
802 | } | 859 | } |
@@ -813,27 +870,29 @@ void lj_gc_barriertrace(global_State *g, uint32_t traceno) | |||
813 | /* -- Allocator ----------------------------------------------------------- */ | 870 | /* -- Allocator ----------------------------------------------------------- */ |
814 | 871 | ||
815 | /* Call pluggable memory allocator to allocate or resize a fragment. */ | 872 | /* Call pluggable memory allocator to allocate or resize a fragment. */ |
816 | void *lj_mem_realloc(lua_State *L, void *p, MSize osz, MSize nsz) | 873 | void *lj_mem_realloc(lua_State *L, void *p, GCSize osz, GCSize nsz) |
817 | { | 874 | { |
818 | global_State *g = G(L); | 875 | global_State *g = G(L); |
819 | lua_assert((osz == 0) == (p == NULL)); | 876 | lj_assertG((osz == 0) == (p == NULL), "realloc API violation"); |
820 | p = g->allocf(g->allocd, p, osz, nsz); | 877 | p = g->allocf(g->allocd, p, osz, nsz); |
821 | if (p == NULL && nsz > 0) | 878 | if (p == NULL && nsz > 0) |
822 | lj_err_mem(L); | 879 | lj_err_mem(L); |
823 | lua_assert((nsz == 0) == (p == NULL)); | 880 | lj_assertG((nsz == 0) == (p == NULL), "allocf API violation"); |
824 | lua_assert(checkptr32(p)); | 881 | lj_assertG(checkptrGC(p), |
882 | "allocated memory address %p outside required range", p); | ||
825 | g->gc.total = (g->gc.total - osz) + nsz; | 883 | g->gc.total = (g->gc.total - osz) + nsz; |
826 | return p; | 884 | return p; |
827 | } | 885 | } |
828 | 886 | ||
829 | /* Allocate new GC object and link it to the root set. */ | 887 | /* Allocate new GC object and link it to the root set. */ |
830 | void * LJ_FASTCALL lj_mem_newgco(lua_State *L, MSize size) | 888 | void * LJ_FASTCALL lj_mem_newgco(lua_State *L, GCSize size) |
831 | { | 889 | { |
832 | global_State *g = G(L); | 890 | global_State *g = G(L); |
833 | GCobj *o = (GCobj *)g->allocf(g->allocd, NULL, 0, size); | 891 | GCobj *o = (GCobj *)g->allocf(g->allocd, NULL, 0, size); |
834 | if (o == NULL) | 892 | if (o == NULL) |
835 | lj_err_mem(L); | 893 | lj_err_mem(L); |
836 | lua_assert(checkptr32(o)); | 894 | lj_assertG(checkptrGC(o), |
895 | "allocated memory address %p outside required range", o); | ||
837 | g->gc.total += size; | 896 | g->gc.total += size; |
838 | setgcrefr(o->gch.nextgc, g->gc.root); | 897 | setgcrefr(o->gch.nextgc, g->gc.root); |
839 | setgcref(g->gc.root, o); | 898 | setgcref(g->gc.root, o); |