diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-05-04 10:32:01 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-05-04 10:32:01 -0300 |
commit | 2376eb634751f92e6bcb9dc8dbc1ef88b9873319 (patch) | |
tree | 579780bc7ff3d1374a701298749eca3634a17edb /lgc.c | |
parent | 8634b2a0119e698e362fdb765f30258e79e1dfd0 (diff) | |
download | lua-2376eb634751f92e6bcb9dc8dbc1ef88b9873319.tar.gz lua-2376eb634751f92e6bcb9dc8dbc1ef88b9873319.tar.bz2 lua-2376eb634751f92e6bcb9dc8dbc1ef88b9873319.zip |
barrier for prototype's cache (with new gray list 'protogray' to keep
prototypes to have their caches visited again) + constant 'MAXMISS'
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 75 |
1 files changed, 67 insertions, 8 deletions
@@ -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 | */ | ||
191 | LUAI_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 | |||
182 | void luaC_fix (lua_State *L, GCObject *o) { | 202 | void 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 | */ |
333 | static void restartcollection (global_State *g) { | 353 | static 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 | */ | ||
512 | static 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 | */ |
484 | static int traverseproto (global_State *g, Proto *f) { | 530 | static 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 | ||
676 | static 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 | */ |
1080 | static void markold (global_State *g, GCObject *from, GCObject *to) { | 1137 | static 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 */ |