summaryrefslogtreecommitdiff
path: root/lgc.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2008-02-19 15:55:09 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2008-02-19 15:55:09 -0300
commite2b366c7601aeecda04f3b7ac5a2bd6eb80521bb (patch)
tree580c94105007087a5029fcb02a0e3cb3be306b54 /lgc.c
parentfa19baab7ffd96cecb1defe4ad81084c612d2704 (diff)
downloadlua-e2b366c7601aeecda04f3b7ac5a2bd6eb80521bb.tar.gz
lua-e2b366c7601aeecda04f3b7ac5a2bd6eb80521bb.tar.bz2
lua-e2b366c7601aeecda04f3b7ac5a2bd6eb80521bb.zip
userdata with finalizers are kept in a separated list
Diffstat (limited to 'lgc.c')
-rw-r--r--lgc.c237
1 files changed, 135 insertions, 102 deletions
diff --git a/lgc.c b/lgc.c
index 770a38fd..dbac2f1a 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 2.42 2007/10/31 15:41:19 roberto Exp roberto $ 2** $Id: lgc.c,v 2.43 2008/02/11 15:46:03 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*/
@@ -29,24 +29,22 @@
29#define GCFINALIZECOST 100 29#define GCFINALIZECOST 100
30 30
31 31
32#define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) 32#define maskcolors cast_byte(~(bitmask(BLACKBIT)|WHITEBITS))
33 33
34#define makewhite(g,x) \ 34#define makewhite(g,x) \
35 ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g))) 35 (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g)))
36 36
37#define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) 37#define white2gray(x) resetbits(gch(x)->marked, WHITEBITS)
38#define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) 38#define black2gray(x) resetbit(gch(x)->marked, BLACKBIT)
39 39
40#define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) 40#define stringmark(s) resetbits((s)->tsv.marked, WHITEBITS)
41 41
42 42
43#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) 43#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT)
44#define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT)
45
46 44
47 45
48#define markvalue(g,o) { checkconsistency(o); \ 46#define markvalue(g,o) { checkconsistency(o); \
49 if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } 47 if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
50 48
51#define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \ 49#define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \
52 reallymarkobject(g, obj2gco(t)); } 50 reallymarkobject(g, obj2gco(t)); }
@@ -89,7 +87,7 @@ static int iscleared (const TValue *o, int iskey) {
89static void reallymarkobject (global_State *g, GCObject *o) { 87static void reallymarkobject (global_State *g, GCObject *o) {
90 lua_assert(iswhite(o) && !isdead(g, o)); 88 lua_assert(iswhite(o) && !isdead(g, o));
91 white2gray(o); 89 white2gray(o);
92 switch (o->gch.tt) { 90 switch (gch(o)->tt) {
93 case LUA_TSTRING: { 91 case LUA_TSTRING: {
94 return; 92 return;
95 } 93 }
@@ -113,7 +111,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
113 break; 111 break;
114 } 112 }
115 case LUA_TTABLE: { 113 case LUA_TTABLE: {
116 linktable(gco2h(o), &g->gray); 114 linktable(gco2t(o), &g->gray);
117 break; 115 break;
118 } 116 }
119 case LUA_TTHREAD: { 117 case LUA_TTHREAD: {
@@ -131,42 +129,30 @@ static void reallymarkobject (global_State *g, GCObject *o) {
131} 129}
132 130
133 131
134static void marktmu (global_State *g) { 132/* move 'dead' udata that need finalization to list 'tobefnz' */
135 GCObject *u = g->tmudata;
136 if (u) {
137 do {
138 u = u->gch.next;
139 makewhite(g, u); /* may be marked, if left from previous GC */
140 reallymarkobject(g, u);
141 } while (u != g->tmudata);
142 }
143}
144
145
146/* move `dead' udata that need finalization to list `tmudata' */
147size_t luaC_separateudata (lua_State *L, int all) { 133size_t luaC_separateudata (lua_State *L, int all) {
148 global_State *g = G(L); 134 global_State *g = G(L);
149 size_t deadmem = 0; 135 size_t deadmem = 0;
150 GCObject **p = &g->mainthread->next; 136 GCObject **p = &g->tmudata;
151 GCObject *curr; 137 GCObject *curr;
152 while ((curr = *p) != NULL) { 138 while ((curr = *p) != NULL) {
153 if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) 139 lua_assert(ttisuserdata(gch(curr)) && !isfinalized(gco2u(curr)));
154 p = &curr->gch.next; /* don't bother with them */ 140 lua_assert(testbit(gch(curr)->marked, SEPARATED));
155 else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { 141 if (all) makewhite(g, curr); /* if 'all', collect all objects */
156 markfinalized(gco2u(curr)); /* don't need finalization */ 142 if (!iswhite(curr)) /* not being collected? */
157 p = &curr->gch.next; 143 p = &gch(curr)->next; /* don't bother with it */
158 } 144 else {
159 else { /* must call its gc method */ 145 l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */
146 reallymarkobject(g, curr); /* won't be collected now */
160 deadmem += sizeudata(gco2u(curr)); 147 deadmem += sizeudata(gco2u(curr));
161 markfinalized(gco2u(curr)); 148 *p = gch(curr)->next; /* remove 'curr' from 'tmudata' list */
162 *p = curr->gch.next; 149 /* link 'curr' at the end of 'tobefnz' list */
163 /* link `curr' at the end of `tmudata' list */ 150 if (g->tobefnz == NULL) /* list is empty? */
164 if (g->tmudata == NULL) /* list is empty? */ 151 g->tobefnz = gch(curr)->next = curr; /* creates a circular list */
165 g->tmudata = curr->gch.next = curr; /* creates a circular list */
166 else { 152 else {
167 curr->gch.next = g->tmudata->gch.next; 153 gch(curr)->next = gch(g->tobefnz)->next;
168 g->tmudata->gch.next = curr; 154 gch(g->tobefnz)->next = curr;
169 g->tmudata = curr; 155 g->tobefnz = curr;
170 } 156 }
171 } 157 }
172 } 158 }
@@ -195,7 +181,7 @@ static int traverseephemeron (global_State *g, Table *h) {
195 int hasclears = 0; 181 int hasclears = 0;
196 int i = h->sizearray; 182 int i = h->sizearray;
197 while (i--) { /* mark array part (numeric keys are 'strong') */ 183 while (i--) { /* mark array part (numeric keys are 'strong') */
198 if (iscollectable(&h->array[i]) && iswhite(gcvalue(&h->array[i]))) { 184 if (valiswhite(&h->array[i])) {
199 marked = 1; 185 marked = 1;
200 reallymarkobject(g, gcvalue(&h->array[i])); 186 reallymarkobject(g, gcvalue(&h->array[i]));
201 } 187 }
@@ -206,7 +192,7 @@ static int traverseephemeron (global_State *g, Table *h) {
206 lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); 192 lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n)));
207 if (ttisnil(gval(n))) /* entry is empty? */ 193 if (ttisnil(gval(n))) /* entry is empty? */
208 removeentry(n); /* remove it */ 194 removeentry(n); /* remove it */
209 else if (iscollectable(gval(n)) && iswhite(gcvalue(gval(n)))) { 195 else if (valiswhite(gval(n))) {
210 /* value is not marked yet */ 196 /* value is not marked yet */
211 if (iscleared(key2tval(n), 1)) /* key is not marked (yet)? */ 197 if (iscleared(key2tval(n), 1)) /* key is not marked (yet)? */
212 hasclears = 1; /* may have to propagate mark from key to value */ 198 hasclears = 1; /* may have to propagate mark from key to value */
@@ -256,10 +242,8 @@ static void traversetable (global_State *g, Table *h) {
256 traverseweakvalue(g, h); 242 traverseweakvalue(g, h);
257 else if (!weakvalue) /* strong values? */ 243 else if (!weakvalue) /* strong values? */
258 traverseephemeron(g, h); 244 traverseephemeron(g, h);
259 else { 245 else
260 lua_assert(weakkey && weakvalue); /* nothing to traverse now */ 246 linktable(h, &g->allweak); /* nothing to traverse now */
261 linktable(h, &g->allweak);
262 }
263 return; 247 return;
264 } /* else go through */ 248 } /* else go through */
265 } 249 }
@@ -350,9 +334,9 @@ static l_mem propagatemark (global_State *g) {
350 GCObject *o = g->gray; 334 GCObject *o = g->gray;
351 lua_assert(isgray(o)); 335 lua_assert(isgray(o));
352 gray2black(o); 336 gray2black(o);
353 switch (o->gch.tt) { 337 switch (gch(o)->tt) {
354 case LUA_TTABLE: { 338 case LUA_TTABLE: {
355 Table *h = gco2h(o); 339 Table *h = gco2t(o);
356 g->gray = h->gclist; 340 g->gray = h->gclist;
357 traversetable(g, h); 341 traversetable(g, h);
358 return sizeof(Table) + sizeof(TValue) * h->sizearray + 342 return sizeof(Table) + sizeof(TValue) * h->sizearray +
@@ -406,8 +390,8 @@ static void convergeephemerons (global_State *g) {
406 g->ephemeron = NULL; 390 g->ephemeron = NULL;
407 changed = 0; 391 changed = 0;
408 while ((w = next) != NULL) { 392 while ((w = next) != NULL) {
409 next = gco2h(w)->gclist; 393 next = gco2t(w)->gclist;
410 if (traverseephemeron(g, gco2h(w))) { 394 if (traverseephemeron(g, gco2t(w))) {
411 changed = 1; 395 changed = 1;
412 propagateall(g); 396 propagateall(g);
413 } 397 }
@@ -422,7 +406,7 @@ static void convergeephemerons (global_State *g) {
422*/ 406*/
423static void cleartable (GCObject *l) { 407static void cleartable (GCObject *l) {
424 while (l) { 408 while (l) {
425 Table *h = gco2h(l); 409 Table *h = gco2t(l);
426 int i = h->sizearray; 410 int i = h->sizearray;
427 while (i--) { 411 while (i--) {
428 TValue *o = &h->array[i]; 412 TValue *o = &h->array[i];
@@ -444,25 +428,18 @@ static void cleartable (GCObject *l) {
444 428
445 429
446static void freeobj (lua_State *L, GCObject *o) { 430static void freeobj (lua_State *L, GCObject *o) {
447 switch (o->gch.tt) { 431 switch (gch(o)->tt) {
448 case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; 432 case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
449 case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; 433 case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break;
450 case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; 434 case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
451 case LUA_TTABLE: luaH_free(L, gco2h(o)); break; 435 case LUA_TTABLE: luaH_free(L, gco2t(o)); break;
452 case LUA_TTHREAD: { 436 case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break;
453 lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); 437 case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;
454 luaE_freethread(L, gco2th(o));
455 break;
456 }
457 case LUA_TSTRING: { 438 case LUA_TSTRING: {
458 G(L)->strt.nuse--; 439 G(L)->strt.nuse--;
459 luaM_freemem(L, o, sizestring(gco2ts(o))); 440 luaM_freemem(L, o, sizestring(gco2ts(o)));
460 break; 441 break;
461 } 442 }
462 case LUA_TUSERDATA: {
463 luaM_freemem(L, o, sizeudata(gco2u(o)));
464 break;
465 }
466 default: lua_assert(0); 443 default: lua_assert(0);
467 } 444 }
468} 445}
@@ -477,18 +454,16 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
477 global_State *g = G(L); 454 global_State *g = G(L);
478 int deadmask = otherwhite(g); 455 int deadmask = otherwhite(g);
479 while ((curr = *p) != NULL && count-- > 0) { 456 while ((curr = *p) != NULL && count-- > 0) {
480 if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ 457 if (ttisthread(gch(curr))) /* sweep open upvalues of each thread */
481 sweepwholelist(L, &gco2th(curr)->openupval); 458 sweepwholelist(L, &gco2th(curr)->openupval);
482 if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */ 459 if ((gch(curr)->marked ^ WHITEBITS) & deadmask) { /* not dead? */
483 lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); 460 lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT));
484 makewhite(g, curr); /* make it white (for next cycle) */ 461 makewhite(g, curr); /* make it white (for next cycle) */
485 p = &curr->gch.next; 462 p = &gch(curr)->next;
486 } 463 }
487 else { /* must erase `curr' */ 464 else { /* must erase `curr' */
488 lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); 465 lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
489 *p = curr->gch.next; 466 *p = gch(curr)->next; /* remove 'curr' from list */
490 if (curr == g->rootgc) /* is the first element of the list? */
491 g->rootgc = curr->gch.next; /* adjust first */
492 freeobj(L, curr); 467 freeobj(L, curr);
493 } 468 }
494 } 469 }
@@ -496,6 +471,15 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
496} 471}
497 472
498 473
474static GCObject **unmarklist (global_State *g, GCObject **p, lu_mem count) {
475 for (; *p != NULL && count-- > 0; p = &gch(*p)->next) {
476 lua_assert(ttisuserdata(gch(*p)) && !isdead(g, *p));
477 makewhite(g, *p);
478 }
479 return p;
480}
481
482
499static void checkSizes (lua_State *L) { 483static void checkSizes (lua_State *L) {
500 global_State *g = G(L); 484 global_State *g = G(L);
501 if (g->strt.nuse < cast(lu_int32, g->strt.size)) 485 if (g->strt.nuse < cast(lu_int32, g->strt.size))
@@ -505,15 +489,16 @@ static void checkSizes (lua_State *L) {
505 489
506 490
507static Udata *udata2finalize (global_State *g) { 491static Udata *udata2finalize (global_State *g) {
508 GCObject *o = g->tmudata->gch.next; /* get first element */ 492 GCObject *o = gch(g->tobefnz)->next; /* get first element */
509 Udata *udata = rawgco2u(o); 493 Udata *udata = rawgco2u(o);
510 /* remove udata from `tmudata' */ 494 /* remove udata from `tobefnz' */
511 if (o == g->tmudata) /* last element? */ 495 if (o == g->tobefnz) /* last element? */
512 g->tmudata = NULL; 496 g->tobefnz = NULL;
513 else 497 else
514 g->tmudata->gch.next = udata->uv.next; 498 gch(g->tobefnz)->next = udata->uv.next;
515 udata->uv.next = g->mainthread->next; /* return it to `root' list */ 499 udata->uv.next = g->mainthread->next; /* return it to `root' list */
516 g->mainthread->next = o; 500 g->mainthread->next = o;
501 resetbit(udata->uv.marked, SEPARATED); /* mark it as such */
517 makewhite(g, o); 502 makewhite(g, o);
518 return udata; 503 return udata;
519} 504}
@@ -522,8 +507,8 @@ static Udata *udata2finalize (global_State *g) {
522static void GCTM (lua_State *L) { 507static void GCTM (lua_State *L) {
523 global_State *g = G(L); 508 global_State *g = G(L);
524 Udata *udata = udata2finalize(g); 509 Udata *udata = udata2finalize(g);
525 const TValue *tm = fasttm(L, udata->uv.metatable, TM_GC); 510 const TValue *tm = gfasttm(g, udata->uv.metatable, TM_GC);
526 if (tm != NULL) { 511 if (tm != NULL && ttisfunction(tm)) {
527 lu_byte oldah = L->allowhook; 512 lu_byte oldah = L->allowhook;
528 lu_mem oldt = g->GCthreshold; 513 lu_mem oldt = g->GCthreshold;
529 L->allowhook = 0; /* stop debug hooks during GC tag method */ 514 L->allowhook = 0; /* stop debug hooks during GC tag method */
@@ -543,15 +528,15 @@ static void GCTM (lua_State *L) {
543*/ 528*/
544void luaC_callGCTM (lua_State *L) { 529void luaC_callGCTM (lua_State *L) {
545 global_State *g = G(L); 530 global_State *g = G(L);
546 GCObject *last = g->tmudata; 531 GCObject *last = g->tobefnz;
547 GCObject *curr; 532 GCObject *curr;
548 if (last == NULL) return; /* empty list? */ 533 if (last == NULL) return; /* empty list? */
549 do { 534 do {
550 curr = g->tmudata->gch.next; /* element to be collected */ 535 curr = gch(g->tobefnz)->next; /* element to be collected */
551 GCTM(L); 536 GCTM(L);
552 } while (curr != last); /* go only until original last */ 537 } while (curr != last); /* go only until original last */
553 /* do not finalize new udata created during previous finalizations */ 538 /* do not finalize new udata created during previous finalizations */
554 while (g->tmudata) 539 while (g->tobefnz)
555 udata2finalize(g); /* simply remove them from list */ 540 udata2finalize(g); /* simply remove them from list */
556} 541}
557 542
@@ -559,10 +544,16 @@ void luaC_callGCTM (lua_State *L) {
559void luaC_freeall (lua_State *L) { 544void luaC_freeall (lua_State *L) {
560 global_State *g = G(L); 545 global_State *g = G(L);
561 int i; 546 int i;
562 g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); /* mask to collect all elements */ 547 lua_assert(g->tobefnz == NULL);
548 /* mask to collect all elements */
549 g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT);
563 sweepwholelist(L, &g->rootgc); 550 sweepwholelist(L, &g->rootgc);
551 lua_assert(g->rootgc == obj2gco(L));
552 sweepwholelist(L, &g->tmudata);
553 lua_assert(g->tmudata == NULL);
564 for (i = 0; i < g->strt.size; i++) /* free all string lists */ 554 for (i = 0; i < g->strt.size; i++) /* free all string lists */
565 sweepwholelist(L, &g->strt.hash[i]); 555 sweepwholelist(L, &g->strt.hash[i]);
556 lua_assert(g->strt.nuse == 0);
566} 557}
567 558
568 559
@@ -573,6 +564,20 @@ static void markmt (global_State *g) {
573} 564}
574 565
575 566
567static void markbeingfnz (global_State *g) {
568 GCObject *u = g->tobefnz;
569 if (u) {
570 do {
571 u = gch(u)->next;
572 lua_assert(testbit(gch(u)->marked, SEPARATED));
573 lua_assert(!iswhite(u)); /* must be marked, if left from previous GC */
574 makewhite(g, u);
575 reallymarkobject(g, u);
576 } while (u != g->tobefnz);
577 }
578}
579
580
576/* mark root set */ 581/* mark root set */
577static void markroot (lua_State *L) { 582static void markroot (lua_State *L) {
578 global_State *g = G(L); 583 global_State *g = G(L);
@@ -584,6 +589,7 @@ static void markroot (lua_State *L) {
584 markvalue(g, gt(g->mainthread)); 589 markvalue(g, gt(g->mainthread));
585 markvalue(g, registry(L)); 590 markvalue(g, registry(L));
586 markmt(g); 591 markmt(g);
592 markbeingfnz(g); /* mark any finalizing userdata left from previous cycle */
587 g->gcstate = GCSpropagate; 593 g->gcstate = GCSpropagate;
588} 594}
589 595
@@ -598,6 +604,14 @@ static void remarkupvals (global_State *g) {
598} 604}
599 605
600 606
607static void marklistofgrays (global_State *g, GCObject **l) {
608 lua_assert(g->gray == NULL); /* no grays left */
609 g->gray = *l; /* now 'l' is new gray list */
610 *l = NULL;
611 propagateall(g);
612}
613
614
601static void atomic (lua_State *L) { 615static void atomic (lua_State *L) {
602 global_State *g = G(L); 616 global_State *g = G(L);
603 size_t udsize; /* total size of userdata to be finalized */ 617 size_t udsize; /* total size of userdata to be finalized */
@@ -612,17 +626,10 @@ static void atomic (lua_State *L) {
612 markobject(g, L); /* mark running thread */ 626 markobject(g, L); /* mark running thread */
613 markmt(g); /* mark basic metatables (again) */ 627 markmt(g); /* mark basic metatables (again) */
614 propagateall(g); 628 propagateall(g);
615 /* remark ephemeron tables */ 629 marklistofgrays(g, &g->ephemeron); /* remark ephemeron tables */
616 g->gray = g->ephemeron; 630 marklistofgrays(g, &g->grayagain); /* remark gray again */
617 g->ephemeron = NULL;
618 propagateall(g);
619 /* remark gray again */
620 g->gray = g->grayagain;
621 g->grayagain = NULL;
622 propagateall(g);
623 convergeephemerons(g); 631 convergeephemerons(g);
624 udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ 632 udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */
625 marktmu(g); /* mark `preserved' userdata */
626 udsize += propagateall(g); /* remark, to propagate `preserveness' */ 633 udsize += propagateall(g); /* remark, to propagate `preserveness' */
627 convergeephemerons(g); 634 convergeephemerons(g);
628 /* remove collected objects from weak tables */ 635 /* remove collected objects from weak tables */
@@ -632,7 +639,6 @@ static void atomic (lua_State *L) {
632 /* flip current white */ 639 /* flip current white */
633 g->currentwhite = cast_byte(otherwhite(g)); 640 g->currentwhite = cast_byte(otherwhite(g));
634 g->sweepstrgc = 0; 641 g->sweepstrgc = 0;
635 g->sweepgc = &g->rootgc;
636 g->gcstate = GCSsweepstring; 642 g->gcstate = GCSsweepstring;
637 g->estimate = g->totalbytes - udsize; /* first estimate */ 643 g->estimate = g->totalbytes - udsize; /* first estimate */
638} 644}
@@ -660,10 +666,20 @@ static l_mem singlestep (lua_State *L) {
660 } 666 }
661 case GCSsweepstring: { 667 case GCSsweepstring: {
662 correctestimate(g, sweepwholelist(L, &g->strt.hash[g->sweepstrgc++])); 668 correctestimate(g, sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]));
663 if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ 669 if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */
664 g->gcstate = GCSsweep; /* end sweep-string phase */ 670 g->sweepgc = &g->tmudata;
671 g->gcstate = GCSsweeptmu; /* end sweep-string phase */
672 }
665 return GCSWEEPCOST; 673 return GCSWEEPCOST;
666 } 674 }
675 case GCSsweeptmu: {
676 g->sweepgc = unmarklist(g, g->sweepgc, GCSWEEPMAX);
677 if (*g->sweepgc == NULL) { /* nothing more to sweep? */
678 g->sweepgc = &g->rootgc;
679 g->gcstate = GCSsweep; /* sweep all other objects */
680 }
681 return GCSWEEPMAX*GCSWEEPCOST;
682 }
667 case GCSsweep: { 683 case GCSsweep: {
668 correctestimate(g, g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX)); 684 correctestimate(g, g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX));
669 if (*g->sweepgc == NULL) /* nothing more to sweep? */ 685 if (*g->sweepgc == NULL) /* nothing more to sweep? */
@@ -671,7 +687,7 @@ static l_mem singlestep (lua_State *L) {
671 return GCSWEEPMAX*GCSWEEPCOST; 687 return GCSWEEPMAX*GCSWEEPCOST;
672 } 688 }
673 case GCSfinalize: { 689 case GCSfinalize: {
674 if (g->tmudata) { 690 if (g->tobefnz) {
675 GCTM(L); 691 GCTM(L);
676 if (g->estimate > GCFINALIZECOST) 692 if (g->estimate > GCFINALIZECOST)
677 g->estimate -= GCFINALIZECOST; 693 g->estimate -= GCFINALIZECOST;
@@ -721,19 +737,17 @@ void luaC_fullgc (lua_State *L, int isemergency) {
721 lua_assert(g->gckind == KGC_NORMAL); 737 lua_assert(g->gckind == KGC_NORMAL);
722 g->gckind = isemergency ? KGC_EMERGENCY : KGC_FORCED; 738 g->gckind = isemergency ? KGC_EMERGENCY : KGC_FORCED;
723 if (g->gcstate <= GCSpropagate) { 739 if (g->gcstate <= GCSpropagate) {
724 /* reset sweep marks to sweep all elements (returning them to white) */
725 g->sweepstrgc = 0;
726 g->sweepgc = &g->rootgc;
727 /* reset other collector lists */ 740 /* reset other collector lists */
728 g->gray = NULL; 741 g->gray = NULL;
729 g->grayagain = NULL; 742 g->grayagain = NULL;
730 g->weak = g->ephemeron = g->allweak = NULL; 743 g->weak = g->ephemeron = g->allweak = NULL;
744 g->sweepstrgc = 0;
731 g->gcstate = GCSsweepstring; 745 g->gcstate = GCSsweepstring;
732 } 746 }
733 lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); 747 lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate);
734 /* finish any pending sweep phase */ 748 /* finish any pending sweep phase */
735 while (g->gcstate != GCSfinalize) { 749 while (g->gcstate != GCSfinalize) {
736 lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); 750 lua_assert(issweep(g));
737 singlestep(L); 751 singlestep(L);
738 } 752 }
739 markroot(L); 753 markroot(L);
@@ -753,7 +767,7 @@ void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
753 global_State *g = G(L); 767 global_State *g = G(L);
754 lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); 768 lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
755 lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); 769 lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
756 lua_assert(ttype(&o->gch) != LUA_TTABLE); 770 lua_assert(ttype(gch(o)) != LUA_TTABLE);
757 /* must keep invariant? */ 771 /* must keep invariant? */
758 if (g->gcstate == GCSpropagate) 772 if (g->gcstate == GCSpropagate)
759 reallymarkobject(g, v); /* restore invariant */ 773 reallymarkobject(g, v); /* restore invariant */
@@ -775,17 +789,17 @@ void luaC_barrierback (lua_State *L, Table *t) {
775 789
776void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { 790void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
777 global_State *g = G(L); 791 global_State *g = G(L);
778 o->gch.next = g->rootgc; 792 gch(o)->marked = luaC_white(g);
793 gch(o)->tt = tt;
794 gch(o)->next = g->rootgc;
779 g->rootgc = o; 795 g->rootgc = o;
780 o->gch.marked = luaC_white(g);
781 o->gch.tt = tt;
782} 796}
783 797
784 798
785void luaC_linkupval (lua_State *L, UpVal *uv) { 799void luaC_linkupval (lua_State *L, UpVal *uv) {
786 global_State *g = G(L); 800 global_State *g = G(L);
787 GCObject *o = obj2gco(uv); 801 GCObject *o = obj2gco(uv);
788 o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ 802 gch(o)->next = g->rootgc; /* link upvalue into `rootgc' list */
789 g->rootgc = o; 803 g->rootgc = o;
790 if (isgray(o)) { 804 if (isgray(o)) {
791 if (g->gcstate == GCSpropagate) { 805 if (g->gcstate == GCSpropagate) {
@@ -799,3 +813,22 @@ void luaC_linkupval (lua_State *L, UpVal *uv) {
799 } 813 }
800} 814}
801 815
816
817void luaC_checkfinalizer (lua_State *L, Udata *u) {
818 global_State *g = G(L);
819 if (testbit(u->uv.marked, SEPARATED) || /* userdata is already separated... */
820 isfinalized(&u->uv) || /* ... or is finalized... */
821 gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */
822 return; /* nothing to be done */
823 else { /* move 'u' from root list to tobefnz list */
824 GCObject **p;
825 for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next)
826 lua_assert(*p != NULL); /* 'u' must be in this list */
827 *p = u->uv.next; /* remove 'u' from root list */
828 u->uv.next = g->tmudata; /* link it in tobefnz list */
829 g->tmudata = obj2gco(u);
830 l_setbit(u->uv.marked, SEPARATED); /* mark it as such */
831 }
832}
833
834