diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-04-11 15:41:09 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-04-11 15:41:09 -0300 |
commit | a3d36fe283c09d4e56474da98f22d13162cc9fec (patch) | |
tree | 1f6e2ed56d50dc14aa669fa5f31a63755abd4553 | |
parent | 9569ad6b0ddcde43eb893d2cfe5bcdb715c0ff20 (diff) | |
download | lua-a3d36fe283c09d4e56474da98f22d13162cc9fec.tar.gz lua-a3d36fe283c09d4e56474da98f22d13162cc9fec.tar.bz2 lua-a3d36fe283c09d4e56474da98f22d13162cc9fec.zip |
Upvalues collected like everything else (with mark-sweep) instead
of reference count (simpler and better for generational mode)
-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) { |