/* move `dead' udata that need finalization to list `tmudata' */ size_t luaC_separateudata (lua_State *L, int all) { global_State *g = G(L); size_t deadmem = 0; GCObject **p = &g->mainthread->next; GCObject *curr; while ((curr = *p) != NULL) { if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) p = &curr->gch.next; /* don't bother with them */ else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { markfinalized(gco2u(curr)); /* don't need finalization */ p = &curr->gch.next; } else { /* must call its gc method */ deadmem += sizeudata(gco2u(curr)); markfinalized(gco2u(curr)); *p = curr->gch.next; /* link `curr' at the end of `tmudata' list */ if (g->tmudata == NULL) /* list is empty? */ g->tmudata = curr->gch.next = curr; /* creates a circular list */ else { curr->gch.next = g->tmudata->gch.next; g->tmudata->gch.next = curr; g->tmudata = curr; } } } return deadmem; }
/* move `dead' udata that need finalization to list `tmudata' */ size_t luaC_separateudata (lua_State *L) { size_t deadmem = 0; GCObject **p = &G(L)->rootudata; GCObject *curr; GCObject *collected = NULL; /* to collect udata with gc event */ GCObject **lastcollected = &collected; while ((curr = *p) != NULL) { lua_assert(curr->gch.tt == LUA_TUSERDATA); if (ismarked(curr) || isfinalized(gcotou(curr))) p = &curr->gch.next; /* don't bother with them */ else if (fasttm(L, gcotou(curr)->uv.metatable, TM_GC) == NULL) { markfinalized(gcotou(curr)); /* don't need finalization */ p = &curr->gch.next; } else { /* must call its gc method */ deadmem += sizeudata(gcotou(curr)->uv.len); *p = curr->gch.next; curr->gch.next = NULL; /* link `curr' at the end of `collected' list */ *lastcollected = curr; lastcollected = &curr->gch.next; } } /* insert collected udata with gc event into `tmudata' list */ *lastcollected = G(L)->tmudata; G(L)->tmudata = collected; return deadmem; }
void luaC_callGCTM (lua_State *L) { lu_byte oldah = L->allowhook; L->allowhook = 0; /* stop debug hooks during GC tag methods */ L->top++; /* reserve space to keep udata while runs its gc method */ while (G(L)->tmudata != NULL) { GCObject *o = G(L)->tmudata; Udata *udata = gcotou(o); G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */ udata->uv.next = G(L)->rootudata; /* return it to `root' list */ G(L)->rootudata = o; setuvalue(L->top - 1, udata); /* keep a reference to it */ unmark(o); markfinalized(udata); do1gcTM(L, udata); } L->top--; L->allowhook = oldah; /* restore hooks */ }
/* Free a C data object. */ void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd) { if (LJ_UNLIKELY(cd->marked & LJ_GC_CDATA_FIN)) { GCobj *root; makewhite(g, obj2gco(cd)); markfinalized(obj2gco(cd)); if ((root = gcref(g->gc.mmudata)) != NULL) { setgcrefr(cd->nextgc, root->gch.nextgc); setgcref(root->gch.nextgc, obj2gco(cd)); setgcref(g->gc.mmudata, obj2gco(cd)); } else { setgcref(cd->nextgc, obj2gco(cd)); setgcref(g->gc.mmudata, obj2gco(cd)); } } else if (LJ_LIKELY(!cdataisv(cd))) { CType *ct = ctype_raw(ctype_ctsG(g), cd->ctypeid); CTSize sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR; lua_assert(ctype_hassize(ct->info) || ctype_isfunc(ct->info) || ctype_isextern(ct->info)); lj_mem_free(g, cd, sizeof(GCcdata) + sz); } else { lj_mem_free(g, memcdatav(cd), sizecdatav(cd)); } }
void luaC_callGCTM (lua_State *L) { lu_byte oldah = L->allowhook; L->allowhook = 0; /* stop debug hooks during GC tag methods */ L->top++; /* reserve space to keep udata while runs its gc method */ #if LUA_REFCOUNT while (G(L)->tmudata_head.next != (GCObject*)&G(L)->tmudata_tail) { GCObject *o = G(L)->tmudata_head.next; Udata *udata = gcotou(o); G(L)->tmudata_head.next = udata->uv.next; /* remove udata from `tmudata' */ udata->uv.prev = (GCObject*)&G(L)->rootudata_head; udata->uv.next = G(L)->rootudata_head.next; if (udata->uv.next) udata->uv.next->uv.prev = o; G(L)->rootudata_head.next = o; #else !LUA_REFCOUNT while (G(L)->tmudata != NULL) { GCObject *o = G(L)->tmudata; Udata *udata = gcotou(o); G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */ udata->uv.next = G(L)->rootudata; /* return it to `root' list */ G(L)->rootudata = o; #endif LUA_REFCOUNT setuvalue(L->top - 1, udata); /* keep a reference to it */ unmark(o); markfinalized(udata); do1gcTM(L, udata); } L->top--; L->allowhook = oldah; /* restore hooks */ } void luaC_sweep (lua_State *L, int all) { if (all) all = 256; /* larger than any mark */ #if LUA_REFCOUNT sweeplist(L, &G(L)->rootudata_head.next, (GCObject*)&G(L)->rootudata_tail, all); #else !LUA_REFCOUNT sweeplist(L, &G(L)->rootudata, NULL, all); #endif LUA_REFCOUNT sweepstrings(L, all); #if LUA_REFCOUNT sweeplist(L, &G(L)->rootgc_head.next, (GCObject*)&G(L)->rootgc_tail, all); #else !LUA_REFCOUNT sweeplist(L, &G(L)->rootgc, NULL, all); #endif LUA_REFCOUNT } /* mark root set */ static void markroot (GCState *st, lua_State *L) { int i; global_State *g = st->g; markobject(st, defaultmeta(L)); for (i = 0; i < LUA_NTYPES; i++) { markobject(st, defaultmetatypes(L, i)); } markobject(st, registry(L)); traversestack(st, g->mainthread); if (L != g->mainthread) /* another thread is running? */ markvalue(st, L); /* cannot collect it */ if (G(L)->userGCFunction) { st->L = g->mainthread; G(L)->userGCFunction(st); } }
static void marktmu (GCState *st) { GCObject *u; #if LUA_REFCOUNT for (u = st->g->tmudata_head.next; u != (GCObject*)&st->g->tmudata_tail; u = u->gch.next) { #else !LUA_REFCOUNT for (u = st->g->tmudata; u; u = u->gch.next) { #endif LUA_REFCOUNT unmark(u); /* may be marked, if left from previous GC */ reallymarkobject(st, u); } } /* move `dead' udata that need finalization to list `tmudata' */ size_t luaC_separateudata (lua_State *L) { size_t deadmem = 0; #if LUA_REFCOUNT GCObject **p = &G(L)->rootudata_head.next; #else !LUA_REFCOUNT GCObject **p = &G(L)->rootudata; #endif LUA_REFCOUNT GCObject *curr; GCObject *collected = NULL; /* to collect udata with gc event */ #if !LUA_REFCOUNT GCObject **lastcollected = &collected; while ((curr = *p) != NULL) { lua_assert(curr->gch.tt == LUA_TUSERDATA); #else LUA_REFCOUNT while ((curr = *p) != (GCObject*)&G(L)->rootudata_tail) { #endif LUA_REFCOUNT if (ismarked(curr) || isfinalized(gcotou(curr))) p = &curr->gch.next; /* don't bother with them */ else if (fasttm(L, gcotou(curr)->uv.metatable, TM_GC) == NULL) { markfinalized(gcotou(curr)); /* don't need finalization */ p = &curr->gch.next; } else { /* must call its gc method */ deadmem += sizeudata(gcotou(curr)->uv.len); *p = curr->gch.next; #if LUA_REFCOUNT Unlink(curr); curr->gch.next = (GCObject*)&G(L)->tmudata_tail; /* link `curr' at the end of `collected' list */ curr->gch.prev = G(L)->tmudata_tail.prev; G(L)->tmudata_tail.prev->gch.next = curr; G(L)->tmudata_tail.prev = curr; #else !LUA_REFCOUNT curr->gch.next = NULL; /* link `curr' at the end of `collected' list */ *lastcollected = curr; lastcollected = &curr->gch.next; #endif LUA_REFCOUNT } } /* insert collected udata with gc event into `tmudata' list */ #if LUA_REFCOUNT // *lastcollected = G(L)->tmudata_head.next; // G(L)->tmudata_head.next = collected; #else !LUA_REFCOUNT *lastcollected = G(L)->tmudata; G(L)->tmudata = collected; #endif LUA_REFCOUNT return deadmem; } static void removekey (lua_State *L, Node *n) { (void)L; setnilvalue(gval(n)); /* remove corresponding value ... */ if (iscollectable(gkey(n))) setttype(gkey(n), LUA_TNONE); /* dead key; remove it */ }