diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2004-02-16 16:09:52 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2004-02-16 16:09:52 -0300 |
commit | 2aaf7394ad17180565423ce360d5faffb60f4e4f (patch) | |
tree | 32caa2d7b0079b4bc9b0ac392d216c5094a6433d /lgc.c | |
parent | b3ce4505296253e6da1fa780c23e7ed012efc88e (diff) | |
download | lua-2aaf7394ad17180565423ce360d5faffb60f4e4f.tar.gz lua-2aaf7394ad17180565423ce360d5faffb60f4e4f.tar.bz2 lua-2aaf7394ad17180565423ce360d5faffb60f4e4f.zip |
more and better tools (assertions & inspectors) to check incremental GC
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 61 |
1 files changed, 39 insertions, 22 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.2 2003/12/12 18:29:34 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 | */ |
@@ -60,6 +60,7 @@ | |||
60 | 60 | ||
61 | 61 | ||
62 | 62 | ||
63 | |||
63 | /* | 64 | /* |
64 | ** computes the size of a collectible object | 65 | ** computes the size of a collectible object |
65 | */ | 66 | */ |
@@ -152,7 +153,7 @@ static void marktmu (global_State *g) { | |||
152 | 153 | ||
153 | 154 | ||
154 | /* move `dead' udata that need finalization to list `tmudata' */ | 155 | /* move `dead' udata that need finalization to list `tmudata' */ |
155 | size_t luaC_separateudata (lua_State *L) { | 156 | size_t luaC_separateudata (lua_State *L, int all) { |
156 | size_t deadmem = 0; | 157 | size_t deadmem = 0; |
157 | GCObject **p = &G(L)->firstudata; | 158 | GCObject **p = &G(L)->firstudata; |
158 | GCObject *curr; | 159 | GCObject *curr; |
@@ -160,7 +161,7 @@ size_t luaC_separateudata (lua_State *L) { | |||
160 | GCObject **lastcollected = &collected; | 161 | GCObject **lastcollected = &collected; |
161 | while ((curr = *p) != NULL) { | 162 | while ((curr = *p) != NULL) { |
162 | lua_assert(curr->gch.tt == LUA_TUSERDATA); | 163 | lua_assert(curr->gch.tt == LUA_TUSERDATA); |
163 | if (!iswhite(curr) || isfinalized(gco2u(curr))) | 164 | if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) |
164 | p = &curr->gch.next; /* don't bother with them */ | 165 | p = &curr->gch.next; /* don't bother with them */ |
165 | else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { | 166 | else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { |
166 | markfinalized(gco2u(curr)); /* don't need finalization */ | 167 | markfinalized(gco2u(curr)); /* don't need finalization */ |
@@ -182,7 +183,7 @@ size_t luaC_separateudata (lua_State *L) { | |||
182 | } | 183 | } |
183 | 184 | ||
184 | 185 | ||
185 | static void traversetable (global_State *g, Table *h) { | 186 | static int traversetable (global_State *g, Table *h) { |
186 | int i; | 187 | int i; |
187 | int weakkey = 0; | 188 | int weakkey = 0; |
188 | int weakvalue = 0; | 189 | int weakvalue = 0; |
@@ -202,7 +203,7 @@ static void traversetable (global_State *g, Table *h) { | |||
202 | g->weak = obj2gco(h); /* ... so put in the appropriate list */ | 203 | g->weak = obj2gco(h); /* ... so put in the appropriate list */ |
203 | } | 204 | } |
204 | } | 205 | } |
205 | if (weakkey && weakvalue) return; | 206 | if (weakkey && weakvalue) return 1; |
206 | if (!weakvalue) { | 207 | if (!weakvalue) { |
207 | i = h->sizearray; | 208 | i = h->sizearray; |
208 | while (i--) | 209 | while (i--) |
@@ -217,6 +218,7 @@ static void traversetable (global_State *g, Table *h) { | |||
217 | condmarkobject(g, gval(n), !weakvalue); | 218 | condmarkobject(g, gval(n), !weakvalue); |
218 | } | 219 | } |
219 | } | 220 | } |
221 | return weakkey || weakvalue; | ||
220 | } | 222 | } |
221 | 223 | ||
222 | 224 | ||
@@ -227,10 +229,8 @@ static void traversetable (global_State *g, Table *h) { | |||
227 | static void traverseproto (global_State *g, Proto *f) { | 229 | static void traverseproto (global_State *g, Proto *f) { |
228 | int i; | 230 | int i; |
229 | if (f->source) stringmark(f->source); | 231 | if (f->source) stringmark(f->source); |
230 | for (i=0; i<f->sizek; i++) { /* mark literal strings */ | 232 | for (i=0; i<f->sizek; i++) /* mark literals */ |
231 | if (ttisstring(f->k+i)) | 233 | markvalue(g, &f->k[i]); |
232 | stringmark(rawtsvalue(f->k+i)); | ||
233 | } | ||
234 | for (i=0; i<f->sizeupvalues; i++) { /* mark upvalue names */ | 234 | for (i=0; i<f->sizeupvalues; i++) { /* mark upvalue names */ |
235 | if (f->upvalues[i]) | 235 | if (f->upvalues[i]) |
236 | stringmark(f->upvalues[i]); | 236 | stringmark(f->upvalues[i]); |
@@ -258,9 +258,8 @@ static void traverseclosure (global_State *g, Closure *cl) { | |||
258 | lua_assert(cl->l.nupvalues == cl->l.p->nups); | 258 | lua_assert(cl->l.nupvalues == cl->l.p->nups); |
259 | markobject(g, hvalue(&cl->l.g)); | 259 | markobject(g, hvalue(&cl->l.g)); |
260 | markobject(g, cl->l.p); | 260 | markobject(g, cl->l.p); |
261 | for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */ | 261 | for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */ |
262 | markobject(g, cl->l.upvals[i]); | 262 | markobject(g, cl->l.upvals[i]); |
263 | } | ||
264 | } | 263 | } |
265 | } | 264 | } |
266 | 265 | ||
@@ -307,7 +306,8 @@ static l_mem propagatemarks (global_State *g, l_mem lim) { | |||
307 | case LUA_TTABLE: { | 306 | case LUA_TTABLE: { |
308 | Table *h = gco2h(o); | 307 | Table *h = gco2h(o); |
309 | g->gray = h->gclist; | 308 | g->gray = h->gclist; |
310 | traversetable(g, h); | 309 | if (traversetable(g, h)) /* table is weak? */ |
310 | black2gray(o); /* keep it gray */ | ||
311 | break; | 311 | break; |
312 | } | 312 | } |
313 | case LUA_TFUNCTION: { | 313 | case LUA_TFUNCTION: { |
@@ -339,7 +339,8 @@ static l_mem propagatemarks (global_State *g, l_mem lim) { | |||
339 | g->grayagain = o; | 339 | g->grayagain = o; |
340 | black2gray(o); | 340 | black2gray(o); |
341 | } | 341 | } |
342 | markvalue(g, &uv->value); | 342 | else |
343 | markvalue(g, &uv->value); | ||
343 | break; | 344 | break; |
344 | } | 345 | } |
345 | default: lua_assert(0); | 346 | default: lua_assert(0); |
@@ -428,6 +429,13 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
428 | } | 429 | } |
429 | 430 | ||
430 | 431 | ||
432 | static void sweepupvalues (global_State *g, lua_State *L1) { | ||
433 | GCObject *curr; | ||
434 | for (curr = L1->openupval; curr != NULL; curr = curr->gch.next) | ||
435 | makewhite(g, curr); | ||
436 | } | ||
437 | |||
438 | |||
431 | static GCObject **sweeplist (lua_State *L, GCObject **p, int all, | 439 | static GCObject **sweeplist (lua_State *L, GCObject **p, int all, |
432 | l_mem *plim) { | 440 | l_mem *plim) { |
433 | GCObject *curr; | 441 | GCObject *curr; |
@@ -439,10 +447,14 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int all, | |||
439 | lim -= objsize(curr); | 447 | lim -= objsize(curr); |
440 | if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) { | 448 | if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) { |
441 | makewhite(g, curr); | 449 | makewhite(g, curr); |
450 | if (curr->gch.tt == LUA_TTHREAD) | ||
451 | sweepupvalues(g, gco2th(curr)); | ||
442 | p = &curr->gch.next; | 452 | p = &curr->gch.next; |
443 | } | 453 | } |
444 | else { | 454 | else { |
445 | *p = curr->gch.next; | 455 | *p = curr->gch.next; |
456 | if (curr == g->rootgc) /* is the first element of the list? */ | ||
457 | g->rootgc = curr->gch.next; /* adjust first */ | ||
446 | freeobj(L, curr); | 458 | freeobj(L, curr); |
447 | } | 459 | } |
448 | if (lim <= 0) break; | 460 | if (lim <= 0) break; |
@@ -537,7 +549,8 @@ void luaC_sweepall (lua_State *L) { | |||
537 | /* mark root set */ | 549 | /* mark root set */ |
538 | static void markroot (lua_State *L) { | 550 | static void markroot (lua_State *L) { |
539 | global_State *g = G(L); | 551 | global_State *g = G(L); |
540 | lua_assert(g->gray == NULL && g->grayagain == NULL); | 552 | lua_assert(g->gray == NULL); |
553 | g->grayagain = NULL; | ||
541 | g->weak = NULL; | 554 | g->weak = NULL; |
542 | makewhite(g, obj2gco(g->mainthread)); | 555 | makewhite(g, obj2gco(g->mainthread)); |
543 | markobject(g, g->mainthread); | 556 | markobject(g, g->mainthread); |
@@ -550,28 +563,30 @@ static void markroot (lua_State *L) { | |||
550 | static void atomic (lua_State *L) { | 563 | static void atomic (lua_State *L) { |
551 | global_State *g = G(L); | 564 | global_State *g = G(L); |
552 | lua_assert(g->gray == NULL); | 565 | lua_assert(g->gray == NULL); |
566 | /* remark weak tables */ | ||
567 | g->gray = g->weak; | ||
568 | g->weak = NULL; | ||
569 | propagatemarks(g, MAXLMEM); | ||
570 | /* remark gray again */ | ||
553 | g->gray = g->grayagain; | 571 | g->gray = g->grayagain; |
554 | g->grayagain = NULL; | 572 | g->grayagain = NULL; |
555 | propagatemarks(g, MAXLMEM); | 573 | propagatemarks(g, MAXLMEM); |
556 | luaC_separateudata(L); /* separate userdata to be preserved */ | 574 | luaC_separateudata(L, 0); /* separate userdata to be preserved */ |
557 | marktmu(g); /* mark `preserved' userdata */ | 575 | marktmu(g); /* mark `preserved' userdata */ |
558 | propagatemarks(g, MAXLMEM); /* remark, to propagate `preserveness' */ | 576 | propagatemarks(g, MAXLMEM); /* remark, to propagate `preserveness' */ |
559 | cleartable(g->weak); /* remove collected objects from weak tables */ | 577 | cleartable(g->weak); /* remove collected objects from weak tables */ |
560 | /* flip current white */ | 578 | /* flip current white */ |
561 | g->currentwhite = otherwhite(g); | 579 | g->currentwhite = otherwhite(g); |
562 | /* first element of root list will be used as temporary head for sweep | 580 | g->sweepgc = &g->rootgc; |
563 | phase, so it won't be swept */ | ||
564 | makewhite(g, g->rootgc); | ||
565 | g->sweepgc = &g->rootgc->gch.next; | ||
566 | g->sweepstrgc = 0; | 581 | g->sweepstrgc = 0; |
567 | g->gcstate = GCSsweepstring; | 582 | g->gcstate = GCSsweepstring; |
568 | g->grayagain = NULL; | ||
569 | } | 583 | } |
570 | 584 | ||
571 | 585 | ||
572 | void luaC_step (lua_State *L) { | 586 | void luaC_step (lua_State *L) { |
573 | global_State *g = G(L); | 587 | global_State *g = G(L); |
574 | l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * 2; | 588 | l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * 2; |
589 | luaC_checkall(L); | ||
575 | switch (g->gcstate) { | 590 | switch (g->gcstate) { |
576 | case GCSpropagate: { | 591 | case GCSpropagate: { |
577 | if (g->gray) | 592 | if (g->gray) |
@@ -593,8 +608,9 @@ void luaC_step (lua_State *L) { | |||
593 | case GCSsweep: { | 608 | case GCSsweep: { |
594 | g->sweepgc = sweeplist(L, g->sweepgc, 0, &lim); | 609 | g->sweepgc = sweeplist(L, g->sweepgc, 0, &lim); |
595 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ | 610 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ |
596 | g->gcstate = GCSfinalize; /* end sweep phase */ | ||
597 | checkSizes(L); | 611 | checkSizes(L); |
612 | sweepupvalues(g, g->mainthread); | ||
613 | g->gcstate = GCSfinalize; /* end sweep phase */ | ||
598 | } | 614 | } |
599 | break; | 615 | break; |
600 | } | 616 | } |
@@ -610,13 +626,14 @@ void luaC_step (lua_State *L) { | |||
610 | default: lua_assert(0); | 626 | default: lua_assert(0); |
611 | } | 627 | } |
612 | g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/2; | 628 | g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/2; |
629 | luaC_checkall(L); | ||
613 | } | 630 | } |
614 | 631 | ||
615 | 632 | ||
616 | void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { | 633 | void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { |
617 | global_State *g = G(L); | 634 | global_State *g = G(L); |
618 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); | 635 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); |
619 | if (g->gcstate >= GCSsweepstring) /* sweeping phases? */ | 636 | if (g->gcstate != GCSpropagate) /* sweeping phases? */ |
620 | black2gray(o); /* just mark as gray to avoid other barriers */ | 637 | black2gray(o); /* just mark as gray to avoid other barriers */ |
621 | else /* breaking invariant! */ | 638 | else /* breaking invariant! */ |
622 | reallymarkobject(g, v); /* restore it */ | 639 | reallymarkobject(g, v); /* restore it */ |