upvalues collected by reference count

This commit is contained in:
Roberto Ierusalimschy
2013-08-27 15:53:35 -03:00
parent 742b7377d3
commit af35c7f398
12 changed files with 157 additions and 205 deletions

22
lapi.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lapi.c,v 2.186 2013/08/05 16:58:28 roberto Exp roberto $ ** $Id: lapi.c,v 2.187 2013/08/16 18:55:49 roberto Exp roberto $
** Lua API ** Lua API
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -1192,7 +1192,7 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
static const char *aux_upvalue (StkId fi, int n, TValue **val, static const char *aux_upvalue (StkId fi, int n, TValue **val,
GCObject **owner) { GCObject **owner, UpVal **uv) {
switch (ttype(fi)) { switch (ttype(fi)) {
case LUA_TCCL: { /* C closure */ case LUA_TCCL: { /* C closure */
CClosure *f = clCvalue(fi); CClosure *f = clCvalue(fi);
@@ -1207,7 +1207,7 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val,
Proto *p = f->p; Proto *p = f->p;
if (!(1 <= n && n <= p->sizeupvalues)) return NULL; if (!(1 <= n && n <= p->sizeupvalues)) return NULL;
*val = f->upvals[n-1]->v; *val = f->upvals[n-1]->v;
if (owner) *owner = obj2gco(f->upvals[n - 1]); if (uv) *uv = f->upvals[n - 1];
name = p->upvalues[n-1].name; name = p->upvalues[n-1].name;
return (name == NULL) ? "" : getstr(name); return (name == NULL) ? "" : getstr(name);
} }
@@ -1220,7 +1220,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
const char *name; const char *name;
TValue *val = NULL; /* to avoid warnings */ TValue *val = NULL; /* to avoid warnings */
lua_lock(L); lua_lock(L);
name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL); name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL);
if (name) { if (name) {
setobj2s(L, L->top, val); setobj2s(L, L->top, val);
api_incr_top(L); api_incr_top(L);
@@ -1233,16 +1233,18 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
const char *name; const char *name;
TValue *val = NULL; /* to avoid warnings */ TValue *val = NULL; /* to avoid warnings */
GCObject *owner = NULL; /* to avoid warnings */ GCObject *owner = NULL;
UpVal *uv = NULL;
StkId fi; StkId fi;
lua_lock(L); lua_lock(L);
fi = index2addr(L, funcindex); fi = index2addr(L, funcindex);
api_checknelems(L, 1); api_checknelems(L, 1);
name = aux_upvalue(fi, n, &val, &owner); name = aux_upvalue(fi, n, &val, &owner, &uv);
if (name) { if (name) {
L->top--; L->top--;
setobj(L, val, L->top); setobj(L, val, L->top);
luaC_barrier(L, owner, L->top); if (owner) { luaC_barrier(L, owner, L->top); }
else if (uv) { luaC_upvalbarrier(L, uv); }
} }
lua_unlock(L); lua_unlock(L);
return name; return name;
@@ -1284,7 +1286,11 @@ LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
LClosure *f1; LClosure *f1;
UpVal **up1 = getupvalref(L, fidx1, n1, &f1); UpVal **up1 = getupvalref(L, fidx1, n1, &f1);
UpVal **up2 = getupvalref(L, fidx2, n2, NULL); UpVal **up2 = getupvalref(L, fidx2, n2, NULL);
luaC_upvdeccount(L, *up1);
*up1 = *up2; *up1 = *up2;
luaC_objbarrier(L, f1, *up2); (*up1)->refcount++;
if (upisopen(*up1)) (*up1)->u.op.touched = 1;
luaC_upvalbarrier(L, *up1);
} }

15
ldo.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ldo.c,v 2.108.1.2 2013/04/19 21:03:23 roberto Exp $ ** $Id: ldo.c,v 2.109 2013/04/19 21:05:04 roberto Exp roberto $
** Stack and Call structure of Lua ** Stack and Call structure of Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -141,10 +141,10 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
static void correctstack (lua_State *L, TValue *oldstack) { static void correctstack (lua_State *L, TValue *oldstack) {
CallInfo *ci; CallInfo *ci;
GCObject *up; UpVal *up;
L->top = (L->top - oldstack) + L->stack; L->top = (L->top - oldstack) + L->stack;
for (up = L->openupval; up != NULL; up = up->gch.next) for (up = L->openupval; up != NULL; up = up->u.op.next)
gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; up->v = (up->v - oldstack) + L->stack;
for (ci = L->ci; ci != NULL; ci = ci->previous) { for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top = (ci->top - oldstack) + L->stack; ci->top = (ci->top - oldstack) + L->stack;
ci->func = (ci->func - oldstack) + L->stack; ci->func = (ci->func - oldstack) + L->stack;
@@ -637,7 +637,6 @@ static void checkmode (lua_State *L, const char *mode, const char *x) {
static void f_parser (lua_State *L, void *ud) { static void f_parser (lua_State *L, void *ud) {
int i;
Closure *cl; Closure *cl;
struct SParser *p = cast(struct SParser *, ud); struct SParser *p = cast(struct SParser *, ud);
int c = zgetc(p->z); /* read first character */ int c = zgetc(p->z); /* read first character */
@@ -650,11 +649,7 @@ static void f_parser (lua_State *L, void *ud) {
cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
} }
lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);
for (i = 0; i < cl->l.nupvalues; i++) { /* initialize upvalues */ luaF_initupvals(L, &cl->l);
UpVal *up = luaF_newupval(L);
cl->l.upvals[i] = up;
luaC_objbarrier(L, cl, up);
}
} }

63
lfunc.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lfunc.c,v 2.34 2013/08/23 13:34:54 roberto Exp roberto $ ** $Id: lfunc.c,v 2.35 2013/08/26 12:41:10 roberto Exp roberto $
** Auxiliary functions to manipulate prototypes and closures ** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -38,32 +38,33 @@ Closure *luaF_newLclosure (lua_State *L, int n) {
} }
UpVal *luaF_newupval (lua_State *L) { void luaF_initupvals (lua_State *L, LClosure *cl) {
UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), int i;
&G(L)->localupv, 0)->uv; for (i = 0; i < cl->nupvalues; i++) {
uv->v = &uv->value; UpVal *uv = luaM_new(L, UpVal);
uv->refcount = 1;
uv->v = &uv->u.value; /* make it closed */
setnilvalue(uv->v); setnilvalue(uv->v);
return uv; cl->upvals[i] = uv;
}
} }
UpVal *luaF_findupval (lua_State *L, StkId level) { UpVal *luaF_findupval (lua_State *L, StkId level) {
global_State *g = G(L); UpVal **pp = &L->openupval;
GCObject **pp = &L->openupval;
UpVal *p; UpVal *p;
UpVal *uv; UpVal *uv;
while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { while (*pp != NULL && (p = *pp)->v >= level) {
GCObject *o = obj2gco(p); lua_assert(upisopen(p));
lua_assert(p->v != &p->value); if (p->v == level) /* found a corresponding upvalue? */
if (p->v == level) { /* found a corresponding upvalue? */ return p; /* return it */
if (isdead(g, o)) /* is it dead? */ pp = &p->u.op.next;
changewhite(o); /* resurrect it */
return p;
}
pp = &p->next;
} }
/* not found: create a new one */ /* not found: create a new one */
uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv; uv = luaM_new(L, UpVal);
uv->refcount = 0;
uv->u.op.next = *pp;
*pp = uv;
uv->v = level; /* current value lives in the stack */ uv->v = level; /* current value lives in the stack */
return uv; return uv;
} }
@@ -71,27 +72,15 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
void luaF_close (lua_State *L, StkId level) { void luaF_close (lua_State *L, StkId level) {
UpVal *uv; UpVal *uv;
global_State *g = G(L); while (L->openupval != NULL && (uv = L->openupval)->v >= level) {
while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) { lua_assert(upisopen(uv));
GCObject *o = obj2gco(uv); L->openupval = uv->u.op.next; /* remove from `open' list */
lua_assert(!isblack(o) && uv->v != &uv->value); if (uv->refcount == 0) /* no references? */
L->openupval = uv->next; /* remove from `open' list */
if (isdead(g, o))
luaM_free(L, uv); /* free upvalue */ luaM_free(L, uv); /* free upvalue */
else { else {
setobj(L, &uv->value, uv->v); /* move value to upvalue slot */ setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */
uv->v = &uv->value; /* now current value lives here */ uv->v = &uv->u.value; /* now current value lives here */
if (islocal(o)) { luaC_upvalbarrier(L, uv);
gch(o)->next = g->localupv; /* link upvalue into 'localupv' list */
g->localupv = o;
resetbit(o->gch.marked, LOCALBLACK);
}
else { /* link upvalue into 'allgc' list */
gch(o)->next = g->allgc;
g->allgc = o;
}
valnolocal(uv->v); /* keep local invariant */
luaC_checkupvalcolor(g, uv);
} }
} }
} }

