From 439d74e29f3234a034777f88b260523afe8c0446 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 16 Aug 2013 15:55:49 -0300 Subject: [PATCH] added 'local' bit (true => object is only refered by local variables) --- lapi.c | 8 ++++++-- lfunc.c | 4 +++- lgc.c | 26 ++++++++++++++++--------- lgc.h | 20 +++++++++++++------ lparser.c | 3 ++- lstate.c | 17 ++++++++++------- lstring.h | 4 ++-- ltests.c | 57 ++++++++++++++++++++++++++++++++++--------------------- lundump.c | 7 +++++-- lvm.c | 3 ++- 10 files changed, 96 insertions(+), 53 deletions(-) diff --git a/lapi.c b/lapi.c index 7c7b6a10..62b5f1a3 100644 --- a/lapi.c +++ b/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.185 2013/07/05 14:29:51 roberto Exp roberto $ +** $Id: lapi.c,v 2.186 2013/08/05 16:58:28 roberto Exp roberto $ ** Lua API ** See Copyright Notice in lua.h */ @@ -586,8 +586,11 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { cl = luaF_newCclosure(L, n); cl->c.f = fn; L->top -= n; - while (n--) + while (n--) { setobj2n(L, &cl->c.upvalue[n], L->top + n); + /* does not need barrier because closure is white */ + valnolocal(L->top + n); /* but needs 'local barrier' */ + } setclCvalue(L, L->top, cl); } api_incr_top(L); @@ -861,6 +864,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { } default: { G(L)->mt[ttnov(obj)] = mt; + if (mt) nolocal(obj2gco(mt)); break; } } diff --git a/lfunc.c b/lfunc.c index 82d05656..cb0b4ef6 100644 --- a/lfunc.c +++ b/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.31 2013/08/05 16:58:28 roberto Exp roberto $ +** $Id: lfunc.c,v 2.32 2013/08/07 12:18:11 roberto Exp roberto $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -80,6 +80,7 @@ void luaF_close (lua_State *L, StkId level) { uv->v = &uv->value; /* now current value lives here */ gch(o)->next = g->allgc; /* link upvalue into 'allgc' list */ g->allgc = o; + valnolocal(uv->v); /* keep local invariant */ luaC_checkupvalcolor(g, uv); } } @@ -88,6 +89,7 @@ void luaF_close (lua_State *L, StkId level) { Proto *luaF_newproto (lua_State *L) { Proto *f = &luaC_newobj(L, LUA_TPROTO, sizeof(Proto), NULL, 0)->p; + nolocal(obj2gco(f)); /* prototypes are never local */ f->k = NULL; f->sizek = 0; f->p = NULL; diff --git a/lgc.c b/lgc.c index 75daf796..e4d6b6c1 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.144 2013/08/07 15:39:09 roberto Exp roberto $ +** $Id: lgc.c,v 2.145 2013/08/13 17:36:44 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -74,11 +74,19 @@ lua_longassert(!iscollectable(obj) || righttt(obj)) -#define markvalue(g,o) { checkconsistency(o); \ +#define marklocalvalue(g,o) { checkconsistency(o); \ if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } -#define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \ - reallymarkobject(g, obj2gco(t)); } +#define markvalue(g,o) { \ + 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); } static void reallymarkobject (global_State *g, GCObject *o); @@ -259,7 +267,7 @@ static void reallymarkobject (global_State *g, GCObject *o) { } case LUA_TUPVAL: { UpVal *uv = gco2uv(o); - markvalue(g, uv->v); + marklocalvalue(g, uv->v); if (uv->v != &uv->value) /* open? */ return; /* open upvalues remain gray */ size = sizeof(UpVal); @@ -331,7 +339,7 @@ static void remarkupvals (global_State *g) { 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 */ + marklocalvalue(g, gco2uv(uv)->v); /* remark upvalue's value */ } } } @@ -486,7 +494,7 @@ static int traverseproto (global_State *g, Proto *f) { static lu_mem traverseCclosure (global_State *g, CClosure *cl) { int i; for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ - markvalue(g, &cl->upvalue[i]); + marklocalvalue(g, &cl->upvalue[i]); return sizeCclosure(cl->nupvalues); } @@ -494,7 +502,7 @@ 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 */ - markobject(g, cl->upvals[i]); + marklocalobject(g, cl->upvals[i]); return sizeLclosure(cl->nupvalues); } @@ -505,7 +513,7 @@ static lu_mem traversestack (global_State *g, lua_State *th) { if (o == NULL) return 1; /* stack not completely built yet */ for (; o < th->top; o++) /* mark live elements in the stack */ - markvalue(g, o); + marklocalvalue(g, o); if (g->gcstate == GCSatomic) { /* final traversal? */ StkId lim = th->stack + th->stacksize; /* real end of stack */ for (; o < lim; o++) /* clear not-marked stack slice */ diff --git a/lgc.h b/lgc.h index 4e38c0fc..846d40d8 100644 --- a/lgc.h +++ b/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.59 2013/08/05 16:58:28 roberto Exp roberto $ +** $Id: lgc.h,v 2.60 2013/08/13 17:36:44 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -79,6 +79,7 @@ #define FINALIZEDBIT 3 /* object has been separated for finalization */ #define SEPARATED 4 /* object is in 'finobj' list or in 'tobefnz' */ #define FIXEDBIT 5 /* object is fixed (should not be collected) */ +#define LOCALBIT 6 /* object is not local */ /* bit 7 is currently used by tests (luaL_checkmemory) */ #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) @@ -88,6 +89,7 @@ #define isblack(x) testbit((x)->gch.marked, BLACKBIT) #define isgray(x) /* neither white nor black */ \ (!testbits((x)->gch.marked, WHITEBITS | bitmask(BLACKBIT))) +#define islocal(x) (!testbit((x)->gch.marked, LOCALBIT)) #define otherwhite(g) (g->currentwhite ^ WHITEBITS) @@ -97,6 +99,9 @@ #define changewhite(x) ((x)->gch.marked ^= WHITEBITS) #define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT) +#define nolocal(x) l_setbit((x)->gch.marked, LOCALBIT) +#define valnolocal(v) { if (iscollectable(v)) nolocal(gcvalue(v)); } + #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) @@ -106,22 +111,25 @@ #define luaC_barrier(L,p,v) { \ - if (iscollectable(v) && isblack(obj2gco(p)) && iswhite(gcvalue(v))) \ + if (iscollectable(v) && \ + (nolocal(gcvalue(v)), isblack(obj2gco(p)) && iswhite(gcvalue(v)))) \ luaC_barrier_(L,obj2gco(p),gcvalue(v)); } #define luaC_barrierback(L,p,v) { \ - if (iscollectable(v) && isblack(obj2gco(p)) && iswhite(gcvalue(v))) \ + if (iscollectable(v) && \ + (nolocal(gcvalue(v)), isblack(obj2gco(p)) && iswhite(gcvalue(v)))) \ luaC_barrierback_(L,p); } #define luaC_objbarrier(L,p,o) { \ - if (isblack(obj2gco(p)) && iswhite(obj2gco(o))) \ + if (nolocal(obj2gco(o)), isblack(obj2gco(p)) && iswhite(obj2gco(o))) \ luaC_barrier_(L,obj2gco(p),obj2gco(o)); } #define luaC_objbarrierback(L,p,o) \ - { if (isblack(obj2gco(p)) && iswhite(obj2gco(o))) luaC_barrierback_(L,p); } + { if (nolocal(obj2gco(o)), isblack(obj2gco(p)) && iswhite(obj2gco(o))) \ + luaC_barrierback_(L,p); } #define luaC_barrierproto(L,p,c) \ - { if (isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); } + { if (nolocal(obj2gco(c)), isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); } LUAI_FUNC void luaC_freeallobjects (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L); diff --git a/lparser.c b/lparser.c index 2cc226d4..c2386b82 100644 --- a/lparser.c +++ b/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.132 2013/04/25 19:35:19 roberto Exp roberto $ +** $Id: lparser.c,v 2.133 2013/04/26 13:07:53 roberto Exp roberto $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -1632,6 +1632,7 @@ Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, incr_top(L); funcstate.f = cl->l.p = luaF_newproto(L); funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ + luaC_objbarrier(L, funcstate.f, funcstate.f->source); lexstate.buff = buff; lexstate.dyd = dyd; dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; diff --git a/lstate.c b/lstate.c index 9c4130a8..a9c321d5 100644 --- a/lstate.c +++ b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.100 2013/08/05 16:58:28 roberto Exp roberto $ +** $Id: lstate.c,v 2.101 2013/08/07 12:18:11 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -159,17 +159,19 @@ static void freestack (lua_State *L) { ** Create registry table and its predefined values */ static void init_registry (lua_State *L, global_State *g) { - TValue mt; + TValue temp; /* create registry */ Table *registry = luaH_new(L); sethvalue(L, &g->l_registry, registry); luaH_resize(L, registry, LUA_RIDX_LAST, 0); + nolocal(obj2gco(registry)); /* registry[LUA_RIDX_MAINTHREAD] = L */ - setthvalue(L, &mt, L); - luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &mt); + setthvalue(L, &temp, L); /* temp = L */ + luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); /* registry[LUA_RIDX_GLOBALS] = table of globals */ - sethvalue(L, &mt, luaH_new(L)); - luaH_setint(L, registry, LUA_RIDX_GLOBALS, &mt); + sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */ + luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp); + valnolocal(&temp); /* keep local invariant */ } @@ -236,6 +238,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) { setthvalue(L, L->top, L1); api_incr_top(L); preinit_state(L1, G(L)); + nolocal(obj2gco(L1)); /* threads are never local */ L1->hookmask = L->hookmask; L1->basehookcount = L->basehookcount; L1->hook = L->hook; @@ -268,7 +271,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { L->next = NULL; L->tt = LUA_TTHREAD; g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); - L->marked = luaC_white(g); + L->marked = luaC_white(g) | bitmask(LOCALBIT); g->gckind = KGC_NORMAL; preinit_state(L, g); g->frealloc = f; diff --git a/lstring.h b/lstring.h index b52a9356..644b5aae 100644 --- a/lstring.h +++ b/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.48 2012/01/25 21:05:40 roberto Exp roberto $ +** $Id: lstring.h,v 1.49 2012/02/01 21:57:15 roberto Exp roberto $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -19,7 +19,7 @@ #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ (sizeof(s)/sizeof(char))-1)) -#define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT) +#define luaS_fix(s) setbits((s)->tsv.marked, bit2mask(FIXEDBIT, LOCALBIT)) /* diff --git a/ltests.c b/ltests.c index e45a82cf..4e087435 100644 --- a/ltests.c +++ b/ltests.c @@ -1,5 +1,5 @@ /* -** $Id: ltests.c,v 2.140 2013/08/05 16:58:28 roberto Exp roberto $ +** $Id: ltests.c,v 2.141 2013/08/07 12:18:11 roberto Exp roberto $ ** Internal Module for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -188,6 +188,25 @@ static int testobjref1 (global_State *g, GCObject *f, GCObject *t) { } +/* +** Check locality +*/ +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 */ + } + return 0; +} + + static void printobj (global_State *g, GCObject *o) { int i = 1; GCObject *p; @@ -198,24 +217,30 @@ static void printobj (global_State *g, GCObject *o) { if (p == NULL) i = 0; /* zero means 'not found' */ else i = -i; /* negative means 'found in findobj list */ } - printf("||%d:%s(%p)-%c(%02X)||", i, ttypename(gch(o)->tt), (void *)o, + printf("||%d:%s(%p)-%s-%c(%02X)||", + i, ttypename(novariant(gch(o)->tt)), (void *)o, + islocal(o)?"L":"NL", isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', gch(o)->marked); } static int testobjref (global_State *g, GCObject *f, GCObject *t) { - int r = testobjref1(g,f,t); - if (!r) { - printf("%d(%02X) - ", g->gcstate, g->currentwhite); + int r1 = testobjref1(g,f,t); + int r2 = testobjref2(f,t); + if (!r1 || !r2) { + if (!r1) + printf("%d(%02X) - ", g->gcstate, g->currentwhite); + else + printf("local violation - "); printobj(g, f); - printf("\t-> "); + printf(" -> "); printobj(g, t); printf("\n"); } - return r; + return r1 && r2; } -#define checkobjref(g,f,t) lua_assert(testobjref(g,f,obj2gco(t))) +#define checkobjref(g,f,t) lua_assert(testobjref(g,f,obj2gco(t))) static void checkvalref (global_State *g, GCObject *f, const TValue *t) { @@ -349,6 +374,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead) { break; } case LUA_TTHREAD: { + lua_assert(!islocal(o)); checkstack(g, gco2th(o)); break; } @@ -617,22 +643,9 @@ static int get_gccolor (lua_State *L) { o = obj_at(L, 1); if (!iscollectable(o)) lua_pushstring(L, "no collectable"); - else { - int marked = gcvalue(o)->gch.marked; - int n = 1; + else lua_pushstring(L, iswhite(gcvalue(o)) ? "white" : isblack(gcvalue(o)) ? "black" : "grey"); - if (testbit(marked, FINALIZEDBIT)) { - lua_pushliteral(L, "/finalized"); n++; - } - if (testbit(marked, SEPARATED)) { - lua_pushliteral(L, "/separated"); n++; - } - if (testbit(marked, FIXEDBIT)) { - lua_pushliteral(L, "/fixed"); n++; - } - lua_concat(L, n); - } return 1; } diff --git a/lundump.c b/lundump.c index 0a8db845..be77d98e 100644 --- a/lundump.c +++ b/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 2.22 2012/05/08 13:53:33 roberto Exp roberto $ +** $Id: lundump.c,v 2.23 2013/04/26 18:48:35 roberto Exp roberto $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -84,9 +84,12 @@ static TString* LoadString(LoadState* S) return NULL; else { + TString* ts; char* s=luaZ_openspace(S->L,S->b,size); LoadBlock(S,s,size*sizeof(char)); - return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ + ts = luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ + nolocal(obj2gco(ts)); /* all strings here anchored in non-thread objects */ + return ts; } } diff --git a/lvm.c b/lvm.c index 67aa58f8..7f86a16c 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.175 2013/06/20 15:02:49 roberto Exp roberto $ +** $Id: lvm.c,v 2.176 2013/07/10 17:15:12 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -416,6 +416,7 @@ 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 */ } luaC_barrierproto(L, p, ncl); p->cache = ncl; /* save it on cache for reuse */