diff options
| -rw-r--r-- | lapi.c | 25 | ||||
| -rw-r--r-- | lfunc.c | 47 | ||||
| -rw-r--r-- | lfunc.h | 18 | ||||
| -rw-r--r-- | lgc.c | 89 | ||||
| -rw-r--r-- | lgc.h | 10 | ||||
| -rw-r--r-- | lobject.h | 22 | ||||
| -rw-r--r-- | lstate.h | 4 | ||||
| -rw-r--r-- | ltm.c | 4 | ||||
| -rw-r--r-- | lvm.c | 5 |
9 files changed, 97 insertions, 127 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lapi.c,v 2.260 2017/02/23 21:07:34 roberto Exp roberto $ | 2 | ** $Id: lapi.c,v 2.261 2017/04/06 13:08:56 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 | */ |
| @@ -1004,7 +1004,7 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, | |||
| 1004 | const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); | 1004 | const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); |
| 1005 | /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ | 1005 | /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ |
| 1006 | setobj(L, f->upvals[0]->v, gt); | 1006 | setobj(L, f->upvals[0]->v, gt); |
| 1007 | luaC_upvalbarrier(L, f->upvals[0], gt); | 1007 | luaC_barrier(L, f->upvals[0], gt); |
| 1008 | } | 1008 | } |
| 1009 | } | 1009 | } |
| 1010 | lua_unlock(L); | 1010 | lua_unlock(L); |
| @@ -1202,13 +1202,13 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) { | |||
| 1202 | 1202 | ||
| 1203 | 1203 | ||
| 1204 | static const char *aux_upvalue (StkId fi, int n, TValue **val, | 1204 | static const char *aux_upvalue (StkId fi, int n, TValue **val, |
| 1205 | CClosure **owner, UpVal **uv) { | 1205 | GCObject **owner) { |
| 1206 | switch (ttype(fi)) { | 1206 | switch (ttype(fi)) { |
| 1207 | case LUA_TCCL: { /* C closure */ | 1207 | case LUA_TCCL: { /* C closure */ |
| 1208 | CClosure *f = clCvalue(fi); | 1208 | CClosure *f = clCvalue(fi); |
| 1209 | if (!(1 <= n && n <= f->nupvalues)) return NULL; | 1209 | if (!(1 <= n && n <= f->nupvalues)) return NULL; |
| 1210 | *val = &f->upvalue[n-1]; | 1210 | *val = &f->upvalue[n-1]; |
| 1211 | if (owner) *owner = f; | 1211 | if (owner) *owner = obj2gco(f); |
| 1212 | return ""; | 1212 | return ""; |
| 1213 | } | 1213 | } |
| 1214 | case LUA_TLCL: { /* Lua closure */ | 1214 | case LUA_TLCL: { /* Lua closure */ |
| @@ -1217,7 +1217,7 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val, | |||
| 1217 | Proto *p = f->p; | 1217 | Proto *p = f->p; |
| 1218 | if (!(1 <= n && n <= p->sizeupvalues)) return NULL; | 1218 | if (!(1 <= n && n <= p->sizeupvalues)) return NULL; |
| 1219 | *val = f->upvals[n-1]->v; | 1219 | *val = f->upvals[n-1]->v; |
| 1220 | if (uv) *uv = f->upvals[n - 1]; | 1220 | if (owner) *owner = obj2gco(f->upvals[n - 1]); |
| 1221 | name = p->upvalues[n-1].name; | 1221 | name = p->upvalues[n-1].name; |
| 1222 | return (name == NULL) ? "(*no name)" : getstr(name); | 1222 | return (name == NULL) ? "(*no name)" : getstr(name); |
| 1223 | } | 1223 | } |
| @@ -1230,7 +1230,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { | |||
| 1230 | const char *name; | 1230 | const char *name; |
| 1231 | TValue *val = NULL; /* to avoid warnings */ | 1231 | TValue *val = NULL; /* to avoid warnings */ |
| 1232 | lua_lock(L); | 1232 | lua_lock(L); |
| 1233 | name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL); | 1233 | name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL); |
| 1234 | if (name) { | 1234 | if (name) { |
| 1235 | setobj2s(L, L->top, val); | 1235 | setobj2s(L, L->top, val); |
| 1236 | api_incr_top(L); | 1236 | api_incr_top(L); |
| @@ -1243,18 +1243,16 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { | |||
| 1243 | LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { | 1243 | LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { |
| 1244 | const char *name; | 1244 | const char *name; |
| 1245 | TValue *val = NULL; /* to avoid warnings */ | 1245 | TValue *val = NULL; /* to avoid warnings */ |
| 1246 | CClosure *owner = NULL; | 1246 | GCObject *owner = NULL; /* to avoid warnings */ |
| 1247 | UpVal *uv = NULL; | ||
| 1248 | StkId fi; | 1247 | StkId fi; |
| 1249 | lua_lock(L); | 1248 | lua_lock(L); |
| 1250 | fi = index2addr(L, funcindex); | 1249 | fi = index2addr(L, funcindex); |
| 1251 | api_checknelems(L, 1); | 1250 | api_checknelems(L, 1); |
| 1252 | name = aux_upvalue(fi, n, &val, &owner, &uv); | 1251 | name = aux_upvalue(fi, n, &val, &owner); |
| 1253 | if (name) { | 1252 | if (name) { |
| 1254 | L->top--; | 1253 | L->top--; |
| 1255 | setobj(L, val, L->top); | 1254 | setobj(L, val, L->top); |
| 1256 | if (owner) { luaC_barrier(L, owner, val); } | 1255 | luaC_barrier(L, owner, val); |
| 1257 | else if (uv) { luaC_upvalbarrier(L, uv, val); } | ||
| 1258 | } | 1256 | } |
| 1259 | lua_unlock(L); | 1257 | lua_unlock(L); |
| 1260 | return name; | 1258 | return name; |
| @@ -1296,11 +1294,8 @@ LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, | |||
| 1296 | LClosure *f1; | 1294 | LClosure *f1; |
| 1297 | UpVal **up1 = getupvalref(L, fidx1, n1, &f1); | 1295 | UpVal **up1 = getupvalref(L, fidx1, n1, &f1); |
| 1298 | UpVal **up2 = getupvalref(L, fidx2, n2, NULL); | 1296 | UpVal **up2 = getupvalref(L, fidx2, n2, NULL); |
| 1299 | luaC_upvdeccount(L, *up1); | ||
| 1300 | *up1 = *up2; | 1297 | *up1 = *up2; |
| 1301 | (*up1)->refcount++; | 1298 | luaC_objbarrier(L, f1, *up1); |
| 1302 | if (upisopen(*up1)) (*up1)->u.open.touched = 1; | ||
| 1303 | luaC_upvalbarrier(L, *up1, (*up1)->v); | ||
| 1304 | } | 1299 | } |
| 1305 | 1300 | ||
| 1306 | 1301 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lfunc.c,v 2.45 2014/11/02 19:19:04 roberto Exp roberto $ | 2 | ** $Id: lfunc.c,v 2.46 2017/04/06 13:08:56 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 | */ |
| @@ -45,31 +45,35 @@ LClosure *luaF_newLclosure (lua_State *L, int n) { | |||
| 45 | void luaF_initupvals (lua_State *L, LClosure *cl) { | 45 | void luaF_initupvals (lua_State *L, LClosure *cl) { |
| 46 | int i; | 46 | int i; |
| 47 | for (i = 0; i < cl->nupvalues; i++) { | 47 | for (i = 0; i < cl->nupvalues; i++) { |
| 48 | UpVal *uv = luaM_new(L, UpVal); | 48 | GCObject *o = luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal)); |
| 49 | uv->refcount = 1; | 49 | UpVal *uv = gco2upv(o); |
| 50 | uv->v = &uv->u.value; /* make it closed */ | 50 | uv->v = &uv->u.value; /* make it closed */ |
| 51 | setnilvalue(uv->v); | 51 | setnilvalue(uv->v); |
| 52 | cl->upvals[i] = uv; | 52 | cl->upvals[i] = uv; |
| 53 | luaC_objbarrier(L, cl, o); | ||
| 53 | } | 54 | } |
| 54 | } | 55 | } |
| 55 | 56 | ||
| 56 | 57 | ||
| 57 | UpVal *luaF_findupval (lua_State *L, StkId level) { | 58 | UpVal *luaF_findupval (lua_State *L, StkId level) { |
| 58 | UpVal **pp = &L->openupval; | 59 | UpVal **pp = &L->openupval; |
| 60 | GCObject *o; | ||
| 59 | UpVal *p; | 61 | UpVal *p; |
| 60 | UpVal *uv; | 62 | UpVal *uv; |
| 61 | lua_assert(isintwups(L) || L->openupval == NULL); | 63 | lua_assert(isintwups(L) || L->openupval == NULL); |
| 62 | while (*pp != NULL && (p = *pp)->v >= level) { | 64 | while ((p = *pp) != NULL && p->v >= level) { |
| 63 | lua_assert(upisopen(p)); | 65 | lua_assert(upisopen(p)); |
| 64 | if (p->v == level) /* found a corresponding upvalue? */ | 66 | if (p->v == level) /* found a corresponding upvalue? */ |
| 65 | return p; /* return it */ | 67 | return p; /* return it */ |
| 66 | pp = &p->u.open.next; | 68 | pp = &p->u.open.next; |
| 67 | } | 69 | } |
| 68 | /* not found: create a new upvalue */ | 70 | /* not found: create a new upvalue between 'pp' and 'p' */ |
| 69 | uv = luaM_new(L, UpVal); | 71 | o = luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal)); |
| 70 | uv->refcount = 0; | 72 | uv = gco2upv(o); |
| 71 | uv->u.open.next = *pp; /* link it to list of open upvalues */ | 73 | uv->u.open.next = p; /* link it to list of open upvalues */ |
| 72 | uv->u.open.touched = 1; | 74 | uv->u.open.previous = pp; |
| 75 | if (p) | ||
| 76 | p->u.open.previous = &uv->u.open.next; | ||
| 73 | *pp = uv; | 77 | *pp = uv; |
| 74 | uv->v = level; /* current value lives in the stack */ | 78 | uv->v = level; /* current value lives in the stack */ |
| 75 | if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ | 79 | if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ |
| @@ -80,19 +84,24 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { | |||
| 80 | } | 84 | } |
| 81 | 85 | ||
| 82 | 86 | ||
| 87 | void luaF_unlinkupval (UpVal *uv) { | ||
| 88 | lua_assert(upisopen(uv)); | ||
| 89 | *uv->u.open.previous = uv->u.open.next; | ||
| 90 | if (uv->u.open.next) | ||
| 91 | uv->u.open.next->u.open.previous = uv->u.open.previous; | ||
| 92 | } | ||
| 93 | |||
| 94 | |||
| 83 | void luaF_close (lua_State *L, StkId level) { | 95 | void luaF_close (lua_State *L, StkId level) { |
| 84 | UpVal *uv; | 96 | UpVal *uv; |
| 85 | while (L->openupval != NULL && (uv = L->openupval)->v >= level) { | 97 | while (L->openupval != NULL && (uv = L->openupval)->v >= level) { |
| 86 | lua_assert(upisopen(uv)); | 98 | TValue *slot = &uv->u.value; /* new position for value */ |
| 87 | L->openupval = uv->u.open.next; /* remove from 'open' list */ | 99 | luaF_unlinkupval(uv); |
| 88 | if (uv->refcount == 0) /* no references? */ | 100 | setobj(L, slot, uv->v); /* move value to upvalue slot */ |
| 89 | luaM_free(L, uv); /* free upvalue */ | 101 | uv->v = slot; /* now current value lives here */ |
| 90 | else { | 102 | if (!iswhite(uv)) |
| 91 | TValue *slot = &uv->u.value; /* new position for value */ | 103 | gray2black(uv); /* closed upvalues cannot be gray */ |
| 92 | setobj(L, slot, uv->v); /* move value to upvalue slot */ | 104 | luaC_barrier(L, uv, slot); |
| 93 | uv->v = slot; /* now current value lives here */ | ||
| 94 | luaC_upvalbarrier(L, uv, slot); | ||
| 95 | } | ||
| 96 | } | 105 | } |
| 97 | } | 106 | } |
| 98 | 107 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lfunc.h,v 2.14 2014/06/19 18:27:20 roberto Exp roberto $ | 2 | ** $Id: lfunc.h,v 2.15 2015/01/13 15:49: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 | */ |
| @@ -29,21 +29,6 @@ | |||
| 29 | #define MAXUPVAL 255 | 29 | #define MAXUPVAL 255 |
| 30 | 30 | ||
| 31 | 31 | ||
| 32 | /* | ||
| 33 | ** Upvalues for Lua closures | ||
| 34 | */ | ||
| 35 | struct UpVal { | ||
| 36 | TValue *v; /* points to stack or to its own value */ | ||
| 37 | lu_mem refcount; /* reference counter */ | ||
| 38 | union { | ||
| 39 | struct { /* (when open) */ | ||
| 40 | UpVal *next; /* linked list */ | ||
| 41 | int touched; /* mark to avoid cycles with dead threads */ | ||
| 42 | } open; | ||
| 43 | TValue value; /* the value (when closed) */ | ||
| 44 | } u; | ||
| 45 | }; | ||
| 46 | |||
| 47 | #define upisopen(up) ((up)->v != &(up)->u.value) | 32 | #define upisopen(up) ((up)->v != &(up)->u.value) |
| 48 | 33 | ||
| 49 | 34 | ||
| @@ -53,6 +38,7 @@ LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems); | |||
| 53 | LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); | 38 | LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); |
| 54 | LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); | 39 | LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); |
| 55 | LUAI_FUNC void luaF_close (lua_State *L, StkId level); | 40 | LUAI_FUNC void luaF_close (lua_State *L, StkId level); |
| 41 | LUAI_FUNC void luaF_unlinkupval (UpVal *uv); | ||
| 56 | LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); | 42 | LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); |
| 57 | LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, | 43 | LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, |
| 58 | int pc); | 44 | int pc); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.218 2017/04/06 13:08:56 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.219 2017/04/10 13:33:04 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 | */ |
| @@ -179,25 +179,11 @@ void luaC_barrierback_ (lua_State *L, Table *t) { | |||
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | 181 | ||
| 182 | /* | ||
| 183 | ** barrier for assignments to closed upvalues. Because upvalues are | ||
| 184 | ** shared among closures, it is impossible to know the color of all | ||
| 185 | ** closures pointing to it. So, we assume that the object being assigned | ||
| 186 | ** must be marked. | ||
| 187 | */ | ||
| 188 | void luaC_upvalbarrier_ (lua_State *L, GCObject *o) { | ||
| 189 | global_State *g = G(L); | ||
| 190 | if (keepinvariant(g) && !isold(o)) { | ||
| 191 | markobject(g, o); | ||
| 192 | setage(o, G_OLD0); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | |||
| 197 | void luaC_fix (lua_State *L, GCObject *o) { | 182 | void luaC_fix (lua_State *L, GCObject *o) { |
| 198 | global_State *g = G(L); | 183 | global_State *g = G(L); |
| 199 | lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ | 184 | lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ |
| 200 | white2gray(o); /* they will be gray forever */ | 185 | white2gray(o); /* they will be gray forever */ |
| 186 | setage(o, G_OLD); /* and old forever */ | ||
| 201 | g->allgc = o->next; /* remove object from 'allgc' list */ | 187 | g->allgc = o->next; /* remove object from 'allgc' list */ |
| 202 | o->next = g->fixedgc; /* link it to 'fixedgc' list */ | 188 | o->next = g->fixedgc; /* link it to 'fixedgc' list */ |
| 203 | g->fixedgc = o; | 189 | g->fixedgc = o; |
| @@ -230,10 +216,11 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { | |||
| 230 | 216 | ||
| 231 | 217 | ||
| 232 | /* | 218 | /* |
| 233 | ** mark an object. Userdata, strings, and closed upvalues are visited | 219 | ** Mark an object. Userdata, strings, and closed upvalues are visited |
| 234 | ** and turned black here. Other objects are marked gray and added | 220 | ** and turned black here. Other objects are marked gray and added |
| 235 | ** to appropriate list to be visited (and turned black) later. (Open | 221 | ** to appropriate list to be visited (and turned black) later. (Open |
| 236 | ** upvalues are already linked in 'headuv' list.) | 222 | ** upvalues are already linked in 'headuv' list. They are kept gray |
| 223 | ** to avoid barriers, as their values will be revisited by the thread.) | ||
| 237 | */ | 224 | */ |
| 238 | static void reallymarkobject (global_State *g, GCObject *o) { | 225 | static void reallymarkobject (global_State *g, GCObject *o) { |
| 239 | reentry: | 226 | reentry: |
| @@ -261,6 +248,14 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
| 261 | } | 248 | } |
| 262 | break; | 249 | break; |
| 263 | } | 250 | } |
| 251 | case LUA_TUPVAL: { | ||
| 252 | UpVal *uv = gco2upv(o); | ||
| 253 | g->GCmemtrav += sizeof(UpVal); | ||
| 254 | if (!upisopen(uv)) /* open upvalues are kept gray */ | ||
| 255 | gray2black(o); | ||
| 256 | markvalue(g, uv->v); /* mark its content */ | ||
| 257 | break; | ||
| 258 | } | ||
| 264 | case LUA_TLCL: { | 259 | case LUA_TLCL: { |
| 265 | linkgclist(gco2lcl(o), g->gray); | 260 | linkgclist(gco2lcl(o), g->gray); |
| 266 | break; | 261 | break; |
| @@ -324,10 +319,8 @@ static void remarkupvals (global_State *g) { | |||
| 324 | *p = thread->twups; /* remove thread from the list */ | 319 | *p = thread->twups; /* remove thread from the list */ |
| 325 | thread->twups = thread; /* mark that it is out of list */ | 320 | thread->twups = thread; /* mark that it is out of list */ |
| 326 | for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { | 321 | for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { |
| 327 | if (uv->u.open.touched) { | 322 | if (!iswhite(uv)) /* upvalue already visited? */ |
| 328 | markvalue(g, uv->v); /* remark upvalue's value */ | 323 | markvalue(g, uv->v); /* mark its value */ |
| 329 | uv->u.open.touched = 0; | ||
| 330 | } | ||
| 331 | } | 324 | } |
| 332 | } | 325 | } |
| 333 | } | 326 | } |
| @@ -516,22 +509,15 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) { | |||
| 516 | } | 509 | } |
| 517 | 510 | ||
| 518 | /* | 511 | /* |
| 519 | ** open upvalues point to values in a thread, so those values should | 512 | ** Traverse a Lua closure, marking its prototype and its upvalues. |
| 520 | ** be marked when the thread is traversed except in the atomic phase | 513 | ** (Both can be NULL while closure is being created.) |
| 521 | ** (because then the value cannot be changed by the thread and the | ||
| 522 | ** thread may not be traversed again) | ||
| 523 | */ | 514 | */ |
| 524 | static lu_mem traverseLclosure (global_State *g, LClosure *cl) { | 515 | static lu_mem traverseLclosure (global_State *g, LClosure *cl) { |
| 525 | int i; | 516 | int i; |
| 526 | markobjectN(g, cl->p); /* mark its prototype */ | 517 | markobjectN(g, cl->p); /* mark its prototype */ |
| 527 | for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ | 518 | for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ |
| 528 | UpVal *uv = cl->upvals[i]; | 519 | UpVal *uv = cl->upvals[i]; |
| 529 | if (uv != NULL) { /* can be NULL while closure is being built */ | 520 | markobjectN(g, uv); /* mark upvalue */ |
| 530 | if (upisopen(uv) && g->gcstate != GCSatomic) | ||
| 531 | uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ | ||
| 532 | else | ||
| 533 | markvalue(g, uv->v); | ||
| 534 | } | ||
| 535 | } | 521 | } |
| 536 | return sizeLclosure(cl->nupvalues); | 522 | return sizeLclosure(cl->nupvalues); |
| 537 | } | 523 | } |
| @@ -569,7 +555,6 @@ static lu_mem traversethread (global_State *g, lua_State *th) { | |||
| 569 | static void propagatemark (global_State *g) { | 555 | static void propagatemark (global_State *g) { |
| 570 | lu_mem size; | 556 | lu_mem size; |
| 571 | GCObject *o = g->gray; | 557 | GCObject *o = g->gray; |
| 572 | lua_assert(ongraylist(o)); | ||
| 573 | gray2black(o); | 558 | gray2black(o); |
| 574 | switch (o->tt) { | 559 | switch (o->tt) { |
| 575 | case LUA_TTABLE: { | 560 | case LUA_TTABLE: { |
| @@ -683,26 +668,10 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) { | |||
| 683 | } | 668 | } |
| 684 | 669 | ||
| 685 | 670 | ||
| 686 | /* | 671 | static void freeupval (lua_State *L, UpVal *uv) { |
| 687 | ** Decrement the reference count of an upvalue. If it goes to zero and | 672 | if (upisopen(uv)) |
| 688 | ** upvalue is closed, delete it. | 673 | luaF_unlinkupval(uv); |
| 689 | */ | 674 | luaM_free(L, uv); |
| 690 | void luaC_upvdeccount (lua_State *L, UpVal *uv) { | ||
| 691 | lua_assert(uv->refcount > 0); | ||
| 692 | uv->refcount--; | ||
| 693 | if (uv->refcount == 0 && !upisopen(uv)) | ||
| 694 | luaM_free(L, uv); | ||
| 695 | } | ||
| 696 | |||
| 697 | |||
| 698 | static void freeLclosure (lua_State *L, LClosure *cl) { | ||
| 699 | int i; | ||
| 700 | for (i = 0; i < cl->nupvalues; i++) { | ||
| 701 | UpVal *uv = cl->upvals[i]; | ||
| 702 | if (uv) | ||
| 703 | luaC_upvdeccount(L, uv); | ||
| 704 | } | ||
| 705 | luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); | ||
| 706 | } | 675 | } |
| 707 | 676 | ||
| 708 | 677 | ||
| @@ -711,8 +680,11 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
| 711 | case LUA_TPROTO: | 680 | case LUA_TPROTO: |
| 712 | luaF_freeproto(L, gco2p(o)); | 681 | luaF_freeproto(L, gco2p(o)); |
| 713 | break; | 682 | break; |
| 683 | case LUA_TUPVAL: | ||
| 684 | freeupval(L, gco2upv(o)); | ||
| 685 | break; | ||
| 714 | case LUA_TLCL: | 686 | case LUA_TLCL: |
| 715 | freeLclosure(L, gco2lcl(o)); | 687 | luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues)); |
| 716 | break; | 688 | break; |
| 717 | case LUA_TCCL: | 689 | case LUA_TCCL: |
| 718 | luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); | 690 | luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); |
| @@ -1144,14 +1116,14 @@ static void correctgraylists (global_State *g) { | |||
| 1144 | 1116 | ||
| 1145 | 1117 | ||
| 1146 | /* | 1118 | /* |
| 1147 | ** Mark 'old1' objects when starting a new young collection. ('old1' | 1119 | ** Mark 'old1' objects when starting a new young collection. (Threads |
| 1148 | ** tables are always black, threads are always gray.) | 1120 | ** and open upvalues are always gray, and do not need to be marked. |
| 1121 | ** All other old objects are black.) | ||
| 1149 | */ | 1122 | */ |
| 1150 | static void markold (global_State *g, GCObject *from, GCObject *to) { | 1123 | static void markold (global_State *g, GCObject *from, GCObject *to) { |
| 1151 | GCObject *p; | 1124 | GCObject *p; |
| 1152 | for (p = from; p != to; p = p->next) { | 1125 | for (p = from; p != to; p = p->next) { |
| 1153 | if (getage(p) == G_OLD1) { | 1126 | if (getage(p) == G_OLD1) { |
| 1154 | lua_assert((p->tt == LUA_TTHREAD) ? isgray(p) : isblack(p)); | ||
| 1155 | if (isblack(p)) { | 1127 | if (isblack(p)) { |
| 1156 | black2gray(p); /* should be '2white', but gray works too */ | 1128 | black2gray(p); /* should be '2white', but gray works too */ |
| 1157 | reallymarkobject(g, p); | 1129 | reallymarkobject(g, p); |
| @@ -1228,6 +1200,8 @@ static void entergen (lua_State *L, global_State *g) { | |||
| 1228 | 1200 | ||
| 1229 | sweep2old(L, &g->tobefnz); | 1201 | sweep2old(L, &g->tobefnz); |
| 1230 | 1202 | ||
| 1203 | setage(g->mainthread, G_OLD); | ||
| 1204 | |||
| 1231 | finishgencycle(L, g); | 1205 | finishgencycle(L, g); |
| 1232 | g->gckind = KGC_GEN; | 1206 | g->gckind = KGC_GEN; |
| 1233 | } | 1207 | } |
| @@ -1282,6 +1256,7 @@ static void genstep (lua_State *L, global_State *g) { | |||
| 1282 | youngcollection(L, g); | 1256 | youngcollection(L, g); |
| 1283 | mem = gettotalbytes(g); | 1257 | mem = gettotalbytes(g); |
| 1284 | luaE_setdebt(g, -((mem / 100) * 20)); | 1258 | luaE_setdebt(g, -((mem / 100) * 20)); |
| 1259 | lua_checkmemory(L); | ||
| 1285 | } | 1260 | } |
| 1286 | 1261 | ||
| 1287 | 1262 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.h,v 2.94 2017/04/06 13:08:56 roberto Exp roberto $ | 2 | ** $Id: lgc.h,v 2.95 2017/04/10 13:33:04 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 | */ |
| @@ -124,8 +124,6 @@ | |||
| 124 | #define changeage(o,f,t) \ | 124 | #define changeage(o,f,t) \ |
| 125 | check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t))) | 125 | check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t))) |
| 126 | 126 | ||
| 127 | #define ongraylist(o) (isgray(o) || getage(o) == G_TOUCHED2) | ||
| 128 | |||
| 129 | 127 | ||
| 130 | /* | 128 | /* |
| 131 | ** Does one step of collection when debt becomes positive. 'pre'/'pos' | 129 | ** Does one step of collection when debt becomes positive. 'pre'/'pos' |
| @@ -153,10 +151,6 @@ | |||
| 153 | (isblack(p) && iswhite(o)) ? \ | 151 | (isblack(p) && iswhite(o)) ? \ |
| 154 | luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) | 152 | luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) |
| 155 | 153 | ||
| 156 | #define luaC_upvalbarrier(L,uv,x) ( \ | ||
| 157 | (iscollectable(x) && !upisopen(uv)) ? \ | ||
| 158 | luaC_upvalbarrier_(L,gcvalue(x)) : cast_void(0)) | ||
| 159 | |||
| 160 | LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); | 154 | LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); |
| 161 | LUAI_FUNC void luaC_freeallobjects (lua_State *L); | 155 | LUAI_FUNC void luaC_freeallobjects (lua_State *L); |
| 162 | LUAI_FUNC void luaC_step (lua_State *L); | 156 | LUAI_FUNC void luaC_step (lua_State *L); |
| @@ -165,9 +159,7 @@ LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); | |||
| 165 | LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); | 159 | LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); |
| 166 | LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); | 160 | LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); |
| 167 | LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o); | 161 | LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o); |
| 168 | LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, GCObject *o); | ||
| 169 | LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); | 162 | LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); |
| 170 | LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv); | ||
| 171 | LUAI_FUNC void luaC_changemode (lua_State *L, int newmode); | 163 | LUAI_FUNC void luaC_changemode (lua_State *L, int newmode); |
| 172 | 164 | ||
| 173 | 165 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lobject.h,v 2.116 2015/11/03 18:33:10 roberto Exp roberto $ | 2 | ** $Id: lobject.h,v 2.117 2016/08/01 19:51:24 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 | */ |
| @@ -19,8 +19,9 @@ | |||
| 19 | /* | 19 | /* |
| 20 | ** Extra tags for non-values | 20 | ** Extra tags for non-values |
| 21 | */ | 21 | */ |
| 22 | #define LUA_TPROTO LUA_NUMTAGS /* function prototypes */ | 22 | #define LUA_TUPVAL LUA_NUMTAGS /* upvalues */ |
| 23 | #define LUA_TDEADKEY (LUA_NUMTAGS+1) /* removed keys in tables */ | 23 | #define LUA_TPROTO (LUA_NUMTAGS+1) /* function prototypes */ |
| 24 | #define LUA_TDEADKEY (LUA_NUMTAGS+2) /* removed keys in tables */ | ||
| 24 | 25 | ||
| 25 | /* | 26 | /* |
| 26 | ** number of all possible tags (including LUA_TNONE but excluding DEADKEY) | 27 | ** number of all possible tags (including LUA_TNONE but excluding DEADKEY) |
| @@ -431,9 +432,20 @@ typedef struct Proto { | |||
| 431 | 432 | ||
| 432 | 433 | ||
| 433 | /* | 434 | /* |
| 434 | ** Lua Upvalues | 435 | ** Upvalues for Lua closures |
| 435 | */ | 436 | */ |
| 436 | typedef struct UpVal UpVal; | 437 | typedef struct UpVal { |
| 438 | CommonHeader; | ||
| 439 | TValue *v; /* points to stack or to its own value */ | ||
| 440 | union { | ||
| 441 | struct { /* (when open) */ | ||
| 442 | struct UpVal *next; /* linked list */ | ||
| 443 | struct UpVal **previous; | ||
| 444 | } open; | ||
| 445 | TValue value; /* the value (when closed) */ | ||
| 446 | } u; | ||
| 447 | } UpVal; | ||
| 448 | |||
| 437 | 449 | ||
| 438 | 450 | ||
| 439 | /* | 451 | /* |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.h,v 2.135 2017/02/23 21:07:34 roberto Exp $ | 2 | ** $Id: lstate.h,v 2.136 2017/04/05 16:50:51 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 | */ |
| @@ -224,6 +224,7 @@ union GCUnion { | |||
| 224 | struct Table h; | 224 | struct Table h; |
| 225 | struct Proto p; | 225 | struct Proto p; |
| 226 | struct lua_State th; /* thread */ | 226 | struct lua_State th; /* thread */ |
| 227 | struct UpVal upv; | ||
| 227 | }; | 228 | }; |
| 228 | 229 | ||
| 229 | 230 | ||
| @@ -240,6 +241,7 @@ union GCUnion { | |||
| 240 | #define gco2t(o) check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h)) | 241 | #define gco2t(o) check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h)) |
| 241 | #define gco2p(o) check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p)) | 242 | #define gco2p(o) check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p)) |
| 242 | #define gco2th(o) check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th)) | 243 | #define gco2th(o) check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th)) |
| 244 | #define gco2upv(o) check_exp((o)->tt == LUA_TUPVAL, &((cast_u(o))->upv)) | ||
| 243 | 245 | ||
| 244 | 246 | ||
| 245 | /* macro to convert a Lua object into a GCObject */ | 247 | /* macro to convert a Lua object into a GCObject */ |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltm.c,v 2.37 2016/02/26 19:20:15 roberto Exp roberto $ | 2 | ** $Id: ltm.c,v 2.38 2016/12/22 13:08:50 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 | */ |
| @@ -30,7 +30,7 @@ LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { | |||
| 30 | "no value", | 30 | "no value", |
| 31 | "nil", "boolean", udatatypename, "number", | 31 | "nil", "boolean", udatatypename, "number", |
| 32 | "string", "table", "function", udatatypename, "thread", | 32 | "string", "table", "function", udatatypename, "thread", |
| 33 | "proto" /* this last case is used for tests only */ | 33 | "upvalue", "proto" /* these last cases are used for tests only */ |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | 36 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lvm.c,v 2.268 2016/02/05 19:59:14 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.269 2017/04/06 13:08:56 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 | */ |
| @@ -642,7 +642,6 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, | |||
| 642 | ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx); | 642 | ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx); |
| 643 | else /* get upvalue from enclosing function */ | 643 | else /* get upvalue from enclosing function */ |
| 644 | ncl->upvals[i] = encup[uv[i].idx]; | 644 | ncl->upvals[i] = encup[uv[i].idx]; |
| 645 | ncl->upvals[i]->refcount++; | ||
| 646 | /* new closure is white, so we do not need a barrier here */ | 645 | /* new closure is white, so we do not need a barrier here */ |
| 647 | } | 646 | } |
| 648 | if (!isblack(p)) /* cache will not break GC invariant? */ | 647 | if (!isblack(p)) /* cache will not break GC invariant? */ |
| @@ -855,7 +854,7 @@ void luaV_execute (lua_State *L) { | |||
| 855 | vmcase(OP_SETUPVAL) { | 854 | vmcase(OP_SETUPVAL) { |
| 856 | UpVal *uv = cl->upvals[GETARG_B(i)]; | 855 | UpVal *uv = cl->upvals[GETARG_B(i)]; |
| 857 | setobj(L, uv->v, ra); | 856 | setobj(L, uv->v, ra); |
| 858 | luaC_upvalbarrier(L, uv, ra); | 857 | luaC_barrier(L, uv, ra); |
| 859 | vmbreak; | 858 | vmbreak; |
| 860 | } | 859 | } |
| 861 | vmcase(OP_SETTABLE) { | 860 | vmcase(OP_SETTABLE) { |
