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.c103
1 files changed, 75 insertions, 28 deletions
diff --git a/src/lj_gc.c b/src/lj_gc.c
index 793d8dac..f231b1ce 100644
--- a/src/lj_gc.c
+++ b/src/lj_gc.c
@@ -20,6 +20,7 @@
20#include "lj_state.h" 20#include "lj_state.h"
21#include "lj_frame.h" 21#include "lj_frame.h"
22#if LJ_HASFFI 22#if LJ_HASFFI
23#include "lj_ctype.h"
23#include "lj_cdata.h" 24#include "lj_cdata.h"
24#endif 25#endif
25#include "lj_trace.h" 26#include "lj_trace.h"
@@ -170,8 +171,9 @@ static int gc_traverse_tab(global_State *g, GCtab *t)
170 while ((c = *modestr++)) { 171 while ((c = *modestr++)) {
171 if (c == 'k') weak |= LJ_GC_WEAKKEY; 172 if (c == 'k') weak |= LJ_GC_WEAKKEY;
172 else if (c == 'v') weak |= LJ_GC_WEAKVAL; 173 else if (c == 'v') weak |= LJ_GC_WEAKVAL;
174 else if (c == 'K') weak = (int)(~0u & ~LJ_GC_WEAKVAL);
173 } 175 }
174 if (weak) { /* Weak tables are cleared in the atomic phase. */ 176 if (weak > 0) { /* Weak tables are cleared in the atomic phase. */
175 t->marked = cast_byte((t->marked & ~LJ_GC_WEAK) | weak); 177 t->marked = cast_byte((t->marked & ~LJ_GC_WEAK) | weak);
176 setgcrefr(t->gclist, g->gc.weak); 178 setgcrefr(t->gclist, g->gc.weak);
177 setgcref(g->gc.weak, obj2gco(t)); 179 setgcref(g->gc.weak, obj2gco(t));
@@ -458,53 +460,98 @@ static void gc_clearweak(GCobj *o)
458 } 460 }
459} 461}
460 462
461/* Finalize one userdata object from mmudata list. */ 463/* Call a userdata or cdata finalizer. */
464static void gc_call_finalizer(global_State *g, lua_State *L,
465 cTValue *mo, GCobj *o)
466{
467 /* Save and restore lots of state around the __gc callback. */
468 uint8_t oldh = hook_save(g);
469 MSize oldt = g->gc.threshold;
470 int errcode;
471 TValue *top;
472 lj_trace_abort(g);
473 top = L->top;
474 L->top = top+2;
475 hook_entergc(g); /* Disable hooks and new traces during __gc. */
476 g->gc.threshold = LJ_MAX_MEM; /* Prevent GC steps. */
477 copyTV(L, top, mo);
478 setgcV(L, top+1, o, ~o->gch.gct);
479 errcode = lj_vm_pcall(L, top+1, 1+0, -1); /* Stack: |mo|o| -> | */
480 hook_restore(g, oldh);
481 g->gc.threshold = oldt; /* Restore GC threshold. */
482 if (errcode)
483 lj_err_throw(L, errcode); /* Propagate errors. */
484}
485
486/* Finalize one userdata or cdata object from the mmudata list. */
462static void gc_finalize(lua_State *L) 487static void gc_finalize(lua_State *L)
463{ 488{
464 global_State *g = G(L); 489 global_State *g = G(L);
465 GCobj *o = gcnext(gcref(g->gc.mmudata)); 490 GCobj *o = gcnext(gcref(g->gc.mmudata));
466 GCudata *ud = gco2ud(o);
467 cTValue *mo; 491 cTValue *mo;
468 lua_assert(gcref(g->jit_L) == NULL); /* Must not be called on trace. */ 492 lua_assert(gcref(g->jit_L) == NULL); /* Must not be called on trace. */
469 /* Unchain from list of userdata to be finalized. */ 493 /* Unchain from list of userdata to be finalized. */
470 if (o == gcref(g->gc.mmudata)) 494 if (o == gcref(g->gc.mmudata))
471 setgcrefnull(g->gc.mmudata); 495 setgcrefnull(g->gc.mmudata);
472 else 496 else
473 setgcrefr(gcref(g->gc.mmudata)->gch.nextgc, ud->nextgc); 497 setgcrefr(gcref(g->gc.mmudata)->gch.nextgc, o->gch.nextgc);
474 /* Add it back to the main userdata list and make it white. */
475 setgcrefr(ud->nextgc, mainthread(g)->nextgc);
476 setgcref(mainthread(g)->nextgc, o);
477 makewhite(g, o); 498 makewhite(g, o);
478 /* Resolve the __gc metamethod. */ 499#if LJ_HASFFI
479 mo = lj_meta_fastg(g, tabref(ud->metatable), MM_gc); 500 if (o->gch.gct == ~LJ_TCDATA) {
480 if (mo) { 501 TValue tmp, *tv;
481 /* Save and restore lots of state around the __gc callback. */ 502 setgcrefr(o->gch.nextgc, g->gc.root); /* Add cdata back to the gc list. */
482 uint8_t oldh = hook_save(g); 503 setgcref(g->gc.root, o);
483 MSize oldt = g->gc.threshold; 504 /* Resolve finalizer. */
484 int errcode; 505 setcdataV(L, &tmp, gco2cd(o));
485 TValue *top; 506 tv = lj_tab_set(L, ctype_ctsG(g)->finalizer, &tmp);
486 lj_trace_abort(g); 507 if (!tvisnil(tv)) {
487 top = L->top; 508 copyTV(L, &tmp, tv);
488 L->top = top+2; 509 setnilV(tv); /* Clear entry in finalizer table. */
489 hook_entergc(g); /* Disable hooks and new traces during __gc. */ 510 gc_call_finalizer(g, L, &tmp, o);
490 g->gc.threshold = LJ_MAX_MEM; /* Prevent GC steps. */ 511 }
491 copyTV(L, top, mo); 512 return;
492 setudataV(L, top+1, ud);
493 errcode = lj_vm_pcall(L, top+1, 1+0, -1); /* Stack: |mo|ud| -> | */
494 hook_restore(g, oldh);
495 g->gc.threshold = oldt; /* Restore GC threshold. */
496 if (errcode)
497 lj_err_throw(L, errcode); /* Propagate errors. */
498 } 513 }
514#endif
515 /* Add userdata back to the main userdata list. */
516 setgcrefr(o->gch.nextgc, mainthread(g)->nextgc);
517 setgcref(mainthread(g)->nextgc, o);
518 /* Resolve the __gc metamethod. */
519 mo = lj_meta_fastg(g, tabref(gco2ud(o)->metatable), MM_gc);
520 if (mo)
521 gc_call_finalizer(g, L, mo, o);
499} 522}
500 523
501/* Finalize all userdata objects from mmudata list. */ 524/* Finalize all userdata objects from mmudata list. */
502void lj_gc_finalizeudata(lua_State *L) 525void lj_gc_finalize_udata(lua_State *L)
503{ 526{
504 while (gcref(G(L)->gc.mmudata) != NULL) 527 while (gcref(G(L)->gc.mmudata) != NULL)
505 gc_finalize(L); 528 gc_finalize(L);
506} 529}
507 530
531#if LJ_HASFFI
532/* Finalize all cdata objects from finalizer table. */
533void lj_gc_finalize_cdata(lua_State *L)
534{
535 global_State *g = G(L);
536 CTState *cts = ctype_ctsG(g);
537 if (cts) {
538 GCtab *t = cts->finalizer;
539 Node *node = noderef(t->node);
540 ptrdiff_t i;
541 setgcrefnull(t->metatable); /* Mark finalizer table as disabled. */
542 for (i = (ptrdiff_t)t->hmask; i >= 0; i--)
543 if (!tvisnil(&node[i].val) && tviscdata(&node[i].key)) {
544 GCobj *o = gcV(&node[i].key);
545 TValue tmp;
546 o->gch.marked &= ~LJ_GC_CDATA_FIN;
547 copyTV(L, &tmp, &node[i].val);
548 setnilV(&node[i].val);
549 gc_call_finalizer(g, L, &tmp, o);
550 }
551 }
552}
553#endif
554
508/* Free all remaining GC objects. */ 555/* Free all remaining GC objects. */
509void lj_gc_freeall(global_State *g) 556void lj_gc_freeall(global_State *g)
510{ 557{