diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2010-03-24 10:07:01 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2010-03-24 10:07:01 -0300 |
commit | 4433dbb5f5ac0bb6118bc49ddf061f194c070814 (patch) | |
tree | 628f9da77c0cf6a80556a9c189f2528a3d7d7ca4 | |
parent | 5cb128ea540b33dbc6be659d5dfc3c64c57d78d9 (diff) | |
download | lua-4433dbb5f5ac0bb6118bc49ddf061f194c070814.tar.gz lua-4433dbb5f5ac0bb6118bc49ddf061f194c070814.tar.bz2 lua-4433dbb5f5ac0bb6118bc49ddf061f194c070814.zip |
userdata with finalizers are kept in a separated list ('udgc'), instead
of at the end of 'rootgc' (which was renamed to 'allgc', as it is not
"root" in the usual meaning for collectors)
-rw-r--r-- | lgc.c | 56 | ||||
-rw-r--r-- | lgc.h | 12 | ||||
-rw-r--r-- | lstate.c | 5 | ||||
-rw-r--r-- | lstate.h | 11 | ||||
-rw-r--r-- | ltests.c | 8 |
5 files changed, 48 insertions, 44 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.68 2010/03/22 18:28:03 roberto Exp $ | 2 | ** $Id: lgc.c,v 2.69 2010/03/23 20:16:06 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 | */ |
@@ -33,8 +33,10 @@ | |||
33 | 33 | ||
34 | #define maskcolors (~(bitmask(BLACKBIT)|WHITEBITS)) | 34 | #define maskcolors (~(bitmask(BLACKBIT)|WHITEBITS)) |
35 | 35 | ||
36 | #define makewhite(g,x) \ | 36 | #define makewhitew(w,x) \ |
37 | (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g))) | 37 | (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | (w))) |
38 | |||
39 | #define makewhite(g,x) makewhitew(luaC_white(g), x) | ||
38 | 40 | ||
39 | #define white2gray(x) resetbits(gch(x)->marked, WHITEBITS) | 41 | #define white2gray(x) resetbits(gch(x)->marked, WHITEBITS) |
40 | #define black2gray(x) resetbit(gch(x)->marked, BLACKBIT) | 42 | #define black2gray(x) resetbit(gch(x)->marked, BLACKBIT) |
@@ -127,7 +129,7 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, | |||
127 | global_State *g = G(L); | 129 | global_State *g = G(L); |
128 | GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset); | 130 | GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset); |
129 | if (list == NULL) | 131 | if (list == NULL) |
130 | list = &g->rootgc; /* standard list for collectable objects */ | 132 | list = &g->allgc; /* standard list for collectable objects */ |
131 | gch(o)->marked = luaC_white(g); | 133 | gch(o)->marked = luaC_white(g); |
132 | gch(o)->tt = tt; | 134 | gch(o)->tt = tt; |
133 | gch(o)->next = *list; | 135 | gch(o)->next = *list; |
@@ -139,8 +141,8 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, | |||
139 | void luaC_linkupval (lua_State *L, UpVal *uv) { | 141 | void luaC_linkupval (lua_State *L, UpVal *uv) { |
140 | global_State *g = G(L); | 142 | global_State *g = G(L); |
141 | GCObject *o = obj2gco(uv); | 143 | GCObject *o = obj2gco(uv); |
142 | gch(o)->next = g->rootgc; /* link upvalue into `rootgc' list */ | 144 | gch(o)->next = g->allgc; /* link upvalue into `allgc' list */ |
143 | g->rootgc = o; | 145 | g->allgc = o; |
144 | if (isgray(o)) { | 146 | if (isgray(o)) { |
145 | if (g->gcstate == GCSpropagate) { | 147 | if (g->gcstate == GCSpropagate) { |
146 | gray2black(o); /* closed upvalues need barrier */ | 148 | gray2black(o); /* closed upvalues need barrier */ |
@@ -549,8 +551,9 @@ static void sweepthread (lua_State *L, lua_State *L1, int alive) { | |||
549 | static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { | 551 | static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { |
550 | GCObject *curr; | 552 | GCObject *curr; |
551 | global_State *g = G(L); | 553 | global_State *g = G(L); |
552 | int deadmask = otherwhite(g); | ||
553 | int gckind = g->gckind; | 554 | int gckind = g->gckind; |
555 | int deadmask = otherwhite(g); | ||
556 | int white = luaC_white(g); | ||
554 | while ((curr = *p) != NULL && count-- > 0) { | 557 | while ((curr = *p) != NULL && count-- > 0) { |
555 | int alive = (gch(curr)->marked ^ WHITEBITS) & deadmask; | 558 | int alive = (gch(curr)->marked ^ WHITEBITS) & deadmask; |
556 | if (gch(curr)->tt == LUA_TTHREAD) | 559 | if (gch(curr)->tt == LUA_TTHREAD) |
@@ -559,7 +562,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { | |||
559 | lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT)); | 562 | lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT)); |
560 | /* in generational mode all live objects are kept black, which | 563 | /* in generational mode all live objects are kept black, which |
561 | means they grow to old generation */ | 564 | means they grow to old generation */ |
562 | if (gckind != KGC_GEN) makewhite(g, curr); | 565 | if (gckind != KGC_GEN) makewhitew(white, curr); |
563 | p = &gch(curr)->next; | 566 | p = &gch(curr)->next; |
564 | } | 567 | } |
565 | else { /* must erase `curr' */ | 568 | else { /* must erase `curr' */ |
@@ -597,8 +600,8 @@ static void checkSizes (lua_State *L) { | |||
597 | static Udata *udata2finalize (global_State *g) { | 600 | static Udata *udata2finalize (global_State *g) { |
598 | GCObject *o = g->tobefnz; /* get first element */ | 601 | GCObject *o = g->tobefnz; /* get first element */ |
599 | g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ | 602 | g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ |
600 | gch(o)->next = g->rootgc; /* return it to `root' list */ | 603 | gch(o)->next = g->allgc; /* return it to 'allgc' list */ |
601 | g->rootgc = o; | 604 | g->allgc = o; |
602 | lua_assert(isfinalized(gch(o))); | 605 | lua_assert(isfinalized(gch(o))); |
603 | resetbit(gch(o)->marked, SEPARATED); /* mark it as such */ | 606 | resetbit(gch(o)->marked, SEPARATED); /* mark it as such */ |
604 | makewhite(g, o); | 607 | makewhite(g, o); |
@@ -643,7 +646,7 @@ static void GCTM (lua_State *L, int propagateerrors) { | |||
643 | /* move 'dead' udata that need finalization to list 'tobefnz' */ | 646 | /* move 'dead' udata that need finalization to list 'tobefnz' */ |
644 | void luaC_separateudata (lua_State *L, int all) { | 647 | void luaC_separateudata (lua_State *L, int all) { |
645 | global_State *g = G(L); | 648 | global_State *g = G(L); |
646 | GCObject **p = &g->mainthread->next; | 649 | GCObject **p = &g->udgc; |
647 | GCObject *curr; | 650 | GCObject *curr; |
648 | GCObject **lastnext = &g->tobefnz; | 651 | GCObject **lastnext = &g->tobefnz; |
649 | /* find last 'next' field in 'tobefnz' list (to insert elements in its end) */ | 652 | /* find last 'next' field in 'tobefnz' list (to insert elements in its end) */ |
@@ -655,7 +658,7 @@ void luaC_separateudata (lua_State *L, int all) { | |||
655 | p = &gch(curr)->next; /* don't bother with it */ | 658 | p = &gch(curr)->next; /* don't bother with it */ |
656 | else { | 659 | else { |
657 | l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ | 660 | l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ |
658 | *p = gch(curr)->next; /* remove 'curr' from 'rootgc' list */ | 661 | *p = gch(curr)->next; /* remove 'curr' from 'udgc' list */ |
659 | /* link 'curr' at the end of 'tobefnz' list */ | 662 | /* link 'curr' at the end of 'tobefnz' list */ |
660 | gch(curr)->next = *lastnext; | 663 | gch(curr)->next = *lastnext; |
661 | *lastnext = curr; | 664 | *lastnext = curr; |
@@ -671,13 +674,12 @@ void luaC_checkfinalizer (lua_State *L, Udata *u) { | |||
671 | isfinalized(&u->uv) || /* ... or is finalized... */ | 674 | isfinalized(&u->uv) || /* ... or is finalized... */ |
672 | gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */ | 675 | gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */ |
673 | return; /* nothing to be done */ | 676 | return; /* nothing to be done */ |
674 | else { /* move 'u' to 2nd part of root list */ | 677 | else { /* move 'u' to 'udgc' list */ |
675 | GCObject **p; | 678 | GCObject **p; |
676 | for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next) | 679 | for (p = &g->allgc; *p != obj2gco(u); p = &gch(*p)->next) ; |
677 | lua_assert(*p != obj2gco(g->mainthread)); /* 'u' must be in this list */ | ||
678 | *p = u->uv.next; /* remove 'u' from root list */ | 680 | *p = u->uv.next; /* remove 'u' from root list */ |
679 | u->uv.next = g->mainthread->next; /* re-link it in list */ | 681 | u->uv.next = g->udgc; /* re-link it in list */ |
680 | g->mainthread->next = obj2gco(u); | 682 | g->udgc = obj2gco(u); |
681 | l_setbit(u->uv.marked, SEPARATED); /* mark it as such */ | 683 | l_setbit(u->uv.marked, SEPARATED); /* mark it as such */ |
682 | } | 684 | } |
683 | } | 685 | } |
@@ -697,8 +699,9 @@ void luaC_freeallobjects (lua_State *L) { | |||
697 | while (g->tobefnz) GCTM(L, 0); /* Call all pending finalizers */ | 699 | while (g->tobefnz) GCTM(L, 0); /* Call all pending finalizers */ |
698 | /* following "white" makes all objects look dead */ | 700 | /* following "white" makes all objects look dead */ |
699 | g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); | 701 | g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); |
700 | sweepwholelist(L, &g->rootgc); | 702 | sweepwholelist(L, &g->udgc); |
701 | lua_assert(g->rootgc == obj2gco(g->mainthread) && | 703 | sweepwholelist(L, &g->allgc); |
704 | lua_assert(g->allgc == obj2gco(g->mainthread) && | ||
702 | g->mainthread->next == NULL); | 705 | g->mainthread->next == NULL); |
703 | for (i = 0; i < g->strt.size; i++) /* free all string lists */ | 706 | for (i = 0; i < g->strt.size; i++) /* free all string lists */ |
704 | sweepwholelist(L, &g->strt.hash[i]); | 707 | sweepwholelist(L, &g->strt.hash[i]); |
@@ -761,19 +764,21 @@ static l_mem singlestep (lua_State *L) { | |||
761 | return GCSWEEPCOST; | 764 | return GCSWEEPCOST; |
762 | } | 765 | } |
763 | else { /* nothing more to sweep */ | 766 | else { /* nothing more to sweep */ |
764 | g->sweepgc = &g->rootgc; | 767 | g->sweepgc = &g->udgc; /* sweep all userdata */ |
765 | g->gcstate = GCSsweep; /* sweep all other objects */ | 768 | g->gcstate = GCSsweepudata; |
769 | checkSizes(L); | ||
766 | return 0; | 770 | return 0; |
767 | } | 771 | } |
768 | } | 772 | } |
773 | case GCSsweepudata: | ||
769 | case GCSsweep: { | 774 | case GCSsweep: { |
770 | if (*g->sweepgc) { | 775 | if (*g->sweepgc) { |
771 | g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); | 776 | g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); |
772 | return GCSWEEPMAX*GCSWEEPCOST; | 777 | return GCSWEEPMAX*GCSWEEPCOST; |
773 | } | 778 | } |
774 | else { /* nothing more to sweep */ | 779 | else { /* go to next phase */ |
775 | checkSizes(L); | 780 | g->sweepgc = &g->allgc; /* useless (but harmless) in GCSsweep case */ |
776 | g->gcstate = GCSfinalize; /* end sweep phase */ | 781 | g->gcstate = (g->gcstate == GCSsweep) ? GCSfinalize : GCSsweep; |
777 | return 0; | 782 | return 0; |
778 | } | 783 | } |
779 | } | 784 | } |
@@ -856,8 +861,7 @@ void luaC_fullgc (lua_State *L, int isemergency) { | |||
856 | g->gcstate = GCSsweepstring; | 861 | g->gcstate = GCSsweepstring; |
857 | } | 862 | } |
858 | /* finish any pending sweep phase */ | 863 | /* finish any pending sweep phase */ |
859 | luaC_runtilstate(L, ~bit2mask(GCSsweepstring, GCSsweep)); | 864 | luaC_runtilstate(L, bit2mask(GCSpause, GCSfinalize)); |
860 | lua_assert(g->gcstate == GCSpause || g->gcstate == GCSfinalize); | ||
861 | g->gcstate = GCSpause; /* start a new collection */ | 865 | g->gcstate = GCSpause; /* start a new collection */ |
862 | /* run collector up to finalizers */ | 866 | /* run collector up to finalizers */ |
863 | luaC_runtilstate(L, bitmask(GCSfinalize)); | 867 | luaC_runtilstate(L, bitmask(GCSfinalize)); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.h,v 2.26 2009/12/11 21:31:14 roberto Exp roberto $ | 2 | ** $Id: lgc.h,v 2.27 2009/12/16 16:42:58 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 | */ |
@@ -18,8 +18,9 @@ | |||
18 | #define GCSpropagate 1 | 18 | #define GCSpropagate 1 |
19 | #define GCSatomic 2 | 19 | #define GCSatomic 2 |
20 | #define GCSsweepstring 3 | 20 | #define GCSsweepstring 3 |
21 | #define GCSsweep 4 | 21 | #define GCSsweepudata 4 |
22 | #define GCSfinalize 5 | 22 | #define GCSsweep 5 |
23 | #define GCSfinalize 6 | ||
23 | 24 | ||
24 | 25 | ||
25 | 26 | ||
@@ -45,12 +46,10 @@ | |||
45 | ** bit 1 - object is white (type 1) | 46 | ** bit 1 - object is white (type 1) |
46 | ** bit 2 - object is black | 47 | ** bit 2 - object is black |
47 | ** bit 3 - for userdata: has been finalized | 48 | ** bit 3 - for userdata: has been finalized |
48 | ** bit 4 - for userdata: it's in 2nd part of rootgc list or in tobefnz | 49 | ** bit 4 - for userdata: it's in 'udgc' list or in 'tobefnz' |
49 | ** bit 5 - object is fixed (should not be collected) | 50 | ** bit 5 - object is fixed (should not be collected) |
50 | ** bit 6 - object is "super" fixed (only the main thread) | 51 | ** bit 6 - object is "super" fixed (only the main thread) |
51 | */ | 52 | */ |
52 | |||
53 | |||
54 | #define WHITE0BIT 0 | 53 | #define WHITE0BIT 0 |
55 | #define WHITE1BIT 1 | 54 | #define WHITE1BIT 1 |
56 | #define BLACKBIT 2 | 55 | #define BLACKBIT 2 |
@@ -58,6 +57,7 @@ | |||
58 | #define SEPARATED 4 | 57 | #define SEPARATED 4 |
59 | #define FIXEDBIT 5 | 58 | #define FIXEDBIT 5 |
60 | #define SFIXEDBIT 6 | 59 | #define SFIXEDBIT 6 |
60 | |||
61 | #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) | 61 | #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) |
62 | 62 | ||
63 | 63 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstate.c,v 2.70 2010/03/19 21:04:17 roberto Exp roberto $ | 2 | ** $Id: lstate.c,v 2.71 2010/03/22 17:45:55 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 | */ |
@@ -264,7 +264,8 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
264 | g->panic = NULL; | 264 | g->panic = NULL; |
265 | g->version = lua_version(NULL); | 265 | g->version = lua_version(NULL); |
266 | g->gcstate = GCSpause; | 266 | g->gcstate = GCSpause; |
267 | g->rootgc = obj2gco(L); | 267 | g->allgc = obj2gco(L); |
268 | g->udgc = NULL; | ||
268 | g->tobefnz = NULL; | 269 | g->tobefnz = NULL; |
269 | g->totalbytes = sizeof(LG); | 270 | g->totalbytes = sizeof(LG); |
270 | g->gcpause = LUAI_GCPAUSE; | 271 | g->gcpause = LUAI_GCPAUSE; |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstate.h,v 2.54 2010/03/13 15:55:42 roberto Exp roberto $ | 2 | ** $Id: lstate.h,v 2.55 2010/03/22 18:28:03 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 | */ |
@@ -19,7 +19,7 @@ | |||
19 | ** Some notes about garbage-collected objects: All objects in Lua must | 19 | ** Some notes about garbage-collected objects: All objects in Lua must |
20 | ** be kept somehow accessible until being freed. | 20 | ** be kept somehow accessible until being freed. |
21 | ** | 21 | ** |
22 | ** Lua keeps most objects linked in list g->rootgc. The link uses field | 22 | ** Lua keeps most objects linked in list g->allgc. The link uses field |
23 | ** 'next' of the CommonHeader. | 23 | ** 'next' of the CommonHeader. |
24 | ** | 24 | ** |
25 | ** Strings are kept in several lists headed by the array g->strt.hash. | 25 | ** Strings are kept in several lists headed by the array g->strt.hash. |
@@ -32,9 +32,7 @@ | |||
32 | ** when traversing the respective threads, but the thread may already be | 32 | ** when traversing the respective threads, but the thread may already be |
33 | ** dead, while the upvalue is still accessible through closures.) | 33 | ** dead, while the upvalue is still accessible through closures.) |
34 | ** | 34 | ** |
35 | ** Userdata with finalizers are kept in the list g->rootgc, but after | 35 | ** Userdata with finalizers are kept in the list g->udgc. |
36 | ** the mainthread, which should be otherwise the last element in the | ||
37 | ** list, as it was the first one inserted there. | ||
38 | ** | 36 | ** |
39 | ** The list g->tobefnz links all userdata being finalized. | 37 | ** The list g->tobefnz links all userdata being finalized. |
40 | 38 | ||
@@ -124,7 +122,8 @@ typedef struct global_State { | |||
124 | lu_byte gcstate; /* state of garbage collector */ | 122 | lu_byte gcstate; /* state of garbage collector */ |
125 | lu_byte gckind; /* kind of GC running */ | 123 | lu_byte gckind; /* kind of GC running */ |
126 | int sweepstrgc; /* position of sweep in `strt' */ | 124 | int sweepstrgc; /* position of sweep in `strt' */ |
127 | GCObject *rootgc; /* list of all collectable objects */ | 125 | GCObject *allgc; /* list of all collectable objects */ |
126 | GCObject *udgc; /* list of collectable userdata with finalizers */ | ||
128 | GCObject **sweepgc; /* current position of sweep */ | 127 | GCObject **sweepgc; /* current position of sweep */ |
129 | GCObject *gray; /* list of gray objects */ | 128 | GCObject *gray; /* list of gray objects */ |
130 | GCObject *grayagain; /* list of objects to be traversed atomically */ | 129 | GCObject *grayagain; /* list of objects to be traversed atomically */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltests.c,v 2.86 2009/12/22 15:32:50 roberto Exp roberto $ | 2 | ** $Id: ltests.c,v 2.87 2010/01/13 16:18:25 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 | */ |
@@ -188,7 +188,7 @@ static int testobjref1 (global_State *g, GCObject *f, GCObject *t) { | |||
188 | static void printobj (global_State *g, GCObject *o) { | 188 | static void printobj (global_State *g, GCObject *o) { |
189 | int i = 0; | 189 | int i = 0; |
190 | GCObject *p; | 190 | GCObject *p; |
191 | for (p = g->rootgc; p != o && p != NULL; p = gch(p)->next) i++; | 191 | for (p = g->allgc; p != o && p != NULL; p = gch(p)->next) i++; |
192 | if (p == NULL) i = -1; | 192 | if (p == NULL) i = -1; |
193 | printf("%d:%s(%p)-%c(%02X)", i, typename(gch(o)->tt), (void *)o, | 193 | printf("%d:%s(%p)-%c(%02X)", i, typename(gch(o)->tt), (void *)o, |
194 | isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', gch(o)->marked); | 194 | isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', gch(o)->marked); |
@@ -375,12 +375,12 @@ int lua_checkmemory (lua_State *L) { | |||
375 | checkliveness(g, &g->l_registry); | 375 | checkliveness(g, &g->l_registry); |
376 | lua_assert(!isdead(g, obj2gco(g->l_gt))); | 376 | lua_assert(!isdead(g, obj2gco(g->l_gt))); |
377 | checkstack(g, g->mainthread); | 377 | checkstack(g, g->mainthread); |
378 | for (o = g->rootgc; o != obj2gco(g->mainthread); o = gch(o)->next) { | 378 | for (o = g->allgc; o != obj2gco(g->mainthread); o = gch(o)->next) { |
379 | lua_assert(!testbits(o->gch.marked, bit2mask(SEPARATED, SFIXEDBIT))); | 379 | lua_assert(!testbits(o->gch.marked, bit2mask(SEPARATED, SFIXEDBIT))); |
380 | checkobject(g, o); | 380 | checkobject(g, o); |
381 | } | 381 | } |
382 | lua_assert(testbit(o->gch.marked, SFIXEDBIT)); | 382 | lua_assert(testbit(o->gch.marked, SFIXEDBIT)); |
383 | for (o = gch(o)->next; o != NULL; o = gch(o)->next) { | 383 | for (o = g->udgc; o != NULL; o = gch(o)->next) { |
384 | lua_assert(gch(o)->tt == LUA_TUSERDATA && | 384 | lua_assert(gch(o)->tt == LUA_TUSERDATA && |
385 | !isdead(g, o) && | 385 | !isdead(g, o) && |
386 | testbit(o->gch.marked, SEPARATED)); | 386 | testbit(o->gch.marked, SEPARATED)); |