diff options
-rw-r--r-- | lapi.c | 8 | ||||
-rw-r--r-- | lgc.c | 237 | ||||
-rw-r--r-- | lgc.h | 17 | ||||
-rw-r--r-- | lstate.c | 11 | ||||
-rw-r--r-- | lstate.h | 15 | ||||
-rw-r--r-- | lstring.c | 14 | ||||
-rw-r--r-- | ltests.c | 32 |
7 files changed, 187 insertions, 147 deletions
@@ -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: { |
@@ -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) { | |||
89 | static void reallymarkobject (global_State *g, GCObject *o) { | 87 | static 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 | ||
134 | static 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' */ | ||
147 | size_t luaC_separateudata (lua_State *L, int all) { | 133 | size_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 | */ |
423 | static void cleartable (GCObject *l) { | 407 | static 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 | ||
446 | static void freeobj (lua_State *L, GCObject *o) { | 430 | static 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 | ||
474 | static 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 | |||
499 | static void checkSizes (lua_State *L) { | 483 | static 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 | ||
507 | static Udata *udata2finalize (global_State *g) { | 491 | static 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) { | |||
522 | static void GCTM (lua_State *L) { | 507 | static 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 | */ |
544 | void luaC_callGCTM (lua_State *L) { | 529 | void 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) { | |||
559 | void luaC_freeall (lua_State *L) { | 544 | void 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 | ||
567 | static 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 */ |
577 | static void markroot (lua_State *L) { | 582 | static 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 | ||
607 | static 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 | |||
601 | static void atomic (lua_State *L) { | 615 | static 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 | ||
776 | void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { | 790 | void 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 | ||
785 | void luaC_linkupval (lua_State *L, UpVal *uv) { | 799 | void 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 | |||
817 | void 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 | |||
@@ -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); | |||
101 | LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); | 107 | LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); |
102 | LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); | 108 | LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); |
103 | LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); | 109 | LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); |
110 | LUAI_FUNC void luaC_checkfinalizer (lua_State *L, Udata *u); | ||
104 | 111 | ||
105 | 112 | ||
106 | #endif | 113 | #endif |
@@ -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 | } |
@@ -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 | */ |
145 | union GCObject { | 146 | union 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)) |
@@ -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 | ||
@@ -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) { | |||
176 | static void printobj (global_State *g, GCObject *o) { | 176 | static 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 | ||
309 | static void checkobject (global_State *g, GCObject *o) { | 309 | static 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)) |
313 | printf(">>> %d %s %02x\n", g->gcstate, luaT_typenames[o->gch.tt], o->gch.marked); | 313 | printf(">>> %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++; |