22
lfunc.h
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lfunc.h,v 2.8 2012/05/08 13:53:33 roberto Exp roberto $ ** $Id: lfunc.h,v 2.9 2013/08/07 12:18:11 roberto Exp roberto $
** Auxiliary functions to manipulate prototypes and closures ** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -18,10 +18,28 @@
cast(int, sizeof(TValue *)*((n)-1))) cast(int, sizeof(TValue *)*((n)-1)))
/*
** Upvalues for Lua closures
*/
struct UpVal {
TValue *v; /* points to stack or to its own value */
unsigned int refcount; /* reference counter */
union {
struct { /* (when open) */
UpVal *next; /* linked list */
int touched; /* mark to avoid cycles with dead threads */
} op;
TValue value; /* the value (when closed) */
} u;
};
#define upisopen(up) ((up)->v != &(up)->u.value)
LUAI_FUNC Proto *luaF_newproto (lua_State *L); LUAI_FUNC Proto *luaF_newproto (lua_State *L);
LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems); LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems);
LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems); LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems);
LUAI_FUNC UpVal *luaF_newupval (lua_State *L); LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (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_freeproto (lua_State *L, Proto *f);

142
lgc.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lgc.c,v 2.151 2013/08/23 13:34:54 roberto Exp roberto $ ** $Id: lgc.c,v 2.152 2013/08/26 12:41:10 roberto Exp roberto $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -85,12 +85,9 @@
lua_longassert(!(iscollectable(o) && islocal(gcvalue(o)))); \ lua_longassert(!(iscollectable(o) && islocal(gcvalue(o)))); \
marklocalvalue(g,o); } marklocalvalue(g,o); }
#define marklocalobject(g,t) { \
if ((t) && iswhite(obj2gco(t))) \
reallymarkobject(g, obj2gco(t)); }
#define markobject(g,t) \ #define markobject(g,t) \
{ lua_assert((t) == NULL || !islocal(obj2gco(t))); marklocalobject(g,t); } { lua_assert((t) == NULL || !islocal(obj2gco(t))); \
if ((t) && iswhite(obj2gco(t))) reallymarkobject(g, obj2gco(t)); }
static void reallymarkobject (global_State *g, GCObject *o); static void reallymarkobject (global_State *g, GCObject *o);
@@ -176,22 +173,18 @@ void luaC_barrierback_ (lua_State *L, GCObject *o) {
/* /*
** check color (and invariants) for an upvalue that is being closed, ** barrier for assignments to closed upvalues. Because upvalues are
** i.e., moved into the 'allgc' list ** shared among closures, it is impossible to know the color of all
** closured pointing to it. So, we assume that the object being assigned
** must be marked.
*/ */
void luaC_checkupvalcolor (global_State *g, UpVal *uv) { LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) {
GCObject *o = obj2gco(uv); global_State *g = G(L);
lua_assert(!isblack(o)); /* open upvalues are never black */ GCObject *o = gcvalue(uv->v);
if (isgray(o)) { lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */
if (keepinvariant(g)) { nolocal(o);
gray2black(o); /* it is being visited now */ if (keepinvariant(g))
markvalue(g, uv->v); markobject(g, o);
}
else {
lua_assert(issweepphase(g));
makewhite(g, o);
}
}
} }
@@ -257,14 +250,6 @@ static void reallymarkobject (global_State *g, GCObject *o) {
size = sizeudata(gco2u(o)); size = sizeudata(gco2u(o));
break; break;
} }
case LUA_TUPVAL: {
UpVal *uv = gco2uv(o);
marklocalvalue(g, uv->v);
if (uv->v != &uv->value) /* open? */
return; /* open upvalues remain gray */
size = sizeof(UpVal);
break;
}
case LUA_TLCL: { case LUA_TLCL: {
gco2lcl(o)->gclist = g->gray; gco2lcl(o)->gclist = g->gray;
g->gray = o; g->gray = o;
@@ -328,10 +313,12 @@ static void remarkupvals (global_State *g) {
for (; thread != NULL; thread = gch(thread)->next) { for (; thread != NULL; thread = gch(thread)->next) {
lua_assert(!isblack(thread)); /* threads are never black */ lua_assert(!isblack(thread)); /* threads are never black */
if (!isgray(thread)) { /* dead thread? */ if (!isgray(thread)) { /* dead thread? */
GCObject *uv = gco2th(thread)->openupval; UpVal *uv = gco2th(thread)->openupval;
for (; uv != NULL; uv = gch(uv)->next) { for (; uv != NULL; uv = uv->u.op.next) {
if (isgray(uv)) /* marked? */ if (uv->u.op.touched) {
marklocalvalue(g, gco2uv(uv)->v); /* remark upvalue's value */ marklocalvalue(g, uv->v); /* remark upvalue's value */
uv->u.op.touched = 0;
}
} }
} }
} }
@@ -493,8 +480,15 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) {
static lu_mem traverseLclosure (global_State *g, LClosure *cl) { static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
int i; int i;
markobject(g, cl->p); /* mark its prototype */ markobject(g, cl->p); /* mark its prototype */
for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */
marklocalobject(g, cl->upvals[i]); UpVal *uv = cl->upvals[i];
if (uv != NULL) {
if (upisopen(uv))
uv->u.op.touched = 1; /* can be marked in 'remarkupvals' */
else
markvalue(g, uv->v);
}
}
return sizeLclosure(cl->nupvalues); return sizeLclosure(cl->nupvalues);
} }
@@ -511,10 +505,14 @@ static lu_mem traversestack (global_State *g, lua_State *th) {
for (; o < lim; o++) /* clear not-marked stack slice */ for (; o < lim; o++) /* clear not-marked stack slice */
setnilvalue(o); setnilvalue(o);
} }
else { /* count call infos to compute size */ else {
CallInfo *ci; CallInfo *ci;
luaE_freeCI(th); /* free extra CallInfo slots */
for (ci = &th->base_ci; ci != th->ci; ci = ci->next) for (ci = &th->base_ci; ci != th->ci; ci = ci->next)
n++; n++; /* count call infos to compute size */
/* should not change the stack during an emergency gc cycle */
if (g->gckind != KGC_EMERGENCY)
luaD_shrinkstack(th);
} }
return sizeof(lua_State) + sizeof(TValue) * th->stacksize + return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
sizeof(CallInfo) * n; sizeof(CallInfo) * n;
@@ -667,18 +665,36 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) {
} }
void luaC_upvdeccount (lua_State *L, UpVal *uv) {
lua_assert(uv->refcount > 0);
uv->refcount--;
if (uv->refcount == 0 && !upisopen(uv))
luaM_free(L, uv);
}
static void freeLclosure (lua_State *L, LClosure *cl) {
int i;
for (i = 0; i < cl->nupvalues; i++) {
UpVal *uv = cl->upvals[i];
if (uv)
luaC_upvdeccount(L, uv);
}
luaM_freemem(L, cl, sizeLclosure(cl->nupvalues));
}
static void freeobj (lua_State *L, GCObject *o) { static void freeobj (lua_State *L, GCObject *o) {
switch (gch(o)->tt) { switch (gch(o)->tt) {
case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
case LUA_TLCL: { case LUA_TLCL: {
luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues)); freeLclosure(L, gco2lcl(o));
break; break;
} }
case LUA_TCCL: { case LUA_TCCL: {
luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues));
break; break;
} }
case LUA_TUPVAL: luaM_free(L, gco2uv(o)); break;
case LUA_TTABLE: luaH_free(L, gco2t(o)); break; case LUA_TTABLE: luaH_free(L, gco2t(o)); break;
case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break;
case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;
@@ -698,20 +714,6 @@ static void freeobj (lua_State *L, GCObject *o) {
static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count);
/*
** sweep the (open) upvalues of a thread and resize its stack and
** list of call-info structures.
*/
static void sweepthread (lua_State *L, lua_State *L1) {
if (L1->stack == NULL) return; /* stack not completely built yet */
sweepwholelist(L, &L1->openupval); /* sweep open upvalues */
luaE_freeCI(L1); /* free extra CallInfo slots */
/* should not change the stack during an emergency gc cycle */
if (G(L)->gckind != KGC_EMERGENCY)
luaD_shrinkstack(L1);
}
/* /*
** sweep at most 'count' elements from a list of GCObjects erasing dead ** 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" ** objects, where a dead (not alive) object is one marked with the "old"
@@ -730,10 +732,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
*p = gch(curr)->next; /* remove 'curr' from list */ *p = gch(curr)->next; /* remove 'curr' from list */
freeobj(L, curr); /* erase 'curr' */ freeobj(L, curr); /* erase 'curr' */
} }
else { else { /* update marks */
if (gch(curr)->tt == LUA_TTHREAD)
sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */
/* update marks */
gch(curr)->marked = cast_byte((marked & maskcolors) | white); gch(curr)->marked = cast_byte((marked & maskcolors) | white);
p = &gch(curr)->next; /* go to next element */ p = &gch(curr)->next; /* go to next element */
} }
@@ -886,16 +885,6 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
*/ */
static void localmarkclosure (LClosure *cl, int bit) {
int i;
for (i = 0; i < cl->nupvalues; i++) {
if (cl->upvals[i]) {
l_setbit(cl->upvals[i]->marked, bit);
}
}
}
/* /*
** Traverse a thread, local marking all its collectable objects ** Traverse a thread, local marking all its collectable objects
*/ */
@@ -904,16 +893,8 @@ static void localmarkthread (lua_State *l) {
if (o == NULL) if (o == NULL)
return; /* stack not completely built yet */ return; /* stack not completely built yet */
for (; o < l->top; o++) { /* mark live elements in the stack */ for (; o < l->top; o++) { /* mark live elements in the stack */
if (iscollectable(o)) { if (iscollectable(o))
GCObject *obj = gcvalue(o); l_setbit(gcvalue(o)->gch.marked, LOCALBLACK);
if (obj->gch.tt == LUA_TLCL && /* is it a Lua closure? */
islocal(obj) && /* is it still local? */
!testbit(obj->gch.marked, LOCALBLACK)) { /* not visited yet? */
/* mark its upvalues as local black */
localmarkclosure(gco2lcl(obj), LOCALBLACK);
}
l_setbit(obj->gch.marked, LOCALBLACK);
}
} }
} }
@@ -937,10 +918,6 @@ static void localsweep (lua_State *L, global_State *g, GCObject **p) {
*p = curr->gch.next; /* remove 'curr' from list */ *p = curr->gch.next; /* remove 'curr' from list */
curr->gch.next = g->allgc; /* link 'curr' in 'allgc' list */ curr->gch.next = g->allgc; /* link 'curr' in 'allgc' list */
g->allgc = curr; g->allgc = curr;
if (curr->gch.tt == LUA_TLCL) { /* is it a Lua closure? */
/* mark its upvalues as non local */
localmarkclosure(gco2lcl(curr), LOCALBIT);
}
} }
else { /* still local */ else { /* still local */
if (testbit(curr->gch.marked, LOCALBLACK)) { /* locally alive? */ if (testbit(curr->gch.marked, LOCALBLACK)) { /* locally alive? */
@@ -965,7 +942,6 @@ static void luaC_localcollection (lua_State *L) {
lua_assert(g->gcstate == GCSpause); lua_assert(g->gcstate == GCSpause);
localmark(g); localmark(g);
localsweep(L, g, &g->localgc); localsweep(L, g, &g->localgc);
localsweep(L, g, &g->localupv);
} }
/* }====================================================== */ /* }====================================================== */
@@ -1036,7 +1012,6 @@ void luaC_freeallobjects (lua_State *L) {
g->gckind = KGC_NORMAL; g->gckind = KGC_NORMAL;
sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */
sweepwholelist(L, &g->localgc); sweepwholelist(L, &g->localgc);
sweepwholelist(L, &g->localupv);
sweepwholelist(L, &g->allgc); sweepwholelist(L, &g->allgc);
sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ sweepwholelist(L, &g->fixedgc); /* collect fixed objects */
lua_assert(g->strt.nuse == 0); lua_assert(g->strt.nuse == 0);
@@ -1119,7 +1094,6 @@ static lu_mem singlestep (lua_State *L) {
} }
else { else {
sweepwholelist(L, &g->localgc); sweepwholelist(L, &g->localgc);
sweepwholelist(L, &g->localupv);
g->gcstate = GCSsweep; g->gcstate = GCSsweep;
return GCLOCALPAUSE / 4; /* some magic for now */ return GCLOCALPAUSE / 4; /* some magic for now */
} }

14
lgc.h
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lgc.h,v 2.65 2013/08/21 20:09:51 roberto Exp roberto $ ** $Id: lgc.h,v 2.66 2013/08/23 13:34:54 roberto Exp roberto $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -55,7 +55,7 @@
** all objects are white again. ** all objects are white again.
*/ */
#define keepinvariant(g) (g->gcstate <= GCSatomic) #define keepinvariant(g) ((g)->gcstate <= GCSatomic)
/* /*
@@ -91,7 +91,7 @@
#define tofinalize(x) testbit((x)->gch.marked, FINALIZEDBIT) #define tofinalize(x) testbit((x)->gch.marked, FINALIZEDBIT)
#define otherwhite(g) (g->currentwhite ^ WHITEBITS) #define otherwhite(g) ((g)->currentwhite ^ WHITEBITS)
#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) #define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow)))
#define isdead(g,v) isdeadm(otherwhite(g), (v)->gch.marked) #define isdead(g,v) isdeadm(otherwhite(g), (v)->gch.marked)
@@ -127,6 +127,10 @@
{ if (nolocal(obj2gco(o)), isblack(obj2gco(p)) && iswhite(obj2gco(o))) \ { if (nolocal(obj2gco(o)), isblack(obj2gco(p)) && iswhite(obj2gco(o))) \
luaC_barrierback_(L,p); } luaC_barrierback_(L,p); }
#define luaC_upvalbarrier(L,uv) \
{ if (iscollectable((uv)->v) && !upisopen(uv)) \
luaC_upvalbarrier_(L,uv); }
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L); LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L);
@@ -138,7 +142,9 @@ LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz,
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); 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_barrierback_ (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c); LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c);
LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv); LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv);
#endif #endif

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lobject.h,v 2.79 2013/08/07 12:18:11 roberto Exp roberto $ ** $Id: lobject.h,v 2.80 2013/08/18 16:12:18 roberto Exp roberto $
** Type definitions for Lua objects ** Type definitions for Lua objects
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -20,13 +20,12 @@
** Extra tags for non-values ** Extra tags for non-values
*/ */
#define LUA_TPROTO LUA_NUMTAGS #define LUA_TPROTO LUA_NUMTAGS
#define LUA_TUPVAL (LUA_NUMTAGS+1) #define LUA_TDEADKEY (LUA_NUMTAGS+1)
#define LUA_TDEADKEY (LUA_NUMTAGS+2)
/* /*
** number of all possible tags (including LUA_TNONE but excluding DEADKEY) ** number of all possible tags (including LUA_TNONE but excluding DEADKEY)
*/ */
#define LUA_TOTALTAGS (LUA_TUPVAL+2) #define LUA_TOTALTAGS (LUA_TPROTO + 2)
/* /*
@@ -392,11 +391,7 @@ typedef struct Proto {
/* /*
** Lua Upvalues ** Lua Upvalues
*/ */
typedef struct UpVal { typedef struct UpVal UpVal;
CommonHeader;
TValue *v; /* points to stack or to its own value */
TValue value; /* the value (when closed) */
} UpVal;
/* /*

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lstate.c,v 2.105 2013/08/23 13:34:54 roberto Exp roberto $ ** $Id: lstate.c,v 2.106 2013/08/26 12:41:10 roberto Exp roberto $
** Global State ** Global State
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -289,7 +289,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->version = lua_version(NULL); g->version = lua_version(NULL);
g->gcstate = GCSpause; g->gcstate = GCSpause;
g->allgc = NULL; g->allgc = NULL;
g->localgc = g->localupv = NULL; g->localgc = NULL;
g->finobj = NULL; g->finobj = NULL;
g->tobefnz = NULL; g->tobefnz = NULL;
g->fixedgc = NULL; g->fixedgc = NULL;

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lstate.h,v 2.89 2013/08/23 13:34:54 roberto Exp roberto $ ** $Id: lstate.h,v 2.90 2013/08/26 12:41:10 roberto Exp roberto $
** Global State ** Global State
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -27,13 +27,6 @@
** List 'fixedgc' keep objects that are not to be collected (currently ** List 'fixedgc' keep objects that are not to be collected (currently
** only small strings, such as reserved words). ** only small strings, such as reserved words).
** **
** Open upvalues are not subject to independent garbage collection. They
** 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.)
**
** Live objects with finalizers are kept in the list g->finobj. The ** Live objects with finalizers are kept in the list g->finobj. The
** list g->tobefnz links all objects being finalized. In particular, an ** list g->tobefnz links all objects being finalized. In particular, an
** object has its FINALIZEDBIT set iff it is in one of these lists. ** object has its FINALIZEDBIT set iff it is in one of these lists.
@@ -128,7 +121,6 @@ typedef struct global_State {
lu_byte gcrunning; /* true if GC is running */ lu_byte gcrunning; /* true if GC is running */
GCObject *allgc; /* list of all collectable objects */ GCObject *allgc; /* list of all collectable objects */
GCObject *localgc; /* list of local objects */ GCObject *localgc; /* list of local objects */
GCObject *localupv; /* list of local upvalues */
GCObject *finobj; /* list of collectable objects with finalizers */ GCObject *finobj; /* list of collectable objects with finalizers */
GCObject **sweepgc; /* current position of sweep in list 'allgc' */ GCObject **sweepgc; /* current position of sweep in list 'allgc' */
GCObject **sweepfin; /* current position of sweep in list 'finobj' */ GCObject **sweepfin; /* current position of sweep in list 'finobj' */
@@ -171,7 +163,7 @@ struct lua_State {
int basehookcount; int basehookcount;
int hookcount; int hookcount;
lua_Hook hook; lua_Hook hook;
GCObject *openupval; /* list of open upvalues in this stack */ UpVal *openupval; /* list of open upvalues in this stack */
GCObject *gclist; GCObject *gclist;
struct lua_longjmp *errorJmp; /* current error recover point */ struct lua_longjmp *errorJmp; /* current error recover point */
ptrdiff_t errfunc; /* current error handling function (stack index) */ ptrdiff_t errfunc; /* current error handling function (stack index) */
@@ -192,7 +184,6 @@ union GCObject {
union Closure cl; union Closure cl;
struct Table h; struct Table h;
struct Proto p; struct Proto p;
struct UpVal uv;
struct lua_State th; /* thread */ struct lua_State th; /* thread */
}; };
@@ -211,7 +202,6 @@ union GCObject {
check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl)) check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl))
#define gco2t(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) #define gco2t(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h))
#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) #define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p))
#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv))
#define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) #define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th))
/* macro to convert any Lua object into a GCObject */ /* macro to convert any Lua object into a GCObject */

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ltests.c,v 2.148 2013/08/22 15:21:48 roberto Exp roberto $ ** $Id: ltests.c,v 2.149 2013/08/26 12:41:10 roberto Exp roberto $
** Internal Module for Debugging of the Lua Implementation ** Internal Module for Debugging of the Lua Implementation
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -195,14 +195,6 @@ static int testobjref2 (GCObject *f, GCObject *t) {
/* not a local or pointed by a thread? */ /* not a local or pointed by a thread? */
if (!islocal(t) || gch(f)->tt == LUA_TTHREAD) if (!islocal(t) || gch(f)->tt == LUA_TTHREAD)
return 1; /* ok */ return 1; /* ok */
if (gch(t)->tt == LUA_TUPVAL) {
lua_assert(gch(f)->tt == LUA_TLCL);
return 1; /* upvalue pointed by a closure */
}
if (gch(f)->tt == LUA_TUPVAL) {
UpVal *uv = gco2uv(f);
return (uv->v != &uv->value); /* open upvalue can point to local stuff */
}
if (gch(f)->tt == LUA_TPROTO && gch(t)->tt == LUA_TLCL) if (gch(f)->tt == LUA_TPROTO && gch(t)->tt == LUA_TLCL)
return 1; /* cache from a prototype */ return 1; /* cache from a prototype */
return 0; return 0;
@@ -311,9 +303,11 @@ static void checkLclosure (global_State *g, LClosure *cl) {
int i; int i;
if (cl->p) checkobjref(g, clgc, cl->p); if (cl->p) checkobjref(g, clgc, cl->p);
for (i=0; i<cl->nupvalues; i++) { for (i=0; i<cl->nupvalues; i++) {
if (cl->upvals[i]) { UpVal *uv = cl->upvals[i];
lua_assert(cl->upvals[i]->tt == LUA_TUPVAL); if (uv) {
checkobjref(g, clgc, cl->upvals[i]); if (!upisopen(uv)) /* only closed upvalues matter to invariant */
checkvalref(g, clgc, uv->v);
lua_assert(uv->refcount > 0);
} }
} }
} }
@@ -332,13 +326,10 @@ static int lua_checkpc (pCallInfo ci) {
static void checkstack (global_State *g, lua_State *L1) { static void checkstack (global_State *g, lua_State *L1) {
StkId o; StkId o;
CallInfo *ci; CallInfo *ci;
GCObject *uvo; UpVal *uv;
lua_assert(!isdead(g, obj2gco(L1))); lua_assert(!isdead(g, obj2gco(L1)));
for (uvo = L1->openupval; uvo != NULL; uvo = gch(uvo)->next) { for (uv = L1->openupval; uv != NULL; uv = uv->u.op.next)
UpVal *uv = gco2uv(uvo); lua_assert(upisopen(uv)); /* 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) { for (ci = L1->ci; ci != NULL; ci = ci->previous) {
lua_assert(ci->top <= L1->stack_last); lua_assert(ci->top <= L1->stack_last);
lua_assert(lua_checkpc(ci)); lua_assert(lua_checkpc(ci));
@@ -357,13 +348,6 @@ static void checkobject (global_State *g, GCObject *o, int maybedead) {
else { else {
lua_assert(g->gcstate != GCSpause || iswhite(o)); lua_assert(g->gcstate != GCSpause || iswhite(o));
switch (gch(o)->tt) { switch (gch(o)->tt) {
case LUA_TUPVAL: {
UpVal *uv = gco2uv(o);
lua_assert(uv->v == &uv->value); /* must be closed */
lua_assert(!isgray(o)); /* closed upvalues are never gray */
checkvalref(g, o, uv->v);
break;
}
case LUA_TUSERDATA: { case LUA_TUSERDATA: {
Table *mt = gco2u(o)->metatable; Table *mt = gco2u(o)->metatable;
if (mt) checkobjref(g, o, mt); if (mt) checkobjref(g, o, mt);
@@ -490,12 +474,6 @@ int lua_checkmemory (lua_State *L) {
for (o = g->localgc; o != NULL; o = gch(o)->next) { for (o = g->localgc; o != NULL; o = gch(o)->next) {
checkobject(g, o, 1); checkobject(g, o, 1);
} }
/* check 'localupv' list */
checkgray(g, g->localupv);
for (o = g->localupv; o != NULL; o = gch(o)->next) {
lua_assert(gch(o)->tt == LUA_TUPVAL);
checkobject(g, o, 1);
}
return 0; return 0;
} }

4
ltm.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ltm.c,v 2.20 2013/05/06 17:19:11 roberto Exp roberto $ ** $Id: ltm.c,v 2.21 2013/08/21 20:09:51 roberto Exp roberto $
** Tag methods ** Tag methods
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -28,7 +28,7 @@ LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = {
"no value", "no value",
"nil", "boolean", udatatypename, "number", "nil", "boolean", udatatypename, "number",
"string", "table", "function", udatatypename, "thread", "string", "table", "function", udatatypename, "thread",
"proto", "upval" /* these last two cases are used for tests only */ "proto" /* this last case is used for tests only */
}; };

7
lvm.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lvm.c,v 2.177 2013/08/16 18:55:49 roberto Exp roberto $ ** $Id: lvm.c,v 2.178 2013/08/19 14:18:43 roberto Exp roberto $
** Lua virtual machine ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -416,7 +416,8 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
ncl->l.upvals[i] = luaF_findupval(L, base + uv[i].idx); ncl->l.upvals[i] = luaF_findupval(L, base + uv[i].idx);
else /* get upvalue from enclosing function */ else /* get upvalue from enclosing function */
ncl->l.upvals[i] = encup[uv[i].idx]; ncl->l.upvals[i] = encup[uv[i].idx];
/* new closure is white and local, so we do not need a barrier here */ ncl->l.upvals[i]->refcount++;
/* new closure is white, so we do not need a barrier here */
} }
if (!isblack(obj2gco(p))) /* cache will not break GC invariant? */ if (!isblack(obj2gco(p))) /* cache will not break GC invariant? */
p->cache = ncl; /* save it on cache for reuse */ p->cache = ncl; /* save it on cache for reuse */
@@ -591,7 +592,7 @@ void luaV_execute (lua_State *L) {
vmcase(OP_SETUPVAL, vmcase(OP_SETUPVAL,
UpVal *uv = cl->upvals[GETARG_B(i)]; UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, ra); setobj(L, uv->v, ra);
luaC_barrier(L, uv, ra); luaC_upvalbarrier(L, uv);
) )
vmcase(OP_SETTABLE, vmcase(OP_SETTABLE,
Protect(luaV_settable(L, ra, RKB(i), RKC(i))); Protect(luaV_settable(L, ra, RKB(i), RKC(i)));