aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-04-11 15:41:09 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-04-11 15:41:09 -0300
commita3d36fe283c09d4e56474da98f22d13162cc9fec (patch)
tree1f6e2ed56d50dc14aa669fa5f31a63755abd4553
parent9569ad6b0ddcde43eb893d2cfe5bcdb715c0ff20 (diff)
downloadlua-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.c25
-rw-r--r--lfunc.c47
-rw-r--r--lfunc.h18
-rw-r--r--lgc.c89
-rw-r--r--lgc.h10
-rw-r--r--lobject.h22
-rw-r--r--lstate.h4
-rw-r--r--ltm.c4
-rw-r--r--lvm.c5
9 files changed, 97 insertions, 127 deletions
diff --git a/lapi.c b/lapi.c
index 25ed81fd..eb67d090 100644
--- a/lapi.c
+++ b/lapi.c
@@ -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
1204static const char *aux_upvalue (StkId fi, int n, TValue **val, 1204static 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) {
1243LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { 1243LUA_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
diff --git a/lfunc.c b/lfunc.c
index 0f839e7c..898104ac 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -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) {
45void luaF_initupvals (lua_State *L, LClosure *cl) { 45void 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
57UpVal *luaF_findupval (lua_State *L, StkId level) { 58UpVal *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
87void 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
83void luaF_close (lua_State *L, StkId level) { 95void 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
diff --git a/lfunc.h b/lfunc.h
index 6fd3fbac..7d0eca4a 100644
--- a/lfunc.h
+++ b/lfunc.h
@@ -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*/
35struct 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);
53LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); 38LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
54LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); 39LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
55LUAI_FUNC void luaF_close (lua_State *L, StkId level); 40LUAI_FUNC void luaF_close (lua_State *L, StkId level);
41LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
56LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); 42LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
57LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, 43LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
58 int pc); 44 int pc);
diff --git a/lgc.c b/lgc.c
index 68a7622f..f4223588 100644
--- a/lgc.c
+++ b/lgc.c
@@ -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*/
188void 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
197void luaC_fix (lua_State *L, GCObject *o) { 182void 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*/
238static void reallymarkobject (global_State *g, GCObject *o) { 225static 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*/
524static lu_mem traverseLclosure (global_State *g, LClosure *cl) { 515static 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) {
569static void propagatemark (global_State *g) { 555static 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/* 671static 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);
690void 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
698static 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*/
1150static void markold (global_State *g, GCObject *from, GCObject *to) { 1123static 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));
1259lua_checkmemory(L);
1285} 1260}
1286 1261
1287 1262
diff --git a/lgc.h b/lgc.h
index 13896d42..396f5a4e 100644
--- a/lgc.h
+++ b/lgc.h
@@ -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
160LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); 154LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
161LUAI_FUNC void luaC_freeallobjects (lua_State *L); 155LUAI_FUNC void luaC_freeallobjects (lua_State *L);
162LUAI_FUNC void luaC_step (lua_State *L); 156LUAI_FUNC void luaC_step (lua_State *L);
@@ -165,9 +159,7 @@ LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
165LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); 159LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
166LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); 160LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
167LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o); 161LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o);
168LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, GCObject *o);
169LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); 162LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
170LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv);
171LUAI_FUNC void luaC_changemode (lua_State *L, int newmode); 163LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);
172 164
173 165
diff --git a/lobject.h b/lobject.h
index eeddfdef..7c521ba2 100644
--- a/lobject.h
+++ b/lobject.h
@@ -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*/
436typedef struct UpVal UpVal; 437typedef 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/*
diff --git a/lstate.h b/lstate.h
index b01859aa..dc74370b 100644
--- a/lstate.h
+++ b/lstate.h
@@ -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 */
diff --git a/ltm.c b/ltm.c
index b664dbed..47341384 100644
--- a/ltm.c
+++ b/ltm.c
@@ -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
diff --git a/lvm.c b/lvm.c
index 81b2a481..32958665 100644
--- a/lvm.c
+++ b/lvm.c
@@ -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) {