diff --git a/lfunc.c b/lfunc.c index a0264fed..82d05656 100644 --- a/lfunc.c +++ b/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.30 2012/10/03 12:36:46 roberto Exp roberto $ +** $Id: lfunc.c,v 2.31 2013/08/05 16:58:28 roberto Exp roberto $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -38,7 +38,7 @@ Closure *luaF_newLclosure (lua_State *L, int n) { UpVal *luaF_newupval (lua_State *L) { UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv; - uv->v = &uv->u.value; + uv->v = &uv->value; setnilvalue(uv->v); return uv; } @@ -51,7 +51,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { UpVal *uv; while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { GCObject *o = obj2gco(p); - lua_assert(p->v != &p->u.value); + lua_assert(p->v != &p->value); if (p->v == level) { /* found a corresponding upvalue? */ if (isdead(g, o)) /* is it dead? */ changewhite(o); /* resurrect it */ @@ -62,42 +62,22 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { /* not found: create a new one */ uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv; uv->v = level; /* current value lives in the stack */ - uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */ - uv->u.l.next = g->uvhead.u.l.next; - uv->u.l.next->u.l.prev = uv; - g->uvhead.u.l.next = uv; - lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); return uv; } -static void unlinkupval (UpVal *uv) { - lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); - uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */ - uv->u.l.prev->u.l.next = uv->u.l.next; -} - - -void luaF_freeupval (lua_State *L, UpVal *uv) { - if (uv->v != &uv->u.value) /* is it open? */ - unlinkupval(uv); /* remove from open list */ - luaM_free(L, uv); /* free upvalue */ -} - - void luaF_close (lua_State *L, StkId level) { UpVal *uv; global_State *g = G(L); while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) { GCObject *o = obj2gco(uv); - lua_assert(!isblack(o) && uv->v != &uv->u.value); + lua_assert(!isblack(o) && uv->v != &uv->value); L->openupval = uv->next; /* remove from `open' list */ if (isdead(g, o)) - luaF_freeupval(L, uv); /* free upvalue */ + luaM_free(L, uv); /* free upvalue */ else { - unlinkupval(uv); /* remove upvalue from 'uvhead' list */ - setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ - uv->v = &uv->u.value; /* now current value lives here */ + setobj(L, &uv->value, uv->v); /* move value to upvalue slot */ + uv->v = &uv->value; /* now current value lives here */ gch(o)->next = g->allgc; /* link upvalue into 'allgc' list */ g->allgc = o; luaC_checkupvalcolor(g, uv); diff --git a/lfunc.h b/lfunc.h index 27d041ce..c5e8b89c 100644 --- a/lfunc.h +++ b/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 2.7 2012/01/20 22:05:50 roberto Exp roberto $ +** $Id: lfunc.h,v 2.8 2012/05/08 13:53:33 roberto Exp roberto $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -25,7 +25,6 @@ LUAI_FUNC UpVal *luaF_newupval (lua_State *L); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC void luaF_close (lua_State *L, StkId level); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); -LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv); LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, int pc); diff --git a/lgc.c b/lgc.c index 8e73ff21..993af884 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.141 2013/04/26 18:26:49 roberto Exp roberto $ +** $Id: lgc.c,v 2.142 2013/08/05 16:58:28 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -258,7 +258,7 @@ static void reallymarkobject (global_State *g, GCObject *o) { case LUA_TUPVAL: { UpVal *uv = gco2uv(o); markvalue(g, uv->v); - if (uv->v != &uv->u.value) /* open? */ + if (uv->v != &uv->value) /* open? */ return; /* open upvalues remain gray */ size = sizeof(UpVal); break; @@ -317,14 +317,21 @@ static void markbeingfnz (global_State *g) { /* -** mark all values stored in marked open upvalues. (See comment in -** 'lstate.h'.) +** Mark all values stored in marked open upvalues from non-marked threads. +** (Values from marked threads were already marked when traversing the +** thread.) */ static void remarkupvals (global_State *g) { - UpVal *uv; - for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { - if (isgray(obj2gco(uv))) - markvalue(g, uv->v); + GCObject *thread = hvalue(&g->l_registry)->next; + for (; thread != NULL; thread = gch(thread)->next) { + lua_assert(!isblack(thread)); /* threads are never black */ + if (!isgray(thread)) { /* dead thread? */ + GCObject *uv = gco2th(thread)->openupval; + for (; uv != NULL; uv = gch(uv)->next) { + if (isgray(uv)) /* marked? */ + markvalue(g, gco2uv(uv)->v); /* remark upvalue's value */ + } + } } } @@ -669,7 +676,7 @@ static void freeobj (lua_State *L, GCObject *o) { luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); break; } - case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; + case LUA_TUPVAL: luaM_free(L, gco2uv(o)); break; case LUA_TTABLE: luaH_free(L, gco2t(o)); break; case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; diff --git a/lobject.h b/lobject.h index 769e96db..ba425fed 100644 --- a/lobject.h +++ b/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.77 2013/05/06 17:17:09 roberto Exp roberto $ +** $Id: lobject.h,v 2.78 2013/05/14 15:59:04 roberto Exp roberto $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -395,13 +395,7 @@ typedef struct Proto { typedef struct UpVal { CommonHeader; TValue *v; /* points to stack or to its own value */ - union { - TValue value; /* the value (when closed) */ - struct { /* double linked list (when open) */ - struct UpVal *prev; - struct UpVal *next; - } l; - } u; + TValue value; /* the value (when closed) */ } UpVal; diff --git a/lstate.c b/lstate.c index c9a397fd..9c4130a8 100644 --- a/lstate.c +++ b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.99 2012/10/02 17:40:53 roberto Exp roberto $ +** $Id: lstate.c,v 2.100 2013/08/05 16:58:28 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -230,7 +230,9 @@ LUA_API lua_State *lua_newthread (lua_State *L) { lua_State *L1; lua_lock(L); luaC_checkGC(L); - L1 = &luaC_newobj(L, LUA_TTHREAD, sizeof(LX), NULL, offsetof(LX, l))->th; + /* create new thread, linked after 'l_registry' */ + L1 = &luaC_newobj(L, LUA_TTHREAD, sizeof(LX), + &hvalue(&G(L)->l_registry)->next, offsetof(LX, l))->th; setthvalue(L, L->top, L1); api_incr_top(L); preinit_state(L1, G(L)); @@ -273,8 +275,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->ud = ud; g->mainthread = L; g->seed = makeseed(L); - g->uvhead.u.l.prev = &g->uvhead; - g->uvhead.u.l.next = &g->uvhead; g->gcrunning = 0; /* no GC while building state */ g->GCestimate = 0; g->strt.size = 0; diff --git a/lstate.h b/lstate.h index ae8c5500..4eda35fd 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.82 2012/07/02 13:37:04 roberto Exp roberto $ +** $Id: lstate.h,v 2.83 2013/08/05 16:58:28 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -20,17 +20,18 @@ ** be kept somehow accessible until being freed. ** ** Lua keeps most objects linked in list g->allgc. The link uses field -** 'next' of the CommonHeader. +** 'next' of the CommonHeader. Threads (except the main one) ar kept +** at the end of the 'allgc' list, after the 'l_registry' (which is +** the first object to be added to the list). ** -** Strings are kept in several lists headed by the array g->strt.hash. +** Short strings are kept in several lists headed by the array g->strt.hash. ** ** Open upvalues are not subject to independent garbage collection. They -** are collected together with their respective threads. Lua keeps a -** double-linked list with all open upvalues (g->uvhead) so that it can -** mark objects referred by them. (They are always gray, so they must -** be remarked in the atomic step. Usually their contents would be marked -** when traversing the respective threads, but the thread may already be -** dead, while the upvalue is still accessible through closures.) +** are collected together with their respective threads. (They are +** always gray, so they must be remarked in the atomic step. Usually +** their contents would be marked when traversing the respective +** threads, but the thread may already be dead, while the upvalue is +** still accessible through closures.) ** ** Objects with finalizers are kept in the list g->finobj. ** @@ -133,7 +134,6 @@ typedef struct global_State { GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ GCObject *allweak; /* list of all-weak tables */ GCObject *tobefnz; /* list of userdata to be GC */ - UpVal uvhead; /* head of double-linked list of all open upvalues */ Mbuffer buff; /* temporary buffer for string concatenation */ int gcpause; /* size of pause between successive GCs */ int gcstepmul; /* GC `granularity' */ diff --git a/ltests.c b/ltests.c index 4378d0ef..e45a82cf 100644 --- a/ltests.c +++ b/ltests.c @@ -1,5 +1,5 @@ /* -** $Id: ltests.c,v 2.139 2013/06/20 21:59:13 roberto Exp roberto $ +** $Id: ltests.c,v 2.140 2013/08/05 16:58:28 roberto Exp roberto $ ** Internal Module for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -310,7 +310,7 @@ static void checkstack (global_State *g, lua_State *L1) { lua_assert(!isdead(g, obj2gco(L1))); for (uvo = L1->openupval; uvo != NULL; uvo = gch(uvo)->next) { UpVal *uv = gco2uv(uvo); - lua_assert(uv->v != &uv->u.value); /* must be open */ + lua_assert(uv->v != &uv->value); /* must be open */ lua_assert(!isblack(uvo)); /* open upvalues cannot be black */ } for (ci = L1->ci; ci != NULL; ci = ci->previous) { @@ -334,7 +334,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead) { switch (gch(o)->tt) { case LUA_TUPVAL: { UpVal *uv = gco2uv(o); - lua_assert(uv->v == &uv->u.value); /* must be closed */ + lua_assert(uv->v == &uv->value); /* must be closed */ lua_assert(!isgray(o)); /* closed upvalues are never gray */ checkvalref(g, o, uv->v); break; @@ -419,8 +419,8 @@ static void checkgray (global_State *g, GCObject *o) { int lua_checkmemory (lua_State *L) { global_State *g = G(L); GCObject *o; - UpVal *uv; int maybedead; + int isthread; if (keepinvariant(g)) { lua_assert(!iswhite(obj2gco(g->mainthread))); lua_assert(!iswhite(gcvalue(&g->l_registry))); @@ -433,9 +433,12 @@ int lua_checkmemory (lua_State *L) { checkgray(g, g->allgc); lua_assert(g->sweepgc == NULL || issweepphase(g)); maybedead = 0; + isthread = 0; /* not traversing threads (yet) */ for (o = g->allgc; o != NULL; o = gch(o)->next) { if (g->sweepgc && o == *g->sweepgc) maybedead = 1; /* part of the list not yet swept */ + if (gch(o)->tt == LUA_TTHREAD) isthread = 1; /* now travesing threads... */ + else lua_assert(!isthread); /* ... and only threads */ checkobject(g, o, maybedead); lua_assert(!testbit(o->gch.marked, SEPARATED)); } @@ -455,14 +458,6 @@ int lua_checkmemory (lua_State *L) { lua_assert(gch(o)->tt == LUA_TUSERDATA || gch(o)->tt == LUA_TTABLE); } - /* check 'uvhead' list */ - for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { - lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); - lua_assert(uv->v != &uv->u.value); /* must be open */ - lua_assert(!isblack(obj2gco(uv))); /* open upvalues are never black */ - if (!isdead(g, obj2gco(uv))) - checkvalref(g, obj2gco(uv), uv->v); - } return 0; }