| /* | |
| ** $Id: lgc.h $ | |
| ** Garbage Collector | |
| ** See Copyright Notice in lua.h | |
| */ | |
| #ifndef lgc_h | |
| #define lgc_h | |
| #include <stddef.h> | |
| #include "lobject.h" | |
| #include "lstate.h" | |
| /* | |
| ** Collectable objects may have one of three colors: white, which means | |
| ** the object is not marked; gray, which means the object is marked, but | |
| ** its references may be not marked; and black, which means that the | |
| ** object and all its references are marked. The main invariant of the | |
| ** garbage collector, while marking objects, is that a black object can | |
| ** never point to a white one. Moreover, any gray object must be in a | |
| ** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it | |
| ** can be visited again before finishing the collection cycle. (Open | |
| ** upvalues are an exception to this rule, as they are attached to | |
| ** a corresponding thread.) These lists have no meaning when the | |
| ** invariant is not being enforced (e.g., sweep phase). | |
| */ | |
| /* | |
| ** Possible states of the Garbage Collector | |
| */ | |
| #define GCSpropagate 0 | |
| #define GCSenteratomic 1 | |
| #define GCSatomic 2 | |
| #define GCSswpallgc 3 | |
| #define GCSswpfinobj 4 | |
| #define GCSswptobefnz 5 | |
| #define GCSswpend 6 | |
| #define GCScallfin 7 | |
| #define GCSpause 8 | |
| #define issweepphase(g) \ | |
| (GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend) | |
| /* | |
| ** macro to tell when main invariant (white objects cannot point to black | |
| ** ones) must be kept. During a collection, the sweep phase may break | |
| ** the invariant, as objects turned white may point to still-black | |
| ** objects. The invariant is restored when sweep ends and all objects | |
| ** are white again. | |
| */ | |
| #define keepinvariant(g) ((g)->gcstate <= GCSatomic) | |
| /* | |
| ** some useful bit tricks | |
| */ | |
| #define resetbits(x,m) ((x) &= cast_byte(~(m))) | |
| #define setbits(x,m) ((x) |= (m)) | |
| #define testbits(x,m) ((x) & (m)) | |
| #define bitmask(b) (1<<(b)) | |
| #define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) | |
| #define l_setbit(x,b) setbits(x, bitmask(b)) | |
| #define resetbit(x,b) resetbits(x, bitmask(b)) | |
| #define testbit(x,b) testbits(x, bitmask(b)) | |
| /* | |
| ** Layout for bit use in 'marked' field. First three bits are | |
| ** used for object "age" in generational mode. Last bit is used | |
| ** by tests. | |
| */ | |
| #define WHITE0BIT 3 /* object is white (type 0) */ | |
| #define WHITE1BIT 4 /* object is white (type 1) */ | |
| #define BLACKBIT 5 /* object is black */ | |
| #define FINALIZEDBIT 6 /* object has been marked for finalization */ | |
| #define TESTBIT 7 | |
| #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) | |
| #define iswhite(x) testbits((x)->marked, WHITEBITS) | |
| #define isblack(x) testbit((x)->marked, BLACKBIT) | |
| #define isgray(x) /* neither white nor black */ \ | |
| (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) | |
| #define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) | |
| #define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) | |
| #define isdeadm(ow,m) ((m) & (ow)) | |
| #define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) | |
| #define changewhite(x) ((x)->marked ^= WHITEBITS) | |
| #define nw2black(x) \ | |
| check_exp(!iswhite(x), l_setbit((x)->marked, BLACKBIT)) | |
| #define luaC_white(g) cast_byte((g)->currentwhite & WHITEBITS) | |
| /* object age in generational mode */ | |
| #define G_NEW 0 /* created in current cycle */ | |
| #define G_SURVIVAL 1 /* created in previous cycle */ | |
| #define G_OLD0 2 /* marked old by frw. barrier in this cycle */ | |
| #define G_OLD1 3 /* first full cycle as old */ | |
| #define G_OLD 4 /* really old object (not to be visited) */ | |
| #define G_TOUCHED1 5 /* old object touched this cycle */ | |
| #define G_TOUCHED2 6 /* old object touched in previous cycle */ | |
| #define AGEBITS 7 /* all age bits (111) */ | |
| #define getage(o) ((o)->marked & AGEBITS) | |
| #define setage(o,a) ((o)->marked = cast_byte(((o)->marked & (~AGEBITS)) | a)) | |
| #define isold(o) (getage(o) > G_SURVIVAL) | |
| /* | |
| ** In generational mode, objects are created 'new'. After surviving one | |
| ** cycle, they become 'survival'. Both 'new' and 'survival' can point | |
| ** to any other object, as they are traversed at the end of the cycle. | |
| ** We call them both 'young' objects. | |
| ** If a survival object survives another cycle, it becomes 'old1'. | |
| ** 'old1' objects can still point to survival objects (but not to | |
| ** new objects), so they still must be traversed. After another cycle | |
| ** (that, being old, 'old1' objects will "survive" no matter what) | |
| ** finally the 'old1' object becomes really 'old', and then they | |
| ** are no more traversed. | |
| ** | |
| ** To keep its invariants, the generational mode uses the same barriers | |
| ** also used by the incremental mode. If a young object is caught in a | |
| ** forward barrier, it cannot become old immediately, because it can | |
| ** still point to other young objects. Instead, it becomes 'old0', | |
| ** which in the next cycle becomes 'old1'. So, 'old0' objects is | |
| ** old but can point to new and survival objects; 'old1' is old | |
| ** but cannot point to new objects; and 'old' cannot point to any | |
| ** young object. | |
| ** | |
| ** If any old object ('old0', 'old1', 'old') is caught in a back | |
| ** barrier, it becomes 'touched1' and goes into a gray list, to be | |
| ** visited at the end of the cycle. There it evolves to 'touched2', | |
| ** which can point to survivals but not to new objects. In yet another | |
| ** cycle then it becomes 'old' again. | |
| ** | |
| ** The generational mode must also control the colors of objects, | |
| ** because of the barriers. While the mutator is running, young objects | |
| ** are kept white. 'old', 'old1', and 'touched2' objects are kept black, | |
| ** as they cannot point to new objects; exceptions are threads and open | |
| ** upvalues, which age to 'old1' and 'old' but are kept gray. 'old0' | |
| ** objects may be gray or black, as in the incremental mode. 'touched1' | |
| ** objects are kept gray, as they must be visited again at the end of | |
| ** the cycle. | |
| */ | |
| /* | |
| ** {====================================================== | |
| ** Default Values for GC parameters | |
| ** ======================================================= | |
| */ | |
| /* | |
| ** Minor collections will shift to major ones after LUAI_MINORMAJOR% | |
| ** bytes become old. | |
| */ | |
| #define LUAI_MINORMAJOR 70 | |
| /* | |
| ** Major collections will shift to minor ones after a collection | |
| ** collects at least LUAI_MAJORMINOR% of the new bytes. | |
| */ | |
| #define LUAI_MAJORMINOR 50 | |
| /* | |
| ** A young (minor) collection will run after creating LUAI_GENMINORMUL% | |
| ** new bytes. | |
| */ | |
| #define LUAI_GENMINORMUL 20 | |
| /* incremental */ | |
| /* Number of bytes must be LUAI_GCPAUSE% before starting new cycle */ | |
| #define LUAI_GCPAUSE 250 | |
| /* | |
| ** Step multiplier: The collector handles LUAI_GCMUL% work units for | |
| ** each new allocated word. (Each "work unit" corresponds roughly to | |
| ** sweeping one object or traversing one slot.) | |
| */ | |
| #define LUAI_GCMUL 200 | |
| /* How many bytes to allocate before next GC step */ | |
| #define LUAI_GCSTEPSIZE (200 * sizeof(Table)) | |
| #define setgcparam(g,p,v) (g->gcparams[LUA_GCP##p] = luaO_codeparam(v)) | |
| #define applygcparam(g,p,x) luaO_applyparam(g->gcparams[LUA_GCP##p], x) | |
| /* }====================================================== */ | |
| /* | |
| ** Control when GC is running: | |
| */ | |
| #define GCSTPUSR 1 /* bit true when GC stopped by user */ | |
| #define GCSTPGC 2 /* bit true when GC stopped by itself */ | |
| #define GCSTPCLS 4 /* bit true when closing Lua state */ | |
| #define gcrunning(g) ((g)->gcstp == 0) | |
| /* | |
| ** Does one step of collection when debt becomes zero. 'pre'/'pos' | |
| ** allows some adjustments to be done only when needed. macro | |
| ** 'condchangemem' is used only for heavy tests (forcing a full | |
| ** GC cycle on every opportunity) | |
| */ | |
| #if !defined(HARDMEMTESTS) | |
| #define condchangemem(L,pre,pos,emg) ((void)0) | |
| #else | |
| #define condchangemem(L,pre,pos,emg) \ | |
| { if (gcrunning(G(L))) { pre; luaC_fullgc(L, emg); pos; } } | |
| #endif | |
| #define luaC_condGC(L,pre,pos) \ | |
| { if (G(L)->GCdebt <= 0) \ | |
| { pre; luaC_step(L); condchangemem(L,{},{},0); pos;} \ | |
| else condchangemem(L,pre,pos,0); } | |
| /* more often than not, 'pre'/'pos' are empty */ | |
| #define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0) | |
| #define luaC_objbarrier(L,p,o) ( \ | |
| (isblack(p) && iswhite(o)) ? \ | |
| luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) | |
| #define luaC_barrier(L,p,v) ( \ | |
| iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0)) | |
| #define luaC_objbarrierback(L,p,o) ( \ | |
| (isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0)) | |
| #define luaC_barrierback(L,p,v) ( \ | |
| iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0)) | |
| LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); | |
| LUAI_FUNC void luaC_freeallobjects (lua_State *L); | |
| LUAI_FUNC void luaC_step (lua_State *L); | |
| LUAI_FUNC void luaC_runtilstate (lua_State *L, int state, int fast); | |
| LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); | |
| LUAI_FUNC GCObject *luaC_newobj (lua_State *L, lu_byte tt, size_t sz); | |
| LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, lu_byte tt, size_t sz, | |
| size_t offset); | |
| LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); | |
| LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); | |
| LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); | |
| LUAI_FUNC void luaC_changemode (lua_State *L, int newmode); | |
| #endif |