aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lapi.c8
-rw-r--r--lgc.c237
-rw-r--r--lgc.h17
-rw-r--r--lstate.c11
-rw-r--r--lstate.h15
-rw-r--r--lstring.c14
-rw-r--r--ltests.c32
7 files changed, 187 insertions, 147 deletions
diff --git a/lapi.c b/lapi.c
index 86c75d51..f76c6e61 100644
--- a/lapi.c
+++ b/lapi.c
@@ -1,12 +1,10 @@
1/* 1/*
2** $Id: lapi.c,v 2.64 2008/02/12 13:34:12 roberto Exp roberto $ 2** $Id: lapi.c,v 2.65 2008/02/14 16:02:58 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*/
6 6
7 7
8#include <assert.h>
9#include <math.h>
10#include <stdarg.h> 8#include <stdarg.h>
11#include <string.h> 9#include <string.h>
12 10
@@ -698,8 +696,10 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
698 } 696 }
699 case LUA_TUSERDATA: { 697 case LUA_TUSERDATA: {
700 uvalue(obj)->metatable = mt; 698 uvalue(obj)->metatable = mt;
701 if (mt) 699 if (mt) {
702 luaC_objbarrier(L, rawuvalue(obj), mt); 700 luaC_objbarrier(L, rawuvalue(obj), mt);
701 luaC_checkfinalizer(L, rawuvalue(obj));
702 }
703 break; 703 break;
704 } 704 }
705 default: { 705 default: {
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
diff --git a/lgc.h b/lgc.h
index 0b7be15e..6697ec26 100644
--- a/lgc.h
+++ b/lgc.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.h,v 2.16 2006/07/11 15:53:29 roberto Exp roberto $ 2** $Id: lgc.h,v 2.17 2007/10/29 16:51:20 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*/
@@ -17,8 +17,13 @@
17#define GCSpause 0 17#define GCSpause 0
18#define GCSpropagate 1 18#define GCSpropagate 1
19#define GCSsweepstring 2 19#define GCSsweepstring 2
20#define GCSsweep 3 20#define GCSsweeptmu 3
21#define GCSfinalize 4 21#define GCSsweep 4
22#define GCSfinalize 5
23
24
25#define issweep(g) \
26 (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep)
22 27
23 28
24/* 29/*
@@ -34,7 +39,6 @@
34#define testbit(x,b) testbits(x, bitmask(b)) 39#define testbit(x,b) testbits(x, bitmask(b))
35#define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2))) 40#define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2)))
36#define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2))) 41#define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2)))
37#define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2)))
38 42
39 43
40 44
@@ -44,6 +48,7 @@
44** bit 1 - object is white (type 1) 48** bit 1 - object is white (type 1)
45** bit 2 - object is black 49** bit 2 - object is black
46** bit 3 - for userdata: has been finalized 50** bit 3 - for userdata: has been finalized
51** bit 4 - for userdata: it's not in rootgc list (it's in tmudata or tobefnz)
47** bit 5 - object is fixed (should not be collected) 52** bit 5 - object is fixed (should not be collected)
48** bit 6 - object is "super" fixed (only the main thread) 53** bit 6 - object is "super" fixed (only the main thread)
49*/ 54*/
@@ -53,12 +58,13 @@
53#define WHITE1BIT 1 58#define WHITE1BIT 1
54#define BLACKBIT 2 59#define BLACKBIT 2
55#define FINALIZEDBIT 3 60#define FINALIZEDBIT 3
61#define SEPARATED 4
56#define FIXEDBIT 5 62#define FIXEDBIT 5
57#define SFIXEDBIT 6 63#define SFIXEDBIT 6
58#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) 64#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
59 65
60 66
61#define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) 67#define iswhite(x) testbits((x)->gch.marked, WHITEBITS)
62#define isblack(x) testbit((x)->gch.marked, BLACKBIT) 68#define isblack(x) testbit((x)->gch.marked, BLACKBIT)
63#define isgray(x) (!isblack(x) && !iswhite(x)) 69#define isgray(x) (!isblack(x) && !iswhite(x))
64 70
@@ -101,6 +107,7 @@ LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt);
101LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); 107LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv);
102LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); 108LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v);
103LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); 109LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t);
110LUAI_FUNC void luaC_checkfinalizer (lua_State *L, Udata *u);
104 111
105 112
106#endif 113#endif
diff --git a/lstate.c b/lstate.c
index 09bf4ba7..a7e1e540 100644
--- a/lstate.c
+++ b/lstate.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.c,v 2.42 2007/10/31 15:41:19 roberto Exp roberto $ 2** $Id: lstate.c,v 2.43 2008/02/11 15:45:30 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*/
@@ -107,8 +107,6 @@ static void close_state (lua_State *L) {
107 global_State *g = G(L); 107 global_State *g = G(L);
108 luaF_close(L, L->stack); /* close all upvalues for this thread */ 108 luaF_close(L, L->stack); /* close all upvalues for this thread */
109 luaC_freeall(L); /* collect all objects */ 109 luaC_freeall(L); /* collect all objects */
110 lua_assert(g->rootgc == obj2gco(L));
111 lua_assert(g->strt.nuse == 0);
112 luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); 110 luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *);
113 luaZ_freebuffer(L, &g->buff); 111 luaZ_freebuffer(L, &g->buff);
114 freestack(L, L); 112 freestack(L, L);
@@ -183,7 +181,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
183 g->gray = NULL; 181 g->gray = NULL;
184 g->grayagain = NULL; 182 g->grayagain = NULL;
185 g->weak = g->ephemeron = g->allweak = NULL; 183 g->weak = g->ephemeron = g->allweak = NULL;
186 g->tmudata = NULL; 184 g->tmudata = g->tobefnz = NULL;
187 g->totalbytes = sizeof(LG); 185 g->totalbytes = sizeof(LG);
188 g->gcpause = LUAI_GCPAUSE; 186 g->gcpause = LUAI_GCPAUSE;
189 g->gcstepmul = LUAI_GCMUL; 187 g->gcstepmul = LUAI_GCMUL;
@@ -210,14 +208,15 @@ LUA_API void lua_close (lua_State *L) {
210 L = G(L)->mainthread; /* only the main thread can be closed */ 208 L = G(L)->mainthread; /* only the main thread can be closed */
211 lua_lock(L); 209 lua_lock(L);
212 luaF_close(L, L->stack); /* close all upvalues for this thread */ 210 luaF_close(L, L->stack); /* close all upvalues for this thread */
213 luaC_separateudata(L, 1); /* separate udata that have GC metamethods */ 211 luaC_separateudata(L, 1); /* separate all udata with GC metamethods */
212 lua_assert(G(L)->tmudata == NULL);
214 L->errfunc = 0; /* no error function during GC metamethods */ 213 L->errfunc = 0; /* no error function during GC metamethods */
215 do { /* repeat until no more errors */ 214 do { /* repeat until no more errors */
216 L->ci = L->base_ci; 215 L->ci = L->base_ci;
217 L->base = L->top = L->ci->base; 216 L->base = L->top = L->ci->base;
218 G(L)->nCcalls = 0; 217 G(L)->nCcalls = 0;
219 } while (luaD_rawrunprotected(L, callallgcTM, NULL) != LUA_OK); 218 } while (luaD_rawrunprotected(L, callallgcTM, NULL) != LUA_OK);
220 lua_assert(G(L)->tmudata == NULL); 219 lua_assert(G(L)->tobefnz == NULL);
221 luai_userstateclose(L); 220 luai_userstateclose(L);
222 close_state(L); 221 close_state(L);
223} 222}
diff --git a/lstate.h b/lstate.h
index 611e7b0d..d130f668 100644
--- a/lstate.h
+++ b/lstate.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.h,v 2.30 2007/10/31 15:41:19 roberto Exp roberto $ 2** $Id: lstate.h,v 2.31 2008/02/11 15:45:30 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*/
@@ -83,10 +83,11 @@ typedef struct global_State {
83 GCObject **sweepgc; /* position of sweep in `rootgc' */ 83 GCObject **sweepgc; /* position of sweep in `rootgc' */
84 GCObject *gray; /* list of gray objects */ 84 GCObject *gray; /* list of gray objects */
85 GCObject *grayagain; /* list of objects to be traversed atomically */ 85 GCObject *grayagain; /* list of objects to be traversed atomically */
86 GCObject *weak; /* list of (something) weak tables */ 86 GCObject *weak; /* list of tables with weak values */
87 GCObject *ephemeron; /* list of ephemeron tables */ 87 GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
88 GCObject *allweak; /* list of all-weak tables */ 88 GCObject *allweak; /* list of all-weak tables */
89 GCObject *tmudata; /* last element of list of userdata to be GC */ 89 GCObject *tmudata; /* list of userdata with finalizers */
90 GCObject *tobefnz; /* last element of list of userdata to be GC */
90 Mbuffer buff; /* temporary buffer for string concatentation */ 91 Mbuffer buff; /* temporary buffer for string concatentation */
91 lu_mem GCthreshold; 92 lu_mem GCthreshold;
92 lu_mem totalbytes; /* number of bytes currently allocated */ 93 lu_mem totalbytes; /* number of bytes currently allocated */
@@ -143,7 +144,7 @@ struct lua_State {
143** Union of all collectable objects 144** Union of all collectable objects
144*/ 145*/
145union GCObject { 146union GCObject {
146 GCheader gch; 147 GCheader gch; /* common header */
147 union TString ts; 148 union TString ts;
148 union Udata u; 149 union Udata u;
149 union Closure cl; 150 union Closure cl;
@@ -154,13 +155,15 @@ union GCObject {
154}; 155};
155 156
156 157
158#define gch(o) (&(o)->gch)
159
157/* macros to convert a GCObject into a specific value */ 160/* macros to convert a GCObject into a specific value */
158#define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) 161#define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts))
159#define gco2ts(o) (&rawgco2ts(o)->tsv) 162#define gco2ts(o) (&rawgco2ts(o)->tsv)
160#define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) 163#define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u))
161#define gco2u(o) (&rawgco2u(o)->uv) 164#define gco2u(o) (&rawgco2u(o)->uv)
162#define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl)) 165#define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl))
163#define gco2h(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) 166#define gco2t(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h))
164#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) 167#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p))
165#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) 168#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv))
166#define ngcotouv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) 169#define ngcotouv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv))
diff --git a/lstring.c b/lstring.c
index f8f0debc..3c40d4ef 100644
--- a/lstring.c
+++ b/lstring.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstring.c,v 2.9 2006/07/11 15:53:29 roberto Exp roberto $ 2** $Id: lstring.c,v 2.10 2007/11/09 18:55:07 roberto Exp roberto $
3** String table (keeps all strings handled by Lua) 3** String table (keeps all strings handled by Lua)
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -32,11 +32,11 @@ void luaS_resize (lua_State *L, int newsize) {
32 for (i=0; i<tb->size; i++) { 32 for (i=0; i<tb->size; i++) {
33 GCObject *p = tb->hash[i]; 33 GCObject *p = tb->hash[i];
34 while (p) { /* for each node in the list */ 34 while (p) { /* for each node in the list */
35 GCObject *next = p->gch.next; /* save next */ 35 GCObject *next = gch(p)->next; /* save next */
36 unsigned int h = gco2ts(p)->hash; 36 unsigned int h = gco2ts(p)->hash;
37 int h1 = lmod(h, newsize); /* new position */ 37 int h1 = lmod(h, newsize); /* new position */
38 lua_assert(cast_int(h%newsize) == lmod(h, newsize)); 38 lua_assert(cast_int(h%newsize) == lmod(h, newsize));
39 p->gch.next = newhash[h1]; /* chain it */ 39 gch(p)->next = newhash[h1]; /* chain it */
40 newhash[h1] = p; 40 newhash[h1] = p;
41 p = next; 41 p = next;
42 } 42 }
@@ -80,7 +80,7 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
80 h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); 80 h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1]));
81 for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; 81 for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)];
82 o != NULL; 82 o != NULL;
83 o = o->gch.next) { 83 o = gch(o)->next) {
84 TString *ts = rawgco2ts(o); 84 TString *ts = rawgco2ts(o);
85 if (h == ts->tsv.hash && ts->tsv.len == l && 85 if (h == ts->tsv.hash && ts->tsv.len == l &&
86 (memcmp(str, getstr(ts), l) == 0)) { 86 (memcmp(str, getstr(ts), l) == 0)) {
@@ -98,14 +98,10 @@ Udata *luaS_newudata (lua_State *L, size_t s, Table *e) {
98 if (s > MAX_SIZET - sizeof(Udata)) 98 if (s > MAX_SIZET - sizeof(Udata))
99 luaM_toobig(L); 99 luaM_toobig(L);
100 u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata))); 100 u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata)));
101 u->uv.marked = luaC_white(G(L)); /* is not finalized */ 101 luaC_link(L, obj2gco(u), LUA_TUSERDATA);
102 u->uv.tt = LUA_TUSERDATA;
103 u->uv.len = s; 102 u->uv.len = s;
104 u->uv.metatable = NULL; 103 u->uv.metatable = NULL;
105 u->uv.env = e; 104 u->uv.env = e;
106 /* chain it on udata list (after main thread) */
107 u->uv.next = G(L)->mainthread->next;
108 G(L)->mainthread->next = obj2gco(u);
109 return u; 105 return u;
110} 106}
111 107
diff --git a/ltests.c b/ltests.c
index c2ec6395..ffed7d1d 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ltests.c,v 2.45 2008/02/11 18:04:26 roberto Exp roberto $ 2** $Id: ltests.c,v 2.46 2008/02/11 19:04:16 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*/
@@ -176,10 +176,10 @@ static int testobjref1 (global_State *g, GCObject *f, GCObject *t) {
176static void printobj (global_State *g, GCObject *o) { 176static void printobj (global_State *g, GCObject *o) {
177 int i = 0; 177 int i = 0;
178 GCObject *p; 178 GCObject *p;
179 for (p = g->rootgc; p != o && p != NULL; p = p->gch.next) i++; 179 for (p = g->rootgc; p != o && p != NULL; p = gch(p)->next) i++;
180 if (p == NULL) i = -1; 180 if (p == NULL) i = -1;
181 printf("%d:%s(%p)-%c(%02X)", i, luaT_typenames[o->gch.tt], (void *)o, 181 printf("%d:%s(%p)-%c(%02X)", i, luaT_typenames[gch(o)->tt], (void *)o,
182 isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', o->gch.marked); 182 isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', gch(o)->marked);
183} 183}
184 184
185 185
@@ -198,7 +198,7 @@ static int testobjref (global_State *g, GCObject *f, GCObject *t) {
198#define checkobjref(g,f,t) lua_assert(testobjref(g,f,obj2gco(t))) 198#define checkobjref(g,f,t) lua_assert(testobjref(g,f,obj2gco(t)))
199 199
200#define checkvalref(g,f,t) lua_assert(!iscollectable(t) || \ 200#define checkvalref(g,f,t) lua_assert(!iscollectable(t) || \
201 ((ttype(t) == (t)->value.gc->gch.tt) && testobjref(g,f,gcvalue(t)))) 201 ((ttype(t) == gch((t)->value.gc)->tt) && testobjref(g,f,gcvalue(t))))
202 202
203 203
204 204
@@ -285,7 +285,7 @@ static void checkstack (global_State *g, lua_State *L1) {
285 CallInfo *ci; 285 CallInfo *ci;
286 GCObject *uvo; 286 GCObject *uvo;
287 lua_assert(!isdead(g, obj2gco(L1))); 287 lua_assert(!isdead(g, obj2gco(L1)));
288 for (uvo = L1->openupval; uvo != NULL; uvo = uvo->gch.next) { 288 for (uvo = L1->openupval; uvo != NULL; uvo = gch(uvo)->next) {
289 UpVal *uv = gco2uv(uvo); 289 UpVal *uv = gco2uv(uvo);
290 lua_assert(uv->v != &uv->u.value); /* must be open */ 290 lua_assert(uv->v != &uv->u.value); /* must be open */
291 lua_assert(!isblack(uvo)); /* open upvalues cannot be black */ 291 lua_assert(!isblack(uvo)); /* open upvalues cannot be black */
@@ -308,14 +308,14 @@ static void checkstack (global_State *g, lua_State *L1) {
308 308
309static void checkobject (global_State *g, GCObject *o) { 309static void checkobject (global_State *g, GCObject *o) {
310 if (isdead(g, o)) 310 if (isdead(g, o))
311/* lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);*/ 311/* lua_assert(issweep(g));*/
312{ if (!(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep)) 312{ if (!issweep(g))
313printf(">>> %d %s %02x\n", g->gcstate, luaT_typenames[o->gch.tt], o->gch.marked); 313printf(">>> %d %s %02x\n", g->gcstate, luaT_typenames[gch(o)->tt], gch(o)->marked);
314} 314}
315 else { 315 else {
316 if (g->gcstate == GCSfinalize) 316 if (g->gcstate == GCSfinalize)
317 lua_assert(iswhite(o)); 317 lua_assert(iswhite(o));
318 switch (o->gch.tt) { 318 switch (gch(o)->tt) {
319 case LUA_TUPVAL: { 319 case LUA_TUPVAL: {
320 UpVal *uv = gco2uv(o); 320 UpVal *uv = gco2uv(o);
321 lua_assert(uv->v == &uv->u.value); /* must be closed */ 321 lua_assert(uv->v == &uv->u.value); /* must be closed */
@@ -329,7 +329,7 @@ printf(">>> %d %s %02x\n", g->gcstate, luaT_typenames[o->gch.tt], o->gch.marke
329 break; 329 break;
330 } 330 }
331 case LUA_TTABLE: { 331 case LUA_TTABLE: {
332 checktable(g, gco2h(o)); 332 checktable(g, gco2t(o));
333 break; 333 break;
334 } 334 }
335 case LUA_TTHREAD: { 335 case LUA_TTHREAD: {
@@ -367,10 +367,10 @@ int lua_checkmemory (lua_State *L) {
367 GCObject *o; 367 GCObject *o;
368 UpVal *uv; 368 UpVal *uv;
369 checkstack(g, g->mainthread); 369 checkstack(g, g->mainthread);
370 for (o = g->rootgc; o != obj2gco(g->mainthread); o = o->gch.next) 370 for (o = g->rootgc; o != NULL; o = gch(o)->next)
371 checkobject(g, o); 371 checkobject(g, o);
372 for (o = o->gch.next; o != NULL; o = o->gch.next) { 372 for (o = g->tmudata; o != NULL; o = gch(o)->next) {
373 lua_assert(o->gch.tt == LUA_TUSERDATA); 373 lua_assert(!isdead(g, o));
374 checkobject(g, o); 374 checkobject(g, o);
375 } 375 }
376 for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { 376 for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
@@ -534,8 +534,10 @@ static int gcstate (lua_State *L) {
534 switch(G(L)->gcstate) { 534 switch(G(L)->gcstate) {
535 case GCSpropagate: lua_pushstring(L, "propagate"); break; 535 case GCSpropagate: lua_pushstring(L, "propagate"); break;
536 case GCSsweepstring: lua_pushstring(L, "sweep strings"); break; 536 case GCSsweepstring: lua_pushstring(L, "sweep strings"); break;
537 case GCSsweeptmu: lua_pushstring(L, "sweep udata with __gc"); break;
537 case GCSsweep: lua_pushstring(L, "sweep"); break; 538 case GCSsweep: lua_pushstring(L, "sweep"); break;
538 case GCSfinalize: lua_pushstring(L, "finalize"); break; 539 case GCSfinalize: lua_pushstring(L, "finalize"); break;
540 default: lua_assert(0);
539 } 541 }
540 return 1; 542 return 1;
541} 543}
@@ -612,7 +614,7 @@ static int string_query (lua_State *L) {
612 else if (s < tb->size) { 614 else if (s < tb->size) {
613 GCObject *ts; 615 GCObject *ts;
614 int n = 0; 616 int n = 0;
615 for (ts = tb->hash[s]; ts; ts = ts->gch.next) { 617 for (ts = tb->hash[s]; ts; ts = gch(ts)->next) {
616 setsvalue2s(L, L->top, gco2ts(ts)); 618 setsvalue2s(L, L->top, gco2ts(ts));
617 incr_top(L); 619 incr_top(L);
618 n++; 620 n++;