diff options
-rw-r--r-- | lgc.c | 106 | ||||
-rw-r--r-- | lgc.h | 30 | ||||
-rw-r--r-- | lstate.c | 8 | ||||
-rw-r--r-- | lstate.h | 31 | ||||
-rw-r--r-- | ltests.c | 14 |
5 files changed, 89 insertions, 100 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.45 2008/06/23 16:51:28 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.46 2008/06/23 22:07:44 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 | */ |
@@ -79,7 +79,7 @@ static void removeentry (Node *n) { | |||
79 | ** The next function tells whether a key or value can be cleared from | 79 | ** The next function tells whether a key or value can be cleared from |
80 | ** a weak table. Non-collectable objects are never removed from weak | 80 | ** a weak table. Non-collectable objects are never removed from weak |
81 | ** tables. Strings behave as `values', so are never removed too. for | 81 | ** tables. Strings behave as `values', so are never removed too. for |
82 | ** other objects: if really collected, cannot keep them; for userdata | 82 | ** other objects: if really collected, cannot keep them; for objects |
83 | ** being finalized, keep them in keys, but not in values | 83 | ** being finalized, keep them in keys, but not in values |
84 | */ | 84 | */ |
85 | static int iscleared (const TValue *o, int iskey) { | 85 | static int iscleared (const TValue *o, int iskey) { |
@@ -205,14 +205,11 @@ static void markmt (global_State *g) { | |||
205 | 205 | ||
206 | 206 | ||
207 | static void markbeingfnz (global_State *g) { | 207 | static void markbeingfnz (global_State *g) { |
208 | GCObject *u = g->tobefnz; | 208 | GCObject *o; |
209 | if (u) { | 209 | for (o = g->tobefnz; o != NULL; o = gch(o)->next) { |
210 | do { | 210 | lua_assert(testbit(gch(o)->marked, SEPARATED)); |
211 | u = gch(u)->next; | 211 | makewhite(g, o); |
212 | lua_assert(testbit(gch(u)->marked, SEPARATED)); | 212 | reallymarkobject(g, o); |
213 | makewhite(g, u); | ||
214 | reallymarkobject(g, u); | ||
215 | } while (u != g->tobefnz); | ||
216 | } | 213 | } |
217 | } | 214 | } |
218 | 215 | ||
@@ -228,7 +225,7 @@ static void markroot (lua_State *L) { | |||
228 | markvalue(g, gt(g->mainthread)); | 225 | markvalue(g, gt(g->mainthread)); |
229 | markvalue(g, registry(L)); | 226 | markvalue(g, registry(L)); |
230 | markmt(g); | 227 | markmt(g); |
231 | markbeingfnz(g); /* mark any finalizing userdata left from previous cycle */ | 228 | markbeingfnz(g); /* mark any finalizing object left from previous cycle */ |
232 | g->gcstate = GCSpropagate; | 229 | g->gcstate = GCSpropagate; |
233 | } | 230 | } |
234 | 231 | ||
@@ -573,17 +570,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { | |||
573 | return p; | 570 | return p; |
574 | } | 571 | } |
575 | 572 | ||
576 | |||
577 | /* sweep list where all objects are alive (dead udata were removed | ||
578 | when separated from this list) */ | ||
579 | static GCObject **unmarklist (global_State *g, GCObject **p, lu_mem count) { | ||
580 | for (; *p != NULL && count-- > 0; p = &gch(*p)->next) { | ||
581 | lua_assert(ttisuserdata(gch(*p)) && !isdead(g, *p)); | ||
582 | makewhite(g, *p); | ||
583 | } | ||
584 | return p; | ||
585 | } | ||
586 | |||
587 | /* }====================================================== */ | 573 | /* }====================================================== */ |
588 | 574 | ||
589 | 575 | ||
@@ -602,18 +588,14 @@ static void checkSizes (lua_State *L) { | |||
602 | 588 | ||
603 | 589 | ||
604 | static Udata *udata2finalize (global_State *g) { | 590 | static Udata *udata2finalize (global_State *g) { |
605 | GCObject *o = gch(g->tobefnz)->next; /* get first element */ | 591 | GCObject *o = g->tobefnz; /* get first element */ |
606 | Udata *udata = rawgco2u(o); | 592 | g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ |
607 | /* remove udata from `tobefnz' */ | 593 | gch(o)->next = g->rootgc; /* return it to `root' list */ |
608 | if (o == g->tobefnz) /* last element? */ | 594 | g->rootgc = o; |
609 | g->tobefnz = NULL; | 595 | lua_assert(isfinalized(gch(o))); |
610 | else | 596 | resetbit(gch(o)->marked, SEPARATED); /* mark it as such */ |
611 | gch(g->tobefnz)->next = udata->uv.next; | ||
612 | udata->uv.next = g->mainthread->next; /* return it to `root' list */ | ||
613 | g->mainthread->next = o; | ||
614 | resetbit(udata->uv.marked, SEPARATED); /* mark it as such */ | ||
615 | makewhite(g, o); | 597 | makewhite(g, o); |
616 | return udata; | 598 | return rawgco2u(o); |
617 | } | 599 | } |
618 | 600 | ||
619 | 601 | ||
@@ -639,28 +621,21 @@ static void GCTM (lua_State *L) { | |||
639 | /* | 621 | /* |
640 | ** Call all GC tag methods | 622 | ** Call all GC tag methods |
641 | */ | 623 | */ |
642 | void luaC_callGCTM (lua_State *L) { | 624 | void luaC_callAllGCTM (lua_State *L) { |
643 | global_State *g = G(L); | 625 | while (G(L)->tobefnz) GCTM(L); |
644 | GCObject *last = g->tobefnz; | ||
645 | GCObject *curr; | ||
646 | if (last == NULL) return; /* empty list? */ | ||
647 | do { | ||
648 | curr = gch(g->tobefnz)->next; /* element to be collected */ | ||
649 | GCTM(L); | ||
650 | } while (curr != last); /* go only until original last */ | ||
651 | /* do not finalize new udata created during previous finalizations */ | ||
652 | while (g->tobefnz) | ||
653 | udata2finalize(g); /* simply remove them from list */ | ||
654 | } | 626 | } |
655 | 627 | ||
656 | 628 | ||
657 | /* move 'dead' udata that need finalization to list 'tobefnz' */ | 629 | /* move 'dead' udata that need finalization to list 'tobefnz' */ |
658 | size_t luaC_separateudata (lua_State *L, int all) { | 630 | size_t luaC_separateudata (lua_State *L, int all) { |
659 | global_State *g = G(L); | 631 | global_State *g = G(L); |
660 | size_t deadmem = 0; | 632 | size_t deadmem = 0; /* total size of all objects to be finalized */ |
661 | GCObject **p = &g->tmudata; | 633 | GCObject **p = &g->mainthread->next; |
662 | GCObject *curr; | 634 | GCObject *curr; |
663 | while ((curr = *p) != NULL) { | 635 | GCObject **lastnext = &g->tobefnz; |
636 | /* find last 'next' field in 'tobefnz' list (to insert elements in its end) */ | ||
637 | while (*lastnext != NULL) lastnext = &gch(*lastnext)->next; | ||
638 | while ((curr = *p) != NULL) { /* traverse all finalizable objects */ | ||
664 | lua_assert(ttisuserdata(gch(curr)) && !isfinalized(gco2u(curr))); | 639 | lua_assert(ttisuserdata(gch(curr)) && !isfinalized(gco2u(curr))); |
665 | lua_assert(testbit(gch(curr)->marked, SEPARATED)); | 640 | lua_assert(testbit(gch(curr)->marked, SEPARATED)); |
666 | if (!(all || iswhite(curr))) /* not being collected? */ | 641 | if (!(all || iswhite(curr))) /* not being collected? */ |
@@ -668,15 +643,11 @@ size_t luaC_separateudata (lua_State *L, int all) { | |||
668 | else { | 643 | else { |
669 | l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ | 644 | l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ |
670 | deadmem += sizeudata(gco2u(curr)); | 645 | deadmem += sizeudata(gco2u(curr)); |
671 | *p = gch(curr)->next; /* remove 'curr' from 'tmudata' list */ | 646 | *p = gch(curr)->next; /* remove 'curr' from 'rootgc' list */ |
672 | /* link 'curr' at the end of 'tobefnz' list */ | 647 | /* link 'curr' at the end of 'tobefnz' list */ |
673 | if (g->tobefnz == NULL) /* list is empty? */ | 648 | gch(curr)->next = *lastnext; |
674 | g->tobefnz = gch(curr)->next = curr; /* creates a circular list */ | 649 | *lastnext = curr; |
675 | else { | 650 | lastnext = &gch(curr)->next; |
676 | gch(curr)->next = gch(g->tobefnz)->next; | ||
677 | gch(g->tobefnz)->next = curr; | ||
678 | g->tobefnz = curr; | ||
679 | } | ||
680 | } | 651 | } |
681 | } | 652 | } |
682 | return deadmem; | 653 | return deadmem; |
@@ -689,13 +660,13 @@ void luaC_checkfinalizer (lua_State *L, Udata *u) { | |||
689 | isfinalized(&u->uv) || /* ... or is finalized... */ | 660 | isfinalized(&u->uv) || /* ... or is finalized... */ |
690 | gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */ | 661 | gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */ |
691 | return; /* nothing to be done */ | 662 | return; /* nothing to be done */ |
692 | else { /* move 'u' from root list to 'tmudata' list */ | 663 | else { /* move 'u' to 2nd part of root list */ |
693 | GCObject **p; | 664 | GCObject **p; |
694 | for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next) | 665 | for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next) |
695 | lua_assert(*p != NULL); /* 'u' must be in this list */ | 666 | lua_assert(*p != obj2gco(g->mainthread)); /* 'u' must be in this list */ |
696 | *p = u->uv.next; /* remove 'u' from root list */ | 667 | *p = u->uv.next; /* remove 'u' from root list */ |
697 | u->uv.next = g->tmudata; /* link it in 'tmudata' list */ | 668 | u->uv.next = g->mainthread->next; /* re-link it in list */ |
698 | g->tmudata = obj2gco(u); | 669 | g->mainthread->next = obj2gco(u); |
699 | l_setbit(u->uv.marked, SEPARATED); /* mark it as such */ | 670 | l_setbit(u->uv.marked, SEPARATED); /* mark it as such */ |
700 | } | 671 | } |
701 | } | 672 | } |
@@ -716,9 +687,8 @@ void luaC_freeall (lua_State *L) { | |||
716 | /* mask to collect all elements */ | 687 | /* mask to collect all elements */ |
717 | g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); | 688 | g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); |
718 | sweepwholelist(L, &g->rootgc); | 689 | sweepwholelist(L, &g->rootgc); |
719 | lua_assert(g->rootgc == obj2gco(L)); | 690 | lua_assert(g->rootgc == obj2gco(g->mainthread)); |
720 | sweepwholelist(L, &g->tmudata); | 691 | lua_assert(g->mainthread->next == NULL); |
721 | lua_assert(g->tmudata == NULL); | ||
722 | for (i = 0; i < g->strt.size; i++) /* free all string lists */ | 692 | for (i = 0; i < g->strt.size; i++) /* free all string lists */ |
723 | sweepwholelist(L, &g->strt.hash[i]); | 693 | sweepwholelist(L, &g->strt.hash[i]); |
724 | lua_assert(g->strt.nuse == 0); | 694 | lua_assert(g->strt.nuse == 0); |
@@ -781,18 +751,10 @@ static l_mem singlestep (lua_State *L) { | |||
781 | case GCSsweepstring: { | 751 | case GCSsweepstring: { |
782 | correctestimate(g, sweepwholelist(L, &g->strt.hash[g->sweepstrgc++])); | 752 | correctestimate(g, sweepwholelist(L, &g->strt.hash[g->sweepstrgc++])); |
783 | if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ | 753 | if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ |
784 | g->sweepgc = &g->tmudata; | ||
785 | g->gcstate = GCSsweeptmu; /* end sweep-string phase */ | ||
786 | } | ||
787 | return GCSWEEPCOST; | ||
788 | } | ||
789 | case GCSsweeptmu: { | ||
790 | g->sweepgc = unmarklist(g, g->sweepgc, GCSWEEPMAX); | ||
791 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ | ||
792 | g->sweepgc = &g->rootgc; | 754 | g->sweepgc = &g->rootgc; |
793 | g->gcstate = GCSsweep; /* sweep all other objects */ | 755 | g->gcstate = GCSsweep; /* sweep all other objects */ |
794 | } | 756 | } |
795 | return GCSWEEPMAX*GCSWEEPCOST; | 757 | return GCSWEEPCOST; |
796 | } | 758 | } |
797 | case GCSsweep: { | 759 | case GCSsweep: { |
798 | correctestimate(g, g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX)); | 760 | correctestimate(g, g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX)); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.h,v 2.17 2007/10/29 16:51:20 roberto Exp roberto $ | 2 | ** $Id: lgc.h,v 2.18 2008/02/19 18:55:09 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,26 +17,24 @@ | |||
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 GCSsweeptmu 3 | 20 | #define GCSsweep 3 |
21 | #define GCSsweep 4 | 21 | #define GCSfinalize 4 |
22 | #define GCSfinalize 5 | ||
23 | 22 | ||
24 | 23 | ||
25 | #define issweep(g) \ | 24 | #define issweep(g) (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep) |
26 | (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep) | ||
27 | 25 | ||
28 | 26 | ||
29 | /* | 27 | /* |
30 | ** some userful bit tricks | 28 | ** some userful bit tricks |
31 | */ | 29 | */ |
32 | #define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) | 30 | #define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) |
33 | #define setbits(x,m) ((x) |= (m)) | 31 | #define setbits(x,m) ((x) |= (m)) |
34 | #define testbits(x,m) ((x) & (m)) | 32 | #define testbits(x,m) ((x) & (m)) |
35 | #define bitmask(b) (1<<(b)) | 33 | #define bitmask(b) (1<<(b)) |
36 | #define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) | 34 | #define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) |
37 | #define l_setbit(x,b) setbits(x, bitmask(b)) | 35 | #define l_setbit(x,b) setbits(x, bitmask(b)) |
38 | #define resetbit(x,b) resetbits(x, bitmask(b)) | 36 | #define resetbit(x,b) resetbits(x, bitmask(b)) |
39 | #define testbit(x,b) testbits(x, bitmask(b)) | 37 | #define testbit(x,b) testbits(x, bitmask(b)) |
40 | #define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2))) | 38 | #define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2))) |
41 | #define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2))) | 39 | #define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2))) |
42 | 40 | ||
@@ -48,7 +46,7 @@ | |||
48 | ** bit 1 - object is white (type 1) | 46 | ** bit 1 - object is white (type 1) |
49 | ** bit 2 - object is black | 47 | ** bit 2 - object is black |
50 | ** bit 3 - for userdata: has been finalized | 48 | ** bit 3 - for userdata: has been finalized |
51 | ** bit 4 - for userdata: it's not in rootgc list (it's in tmudata or tobefnz) | 49 | ** bit 4 - for userdata: it's in 2nd part of rootgc list or in tobefnz |
52 | ** bit 5 - object is fixed (should not be collected) | 50 | ** bit 5 - object is fixed (should not be collected) |
53 | ** bit 6 - object is "super" fixed (only the main thread) | 51 | ** bit 6 - object is "super" fixed (only the main thread) |
54 | */ | 52 | */ |
@@ -99,7 +97,7 @@ | |||
99 | { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } | 97 | { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } |
100 | 98 | ||
101 | LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all); | 99 | LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all); |
102 | LUAI_FUNC void luaC_callGCTM (lua_State *L); | 100 | LUAI_FUNC void luaC_callAllGCTM (lua_State *L); |
103 | LUAI_FUNC void luaC_freeall (lua_State *L); | 101 | LUAI_FUNC void luaC_freeall (lua_State *L); |
104 | LUAI_FUNC void luaC_step (lua_State *L); | 102 | LUAI_FUNC void luaC_step (lua_State *L); |
105 | LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); | 103 | LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstate.c,v 2.43 2008/02/11 15:45:30 roberto Exp roberto $ | 2 | ** $Id: lstate.c,v 2.44 2008/02/19 18:55:09 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 | */ |
@@ -181,7 +181,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
181 | g->gray = NULL; | 181 | g->gray = NULL; |
182 | g->grayagain = NULL; | 182 | g->grayagain = NULL; |
183 | g->weak = g->ephemeron = g->allweak = NULL; | 183 | g->weak = g->ephemeron = g->allweak = NULL; |
184 | g->tmudata = g->tobefnz = NULL; | 184 | g->tobefnz = NULL; |
185 | g->totalbytes = sizeof(LG); | 185 | g->totalbytes = sizeof(LG); |
186 | g->gcpause = LUAI_GCPAUSE; | 186 | g->gcpause = LUAI_GCPAUSE; |
187 | g->gcstepmul = LUAI_GCMUL; | 187 | g->gcstepmul = LUAI_GCMUL; |
@@ -200,7 +200,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
200 | 200 | ||
201 | static void callallgcTM (lua_State *L, void *ud) { | 201 | static void callallgcTM (lua_State *L, void *ud) { |
202 | UNUSED(ud); | 202 | UNUSED(ud); |
203 | luaC_callGCTM(L); /* call GC metamethods for all udata */ | 203 | luaC_callAllGCTM(L); /* call GC metamethods for all udata */ |
204 | } | 204 | } |
205 | 205 | ||
206 | 206 | ||
@@ -209,7 +209,7 @@ LUA_API void lua_close (lua_State *L) { | |||
209 | lua_lock(L); | 209 | lua_lock(L); |
210 | luaF_close(L, L->stack); /* close all upvalues for this thread */ | 210 | luaF_close(L, L->stack); /* close all upvalues for this thread */ |
211 | luaC_separateudata(L, 1); /* separate all udata with GC metamethods */ | 211 | luaC_separateudata(L, 1); /* separate all udata with GC metamethods */ |
212 | lua_assert(G(L)->tmudata == NULL); | 212 | lua_assert(L->next == NULL); |
213 | L->errfunc = 0; /* no error function during GC metamethods */ | 213 | L->errfunc = 0; /* no error function during GC metamethods */ |
214 | do { /* repeat until no more errors */ | 214 | do { /* repeat until no more errors */ |
215 | L->ci = L->base_ci; | 215 | L->ci = L->base_ci; |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstate.h,v 2.32 2008/02/19 18:55:09 roberto Exp roberto $ | 2 | ** $Id: lstate.h,v 2.33 2008/06/23 16:51:08 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 | */ |
@@ -14,6 +14,32 @@ | |||
14 | #include "lzio.h" | 14 | #include "lzio.h" |
15 | 15 | ||
16 | 16 | ||
17 | /* | ||
18 | |||
19 | ** Some notes about garbage-collected objects: All objects in Lua must | ||
20 | ** be kept somehow accessible until being freed. | ||
21 | ** | ||
22 | ** Lua keeps most objects linked in list g->rootgc. The link uses field | ||
23 | ** 'next' of the CommonHeader. | ||
24 | ** | ||
25 | ** Strings are kept in several lists headed by the array g->strt.hash. | ||
26 | ** | ||
27 | ** Open upvalues are not subject to independent garbage collection. They | ||
28 | ** are collected together with their respective threads. Lua keeps a | ||
29 | ** double-linked list with all open upvalues (g->uvhead) so that it can | ||
30 | ** mark objects referred by them. (They are always gray, so they must | ||
31 | ** be remarked in the atomic step. Usually their contents would be marked | ||
32 | ** when traversing the respective threads, but the thread may already be | ||
33 | ** dead, while the upvalue is still accessible through closures.) | ||
34 | ** | ||
35 | ** Userdata with finalizers are kept in the list g->rootgc, but after | ||
36 | ** the mainthread, which should be otherwise the last element in the | ||
37 | ** list, as it was the first one inserted there. | ||
38 | ** | ||
39 | ** The list g->tobefnz links all userdata being finalized. | ||
40 | |||
41 | */ | ||
42 | |||
17 | 43 | ||
18 | struct lua_longjmp; /* defined in ldo.c */ | 44 | struct lua_longjmp; /* defined in ldo.c */ |
19 | 45 | ||
@@ -86,8 +112,7 @@ typedef struct global_State { | |||
86 | GCObject *weak; /* list of tables with weak values */ | 112 | GCObject *weak; /* list of tables with weak values */ |
87 | GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ | 113 | GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ |
88 | GCObject *allweak; /* list of all-weak tables */ | 114 | GCObject *allweak; /* list of all-weak tables */ |
89 | GCObject *tmudata; /* list of userdata with finalizers */ | 115 | GCObject *tobefnz; /* list of userdata to be GC */ |
90 | GCObject *tobefnz; /* last element of list of userdata to be GC */ | ||
91 | Mbuffer buff; /* temporary buffer for string concatentation */ | 116 | Mbuffer buff; /* temporary buffer for string concatentation */ |
92 | lu_mem GCthreshold; | 117 | lu_mem GCthreshold; |
93 | lu_mem totalbytes; /* number of bytes currently allocated */ | 118 | lu_mem totalbytes; /* number of bytes currently allocated */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltests.c,v 2.51 2008/06/13 17:07:10 roberto Exp roberto $ | 2 | ** $Id: ltests.c,v 2.52 2008/06/23 16:50:34 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 | */ |
@@ -365,10 +365,15 @@ int lua_checkmemory (lua_State *L) { | |||
365 | GCObject *o; | 365 | GCObject *o; |
366 | UpVal *uv; | 366 | UpVal *uv; |
367 | checkstack(g, g->mainthread); | 367 | checkstack(g, g->mainthread); |
368 | for (o = g->rootgc; o != NULL; o = gch(o)->next) | 368 | for (o = g->rootgc; o != obj2gco(g->mainthread); o = gch(o)->next) { |
369 | lua_assert(!testbits(o->gch.marked, bit2mask(SEPARATED, SFIXEDBIT))); | ||
369 | checkobject(g, o); | 370 | checkobject(g, o); |
370 | for (o = g->tmudata; o != NULL; o = gch(o)->next) { | 371 | } |
371 | lua_assert(!isdead(g, o)); | 372 | lua_assert(testbit(o->gch.marked, SFIXEDBIT)); |
373 | for (o = gch(o)->next; o != NULL; o = gch(o)->next) { | ||
374 | lua_assert(gch(o)->tt == LUA_TUSERDATA && | ||
375 | !isdead(g, o) && | ||
376 | testbit(o->gch.marked, SEPARATED)); | ||
372 | checkobject(g, o); | 377 | checkobject(g, o); |
373 | } | 378 | } |
374 | for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { | 379 | for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { |
@@ -535,7 +540,6 @@ static int gcstate (lua_State *L) { | |||
535 | switch(G(L)->gcstate) { | 540 | switch(G(L)->gcstate) { |
536 | case GCSpropagate: lua_pushstring(L, "propagate"); break; | 541 | case GCSpropagate: lua_pushstring(L, "propagate"); break; |
537 | case GCSsweepstring: lua_pushstring(L, "sweep strings"); break; | 542 | case GCSsweepstring: lua_pushstring(L, "sweep strings"); break; |
538 | case GCSsweeptmu: lua_pushstring(L, "sweep udata with __gc"); break; | ||
539 | case GCSsweep: lua_pushstring(L, "sweep"); break; | 543 | case GCSsweep: lua_pushstring(L, "sweep"); break; |
540 | case GCSfinalize: lua_pushstring(L, "finalize"); break; | 544 | case GCSfinalize: lua_pushstring(L, "finalize"); break; |
541 | default: lua_assert(0); | 545 | default: lua_assert(0); |