diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2013-08-27 15:53:35 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2013-08-27 15:53:35 -0300 |
| commit | af35c7f398e8149b5f2481b63b399674e4ecdf7e (patch) | |
| tree | 7d74f5c81bb0e2555cab4bce00a94a12a6d78604 | |
| parent | 742b7377d38e43224ee5dda4bb83a42763c20af8 (diff) | |
| download | lua-af35c7f398e8149b5f2481b63b399674e4ecdf7e.tar.gz lua-af35c7f398e8149b5f2481b63b399674e4ecdf7e.tar.bz2 lua-af35c7f398e8149b5f2481b63b399674e4ecdf7e.zip | |
upvalues collected by reference count
| -rw-r--r-- | lapi.c | 22 | ||||
| -rw-r--r-- | ldo.c | 15 | ||||
| -rw-r--r-- | lfunc.c | 65 | ||||
| -rw-r--r-- | lfunc.h | 22 | ||||
| -rw-r--r-- | lgc.c | 142 | ||||
| -rw-r--r-- | lgc.h | 14 | ||||
| -rw-r--r-- | lobject.h | 13 | ||||
| -rw-r--r-- | lstate.c | 4 | ||||
| -rw-r--r-- | lstate.h | 14 | ||||
| -rw-r--r-- | ltests.c | 40 | ||||
| -rw-r--r-- | ltm.c | 4 | ||||
| -rw-r--r-- | lvm.c | 7 |
12 files changed, 157 insertions, 205 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lapi.c,v 2.186 2013/08/05 16:58:28 roberto Exp roberto $ | 2 | ** $Id: lapi.c,v 2.187 2013/08/16 18:55:49 roberto Exp roberto $ |
| 3 | ** Lua API | 3 | ** Lua API |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -1192,7 +1192,7 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) { | |||
| 1192 | 1192 | ||
| 1193 | 1193 | ||
| 1194 | static const char *aux_upvalue (StkId fi, int n, TValue **val, | 1194 | static const char *aux_upvalue (StkId fi, int n, TValue **val, |
| 1195 | GCObject **owner) { | 1195 | GCObject **owner, UpVal **uv) { |
| 1196 | switch (ttype(fi)) { | 1196 | switch (ttype(fi)) { |
| 1197 | case LUA_TCCL: { /* C closure */ | 1197 | case LUA_TCCL: { /* C closure */ |
| 1198 | CClosure *f = clCvalue(fi); | 1198 | CClosure *f = clCvalue(fi); |
| @@ -1207,7 +1207,7 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val, | |||
| 1207 | Proto *p = f->p; | 1207 | Proto *p = f->p; |
| 1208 | if (!(1 <= n && n <= p->sizeupvalues)) return NULL; | 1208 | if (!(1 <= n && n <= p->sizeupvalues)) return NULL; |
| 1209 | *val = f->upvals[n-1]->v; | 1209 | *val = f->upvals[n-1]->v; |
| 1210 | if (owner) *owner = obj2gco(f->upvals[n - 1]); | 1210 | if (uv) *uv = f->upvals[n - 1]; |
| 1211 | name = p->upvalues[n-1].name; | 1211 | name = p->upvalues[n-1].name; |
| 1212 | return (name == NULL) ? "" : getstr(name); | 1212 | return (name == NULL) ? "" : getstr(name); |
| 1213 | } | 1213 | } |
| @@ -1220,7 +1220,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { | |||
| 1220 | const char *name; | 1220 | const char *name; |
| 1221 | TValue *val = NULL; /* to avoid warnings */ | 1221 | TValue *val = NULL; /* to avoid warnings */ |
| 1222 | lua_lock(L); | 1222 | lua_lock(L); |
| 1223 | name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL); | 1223 | name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL); |
| 1224 | if (name) { | 1224 | if (name) { |
| 1225 | setobj2s(L, L->top, val); | 1225 | setobj2s(L, L->top, val); |
| 1226 | api_incr_top(L); | 1226 | api_incr_top(L); |
| @@ -1233,16 +1233,18 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { | |||
| 1233 | LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { | 1233 | LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { |
| 1234 | const char *name; | 1234 | const char *name; |
| 1235 | TValue *val = NULL; /* to avoid warnings */ | 1235 | TValue *val = NULL; /* to avoid warnings */ |
| 1236 | GCObject *owner = NULL; /* to avoid warnings */ | 1236 | GCObject *owner = NULL; |
| 1237 | UpVal *uv = NULL; | ||
| 1237 | StkId fi; | 1238 | StkId fi; |
| 1238 | lua_lock(L); | 1239 | lua_lock(L); |
| 1239 | fi = index2addr(L, funcindex); | 1240 | fi = index2addr(L, funcindex); |
| 1240 | api_checknelems(L, 1); | 1241 | api_checknelems(L, 1); |
| 1241 | name = aux_upvalue(fi, n, &val, &owner); | 1242 | name = aux_upvalue(fi, n, &val, &owner, &uv); |
| 1242 | if (name) { | 1243 | if (name) { |
| 1243 | L->top--; | 1244 | L->top--; |
| 1244 | setobj(L, val, L->top); | 1245 | setobj(L, val, L->top); |
| 1245 | luaC_barrier(L, owner, L->top); | 1246 | if (owner) { luaC_barrier(L, owner, L->top); } |
| 1247 | else if (uv) { luaC_upvalbarrier(L, uv); } | ||
| 1246 | } | 1248 | } |
| 1247 | lua_unlock(L); | 1249 | lua_unlock(L); |
| 1248 | return name; | 1250 | return name; |
| @@ -1284,7 +1286,11 @@ LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, | |||
| 1284 | LClosure *f1; | 1286 | LClosure *f1; |
| 1285 | UpVal **up1 = getupvalref(L, fidx1, n1, &f1); | 1287 | UpVal **up1 = getupvalref(L, fidx1, n1, &f1); |
| 1286 | UpVal **up2 = getupvalref(L, fidx2, n2, NULL); | 1288 | UpVal **up2 = getupvalref(L, fidx2, n2, NULL); |
| 1289 | luaC_upvdeccount(L, *up1); | ||
| 1287 | *up1 = *up2; | 1290 | *up1 = *up2; |
| 1288 | luaC_objbarrier(L, f1, *up2); | 1291 | (*up1)->refcount++; |
| 1292 | if (upisopen(*up1)) (*up1)->u.op.touched = 1; | ||
| 1293 | luaC_upvalbarrier(L, *up1); | ||
| 1289 | } | 1294 | } |
| 1290 | 1295 | ||
| 1296 | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ldo.c,v 2.108.1.2 2013/04/19 21:03:23 roberto Exp $ | 2 | ** $Id: ldo.c,v 2.109 2013/04/19 21:05:04 roberto Exp roberto $ |
| 3 | ** Stack and Call structure of Lua | 3 | ** Stack and Call structure of Lua |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -141,10 +141,10 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { | |||
| 141 | 141 | ||
| 142 | static void correctstack (lua_State *L, TValue *oldstack) { | 142 | static void correctstack (lua_State *L, TValue *oldstack) { |
| 143 | CallInfo *ci; | 143 | CallInfo *ci; |
| 144 | GCObject *up; | 144 | UpVal *up; |
| 145 | L->top = (L->top - oldstack) + L->stack; | 145 | L->top = (L->top - oldstack) + L->stack; |
| 146 | for (up = L->openupval; up != NULL; up = up->gch.next) | 146 | for (up = L->openupval; up != NULL; up = up->u.op.next) |
| 147 | gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; | 147 | up->v = (up->v - oldstack) + L->stack; |
| 148 | for (ci = L->ci; ci != NULL; ci = ci->previous) { | 148 | for (ci = L->ci; ci != NULL; ci = ci->previous) { |
| 149 | ci->top = (ci->top - oldstack) + L->stack; | 149 | ci->top = (ci->top - oldstack) + L->stack; |
| 150 | ci->func = (ci->func - oldstack) + L->stack; | 150 | ci->func = (ci->func - oldstack) + L->stack; |
| @@ -637,7 +637,6 @@ static void checkmode (lua_State *L, const char *mode, const char *x) { | |||
| 637 | 637 | ||
| 638 | 638 | ||
| 639 | static void f_parser (lua_State *L, void *ud) { | 639 | static void f_parser (lua_State *L, void *ud) { |
| 640 | int i; | ||
| 641 | Closure *cl; | 640 | Closure *cl; |
| 642 | struct SParser *p = cast(struct SParser *, ud); | 641 | struct SParser *p = cast(struct SParser *, ud); |
| 643 | int c = zgetc(p->z); /* read first character */ | 642 | int c = zgetc(p->z); /* read first character */ |
| @@ -650,11 +649,7 @@ static void f_parser (lua_State *L, void *ud) { | |||
| 650 | cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); | 649 | cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); |
| 651 | } | 650 | } |
| 652 | lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); | 651 | lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); |
| 653 | for (i = 0; i < cl->l.nupvalues; i++) { /* initialize upvalues */ | 652 | luaF_initupvals(L, &cl->l); |
| 654 | UpVal *up = luaF_newupval(L); | ||
| 655 | cl->l.upvals[i] = up; | ||
| 656 | luaC_objbarrier(L, cl, up); | ||
| 657 | } | ||
| 658 | } | 653 | } |
| 659 | 654 | ||
| 660 | 655 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lfunc.c,v 2.34 2013/08/23 13:34:54 roberto Exp roberto $ | 2 | ** $Id: lfunc.c,v 2.35 2013/08/26 12:41:10 roberto Exp roberto $ |
| 3 | ** Auxiliary functions to manipulate prototypes and closures | 3 | ** Auxiliary functions to manipulate prototypes and closures |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -38,32 +38,33 @@ Closure *luaF_newLclosure (lua_State *L, int n) { | |||
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | 40 | ||
| 41 | UpVal *luaF_newupval (lua_State *L) { | 41 | void luaF_initupvals (lua_State *L, LClosure *cl) { |
| 42 | UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), | 42 | int i; |
| 43 | &G(L)->localupv, 0)->uv; | 43 | for (i = 0; i < cl->nupvalues; i++) { |
| 44 | uv->v = &uv->value; | 44 | UpVal *uv = luaM_new(L, UpVal); |
| 45 | setnilvalue(uv->v); | 45 | uv->refcount = 1; |
| 46 | return uv; | 46 | uv->v = &uv->u.value; /* make it closed */ |
| 47 | setnilvalue(uv->v); | ||
| 48 | cl->upvals[i] = uv; | ||
| 49 | } | ||
| 47 | } | 50 | } |
| 48 | 51 | ||
| 49 | 52 | ||
| 50 | UpVal *luaF_findupval (lua_State *L, StkId level) { | 53 | UpVal *luaF_findupval (lua_State *L, StkId level) { |
| 51 | global_State *g = G(L); | 54 | UpVal **pp = &L->openupval; |
| 52 | GCObject **pp = &L->openupval; | ||
| 53 | UpVal *p; | 55 | UpVal *p; |
| 54 | UpVal *uv; | 56 | UpVal *uv; |
| 55 | while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { | 57 | while (*pp != NULL && (p = *pp)->v >= level) { |
| 56 | GCObject *o = obj2gco(p); | 58 | lua_assert(upisopen(p)); |
| 57 | lua_assert(p->v != &p->value); | 59 | if (p->v == level) /* found a corresponding upvalue? */ |
| 58 | if (p->v == level) { /* found a corresponding upvalue? */ | 60 | return p; /* return it */ |
| 59 | if (isdead(g, o)) /* is it dead? */ | 61 | pp = &p->u.op.next; |
| 60 | changewhite(o); /* resurrect it */ | ||
| 61 | return p; | ||
| 62 | } | ||
| 63 | pp = &p->next; | ||
| 64 | } | 62 | } |
| 65 | /* not found: create a new one */ | 63 | /* not found: create a new one */ |
| 66 | uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv; | 64 | uv = luaM_new(L, UpVal); |
| 65 | uv->refcount = 0; | ||
| 66 | uv->u.op.next = *pp; | ||
| 67 | *pp = uv; | ||
| 67 | uv->v = level; /* current value lives in the stack */ | 68 | uv->v = level; /* current value lives in the stack */ |
| 68 | return uv; | 69 | return uv; |
| 69 | } | 70 | } |
| @@ -71,27 +72,15 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { | |||
| 71 | 72 | ||
| 72 | void luaF_close (lua_State *L, StkId level) { | 73 | void luaF_close (lua_State *L, StkId level) { |
| 73 | UpVal *uv; | 74 | UpVal *uv; |
| 74 | global_State *g = G(L); | 75 | while (L->openupval != NULL && (uv = L->openupval)->v >= level) { |
| 75 | while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) { | 76 | lua_assert(upisopen(uv)); |
| 76 | GCObject *o = obj2gco(uv); | 77 | L->openupval = uv->u.op.next; /* remove from `open' list */ |
| 77 | lua_assert(!isblack(o) && uv->v != &uv->value); | 78 | if (uv->refcount == 0) /* no references? */ |
| 78 | L->openupval = uv->next; /* remove from `open' list */ | ||
| 79 | if (isdead(g, o)) | ||
| 80 | luaM_free(L, uv); /* free upvalue */ | 79 | luaM_free(L, uv); /* free upvalue */ |
| 81 | else { | 80 | else { |
| 82 | setobj(L, &uv->value, uv->v); /* move value to upvalue slot */ | 81 | setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ |
| 83 | uv->v = &uv->value; /* now current value lives here */ | 82 | uv->v = &uv->u.value; /* now current value lives here */ |
| 84 | if (islocal(o)) { | 83 | luaC_upvalbarrier(L, uv); |
| 85 | gch(o)->next = g->localupv; /* link upvalue into 'localupv' list */ | ||
| 86 | g->localupv = o; | ||
| 87 | resetbit(o->gch.marked, LOCALBLACK); | ||
| 88 | } | ||
| 89 | else { /* link upvalue into 'allgc' list */ | ||
| 90 | gch(o)->next = g->allgc; | ||
| 91 | g->allgc = o; | ||
| 92 | } | ||
| 93 | valnolocal(uv->v); /* keep local invariant */ | ||
| 94 | luaC_checkupvalcolor(g, uv); | ||
| 95 | } | 84 | } |
| 96 | } | 85 | } |
| 97 | } | 86 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lfunc.h,v 2.8 2012/05/08 13:53:33 roberto Exp roberto $ | 2 | ** $Id: lfunc.h,v 2.9 2013/08/07 12:18:11 roberto Exp roberto $ |
| 3 | ** Auxiliary functions to manipulate prototypes and closures | 3 | ** Auxiliary functions to manipulate prototypes and closures |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -18,10 +18,28 @@ | |||
| 18 | cast(int, sizeof(TValue *)*((n)-1))) | 18 | cast(int, sizeof(TValue *)*((n)-1))) |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | /* | ||
| 22 | ** Upvalues for Lua closures | ||
| 23 | */ | ||
| 24 | struct UpVal { | ||
| 25 | TValue *v; /* points to stack or to its own value */ | ||
| 26 | unsigned int refcount; /* reference counter */ | ||
| 27 | union { | ||
| 28 | struct { /* (when open) */ | ||
| 29 | UpVal *next; /* linked list */ | ||
| 30 | int touched; /* mark to avoid cycles with dead threads */ | ||
| 31 | } op; | ||
| 32 | TValue value; /* the value (when closed) */ | ||
| 33 | } u; | ||
| 34 | }; | ||
| 35 | |||
| 36 | #define upisopen(up) ((up)->v != &(up)->u.value) | ||
| 37 | |||
| 38 | |||
| 21 | LUAI_FUNC Proto *luaF_newproto (lua_State *L); | 39 | LUAI_FUNC Proto *luaF_newproto (lua_State *L); |
| 22 | LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems); | 40 | LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems); |
| 23 | LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems); | 41 | LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems); |
| 24 | LUAI_FUNC UpVal *luaF_newupval (lua_State *L); | 42 | LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); |
| 25 | LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); | 43 | LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); |
| 26 | LUAI_FUNC void luaF_close (lua_State *L, StkId level); | 44 | LUAI_FUNC void luaF_close (lua_State *L, StkId level); |
| 27 | LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); | 45 | LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.151 2013/08/23 13:34:54 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.152 2013/08/26 12:41:10 roberto Exp roberto $ |
| 3 | ** Garbage Collector | 3 | ** Garbage Collector |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -85,12 +85,9 @@ | |||
| 85 | lua_longassert(!(iscollectable(o) && islocal(gcvalue(o)))); \ | 85 | lua_longassert(!(iscollectable(o) && islocal(gcvalue(o)))); \ |
| 86 | marklocalvalue(g,o); } | 86 | marklocalvalue(g,o); } |
| 87 | 87 | ||
| 88 | #define marklocalobject(g,t) { \ | ||
| 89 | if ((t) && iswhite(obj2gco(t))) \ | ||
| 90 | reallymarkobject(g, obj2gco(t)); } | ||
| 91 | |||
| 92 | #define markobject(g,t) \ | 88 | #define markobject(g,t) \ |
| 93 | { lua_assert((t) == NULL || !islocal(obj2gco(t))); marklocalobject(g,t); } | 89 | { lua_assert((t) == NULL || !islocal(obj2gco(t))); \ |
| 90 | if ((t) && iswhite(obj2gco(t))) reallymarkobject(g, obj2gco(t)); } | ||
| 94 | 91 | ||
| 95 | static void reallymarkobject (global_State *g, GCObject *o); | 92 | static void reallymarkobject (global_State *g, GCObject *o); |
| 96 | 93 | ||
| @@ -176,22 +173,18 @@ void luaC_barrierback_ (lua_State *L, GCObject *o) { | |||
| 176 | 173 | ||
| 177 | 174 | ||
| 178 | /* | 175 | /* |
| 179 | ** check color (and invariants) for an upvalue that is being closed, | 176 | ** barrier for assignments to closed upvalues. Because upvalues are |
| 180 | ** i.e., moved into the 'allgc' list | 177 | ** shared among closures, it is impossible to know the color of all |
| 178 | ** closured pointing to it. So, we assume that the object being assigned | ||
| 179 | ** must be marked. | ||
| 181 | */ | 180 | */ |
| 182 | void luaC_checkupvalcolor (global_State *g, UpVal *uv) { | 181 | LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { |
| 183 | GCObject *o = obj2gco(uv); | 182 | global_State *g = G(L); |
| 184 | lua_assert(!isblack(o)); /* open upvalues are never black */ | 183 | GCObject *o = gcvalue(uv->v); |
| 185 | if (isgray(o)) { | 184 | lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ |
| 186 | if (keepinvariant(g)) { | 185 | nolocal(o); |
| 187 | gray2black(o); /* it is being visited now */ | 186 | if (keepinvariant(g)) |
| 188 | markvalue(g, uv->v); | 187 | markobject(g, o); |
| 189 | } | ||
| 190 | else { | ||
| 191 | lua_assert(issweepphase(g)); | ||
| 192 | makewhite(g, o); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | } | 188 | } |
| 196 | 189 | ||
| 197 | 190 | ||
| @@ -257,14 +250,6 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
| 257 | size = sizeudata(gco2u(o)); | 250 | size = sizeudata(gco2u(o)); |
| 258 | break; | 251 | break; |
| 259 | } | 252 | } |
| 260 | case LUA_TUPVAL: { | ||
| 261 | UpVal *uv = gco2uv(o); | ||
| 262 | marklocalvalue(g, uv->v); | ||
| 263 | if (uv->v != &uv->value) /* open? */ | ||
| 264 | return; /* open upvalues remain gray */ | ||
| 265 | size = sizeof(UpVal); | ||
| 266 | break; | ||
| 267 | } | ||
| 268 | case LUA_TLCL: { | 253 | case LUA_TLCL: { |
| 269 | gco2lcl(o)->gclist = g->gray; | 254 | gco2lcl(o)->gclist = g->gray; |
| 270 | g->gray = o; | 255 | g->gray = o; |
| @@ -328,10 +313,12 @@ static void remarkupvals (global_State *g) { | |||
| 328 | for (; thread != NULL; thread = gch(thread)->next) { | 313 | for (; thread != NULL; thread = gch(thread)->next) { |
| 329 | lua_assert(!isblack(thread)); /* threads are never black */ | 314 | lua_assert(!isblack(thread)); /* threads are never black */ |
| 330 | if (!isgray(thread)) { /* dead thread? */ | 315 | if (!isgray(thread)) { /* dead thread? */ |
| 331 | GCObject *uv = gco2th(thread)->openupval; | 316 | UpVal *uv = gco2th(thread)->openupval; |
| 332 | for (; uv != NULL; uv = gch(uv)->next) { | 317 | for (; uv != NULL; uv = uv->u.op.next) { |
| 333 | if (isgray(uv)) /* marked? */ | 318 | if (uv->u.op.touched) { |
| 334 | marklocalvalue(g, gco2uv(uv)->v); /* remark upvalue's value */ | 319 | marklocalvalue(g, uv->v); /* remark upvalue's value */ |
| 320 | uv->u.op.touched = 0; | ||
| 321 | } | ||
| 335 | } | 322 | } |
| 336 | } | 323 | } |
| 337 | } | 324 | } |
| @@ -493,8 +480,15 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) { | |||
| 493 | static lu_mem traverseLclosure (global_State *g, LClosure *cl) { | 480 | static lu_mem traverseLclosure (global_State *g, LClosure *cl) { |
| 494 | int i; | 481 | int i; |
| 495 | markobject(g, cl->p); /* mark its prototype */ | 482 | markobject(g, cl->p); /* mark its prototype */ |
| 496 | for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ | 483 | for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ |
| 497 | marklocalobject(g, cl->upvals[i]); | 484 | UpVal *uv = cl->upvals[i]; |
| 485 | if (uv != NULL) { | ||
| 486 | if (upisopen(uv)) | ||
| 487 | uv->u.op.touched = 1; /* can be marked in 'remarkupvals' */ | ||
| 488 | else | ||
| 489 | markvalue(g, uv->v); | ||
| 490 | } | ||
| 491 | } | ||
| 498 | return sizeLclosure(cl->nupvalues); | 492 | return sizeLclosure(cl->nupvalues); |
| 499 | } | 493 | } |
| 500 | 494 | ||
| @@ -511,10 +505,14 @@ static lu_mem traversestack (global_State *g, lua_State *th) { | |||
| 511 | for (; o < lim; o++) /* clear not-marked stack slice */ | 505 | for (; o < lim; o++) /* clear not-marked stack slice */ |
| 512 | setnilvalue(o); | 506 | setnilvalue(o); |
| 513 | } | 507 | } |
| 514 | else { /* count call infos to compute size */ | 508 | else { |
| 515 | CallInfo *ci; | 509 | CallInfo *ci; |
| 510 | luaE_freeCI(th); /* free extra CallInfo slots */ | ||
| 516 | for (ci = &th->base_ci; ci != th->ci; ci = ci->next) | 511 | for (ci = &th->base_ci; ci != th->ci; ci = ci->next) |
| 517 | n++; | 512 | n++; /* count call infos to compute size */ |
| 513 | /* should not change the stack during an emergency gc cycle */ | ||
| 514 | if (g->gckind != KGC_EMERGENCY) | ||
| 515 | luaD_shrinkstack(th); | ||
| 518 | } | 516 | } |
| 519 | return sizeof(lua_State) + sizeof(TValue) * th->stacksize + | 517 | return sizeof(lua_State) + sizeof(TValue) * th->stacksize + |
| 520 | sizeof(CallInfo) * n; | 518 | sizeof(CallInfo) * n; |
| @@ -667,18 +665,36 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) { | |||
| 667 | } | 665 | } |
| 668 | 666 | ||
| 669 | 667 | ||
| 668 | void luaC_upvdeccount (lua_State *L, UpVal *uv) { | ||
| 669 | lua_assert(uv->refcount > 0); | ||
| 670 | uv->refcount--; | ||
| 671 | if (uv->refcount == 0 && !upisopen(uv)) | ||
| 672 | luaM_free(L, uv); | ||
| 673 | } | ||
| 674 | |||
| 675 | |||
| 676 | static void freeLclosure (lua_State *L, LClosure *cl) { | ||
| 677 | int i; | ||
| 678 | for (i = 0; i < cl->nupvalues; i++) { | ||
| 679 | UpVal *uv = cl->upvals[i]; | ||
| 680 | if (uv) | ||
| 681 | luaC_upvdeccount(L, uv); | ||
| 682 | } | ||
| 683 | luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); | ||
| 684 | } | ||
| 685 | |||
| 686 | |||
| 670 | static void freeobj (lua_State *L, GCObject *o) { | 687 | static void freeobj (lua_State *L, GCObject *o) { |
| 671 | switch (gch(o)->tt) { | 688 | switch (gch(o)->tt) { |
| 672 | case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; | 689 | case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; |
| 673 | case LUA_TLCL: { | 690 | case LUA_TLCL: { |
| 674 | luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues)); | 691 | freeLclosure(L, gco2lcl(o)); |
| 675 | break; | 692 | break; |
| 676 | } | 693 | } |
| 677 | case LUA_TCCL: { | 694 | case LUA_TCCL: { |
| 678 | luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); | 695 | luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); |
| 679 | break; | 696 | break; |
| 680 | } | 697 | } |
| 681 | case LUA_TUPVAL: luaM_free(L, gco2uv(o)); break; | ||
| 682 | case LUA_TTABLE: luaH_free(L, gco2t(o)); break; | 698 | case LUA_TTABLE: luaH_free(L, gco2t(o)); break; |
| 683 | case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; | 699 | case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; |
| 684 | case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; | 700 | case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; |
| @@ -699,20 +715,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); | |||
| 699 | 715 | ||
| 700 | 716 | ||
| 701 | /* | 717 | /* |
| 702 | ** sweep the (open) upvalues of a thread and resize its stack and | ||
| 703 | ** list of call-info structures. | ||
| 704 | */ | ||
| 705 | static void sweepthread (lua_State *L, lua_State *L1) { | ||
| 706 | if (L1->stack == NULL) return; /* stack not completely built yet */ | ||
| 707 | sweepwholelist(L, &L1->openupval); /* sweep open upvalues */ | ||
| 708 | luaE_freeCI(L1); /* free extra CallInfo slots */ | ||
| 709 | /* should not change the stack during an emergency gc cycle */ | ||
| 710 | if (G(L)->gckind != KGC_EMERGENCY) | ||
| 711 | luaD_shrinkstack(L1); | ||
| 712 | } | ||
| 713 | |||
| 714 | |||
| 715 | /* | ||
| 716 | ** sweep at most 'count' elements from a list of GCObjects erasing dead | 718 | ** sweep at most 'count' elements from a list of GCObjects erasing dead |
| 717 | ** objects, where a dead (not alive) object is one marked with the "old" | 719 | ** objects, where a dead (not alive) object is one marked with the "old" |
| 718 | ** (non current) white and not fixed; change all non-dead objects back | 720 | ** (non current) white and not fixed; change all non-dead objects back |
| @@ -730,10 +732,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { | |||
| 730 | *p = gch(curr)->next; /* remove 'curr' from list */ | 732 | *p = gch(curr)->next; /* remove 'curr' from list */ |
| 731 | freeobj(L, curr); /* erase 'curr' */ | 733 | freeobj(L, curr); /* erase 'curr' */ |
| 732 | } | 734 | } |
| 733 | else { | 735 | else { /* update marks */ |
| 734 | if (gch(curr)->tt == LUA_TTHREAD) | ||
| 735 | sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */ | ||
| 736 | /* update marks */ | ||
| 737 | gch(curr)->marked = cast_byte((marked & maskcolors) | white); | 736 | gch(curr)->marked = cast_byte((marked & maskcolors) | white); |
| 738 | p = &gch(curr)->next; /* go to next element */ | 737 | p = &gch(curr)->next; /* go to next element */ |
| 739 | } | 738 | } |
| @@ -886,16 +885,6 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { | |||
| 886 | */ | 885 | */ |
| 887 | 886 | ||
| 888 | 887 | ||
| 889 | static void localmarkclosure (LClosure *cl, int bit) { | ||
| 890 | int i; | ||
| 891 | for (i = 0; i < cl->nupvalues; i++) { | ||
| 892 | if (cl->upvals[i]) { | ||
| 893 | l_setbit(cl->upvals[i]->marked, bit); | ||
| 894 | } | ||
| 895 | } | ||
| 896 | } | ||
| 897 | |||
| 898 | |||
| 899 | /* | 888 | /* |
| 900 | ** Traverse a thread, local marking all its collectable objects | 889 | ** Traverse a thread, local marking all its collectable objects |
| 901 | */ | 890 | */ |
| @@ -904,16 +893,8 @@ static void localmarkthread (lua_State *l) { | |||
| 904 | if (o == NULL) | 893 | if (o == NULL) |
| 905 | return; /* stack not completely built yet */ | 894 | return; /* stack not completely built yet */ |
| 906 | for (; o < l->top; o++) { /* mark live elements in the stack */ | 895 | for (; o < l->top; o++) { /* mark live elements in the stack */ |
| 907 | if (iscollectable(o)) { | 896 | if (iscollectable(o)) |
| 908 | GCObject *obj = gcvalue(o); | 897 | l_setbit(gcvalue(o)->gch.marked, LOCALBLACK); |
| 909 | if (obj->gch.tt == LUA_TLCL && /* is it a Lua closure? */ | ||
| 910 | islocal(obj) && /* is it still local? */ | ||
| 911 | !testbit(obj->gch.marked, LOCALBLACK)) { /* not visited yet? */ | ||
| 912 | /* mark its upvalues as local black */ | ||
| 913 | localmarkclosure(gco2lcl(obj), LOCALBLACK); | ||
| 914 | } | ||
| 915 | l_setbit(obj->gch.marked, LOCALBLACK); | ||
| 916 | } | ||
| 917 | } | 898 | } |
| 918 | } | 899 | } |
| 919 | 900 | ||
| @@ -937,10 +918,6 @@ static void localsweep (lua_State *L, global_State *g, GCObject **p) { | |||
| 937 | *p = curr->gch.next; /* remove 'curr' from list */ | 918 | *p = curr->gch.next; /* remove 'curr' from list */ |
| 938 | curr->gch.next = g->allgc; /* link 'curr' in 'allgc' list */ | 919 | curr->gch.next = g->allgc; /* link 'curr' in 'allgc' list */ |
| 939 | g->allgc = curr; | 920 | g->allgc = curr; |
| 940 | if (curr->gch.tt == LUA_TLCL) { /* is it a Lua closure? */ | ||
| 941 | /* mark its upvalues as non local */ | ||
| 942 | localmarkclosure(gco2lcl(curr), LOCALBIT); | ||
| 943 | } | ||
| 944 | } | 921 | } |
| 945 | else { /* still local */ | 922 | else { /* still local */ |
| 946 | if (testbit(curr->gch.marked, LOCALBLACK)) { /* locally alive? */ | 923 | if (testbit(curr->gch.marked, LOCALBLACK)) { /* locally alive? */ |
| @@ -965,7 +942,6 @@ static void luaC_localcollection (lua_State *L) { | |||
| 965 | lua_assert(g->gcstate == GCSpause); | 942 | lua_assert(g->gcstate == GCSpause); |
| 966 | localmark(g); | 943 | localmark(g); |
| 967 | localsweep(L, g, &g->localgc); | 944 | localsweep(L, g, &g->localgc); |
| 968 | localsweep(L, g, &g->localupv); | ||
| 969 | } | 945 | } |
| 970 | 946 | ||
| 971 | /* }====================================================== */ | 947 | /* }====================================================== */ |
| @@ -1036,7 +1012,6 @@ void luaC_freeallobjects (lua_State *L) { | |||
| 1036 | g->gckind = KGC_NORMAL; | 1012 | g->gckind = KGC_NORMAL; |
| 1037 | sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ | 1013 | sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ |
| 1038 | sweepwholelist(L, &g->localgc); | 1014 | sweepwholelist(L, &g->localgc); |
| 1039 | sweepwholelist(L, &g->localupv); | ||
| 1040 | sweepwholelist(L, &g->allgc); | 1015 | sweepwholelist(L, &g->allgc); |
| 1041 | sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ | 1016 | sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ |
| 1042 | lua_assert(g->strt.nuse == 0); | 1017 | lua_assert(g->strt.nuse == 0); |
| @@ -1119,7 +1094,6 @@ static lu_mem singlestep (lua_State *L) { | |||
| 1119 | } | 1094 | } |
| 1120 | else { | 1095 | else { |
| 1121 | sweepwholelist(L, &g->localgc); | 1096 | sweepwholelist(L, &g->localgc); |
| 1122 | sweepwholelist(L, &g->localupv); | ||
| 1123 | g->gcstate = GCSsweep; | 1097 | g->gcstate = GCSsweep; |
| 1124 | return GCLOCALPAUSE / 4; /* some magic for now */ | 1098 | return GCLOCALPAUSE / 4; /* some magic for now */ |
| 1125 | } | 1099 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.h,v 2.65 2013/08/21 20:09:51 roberto Exp roberto $ | 2 | ** $Id: lgc.h,v 2.66 2013/08/23 13:34:54 roberto Exp roberto $ |
| 3 | ** Garbage Collector | 3 | ** Garbage Collector |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -55,7 +55,7 @@ | |||
| 55 | ** all objects are white again. | 55 | ** all objects are white again. |
| 56 | */ | 56 | */ |
| 57 | 57 | ||
| 58 | #define keepinvariant(g) (g->gcstate <= GCSatomic) | 58 | #define keepinvariant(g) ((g)->gcstate <= GCSatomic) |
| 59 | 59 | ||
| 60 | 60 | ||
| 61 | /* | 61 | /* |
| @@ -91,7 +91,7 @@ | |||
| 91 | 91 | ||
| 92 | #define tofinalize(x) testbit((x)->gch.marked, FINALIZEDBIT) | 92 | #define tofinalize(x) testbit((x)->gch.marked, FINALIZEDBIT) |
| 93 | 93 | ||
| 94 | #define otherwhite(g) (g->currentwhite ^ WHITEBITS) | 94 | #define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) |
| 95 | #define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) | 95 | #define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) |
| 96 | #define isdead(g,v) isdeadm(otherwhite(g), (v)->gch.marked) | 96 | #define isdead(g,v) isdeadm(otherwhite(g), (v)->gch.marked) |
| 97 | 97 | ||
| @@ -127,6 +127,10 @@ | |||
| 127 | { if (nolocal(obj2gco(o)), isblack(obj2gco(p)) && iswhite(obj2gco(o))) \ | 127 | { if (nolocal(obj2gco(o)), isblack(obj2gco(p)) && iswhite(obj2gco(o))) \ |
| 128 | luaC_barrierback_(L,p); } | 128 | luaC_barrierback_(L,p); } |
| 129 | 129 | ||
| 130 | #define luaC_upvalbarrier(L,uv) \ | ||
| 131 | { if (iscollectable((uv)->v) && !upisopen(uv)) \ | ||
| 132 | luaC_upvalbarrier_(L,uv); } | ||
| 133 | |||
| 130 | LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); | 134 | LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); |
| 131 | LUAI_FUNC void luaC_freeallobjects (lua_State *L); | 135 | LUAI_FUNC void luaC_freeallobjects (lua_State *L); |
| 132 | LUAI_FUNC void luaC_step (lua_State *L); | 136 | 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, | |||
| 138 | LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); | 142 | LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); |
| 139 | LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); | 143 | LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); |
| 140 | LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c); | 144 | LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c); |
| 145 | LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv); | ||
| 141 | LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); | 146 | LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); |
| 142 | LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv); | 147 | LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv); |
| 148 | |||
| 143 | 149 | ||
| 144 | #endif | 150 | #endif |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lobject.h,v 2.79 2013/08/07 12:18:11 roberto Exp roberto $ | 2 | ** $Id: lobject.h,v 2.80 2013/08/18 16:12:18 roberto Exp roberto $ |
| 3 | ** Type definitions for Lua objects | 3 | ** Type definitions for Lua objects |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -20,13 +20,12 @@ | |||
| 20 | ** Extra tags for non-values | 20 | ** Extra tags for non-values |
| 21 | */ | 21 | */ |
| 22 | #define LUA_TPROTO LUA_NUMTAGS | 22 | #define LUA_TPROTO LUA_NUMTAGS |
| 23 | #define LUA_TUPVAL (LUA_NUMTAGS+1) | 23 | #define LUA_TDEADKEY (LUA_NUMTAGS+1) |
| 24 | #define LUA_TDEADKEY (LUA_NUMTAGS+2) | ||
| 25 | 24 | ||
| 26 | /* | 25 | /* |
| 27 | ** number of all possible tags (including LUA_TNONE but excluding DEADKEY) | 26 | ** number of all possible tags (including LUA_TNONE but excluding DEADKEY) |
| 28 | */ | 27 | */ |
| 29 | #define LUA_TOTALTAGS (LUA_TUPVAL+2) | 28 | #define LUA_TOTALTAGS (LUA_TPROTO + 2) |
| 30 | 29 | ||
| 31 | 30 | ||
| 32 | /* | 31 | /* |
| @@ -392,11 +391,7 @@ typedef struct Proto { | |||
| 392 | /* | 391 | /* |
| 393 | ** Lua Upvalues | 392 | ** Lua Upvalues |
| 394 | */ | 393 | */ |
| 395 | typedef struct UpVal { | 394 | typedef struct UpVal UpVal; |
| 396 | CommonHeader; | ||
| 397 | TValue *v; /* points to stack or to its own value */ | ||
| 398 | TValue value; /* the value (when closed) */ | ||
| 399 | } UpVal; | ||
| 400 | 395 | ||
| 401 | 396 | ||
| 402 | /* | 397 | /* |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.c,v 2.105 2013/08/23 13:34:54 roberto Exp roberto $ | 2 | ** $Id: lstate.c,v 2.106 2013/08/26 12:41:10 roberto Exp roberto $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -289,7 +289,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
| 289 | g->version = lua_version(NULL); | 289 | g->version = lua_version(NULL); |
| 290 | g->gcstate = GCSpause; | 290 | g->gcstate = GCSpause; |
| 291 | g->allgc = NULL; | 291 | g->allgc = NULL; |
| 292 | g->localgc = g->localupv = NULL; | 292 | g->localgc = NULL; |
| 293 | g->finobj = NULL; | 293 | g->finobj = NULL; |
| 294 | g->tobefnz = NULL; | 294 | g->tobefnz = NULL; |
| 295 | g->fixedgc = NULL; | 295 | g->fixedgc = NULL; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.h,v 2.89 2013/08/23 13:34:54 roberto Exp roberto $ | 2 | ** $Id: lstate.h,v 2.90 2013/08/26 12:41:10 roberto Exp roberto $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -27,13 +27,6 @@ | |||
| 27 | ** List 'fixedgc' keep objects that are not to be collected (currently | 27 | ** List 'fixedgc' keep objects that are not to be collected (currently |
| 28 | ** only small strings, such as reserved words). | 28 | ** only small strings, such as reserved words). |
| 29 | ** | 29 | ** |
| 30 | ** Open upvalues are not subject to independent garbage collection. They | ||
| 31 | ** are collected together with their respective threads. (They are | ||
| 32 | ** always gray, so they must be remarked in the atomic step. Usually | ||
| 33 | ** their contents would be marked when traversing the respective | ||
| 34 | ** threads, but the thread may already be dead, while the upvalue is | ||
| 35 | ** still accessible through closures.) | ||
| 36 | ** | ||
| 37 | ** Live objects with finalizers are kept in the list g->finobj. The | 30 | ** Live objects with finalizers are kept in the list g->finobj. The |
| 38 | ** list g->tobefnz links all objects being finalized. In particular, an | 31 | ** list g->tobefnz links all objects being finalized. In particular, an |
| 39 | ** object has its FINALIZEDBIT set iff it is in one of these lists. | 32 | ** object has its FINALIZEDBIT set iff it is in one of these lists. |
| @@ -128,7 +121,6 @@ typedef struct global_State { | |||
| 128 | lu_byte gcrunning; /* true if GC is running */ | 121 | lu_byte gcrunning; /* true if GC is running */ |
| 129 | GCObject *allgc; /* list of all collectable objects */ | 122 | GCObject *allgc; /* list of all collectable objects */ |
| 130 | GCObject *localgc; /* list of local objects */ | 123 | GCObject *localgc; /* list of local objects */ |
| 131 | GCObject *localupv; /* list of local upvalues */ | ||
| 132 | GCObject *finobj; /* list of collectable objects with finalizers */ | 124 | GCObject *finobj; /* list of collectable objects with finalizers */ |
| 133 | GCObject **sweepgc; /* current position of sweep in list 'allgc' */ | 125 | GCObject **sweepgc; /* current position of sweep in list 'allgc' */ |
| 134 | GCObject **sweepfin; /* current position of sweep in list 'finobj' */ | 126 | GCObject **sweepfin; /* current position of sweep in list 'finobj' */ |
| @@ -171,7 +163,7 @@ struct lua_State { | |||
| 171 | int basehookcount; | 163 | int basehookcount; |
| 172 | int hookcount; | 164 | int hookcount; |
| 173 | lua_Hook hook; | 165 | lua_Hook hook; |
| 174 | GCObject *openupval; /* list of open upvalues in this stack */ | 166 | UpVal *openupval; /* list of open upvalues in this stack */ |
| 175 | GCObject *gclist; | 167 | GCObject *gclist; |
| 176 | struct lua_longjmp *errorJmp; /* current error recover point */ | 168 | struct lua_longjmp *errorJmp; /* current error recover point */ |
| 177 | ptrdiff_t errfunc; /* current error handling function (stack index) */ | 169 | ptrdiff_t errfunc; /* current error handling function (stack index) */ |
| @@ -192,7 +184,6 @@ union GCObject { | |||
| 192 | union Closure cl; | 184 | union Closure cl; |
| 193 | struct Table h; | 185 | struct Table h; |
| 194 | struct Proto p; | 186 | struct Proto p; |
| 195 | struct UpVal uv; | ||
| 196 | struct lua_State th; /* thread */ | 187 | struct lua_State th; /* thread */ |
| 197 | }; | 188 | }; |
| 198 | 189 | ||
| @@ -211,7 +202,6 @@ union GCObject { | |||
| 211 | check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl)) | 202 | check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl)) |
| 212 | #define gco2t(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) | 203 | #define gco2t(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) |
| 213 | #define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) | 204 | #define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) |
| 214 | #define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) | ||
| 215 | #define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) | 205 | #define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) |
| 216 | 206 | ||
| 217 | /* macro to convert any Lua object into a GCObject */ | 207 | /* macro to convert any Lua object into a GCObject */ |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltests.c,v 2.148 2013/08/22 15:21:48 roberto Exp roberto $ | 2 | ** $Id: ltests.c,v 2.149 2013/08/26 12:41:10 roberto Exp roberto $ |
| 3 | ** Internal Module for Debugging of the Lua Implementation | 3 | ** Internal Module for Debugging of the Lua Implementation |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -195,14 +195,6 @@ static int testobjref2 (GCObject *f, GCObject *t) { | |||
| 195 | /* not a local or pointed by a thread? */ | 195 | /* not a local or pointed by a thread? */ |
| 196 | if (!islocal(t) || gch(f)->tt == LUA_TTHREAD) | 196 | if (!islocal(t) || gch(f)->tt == LUA_TTHREAD) |
| 197 | return 1; /* ok */ | 197 | return 1; /* ok */ |
| 198 | if (gch(t)->tt == LUA_TUPVAL) { | ||
| 199 | lua_assert(gch(f)->tt == LUA_TLCL); | ||
| 200 | return 1; /* upvalue pointed by a closure */ | ||
| 201 | } | ||
| 202 | if (gch(f)->tt == LUA_TUPVAL) { | ||
| 203 | UpVal *uv = gco2uv(f); | ||
| 204 | return (uv->v != &uv->value); /* open upvalue can point to local stuff */ | ||
| 205 | } | ||
| 206 | if (gch(f)->tt == LUA_TPROTO && gch(t)->tt == LUA_TLCL) | 198 | if (gch(f)->tt == LUA_TPROTO && gch(t)->tt == LUA_TLCL) |
| 207 | return 1; /* cache from a prototype */ | 199 | return 1; /* cache from a prototype */ |
| 208 | return 0; | 200 | return 0; |
| @@ -311,9 +303,11 @@ static void checkLclosure (global_State *g, LClosure *cl) { | |||
| 311 | int i; | 303 | int i; |
| 312 | if (cl->p) checkobjref(g, clgc, cl->p); | 304 | if (cl->p) checkobjref(g, clgc, cl->p); |
| 313 | for (i=0; i<cl->nupvalues; i++) { | 305 | for (i=0; i<cl->nupvalues; i++) { |
| 314 | if (cl->upvals[i]) { | 306 | UpVal *uv = cl->upvals[i]; |
| 315 | lua_assert(cl->upvals[i]->tt == LUA_TUPVAL); | 307 | if (uv) { |
| 316 | checkobjref(g, clgc, cl->upvals[i]); | 308 | if (!upisopen(uv)) /* only closed upvalues matter to invariant */ |
| 309 | checkvalref(g, clgc, uv->v); | ||
| 310 | lua_assert(uv->refcount > 0); | ||
| 317 | } | 311 | } |
| 318 | } | 312 | } |
| 319 | } | 313 | } |
| @@ -332,13 +326,10 @@ static int lua_checkpc (pCallInfo ci) { | |||
| 332 | static void checkstack (global_State *g, lua_State *L1) { | 326 | static void checkstack (global_State *g, lua_State *L1) { |
| 333 | StkId o; | 327 | StkId o; |
| 334 | CallInfo *ci; | 328 | CallInfo *ci; |
| 335 | GCObject *uvo; | 329 | UpVal *uv; |
| 336 | lua_assert(!isdead(g, obj2gco(L1))); | 330 | lua_assert(!isdead(g, obj2gco(L1))); |
| 337 | for (uvo = L1->openupval; uvo != NULL; uvo = gch(uvo)->next) { | 331 | for (uv = L1->openupval; uv != NULL; uv = uv->u.op.next) |
| 338 | UpVal *uv = gco2uv(uvo); | 332 | lua_assert(upisopen(uv)); /* must be open */ |
| 339 | lua_assert(uv->v != &uv->value); /* must be open */ | ||
| 340 | lua_assert(!isblack(uvo)); /* open upvalues cannot be black */ | ||
| 341 | } | ||
| 342 | for (ci = L1->ci; ci != NULL; ci = ci->previous) { | 333 | for (ci = L1->ci; ci != NULL; ci = ci->previous) { |
| 343 | lua_assert(ci->top <= L1->stack_last); | 334 | lua_assert(ci->top <= L1->stack_last); |
| 344 | lua_assert(lua_checkpc(ci)); | 335 | lua_assert(lua_checkpc(ci)); |
| @@ -357,13 +348,6 @@ static void checkobject (global_State *g, GCObject *o, int maybedead) { | |||
| 357 | else { | 348 | else { |
| 358 | lua_assert(g->gcstate != GCSpause || iswhite(o)); | 349 | lua_assert(g->gcstate != GCSpause || iswhite(o)); |
| 359 | switch (gch(o)->tt) { | 350 | switch (gch(o)->tt) { |
| 360 | case LUA_TUPVAL: { | ||
| 361 | UpVal *uv = gco2uv(o); | ||
| 362 | lua_assert(uv->v == &uv->value); /* must be closed */ | ||
| 363 | lua_assert(!isgray(o)); /* closed upvalues are never gray */ | ||
| 364 | checkvalref(g, o, uv->v); | ||
| 365 | break; | ||
| 366 | } | ||
| 367 | case LUA_TUSERDATA: { | 351 | case LUA_TUSERDATA: { |
| 368 | Table *mt = gco2u(o)->metatable; | 352 | Table *mt = gco2u(o)->metatable; |
| 369 | if (mt) checkobjref(g, o, mt); | 353 | if (mt) checkobjref(g, o, mt); |
| @@ -490,12 +474,6 @@ int lua_checkmemory (lua_State *L) { | |||
| 490 | for (o = g->localgc; o != NULL; o = gch(o)->next) { | 474 | for (o = g->localgc; o != NULL; o = gch(o)->next) { |
| 491 | checkobject(g, o, 1); | 475 | checkobject(g, o, 1); |
| 492 | } | 476 | } |
| 493 | /* check 'localupv' list */ | ||
| 494 | checkgray(g, g->localupv); | ||
| 495 | for (o = g->localupv; o != NULL; o = gch(o)->next) { | ||
| 496 | lua_assert(gch(o)->tt == LUA_TUPVAL); | ||
| 497 | checkobject(g, o, 1); | ||
| 498 | } | ||
| 499 | return 0; | 477 | return 0; |
| 500 | } | 478 | } |
| 501 | 479 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltm.c,v 2.20 2013/05/06 17:19:11 roberto Exp roberto $ | 2 | ** $Id: ltm.c,v 2.21 2013/08/21 20:09:51 roberto Exp roberto $ |
| 3 | ** Tag methods | 3 | ** Tag methods |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -28,7 +28,7 @@ LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { | |||
| 28 | "no value", | 28 | "no value", |
| 29 | "nil", "boolean", udatatypename, "number", | 29 | "nil", "boolean", udatatypename, "number", |
| 30 | "string", "table", "function", udatatypename, "thread", | 30 | "string", "table", "function", udatatypename, "thread", |
| 31 | "proto", "upval" /* these last two cases are used for tests only */ | 31 | "proto" /* this last case is used for tests only */ |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | 34 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lvm.c,v 2.177 2013/08/16 18:55:49 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.178 2013/08/19 14:18:43 roberto Exp roberto $ |
| 3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -416,7 +416,8 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, | |||
| 416 | ncl->l.upvals[i] = luaF_findupval(L, base + uv[i].idx); | 416 | ncl->l.upvals[i] = luaF_findupval(L, base + uv[i].idx); |
| 417 | else /* get upvalue from enclosing function */ | 417 | else /* get upvalue from enclosing function */ |
| 418 | ncl->l.upvals[i] = encup[uv[i].idx]; | 418 | ncl->l.upvals[i] = encup[uv[i].idx]; |
| 419 | /* new closure is white and local, so we do not need a barrier here */ | 419 | ncl->l.upvals[i]->refcount++; |
| 420 | /* new closure is white, so we do not need a barrier here */ | ||
| 420 | } | 421 | } |
| 421 | if (!isblack(obj2gco(p))) /* cache will not break GC invariant? */ | 422 | if (!isblack(obj2gco(p))) /* cache will not break GC invariant? */ |
| 422 | p->cache = ncl; /* save it on cache for reuse */ | 423 | p->cache = ncl; /* save it on cache for reuse */ |
| @@ -591,7 +592,7 @@ void luaV_execute (lua_State *L) { | |||
| 591 | vmcase(OP_SETUPVAL, | 592 | vmcase(OP_SETUPVAL, |
| 592 | UpVal *uv = cl->upvals[GETARG_B(i)]; | 593 | UpVal *uv = cl->upvals[GETARG_B(i)]; |
| 593 | setobj(L, uv->v, ra); | 594 | setobj(L, uv->v, ra); |
| 594 | luaC_barrier(L, uv, ra); | 595 | luaC_upvalbarrier(L, uv); |
| 595 | ) | 596 | ) |
| 596 | vmcase(OP_SETTABLE, | 597 | vmcase(OP_SETTABLE, |
| 597 | Protect(luaV_settable(L, ra, RKB(i), RKC(i))); | 598 | Protect(luaV_settable(L, ra, RKB(i), RKC(i))); |
