diff --git a/lapi.c b/lapi.c index 62b5f1a3..f4a8beb4 100644 --- a/lapi.c +++ b/lapi.c @@ -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 ** 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, - GCObject **owner) { + GCObject **owner, UpVal **uv) { switch (ttype(fi)) { case LUA_TCCL: { /* C closure */ CClosure *f = clCvalue(fi); @@ -1207,7 +1207,7 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val, Proto *p = f->p; if (!(1 <= n && n <= p->sizeupvalues)) return NULL; *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; 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; TValue *val = NULL; /* to avoid warnings */ lua_lock(L); - name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL); + name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL); if (name) { setobj2s(L, L->top, val); 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) { const char *name; TValue *val = NULL; /* to avoid warnings */ - GCObject *owner = NULL; /* to avoid warnings */ + GCObject *owner = NULL; + UpVal *uv = NULL; StkId fi; lua_lock(L); fi = index2addr(L, funcindex); api_checknelems(L, 1); - name = aux_upvalue(fi, n, &val, &owner); + name = aux_upvalue(fi, n, &val, &owner, &uv); if (name) { 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); return name; @@ -1284,7 +1286,11 @@ LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, LClosure *f1; UpVal **up1 = getupvalref(L, fidx1, n1, &f1); UpVal **up2 = getupvalref(L, fidx2, n2, NULL); + luaC_upvdeccount(L, *up1); *up1 = *up2; - luaC_objbarrier(L, f1, *up2); + (*up1)->refcount++; + if (upisopen(*up1)) (*up1)->u.op.touched = 1; + luaC_upvalbarrier(L, *up1); } + diff --git a/ldo.c b/ldo.c index 47e80f8a..d90bf263 100644 --- a/ldo.c +++ b/ldo.c @@ -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 ** 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) { CallInfo *ci; - GCObject *up; + UpVal *up; L->top = (L->top - oldstack) + L->stack; - for (up = L->openupval; up != NULL; up = up->gch.next) - gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; + for (up = L->openupval; up != NULL; up = up->u.op.next) + up->v = (up->v - oldstack) + L->stack; for (ci = L->ci; ci != NULL; ci = ci->previous) { ci->top = (ci->top - 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) { - int i; Closure *cl; struct SParser *p = cast(struct SParser *, ud); 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); } lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); - for (i = 0; i < cl->l.nupvalues; i++) { /* initialize upvalues */ - UpVal *up = luaF_newupval(L); - cl->l.upvals[i] = up; - luaC_objbarrier(L, cl, up); - } + luaF_initupvals(L, &cl->l); } diff --git a/lfunc.c b/lfunc.c index 654344a6..5bbae69c 100644 --- a/lfunc.c +++ b/lfunc.c @@ -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 ** See Copyright Notice in lua.h */ @@ -38,32 +38,33 @@ Closure *luaF_newLclosure (lua_State *L, int n) { } -UpVal *luaF_newupval (lua_State *L) { - UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), - &G(L)->localupv, 0)->uv; - uv->v = &uv->value; - setnilvalue(uv->v); - return uv; +void luaF_initupvals (lua_State *L, LClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) { + UpVal *uv = luaM_new(L, UpVal); + uv->refcount = 1; + uv->v = &uv->u.value; /* make it closed */ + setnilvalue(uv->v); + cl->upvals[i] = uv; + } } UpVal *luaF_findupval (lua_State *L, StkId level) { - global_State *g = G(L); - GCObject **pp = &L->openupval; + UpVal **pp = &L->openupval; UpVal *p; UpVal *uv; - while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { - GCObject *o = obj2gco(p); - 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 */ - return p; - } - pp = &p->next; + while (*pp != NULL && (p = *pp)->v >= level) { + lua_assert(upisopen(p)); + if (p->v == level) /* found a corresponding upvalue? */ + return p; /* return it */ + pp = &p->u.op.next; } /* 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 */ return uv; } @@ -71,27 +72,15 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { 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->value); - L->openupval = uv->next; /* remove from `open' list */ - if (isdead(g, o)) + while (L->openupval != NULL && (uv = L->openupval)->v >= level) { + lua_assert(upisopen(uv)); + L->openupval = uv->u.op.next; /* remove from `open' list */ + if (uv->refcount == 0) /* no references? */ luaM_free(L, uv); /* free upvalue */ else { - setobj(L, &uv->value, uv->v); /* move value to upvalue slot */ - uv->v = &uv->value; /* now current value lives here */ - if (islocal(o)) { - 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); + setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ + uv->v = &uv->u.value; /* now current value lives here */ + luaC_upvalbarrier(L, uv); } } } diff --git a/lfunc.h b/lfunc.h index c5e8b89c..39dbc901 100644 --- a/lfunc.h +++ b/lfunc.h @@ -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 ** See Copyright Notice in lua.h */ @@ -18,10 +18,28 @@ 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 Closure *luaF_newCclosure (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 void luaF_close (lua_State *L, StkId level); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); diff --git a/lgc.c b/lgc.c index d87d5afe..f09af8e7 100644 --- a/lgc.c +++ b/lgc.c @@ -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 ** See Copyright Notice in lua.h */ @@ -85,12 +85,9 @@ lua_longassert(!(iscollectable(o) && islocal(gcvalue(o)))); \ marklocalvalue(g,o); } -#define marklocalobject(g,t) { \ - if ((t) && iswhite(obj2gco(t))) \ - reallymarkobject(g, obj2gco(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); @@ -176,22 +173,18 @@ void luaC_barrierback_ (lua_State *L, GCObject *o) { /* -** check color (and invariants) for an upvalue that is being closed, -** i.e., moved into the 'allgc' list +** barrier for assignments to closed upvalues. Because upvalues are +** 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) { - GCObject *o = obj2gco(uv); - lua_assert(!isblack(o)); /* open upvalues are never black */ - if (isgray(o)) { - if (keepinvariant(g)) { - gray2black(o); /* it is being visited now */ - markvalue(g, uv->v); - } - else { - lua_assert(issweepphase(g)); - makewhite(g, o); - } - } +LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { + global_State *g = G(L); + GCObject *o = gcvalue(uv->v); + lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ + nolocal(o); + if (keepinvariant(g)) + markobject(g, o); } @@ -257,14 +250,6 @@ static void reallymarkobject (global_State *g, GCObject *o) { size = sizeudata(gco2u(o)); 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: { gco2lcl(o)->gclist = g->gray; g->gray = o; @@ -328,10 +313,12 @@ static void remarkupvals (global_State *g) { 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? */ - marklocalvalue(g, gco2uv(uv)->v); /* remark upvalue's value */ + UpVal *uv = gco2th(thread)->openupval; + for (; uv != NULL; uv = uv->u.op.next) { + if (uv->u.op.touched) { + 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) { int i; markobject(g, cl->p); /* mark its prototype */ - for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ - marklocalobject(g, cl->upvals[i]); + for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ + 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); } @@ -511,10 +505,14 @@ static lu_mem traversestack (global_State *g, lua_State *th) { for (; o < lim; o++) /* clear not-marked stack slice */ setnilvalue(o); } - else { /* count call infos to compute size */ + else { CallInfo *ci; + luaE_freeCI(th); /* free extra CallInfo slots */ 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 + 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) { switch (gch(o)->tt) { case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; case LUA_TLCL: { - luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues)); + freeLclosure(L, gco2lcl(o)); break; } case LUA_TCCL: { luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); 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; @@ -698,20 +714,6 @@ static void freeobj (lua_State *L, GCObject *o) { 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 ** 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 */ freeobj(L, curr); /* erase 'curr' */ } - else { - if (gch(curr)->tt == LUA_TTHREAD) - sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */ - /* update marks */ + else { /* update marks */ gch(curr)->marked = cast_byte((marked & maskcolors) | white); 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 */ @@ -904,16 +893,8 @@ static void localmarkthread (lua_State *l) { if (o == NULL) return; /* stack not completely built yet */ for (; o < l->top; o++) { /* mark live elements in the stack */ - if (iscollectable(o)) { - GCObject *obj = gcvalue(o); - 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); - } + if (iscollectable(o)) + l_setbit(gcvalue(o)->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 */ curr->gch.next = g->allgc; /* link 'curr' in 'allgc' list */ 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 */ if (testbit(curr->gch.marked, LOCALBLACK)) { /* locally alive? */ @@ -965,7 +942,6 @@ static void luaC_localcollection (lua_State *L) { lua_assert(g->gcstate == GCSpause); localmark(g); localsweep(L, g, &g->localgc); - localsweep(L, g, &g->localupv); } /* }====================================================== */ @@ -1036,7 +1012,6 @@ void luaC_freeallobjects (lua_State *L) { g->gckind = KGC_NORMAL; sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ sweepwholelist(L, &g->localgc); - sweepwholelist(L, &g->localupv); sweepwholelist(L, &g->allgc); sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ lua_assert(g->strt.nuse == 0); @@ -1119,7 +1094,6 @@ static lu_mem singlestep (lua_State *L) { } else { sweepwholelist(L, &g->localgc); - sweepwholelist(L, &g->localupv); g->gcstate = GCSsweep; return GCLOCALPAUSE / 4; /* some magic for now */ } diff --git a/lgc.h b/lgc.h index b931ae1a..13563db3 100644 --- a/lgc.h +++ b/lgc.h @@ -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 ** See Copyright Notice in lua.h */ @@ -55,7 +55,7 @@ ** 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 otherwhite(g) (g->currentwhite ^ WHITEBITS) +#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) #define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) #define isdead(g,v) isdeadm(otherwhite(g), (v)->gch.marked) @@ -127,6 +127,10 @@ { if (nolocal(obj2gco(o)), isblack(obj2gco(p)) && iswhite(obj2gco(o))) \ 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_freeallobjects (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_barrierback_ (lua_State *L, GCObject *o); 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_checkupvalcolor (global_State *g, UpVal *uv); +LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv); + #endif diff --git a/lobject.h b/lobject.h index 3ab75ad5..e9a20915 100644 --- a/lobject.h +++ b/lobject.h @@ -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 ** See Copyright Notice in lua.h */ @@ -20,13 +20,12 @@ ** Extra tags for non-values */ #define LUA_TPROTO LUA_NUMTAGS -#define LUA_TUPVAL (LUA_NUMTAGS+1) -#define LUA_TDEADKEY (LUA_NUMTAGS+2) +#define LUA_TDEADKEY (LUA_NUMTAGS+1) /* ** 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 */ -typedef struct UpVal { - CommonHeader; - TValue *v; /* points to stack or to its own value */ - TValue value; /* the value (when closed) */ -} UpVal; +typedef struct UpVal UpVal; /* diff --git a/lstate.c b/lstate.c index e6a75dbb..4d141aec 100644 --- a/lstate.c +++ b/lstate.c @@ -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 ** 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->gcstate = GCSpause; g->allgc = NULL; - g->localgc = g->localupv = NULL; + g->localgc = NULL; g->finobj = NULL; g->tobefnz = NULL; g->fixedgc = NULL; diff --git a/lstate.h b/lstate.h index 02180df7..e0aed2d9 100644 --- a/lstate.h +++ b/lstate.h @@ -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 ** See Copyright Notice in lua.h */ @@ -27,13 +27,6 @@ ** List 'fixedgc' keep objects that are not to be collected (currently ** 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 ** list g->tobefnz links all objects being finalized. In particular, an ** 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 */ GCObject *allgc; /* list of all collectable objects */ GCObject *localgc; /* list of local objects */ - GCObject *localupv; /* list of local upvalues */ GCObject *finobj; /* list of collectable objects with finalizers */ GCObject **sweepgc; /* current position of sweep in list 'allgc' */ GCObject **sweepfin; /* current position of sweep in list 'finobj' */ @@ -171,7 +163,7 @@ struct lua_State { int basehookcount; int hookcount; lua_Hook hook; - GCObject *openupval; /* list of open upvalues in this stack */ + UpVal *openupval; /* list of open upvalues in this stack */ GCObject *gclist; struct lua_longjmp *errorJmp; /* current error recover point */ ptrdiff_t errfunc; /* current error handling function (stack index) */ @@ -192,7 +184,6 @@ union GCObject { union Closure cl; struct Table h; struct Proto p; - struct UpVal uv; struct lua_State th; /* thread */ }; @@ -211,7 +202,6 @@ union GCObject { check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl)) #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 gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) #define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) /* macro to convert any Lua object into a GCObject */ diff --git a/ltests.c b/ltests.c index 199a492f..e2057736 100644 --- a/ltests.c +++ b/ltests.c @@ -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 ** 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? */ if (!islocal(t) || gch(f)->tt == LUA_TTHREAD) 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) return 1; /* cache from a prototype */ return 0; @@ -311,9 +303,11 @@ static void checkLclosure (global_State *g, LClosure *cl) { int i; if (cl->p) checkobjref(g, clgc, cl->p); for (i=0; inupvalues; i++) { - if (cl->upvals[i]) { - lua_assert(cl->upvals[i]->tt == LUA_TUPVAL); - checkobjref(g, clgc, cl->upvals[i]); + UpVal *uv = cl->upvals[i]; + if (uv) { + 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) { StkId o; CallInfo *ci; - GCObject *uvo; + UpVal *uv; 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->value); /* must be open */ - lua_assert(!isblack(uvo)); /* open upvalues cannot be black */ - } + for (uv = L1->openupval; uv != NULL; uv = uv->u.op.next) + lua_assert(upisopen(uv)); /* must be open */ for (ci = L1->ci; ci != NULL; ci = ci->previous) { lua_assert(ci->top <= L1->stack_last); lua_assert(lua_checkpc(ci)); @@ -357,13 +348,6 @@ static void checkobject (global_State *g, GCObject *o, int maybedead) { else { lua_assert(g->gcstate != GCSpause || iswhite(o)); 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: { Table *mt = gco2u(o)->metatable; 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) { 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; } diff --git a/ltm.c b/ltm.c index aa290185..62c1430c 100644 --- a/ltm.c +++ b/ltm.c @@ -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 ** See Copyright Notice in lua.h */ @@ -28,7 +28,7 @@ LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { "no value", "nil", "boolean", udatatypename, "number", "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 */ }; diff --git a/lvm.c b/lvm.c index d29c0118..5ebeb30d 100644 --- a/lvm.c +++ b/lvm.c @@ -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 ** 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); else /* get upvalue from enclosing function */ 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? */ p->cache = ncl; /* save it on cache for reuse */ @@ -591,7 +592,7 @@ void luaV_execute (lua_State *L) { vmcase(OP_SETUPVAL, UpVal *uv = cl->upvals[GETARG_B(i)]; setobj(L, uv->v, ra); - luaC_barrier(L, uv, ra); + luaC_upvalbarrier(L, uv); ) vmcase(OP_SETTABLE, Protect(luaV_settable(L, ra, RKB(i), RKC(i)));