double-linked list of all upvalues elliminated and changed to a

traversal of all non-marked threads
This commit is contained in:
Roberto Ierusalimschy 2013-08-07 09:18:11 -03:00
parent 677d90165f
commit 623e388bb4
7 changed files with 47 additions and 72 deletions

34
lfunc.c
View File

@ -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);

View File

@ -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);

25
lgc.c
View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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' */

View File

@ -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;
}