aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lfunc.h9
-rw-r--r--lgc.c75
-rw-r--r--lgc.h6
-rw-r--r--lstate.c4
-rw-r--r--lstate.h6
-rw-r--r--ltests.c5
-rw-r--r--lvm.c12
7 files changed, 95 insertions, 22 deletions
diff --git a/lfunc.h b/lfunc.h
index 7d0eca4a..eca83e4f 100644
--- a/lfunc.h
+++ b/lfunc.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lfunc.h,v 2.15 2015/01/13 15:49:11 roberto Exp roberto $ 2** $Id: lfunc.h,v 2.16 2017/04/11 18:41:09 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*/
@@ -32,6 +32,13 @@
32#define upisopen(up) ((up)->v != &(up)->u.value) 32#define upisopen(up) ((up)->v != &(up)->u.value)
33 33
34 34
35/*
36** maximum number of misses before giving up the cache of closures
37** in prototypes
38*/
39#define MAXMISS 10
40
41
35LUAI_FUNC Proto *luaF_newproto (lua_State *L); 42LUAI_FUNC Proto *luaF_newproto (lua_State *L);
36LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems); 43LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems);
37LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems); 44LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems);
diff --git a/lgc.c b/lgc.c
index 65f4909c..a0253405 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 2.226 2017/04/24 17:52:18 roberto Exp roberto $ 2** $Id: lgc.c,v 2.227 2017/04/30 20:43:26 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,6 +179,26 @@ void luaC_barrierback_ (lua_State *L, Table *t) {
179} 179}
180 180
181 181
182/*
183** Barrier for prototype's cache of closures. For an 'old1'
184** object, making it gray stops it from being visited by 'markold',
185** so it is linked in the 'grayagain' list to ensure it will be
186** visited. Otherwise, it goes to 'protogray', as only its 'cache' field
187** needs to be revisited. (A prototype to be in this barrier must be
188** already finished, so its other fields cannot change and do not need
189** to be revisited.)
190*/
191LUAI_FUNC void luaC_protobarrier_ (lua_State *L, Proto *p) {
192 global_State *g = G(L);
193 lua_assert(g->gckind != KGC_GEN || isold(p));
194 if (getage(p) == G_OLD1) /* still need to be visited? */
195 linkgclist(p, g->grayagain); /* link it in 'grayagain' */
196 else
197 linkgclist(p, g->protogray); /* link it in 'protogray' */
198 black2gray(p); /* make prototype gray (to avoid other barriers) */
199}
200
201
182void luaC_fix (lua_State *L, GCObject *o) { 202void luaC_fix (lua_State *L, GCObject *o) {
183 global_State *g = G(L); 203 global_State *g = G(L);
184 lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ 204 lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */
@@ -332,7 +352,7 @@ static void remarkupvals (global_State *g) {
332*/ 352*/
333static void restartcollection (global_State *g) { 353static void restartcollection (global_State *g) {
334 g->gray = g->grayagain = NULL; 354 g->gray = g->grayagain = NULL;
335 g->weak = g->allweak = g->ephemeron = NULL; 355 g->weak = g->allweak = g->ephemeron = g->protogray = NULL;
336 markobject(g, g->mainthread); 356 markobject(g, g->mainthread);
337 markvalue(g, &g->l_registry); 357 markvalue(g, &g->l_registry);
338 markmt(g); 358 markmt(g);
@@ -477,15 +497,39 @@ static lu_mem traversetable (global_State *g, Table *h) {
477 497
478 498
479/* 499/*
500** Check the cache of a prototype, to keep invariants. If the
501** cache is white, clear it. (A cache should not prevent the
502** collection of its reference.) Otherwise, if in generational
503** mode, check the generational invariant. If the cache is old,
504** everything is ok. If the prototype is 'old0', everything
505** is ok too. (It will naturally be visited again.) If the
506** prototype is older than 'old0', then its cache (whith is new)
507** must be visited again in the next collection, so the prototype
508** goes to the 'protogray' list. (If the prototype has a cache,
509** it is already immutable and does not need other barriers;
510** then, it can become gray without problems for its other fields.)
511*/
512static void checkprotocache (global_State *g, Proto *p) {
513 if (p->cache) {
514 if (iswhite(p->cache))
515 p->cache = NULL; /* allow cache to be collected */
516 else if (g->gckind == KGC_GEN && !isold(p->cache) && getage(p) >= G_OLD1) {
517 linkgclist(p, g->protogray); /* link it in 'protogray' */
518 black2gray(p); /* make prototype gray */
519 }
520 }
521 p->cachemiss = 0; /* restart counting */
522}
523
524
525/*
480** Traverse a prototype. (While a prototype is being build, its 526** Traverse a prototype. (While a prototype is being build, its
481** arrays can be larger than needed; the extra slots are filled with 527** arrays can be larger than needed; the extra slots are filled with
482** NULL, so the use of 'markobjectN') 528** NULL, so the use of 'markobjectN')
483*/ 529*/
484static int traverseproto (global_State *g, Proto *f) { 530static int traverseproto (global_State *g, Proto *f) {
485 int i; 531 int i;
486 if (f->cache && iswhite(f->cache)) 532 checkprotocache(g, f);
487 f->cache = NULL; /* allow cache to be collected */
488 f->cachemiss = 0; /* restart counting */
489 markobjectN(g, f->source); 533 markobjectN(g, f->source);
490 for (i = 0; i < f->sizek; i++) /* mark literals */ 534 for (i = 0; i < f->sizek; i++) /* mark literals */
491 markvalue(g, &f->k[i]); 535 markvalue(g, &f->k[i]);
@@ -629,6 +673,19 @@ static void convergeephemerons (global_State *g) {
629** ======================================================= 673** =======================================================
630*/ 674*/
631 675
676static void clearprotolist (global_State *g) {
677 GCObject *p = g->protogray;
678 g->protogray = NULL;
679 while (p != NULL) {
680 Proto *pp = gco2p(p);
681 GCObject *next = pp->gclist;
682 lua_assert(isgray(pp) && (pp->cache != NULL || pp->cachemiss >= MAXMISS));
683 gray2black(pp);
684 checkprotocache(g, pp);
685 p = next;
686 }
687}
688
632 689
633/* 690/*
634** clear entries with unmarked keys from all weaktables in list 'l' 691** clear entries with unmarked keys from all weaktables in list 'l'
@@ -1073,14 +1130,15 @@ static void correctgraylists (global_State *g) {
1073 1130
1074 1131
1075/* 1132/*
1076** Mark 'old1' objects when starting a new young collection. (Threads 1133** Mark 'old1' objects when starting a new young collection.
1077** and open upvalues are always gray, and do not need to be marked. 1134** Gray objects are already in some gray list, and so will be visited
1078** All other old objects are black.) 1135** in the atomic step.
1079*/ 1136*/
1080static void markold (global_State *g, GCObject *from, GCObject *to) { 1137static void markold (global_State *g, GCObject *from, GCObject *to) {
1081 GCObject *p; 1138 GCObject *p;
1082 for (p = from; p != to; p = p->next) { 1139 for (p = from; p != to; p = p->next) {
1083 if (getage(p) == G_OLD1) { 1140 if (getage(p) == G_OLD1) {
1141 lua_assert(!iswhite(p));
1084 if (isblack(p)) { 1142 if (isblack(p)) {
1085 black2gray(p); /* should be '2white', but gray works too */ 1143 black2gray(p); /* should be '2white', but gray works too */
1086 reallymarkobject(g, p); 1144 reallymarkobject(g, p);
@@ -1337,6 +1395,7 @@ static l_mem atomic (lua_State *L) {
1337 clearvalues(g, g->weak, origweak); 1395 clearvalues(g, g->weak, origweak);
1338 clearvalues(g, g->allweak, origall); 1396 clearvalues(g, g->allweak, origall);
1339 luaS_clearcache(g); 1397 luaS_clearcache(g);
1398 clearprotolist(g);
1340 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ 1399 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
1341 lua_assert(g->gray == NULL); 1400 lua_assert(g->gray == NULL);
1342 work += g->GCmemtrav; /* complete counting */ 1401 work += g->GCmemtrav; /* complete counting */
diff --git a/lgc.h b/lgc.h
index 396f5a4e..6ee0b012 100644
--- a/lgc.h
+++ b/lgc.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.h,v 2.95 2017/04/10 13:33:04 roberto Exp roberto $ 2** $Id: lgc.h,v 2.96 2017/04/11 18:41:09 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*/
@@ -151,6 +151,9 @@
151 (isblack(p) && iswhite(o)) ? \ 151 (isblack(p) && iswhite(o)) ? \
152 luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) 152 luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
153 153
154#define luaC_protobarrier(L,p,o) \
155 (isblack(p) ? luaC_protobarrier_(L,p) : cast_void(0))
156
154LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); 157LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
155LUAI_FUNC void luaC_freeallobjects (lua_State *L); 158LUAI_FUNC void luaC_freeallobjects (lua_State *L);
156LUAI_FUNC void luaC_step (lua_State *L); 159LUAI_FUNC void luaC_step (lua_State *L);
@@ -159,6 +162,7 @@ LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
159LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); 162LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
160LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); 163LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
161LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o); 164LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o);
165LUAI_FUNC void luaC_protobarrier_ (lua_State *L, Proto *p);
162LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); 166LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
163LUAI_FUNC void luaC_changemode (lua_State *L, int newmode); 167LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);
164 168
diff --git a/lstate.c b/lstate.c
index 653c90f2..3bce076d 100644
--- a/lstate.c
+++ b/lstate.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.c,v 2.137 2017/04/12 18:56:25 roberto Exp roberto $ 2** $Id: lstate.c,v 2.138 2017/04/24 16:59:26 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*/
@@ -324,7 +324,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
324 g->finobjsur = g->finobjold = g->finobjrold = NULL; 324 g->finobjsur = g->finobjold = g->finobjrold = NULL;
325 g->sweepgc = NULL; 325 g->sweepgc = NULL;
326 g->gray = g->grayagain = NULL; 326 g->gray = g->grayagain = NULL;
327 g->weak = g->ephemeron = g->allweak = NULL; 327 g->weak = g->ephemeron = g->allweak = g->protogray = NULL;
328 g->twups = NULL; 328 g->twups = NULL;
329 g->totalbytes = sizeof(LG); 329 g->totalbytes = sizeof(LG);
330 g->GCdebt = 0; 330 g->GCdebt = 0;
diff --git a/lstate.h b/lstate.h
index d2f23839..533d6ad6 100644
--- a/lstate.h
+++ b/lstate.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.h,v 2.138 2017/04/19 17:02:50 roberto Exp roberto $ 2** $Id: lstate.h,v 2.139 2017/04/24 16:59:26 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*/
@@ -43,7 +43,8 @@
43** 'weak': tables with weak values to be cleared; 43** 'weak': tables with weak values to be cleared;
44** 'ephemeron': ephemeron tables with white->white entries; 44** 'ephemeron': ephemeron tables with white->white entries;
45** 'allweak': tables with weak keys and/or weak values to be cleared. 45** 'allweak': tables with weak keys and/or weak values to be cleared.
46** The last three lists are used only during the atomic phase. 46** There is also a list 'protogray' for prototypes that need to have
47** their caches cleared.
47 48
48*/ 49*/
49 50
@@ -159,6 +160,7 @@ typedef struct global_State {
159 GCObject *weak; /* list of tables with weak values */ 160 GCObject *weak; /* list of tables with weak values */
160 GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ 161 GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
161 GCObject *allweak; /* list of all-weak tables */ 162 GCObject *allweak; /* list of all-weak tables */
163 GCObject *protogray; /* list of prototypes with "new" caches */
162 GCObject *tobefnz; /* list of userdata to be GC */ 164 GCObject *tobefnz; /* list of userdata to be GC */
163 GCObject *fixedgc; /* list of objects not to be collected */ 165 GCObject *fixedgc; /* list of objects not to be collected */
164 /* fields for generational collector */ 166 /* fields for generational collector */
diff --git a/ltests.c b/ltests.c
index 4ac2c702..93a84284 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ltests.c,v 2.215 2017/04/24 16:59:26 roberto Exp roberto $ 2** $Id: ltests.c,v 2.216 2017/04/24 18:06:12 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*/
@@ -409,6 +409,8 @@ static void checkobject (global_State *g, GCObject *o, int maybedead,
409 getage(o) == G_TOUCHED1 || 409 getage(o) == G_TOUCHED1 ||
410 getage(o) == G_OLD0 || 410 getage(o) == G_OLD0 ||
411 o->tt == LUA_TTHREAD || 411 o->tt == LUA_TTHREAD ||
412 (o->tt == LUA_TPROTO &&
413 (gco2p(o)->cache != NULL || gco2p(o)->cachemiss >= MAXMISS)) ||
412 (o->tt == LUA_TUPVAL && upisopen(gco2upv(o)))); 414 (o->tt == LUA_TUPVAL && upisopen(gco2upv(o))));
413 } 415 }
414 } 416 }
@@ -446,6 +448,7 @@ static void markgrays (global_State *g) {
446 checkgraylist(g, g->weak); 448 checkgraylist(g, g->weak);
447 checkgraylist(g, g->ephemeron); 449 checkgraylist(g, g->ephemeron);
448 checkgraylist(g, g->allweak); 450 checkgraylist(g, g->allweak);
451 checkgraylist(g, g->protogray);
449} 452}
450 453
451 454
diff --git a/lvm.c b/lvm.c
index 744ca6dd..28833458 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lvm.c,v 2.274 2017/04/28 20:57:45 roberto Exp roberto $ 2** $Id: lvm.c,v 2.275 2017/04/30 20:43:26 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*/
@@ -626,9 +626,7 @@ static LClosure *getcached (Proto *p, UpVal **encup, StkId base) {
626 626
627/* 627/*
628** create a new Lua closure, push it in the stack, and initialize 628** create a new Lua closure, push it in the stack, and initialize
629** its upvalues. Note that the closure is not cached if prototype is 629** its upvalues. ???
630** already black (which means that 'cache' was already cleared by the
631** GC).
632*/ 630*/
633static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, 631static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
634 StkId ra) { 632 StkId ra) {
@@ -645,11 +643,11 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
645 ncl->upvals[i] = encup[uv[i].idx]; 643 ncl->upvals[i] = encup[uv[i].idx];
646 /* new closure is white, so we do not need a barrier here */ 644 /* new closure is white, so we do not need a barrier here */
647 } 645 }
648 if (p->cachemiss >= 10) /* too many missings? */ 646 if (p->cachemiss >= MAXMISS) /* too many missings? */
649 p->cache = NULL; /* give up cache */ 647 p->cache = NULL; /* give up cache */
650 else { 648 else {
651 if (!isblack(p)) /* cache will not break GC invariant? */ 649 p->cache = ncl; /* save it on cache for reuse */
652 p->cache = ncl; /* save it on cache for reuse */ 650 luaC_protobarrier(L, p, ncl);
653 p->cachemiss++; 651 p->cachemiss++;
654 } 652 }
655} 653}