private static GCObjectRef sweeplist(lua_State L, GCObjectRef p, lu_mem count) { GCObject curr; global_State g = G(L); int deadmask = otherwhite(g); while ((curr = p.get()) != null && count-- > 0) { if (curr.gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ { sweepwholelist(L, new OpenValRef(gco2th(curr))); } if (((curr.gch.marked ^ WHITEBITS) & deadmask) != 0) /* not dead? */ { lua_assert(isdead(g, curr) || testbit(curr.gch.marked, FIXEDBIT)); makewhite(g, curr); /* make it white (for next cycle) */ p = new NextRef(curr.gch); } else /* must erase `curr' */ { lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); p.set(curr.gch.next); if (curr == g.rootgc) /* is the first element of the list? */ { g.rootgc = curr.gch.next; /* adjust first */ } freeobj(L, curr); } } return(p); }
private static void GCTM(lua_State L) { global_State g = G(L); GCObject o = g.tmudata.gch.next; /* get first element */ Udata udata = rawgco2u(o); TValue tm; /* remove udata from `tmudata' */ if (o == g.tmudata) /* last element? */ { g.tmudata = null; } else { g.tmudata.gch.next = udata.uv.next; } udata.uv.next = g.mainthread.next; /* return it to `root' list */ g.mainthread.next = o; makewhite(g, o); tm = fasttm(L, udata.uv.metatable, TMS.TM_GC); if (tm != null) { lu_byte oldah = L.allowhook; lu_mem oldt = (lu_mem)g.GCthreshold; L.allowhook = 0; /* stop debug hooks during GC tag method */ g.GCthreshold = 2 * g.totalbytes; /* avoid GC steps */ setobj2s(L, L.top, tm); setuvalue(L, L.top + 1, udata); L.top += 2; luaD_call(L, L.top - 2, 0); L.allowhook = oldah; /* restore hooks */ g.GCthreshold = (uint)oldt; /* restore threshold */ } }
private static void GCTM(lua_State L, int propagateerrors) { global_State g = G(L); Udata udata = udata2finalize(g); /*const*/ TValue tm = gfasttm(g, udata.uv.metatable, TMS.TM_GC); if (tm != null && ttisfunction(tm)) { int status; lu_byte oldah = L.allowhook; lu_mem oldt = (lu_mem)g.GCthreshold; L.allowhook = 0; /* stop debug hooks during GC tag method */ g.GCthreshold = 2 * g.totalbytes; /* avoid GC steps */ setobj2s(L, L.top, tm); setuvalue(L, L.top + 1, udata); L.top += 2; status = luaD_pcall(L, dothecall, null, savestack(L, L.top - 2), 0); if (status != LUA_OK && propagateerrors != 0) /* error while running __gc? */ { if (status == LUA_ERRRUN) /* is there an error msg.? */ { luaO_pushfstring(L, "error in __gc tag method (%s)", lua_tostring(L, -1)); status = LUA_ERRGCMM; /* error in __gc metamethod */ } luaD_throw(L, status); /* re-send error */ } L.allowhook = oldah; /* restore hooks */ g.GCthreshold = (uint)oldt; /* restore threshold */ } }
private static void correctestimate(global_State g, correctestimate_delegate s) { lu_mem old = g.totalbytes; s(); lua_assert(old >= g.totalbytes); g.estimate -= old - g.totalbytes; }
private static GCObjectRef sweeplist(lua_State L, GCObjectRef p, lu_mem count) { GCObject curr; global_State g = G(L); int deadmask = otherwhite(g); while ((curr = p.get()) != null && count-- > 0) { if (ttisthread(gch(curr))) /* sweep open upvalues of each thread */ { sweepwholelist(L, new OpenValRef(gco2th(curr))); } if (((gch(curr).marked ^ WHITEBITS) & deadmask) != 0) /* not dead? */ { lua_assert(isdead(g, curr) || testbit(gch(curr).marked, FIXEDBIT)); makewhite(g, curr); /* make it white (for next cycle) */ p = new NextRef(gch(curr)); } else /* must erase `curr' */ { lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); p.set(gch(curr).next); /* remove 'curr' from list */ freeobj(L, curr); } } return(p); }
private static GCObjectRef sweeplist(lua_State L, GCObjectRef p, lu_mem count) { GCObject curr; global_State g = G(L); int deadmask = otherwhite(g); while ((curr = p.get()) != null && count-- > 0) { int alive = (gch(curr).marked ^ WHITEBITS) & deadmask; if (ttisthread(gch(curr))) { sweepthread(L, gco2th(curr), alive); } if (alive != 0) { lua_assert(isdead(g, curr) || testbit(gch(curr).marked, FIXEDBIT)); makewhite(g, curr); /* make it white (for next cycle) */ p = new NextRef(gch(curr)); } else /* must erase `curr' */ { lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); p.set(gch(curr).next); /* remove 'curr' from list */ freeobj(L, curr); } } return(p); }
private static GCObjectRef SweepList(LuaState L, GCObjectRef p, lu_mem count) { GCObject curr; GlobalState g = G(L); int deadmask = OtherWhite(g); while ((curr = p.get()) != null && count-- > 0) { if (curr.gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ { SweepWholeList(L, new OpenValRef(gco2th(curr))); } if (((curr.gch.marked ^ WHITEBITS) & deadmask) != 0) /* not dead? */ { LuaAssert(!IsDead(g, curr) || TestBit(curr.gch.marked, FIXEDBIT)); MakeWhite(g, curr); /* make it white (for next cycle) */ p = new NextRef(curr.gch); } else /* must erase `curr' */ { LuaAssert(IsDead(g, curr) || deadmask == BitMask(SFIXEDBIT)); p.set(curr.gch.next); if (curr == g.rootgc) /* is the first element of the list? */ { g.rootgc = curr.gch.next; /* adjust first */ } FreeObj(L, curr); } } return(p); }
//private static GCObject nullp = null; //FIXME:see nullp in global_State /* ** sweep at most 'count' elements from a list of GCObjects erasing dead ** objects, where a dead (not alive) object is one marked with the "old" ** (non current) white and not fixed. ** In non-generational mode, change all non-dead objects back to white, ** preparing for next collection cycle. ** In generational mode, keep black objects black, and also mark them as ** old; stop when hitting an old object, as all objects after that ** one will be old too. ** When object is a thread, sweep its list of open upvalues too. */ private static GCObjectRef sweeplist(lua_State L, GCObjectRef p, lu_mem count) { global_State g = G(L); int ow = otherwhite(g); int toclear, toset; /* bits to clear and to set in all live objects */ int tostop; /* stop sweep when this is true */ l_mem debt = g.GCdebt; /* current debt */ if (isgenerational(g)) /* generational mode? */ { toclear = ~0; /* clear nothing */ toset = bitmask(OLDBIT); /* set the old bit of all surviving objects */ tostop = bitmask(OLDBIT); /* do not sweep old generation */ } else /* normal mode */ { toclear = maskcolors; /* clear all color bits + old bit */ toset = luaC_white(g); /* make object white */ tostop = 0; /* do not stop */ } while (p.get() != null && count-- > 0) { GCObject curr = p.get(); int marked = gch(curr).marked; if (isdeadm(ow, marked)) /* is 'curr' dead? */ { p.set(gch(curr).next); /* remove 'curr' from list */ freeobj(L, curr); /* erase 'curr' */ } else { if (gch(curr).tt == LUA_TTHREAD) { sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */ } if (testbits((byte)marked, tostop)) //FIXME:(byte) //static GCObject *nullp = NULL; //FIXME:moved, see upper { p = new NullpRef(g); /* stop sweeping this list */ break; } /* update marks */ gch(curr).marked = cast_byte((marked & toclear) | toset); p = new NextRef(gch(curr)); /* go to next element */ } } luaE_setdebt(g, debt); /* sweeping should not change debt */ return(p); }
private static void GCTM(lua_State L) { global_State g = G(L); Udata udata = udata2finalize(g); /*const*/ TValue tm = fasttm(L, udata.uv.metatable, TMS.TM_GC); if (tm != null) { lu_byte oldah = L.allowhook; lu_mem oldt = (lu_mem)g.GCthreshold; L.allowhook = 0; /* stop debug hooks during GC tag method */ g.GCthreshold = 2 * g.totalbytes; /* avoid GC steps */ setobj2s(L, L.top, tm); setuvalue(L, L.top + 1, udata); L.top += 2; luaD_call(L, L.top - 2, 0); L.allowhook = oldah; /* restore hooks */ g.GCthreshold = (uint)oldt; /* restore threshold */ } }
public static void luaC_step(lua_State L) { global_State g = G(L); l_mem lim = (l_mem)((GCSTEPSIZE / 100) * g.gcstepmul); /* how much to work */ lu_mem debt = g.totalbytes - g.GCthreshold; lua_assert(g.gckind == KGC_NORMAL); do /* always perform at least one single step */ { lim -= singlestep(L); } while (lim > 0 && g.gcstate != GCSpause); g.GCthreshold = (uint)((g.gcstate != GCSpause) ? g.totalbytes + GCSTEPSIZE : (g.totalbytes / 100) * g.gcpause); //FIXME:(uint) /* compensate if GC is "behind schedule" (has some debt to pay) */ if (g.GCthreshold > debt) { g.GCthreshold -= debt; } }
/* ** Garbage-collection function */ public static int lua_gc(lua_State L, int what, int data) { int res = 0; global_State g; lua_lock(L); g = G(L); switch (what) { case LUA_GCSTOP: { g.gcrunning = 0; break; } case LUA_GCRESTART: { luaE_setdebt(g, 0); g.gcrunning = 1; break; } case LUA_GCCOLLECT: { luaC_fullgc(L, 0); break; } case LUA_GCCOUNT: { /* GC values are expressed in Kbytes: #bytes/2^10 */ res = cast_int(gettotalbytes(g) >> 10); break; } case LUA_GCCOUNTB: { res = cast_int(gettotalbytes(g) & 0x3ff); break; } case LUA_GCSTEP: { if (g.gckind == KGC_GEN) /* generational mode? */ { res = (g.GCestimate == 0)?1:0; /* true if it will do major collection */ luaC_forcestep(L); /* do a single step */ } else { lu_mem debt = (lu_mem)(data) * 1024 - GCSTEPSIZE; if (g.gcrunning != 0) { debt += (uint)g.GCdebt; /* include current debt */ } luaE_setdebt(g, (int)debt); luaC_forcestep(L); if (g.gcstate == GCSpause) /* end of cycle? */ { res = 1; /* signal it */ } } break; } case LUA_GCSETPAUSE: { res = g.gcpause; g.gcpause = data; break; } case LUA_GCSETMAJORINC: { res = g.gcmajorinc; g.gcmajorinc = data; break; } case LUA_GCSETSTEPMUL: { res = g.gcstepmul; g.gcstepmul = data; break; } case LUA_GCISRUNNING: { res = g.gcrunning; break; } case LUA_GCGEN: { /* change collector to generational mode */ luaC_changemode(L, KGC_GEN); break; } case LUA_GCINC: { /* change collector to incremental mode */ luaC_changemode(L, KGC_NORMAL); break; } default: res = -1; /* invalid option */ break; //FIXME: added } lua_unlock(L); return(res); }
/* ** Garbage-collection function */ public static int lua_gc(lua_State L, int what, int data) { int res = 0; global_State g; lua_lock(L); g = G(L); switch (what) { case LUA_GCSTOP: { g.GCthreshold = MAX_LUMEM; break; } case LUA_GCRESTART: { g.GCthreshold = g.totalbytes; break; } case LUA_GCCOLLECT: { luaC_fullgc(L, 0); break; } case LUA_GCCOUNT: { /* GC values are expressed in Kbytes: #bytes/2^10 */ res = cast_int(g.totalbytes >> 10); break; } case LUA_GCCOUNTB: { res = cast_int(g.totalbytes & 0x3ff); break; } case LUA_GCSTEP: { lu_mem a = ((lu_mem)data << 10); if (a <= g.totalbytes) { g.GCthreshold = (uint)(g.totalbytes - a); } else { g.GCthreshold = 0; } while (g.GCthreshold <= g.totalbytes) { luaC_step(L); } if (g.gcstate == GCSpause) /* end of cycle? */ { res = 1; /* signal it */ } break; } case LUA_GCSETPAUSE: { res = g.gcpause; g.gcpause = data; break; } case LUA_GCSETSTEPMUL: { res = g.gcstepmul; g.gcstepmul = data; break; } default: res = -1; /* invalid option */ break; } lua_unlock(L); return(res); }
private static l_mem singlestep(lua_State L) { global_State g = G(L); /*lua_checkmemory(L);*/ switch (g.gcstate) { case GCSpause: { markroot(L); /* start a new collection */ return(0); } case GCSpropagate: { if (g.gray != null) { return(propagatemark(g)); } else /* no more `gray' objects */ { atomic(L); /* finish mark phase */ return(0); } } case GCSsweepstring: { lu_mem old = (lu_mem)g.totalbytes; sweepwholelist(L, new ArrayRef(g.strt.hash, g.sweepstrgc++)); if (g.sweepstrgc >= g.strt.size) /* nothing more to sweep? */ { g.gcstate = GCSsweep; /* end sweep-string phase */ } lua_assert(old >= g.totalbytes); g.estimate -= (uint)(old - g.totalbytes); return(GCSWEEPCOST); } case GCSsweep: { lu_mem old = (lu_mem)g.totalbytes; g.sweepgc = sweeplist(L, g.sweepgc, GCSWEEPMAX); if (g.sweepgc.get() == null) /* nothing more to sweep? */ { checkSizes(L); g.gcstate = GCSfinalize; /* end sweep phase */ } lua_assert(old >= g.totalbytes); g.estimate -= (uint)(old - g.totalbytes); return(GCSWEEPMAX * GCSWEEPCOST); } case GCSfinalize: { if (g.tmudata != null) { GCTM(L); if (g.estimate > GCFINALIZECOST) { g.estimate -= GCFINALIZECOST; } return(GCFINALIZECOST); } else { g.gcstate = GCSpause; /* end collection */ g.gcdept = 0; return(0); } } default: lua_assert(0); return(0); } }
private static GCObjectRef SweepList (LuaState L, GCObjectRef p, lu_mem count) { GCObject curr; GlobalState g = G(L); int deadmask = OtherWhite(g); while ((curr = p.get()) != null && count-- > 0) { if (curr.gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ SweepWholeList(L, new OpenValRef( gco2th(curr) )); if (((curr.gch.marked ^ WHITEBITS) & deadmask) != 0) { /* not dead? */ LuaAssert(!IsDead(g, curr) || TestBit(curr.gch.marked, FIXEDBIT)); MakeWhite(g, curr); /* make it white (for next cycle) */ p = new NextRef(curr.gch); } else { /* must erase `curr' */ LuaAssert(IsDead(g, curr) || deadmask == BitMask(SFIXEDBIT)); p.set( curr.gch.next ); if (curr == g.rootgc) /* is the first element of the list? */ g.rootgc = curr.gch.next; /* adjust first */ FreeObj(L, curr); } } return p; }
/* ** Garbage-collection function */ public static int lua_gc(lua_State L, int what, int data) { int res = 0; global_State g; lua_lock(L); g = G(L); switch (what) { case LUA_GCSTOP: { g.GCthreshold = MAX_LUMEM; break; } case LUA_GCRESTART: { g.GCthreshold = g.totalbytes; break; } case LUA_GCCOLLECT: { luaC_fullgc(L, 0); break; } case LUA_GCCOUNT: { /* GC values are expressed in Kbytes: #bytes/2^10 */ res = cast_int(g.totalbytes >> 10); break; } case LUA_GCCOUNTB: { res = cast_int(g.totalbytes & 0x3ff); break; } case LUA_GCSTEP: { lu_mem oldts = g.GCthreshold; lu_mem a = ((lu_mem)data << 10); g.GCthreshold = (a <= g.totalbytes) ? g.totalbytes - a : 0; while (g.GCthreshold <= g.totalbytes) { luaC_step(L); if (g.gcstate == GCSpause) /* end of cycle? */ { res = 1; /* signal it */ break; } } if (oldts == MAX_LUMEM) /* collector was stopped? */ { g.GCthreshold = oldts; /* keep it that way */ } break; } case LUA_GCSETPAUSE: { res = g.gcpause; g.gcpause = data; break; } case LUA_GCSETSTEPMUL: { res = g.gcstepmul; g.gcstepmul = data; break; } case LUA_GCISRUNNING: { res = (g.GCthreshold != MAX_LUMEM ? 1 : 0); break; } default: res = -1; /* invalid option */ break; //FIXME: added } lua_unlock(L); return(res); }
private static GCObjectRef sweeplist (lua_State L, GCObjectRef p, lu_mem count) { GCObject curr; global_State g = G(L); int deadmask = otherwhite(g); while ((curr = p.get()) != null && count-- > 0) { if (curr.gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ sweepwholelist(L, new OpenValRef( gco2th(curr) )); if (((curr.gch.marked ^ WHITEBITS) & deadmask) != 0) { /* not dead? */ lua_assert(isdead(g, curr) || testbit(curr.gch.marked, FIXEDBIT)); makewhite(g, curr); /* make it white (for next cycle) */ p = new NextRef(curr.gch); } else { /* must erase `curr' */ lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); p.set( curr.gch.next ); if (curr == g.rootgc) /* is the first element of the list? */ g.rootgc = curr.gch.next; /* adjust first */ freeobj(L, curr); } } return p; }