aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2013-09-03 12:37:10 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2013-09-03 12:37:10 -0300
commitaeff4f79fa10caef29617652aa49b77055f4045e (patch)
tree8f411b76c7c0b496c01224a36852ed38527dba3d
parent1bf4faec64aca03e1036235e72675f0617124140 (diff)
downloadlua-aeff4f79fa10caef29617652aa49b77055f4045e.tar.gz
lua-aeff4f79fa10caef29617652aa49b77055f4045e.tar.bz2
lua-aeff4f79fa10caef29617652aa49b77055f4045e.zip
local collection now calls finalizers
-rw-r--r--bugs19
-rw-r--r--lgc.c120
-rw-r--r--lgc.h11
-rw-r--r--lstate.c6
-rw-r--r--lstate.h5
-rw-r--r--ltests.c63
6 files changed, 144 insertions, 80 deletions
diff --git a/bugs b/bugs
index 14d143bb..d1f429a6 100644
--- a/bugs
+++ b/bugs
@@ -1880,8 +1880,8 @@ patch = [[
1880+++ lundump.c 2008/04/04 19:51:41 2.7.1.4 1880+++ lundump.c 2008/04/04 19:51:41 2.7.1.4
1881@@ -1,5 +1,5 @@ 1881@@ -1,5 +1,5 @@
1882 /* 1882 /*
1883-** $Id: bugs,v 1.125 2013/07/05 18:02:28 roberto Exp roberto $ 1883-** $Id: bugs,v 1.126 2013/08/30 15:51:12 roberto Exp roberto $
1884+** $Id: bugs,v 1.125 2013/07/05 18:02:28 roberto Exp roberto $ 1884+** $Id: bugs,v 1.126 2013/08/30 15:51:12 roberto Exp roberto $
1885 ** load precompiled Lua chunks 1885 ** load precompiled Lua chunks
1886 ** See Copyright Notice in lua.h 1886 ** See Copyright Notice in lua.h
1887 */ 1887 */
@@ -3133,7 +3133,20 @@ patch = [[
3133 return ts; 3133 return ts;
3134]] 3134]]
3135} 3135}
3136]=] 3136]
3137
3138
3139Bug{
3140what = [[Call to macro 'luai_userstateclose' should be done only
3141after the calls to __gc methods.]],
3142report = [[Jean-Luc Jumpertz, 2013/09/02]],
3143since = [[ ]],
3144fix = nil,
3145example = [[No example]],
3146patch = [[
3147]]
3148}
3149]=]=]
3137 3150
3138 3151
3139--[=[ 3152--[=[
diff --git a/lgc.c b/lgc.c
index aaa57a07..da1d3fdc 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 2.156 2013/08/29 13:34:16 roberto Exp roberto $ 2** $Id: lgc.c,v 2.157 2013/08/30 19:14:26 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*/
@@ -777,8 +777,16 @@ static GCObject *udata2finalize (global_State *g) {
777 GCObject *o = g->tobefnz; /* get first element */ 777 GCObject *o = g->tobefnz; /* get first element */
778 lua_assert(tofinalize(o)); 778 lua_assert(tofinalize(o));
779 g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ 779 g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */
780 gch(o)->next = g->allgc; /* return it to 'allgc' list */ 780 if (islocal(o)) {
781 g->allgc = o; 781 lua_assert(!testbit(gch(o)->marked, LOCALMARK));
782 gch(o)->next = g->localgc; /* return it to 'localgc' list */
783 g->localgc = o;
784 }
785 else { /* return it to 'allgc' list */
786 gch(o)->next = g->allgc;
787 g->allgc = o;
788 l_setbit(gch(o)->marked, LOCALMARK);
789 }
782 resetbit(gch(o)->marked, FINALIZEDBIT); /* object is back in 'allgc' */ 790 resetbit(gch(o)->marked, FINALIZEDBIT); /* object is back in 'allgc' */
783 if (!keepinvariant(g)) /* not keeping invariant? */ 791 if (!keepinvariant(g)) /* not keeping invariant? */
784 makewhite(g, o); /* "sweep" object */ 792 makewhite(g, o); /* "sweep" object */
@@ -825,23 +833,38 @@ static void GCTM (lua_State *L, int propagateerrors) {
825 833
826 834
827/* 835/*
828** move all unreachable objects (or 'all' objects) that need 836** call all pending finalizers
829** finalization from list 'finobj' to list 'tobefnz' (to be finalized)
830*/ 837*/
831static void separatetobefnz (lua_State *L, int all) { 838static void callallpendingfinalizers (lua_State *L, int propagateerrors) {
832 global_State *g = G(L); 839 global_State *g = G(L);
833 GCObject **p = &g->finobj; 840 while (g->tobefnz)
841 GCTM(L, propagateerrors);
842}
843
844
845/*
846** find last 'next' field in list 'p' list (to add elements in its end)
847*/
848static GCObject **findlast (GCObject **p) {
849 while (*p != NULL)
850 p = &gch(*p)->next;
851 return p;
852}
853
854
855/*
856** move all unreachable objects (or 'all' objects) that need
857** finalization from list 'p' to list 'tobefnz' (to be finalized)
858*/
859static void separatetobefnz_aux (global_State *g, GCObject **p, int all) {
834 GCObject *curr; 860 GCObject *curr;
835 GCObject **lastnext = &g->tobefnz; 861 GCObject **lastnext = findlast(&g->tobefnz);
836 /* find last 'next' field in 'tobefnz' list (to add elements in its end) */
837 while (*lastnext != NULL)
838 lastnext = &gch(*lastnext)->next;
839 while ((curr = *p) != NULL) { /* traverse all finalizable objects */ 862 while ((curr = *p) != NULL) { /* traverse all finalizable objects */
840 lua_assert(tofinalize(curr)); 863 lua_assert(tofinalize(curr));
841 if (!(iswhite(curr) || all)) /* not being collected? */ 864 if (!(iswhite(curr) || all)) /* not being collected? */
842 p = &gch(curr)->next; /* don't bother with it */ 865 p = &gch(curr)->next; /* don't bother with it */
843 else { 866 else {
844 *p = gch(curr)->next; /* remove 'curr' from 'finobj' list */ 867 *p = gch(curr)->next; /* remove 'curr' from "fin" list */
845 gch(curr)->next = *lastnext; /* link at the end of 'tobefnz' list */ 868 gch(curr)->next = *lastnext; /* link at the end of 'tobefnz' list */
846 *lastnext = curr; 869 *lastnext = curr;
847 lastnext = &gch(curr)->next; 870 lastnext = &gch(curr)->next;
@@ -850,9 +873,15 @@ static void separatetobefnz (lua_State *L, int all) {
850} 873}
851 874
852 875
876static void separatetobefnz (global_State *g, int all) {
877 separatetobefnz_aux(g, &g->localfin, all);
878 separatetobefnz_aux(g, &g->finobj, all);
879}
880
881
853/* 882/*
854** if object 'o' has a finalizer, remove it from 'allgc' list (must 883** if object 'o' has a finalizer, remove it from 'allgc' list (must
855** search the list to find it) and link it in 'finobj' list. 884** search the list to find it) and link it in 'localfin' or 'finobj' list.
856*/ 885*/
857void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { 886void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
858 global_State *g = G(L); 887 global_State *g = G(L);
@@ -869,11 +898,11 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
869 /* search for pointer pointing to 'o' */ 898 /* search for pointer pointing to 'o' */
870 p = (testbit(ho->marked, LOCALMARK)) ? &g->allgc : &g->localgc; 899 p = (testbit(ho->marked, LOCALMARK)) ? &g->allgc : &g->localgc;
871 for (; *p != o; p = &gch(*p)->next) { /* empty */ } 900 for (; *p != o; p = &gch(*p)->next) { /* empty */ }
872 *p = ho->next; /* remove 'o' from 'allgc' list */ 901 *p = ho->next; /* remove 'o' from its list */
873 ho->next = g->finobj; /* link it in list 'finobj' */ 902 p = (testbit(ho->marked, LOCALMARK)) ? &g->finobj : &g->localfin;
874 g->finobj = o; 903 ho->next = *p; /* link it in a "fin" list */
904 *p = o;
875 l_setbit(ho->marked, FINALIZEDBIT); /* mark it as such */ 905 l_setbit(ho->marked, FINALIZEDBIT); /* mark it as such */
876 l_setbit(ho->marked, LOCALMARK); /* not in 'localgc' anymore */
877 if (!keepinvariant(g)) /* not keeping invariant? */ 906 if (!keepinvariant(g)) /* not keeping invariant? */
878 makewhite(g, o); /* "sweep" object */ 907 makewhite(g, o); /* "sweep" object */
879 } 908 }
@@ -918,7 +947,8 @@ static void localmark (global_State *g) {
918} 947}
919 948
920 949
921static void localsweep (lua_State *L, global_State *g, GCObject **p) { 950static void localsweep (lua_State *L, global_State *g) {
951 GCObject **p = &g->localgc;
922 while (*p != NULL) { 952 while (*p != NULL) {
923 GCObject *curr = *p; 953 GCObject *curr = *p;
924 if (!islocal(curr)) { /* is 'curr' no more local? */ 954 if (!islocal(curr)) { /* is 'curr' no more local? */
@@ -946,11 +976,41 @@ static void localsweep (lua_State *L, global_State *g, GCObject **p) {
946} 976}
947 977
948 978
979static void separatelocal (global_State *g, int all) {
980 GCObject **p = &g->localfin;
981 GCObject **lastnext = findlast(&g->tobefnz);
982 while (*p != NULL) {
983 GCObject *curr = *p;
984 if (!islocal(curr)) { /* is 'curr' no more local? */
985 *p = curr->gch.next; /* remove 'curr' from list */
986 curr->gch.next = g->finobj; /* link 'curr' in 'finobj' list */
987 g->finobj = curr;
988 /* mark it as out of local list */
989 l_setbit(curr->gch.marked, LOCALMARK);
990 }
991 else { /* still local */
992 if (testbit(curr->gch.marked, LOCALMARK) && !all) { /* locally alive? */
993 resetbit(curr->gch.marked, LOCALMARK);
994 p = &curr->gch.next; /* go to next element */
995 }
996 else { /* object is "dead" */
997 *p = curr->gch.next; /* remove 'curr' from list */
998 curr->gch.next = *lastnext; /* link at the end of 'tobefnz' list */
999 *lastnext = curr;
1000 lastnext = &curr->gch.next;
1001 }
1002 }
1003 }
1004}
1005
1006
949static void luaC_localcollection (lua_State *L) { 1007static void luaC_localcollection (lua_State *L) {
950 global_State *g = G(L); 1008 global_State *g = G(L);
951 lua_assert(g->gcstate == GCSpause); 1009 lua_assert(g->gcstate == GCSpause);
952 localmark(g); 1010 localmark(g);
953 localsweep(L, g, &g->localgc); 1011 localsweep(L, g);
1012 separatelocal(g, 0);
1013 callallpendingfinalizers(L, 1);
954} 1014}
955 1015
956/* }====================================================== */ 1016/* }====================================================== */
@@ -997,24 +1057,15 @@ static int entersweep (lua_State *L) {
997} 1057}
998 1058
999 1059
1000/*
1001** call all pending finalizers
1002*/
1003static void callallpendingfinalizers (lua_State *L, int propagateerrors) {
1004 global_State *g = G(L);
1005 while (g->tobefnz)
1006 GCTM(L, propagateerrors);
1007}
1008
1009
1010void luaC_freeallobjects (lua_State *L) { 1060void luaC_freeallobjects (lua_State *L) {
1011 global_State *g = G(L); 1061 global_State *g = G(L);
1012 separatetobefnz(L, 1); /* separate all objects with finalizers */ 1062 separatetobefnz(g, 1); /* separate all objects with finalizers */
1013 lua_assert(g->finobj == NULL); 1063 lua_assert(g->finobj == NULL && g->localfin == NULL);
1014 callallpendingfinalizers(L, 0); 1064 callallpendingfinalizers(L, 0);
1015 g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ 1065 g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */
1016 g->gckind = KGC_NORMAL; 1066 g->gckind = KGC_NORMAL;
1017 sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ 1067 sweepwholelist(L, &g->localfin); /* finalizers can create objs. with fins. */
1068 sweepwholelist(L, &g->finobj);
1018 sweepwholelist(L, &g->localgc); 1069 sweepwholelist(L, &g->localgc);
1019 sweepwholelist(L, &g->allgc); 1070 sweepwholelist(L, &g->allgc);
1020 sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ 1071 sweepwholelist(L, &g->fixedgc); /* collect fixed objects */
@@ -1045,7 +1096,7 @@ static l_mem atomic (lua_State *L) {
1045 clearvalues(g, g->allweak, NULL); 1096 clearvalues(g, g->allweak, NULL);
1046 origweak = g->weak; origall = g->allweak; 1097 origweak = g->weak; origall = g->allweak;
1047 work += g->GCmemtrav; /* stop counting (objects being finalized) */ 1098 work += g->GCmemtrav; /* stop counting (objects being finalized) */
1048 separatetobefnz(L, 0); /* separate objects to be finalized */ 1099 separatetobefnz(g, 0); /* separate objects to be finalized */
1049 markbeingfnz(g); /* mark objects that will be finalized */ 1100 markbeingfnz(g); /* mark objects that will be finalized */
1050 propagateall(g); /* remark, to propagate `preserveness' */ 1101 propagateall(g); /* remark, to propagate `preserveness' */
1051 work -= g->GCmemtrav; /* restart counting */ 1102 work -= g->GCmemtrav; /* restart counting */
@@ -1106,6 +1157,9 @@ static lu_mem singlestep (lua_State *L) {
1106 return work + sw * GCSWEEPCOST; 1157 return work + sw * GCSWEEPCOST;
1107 } 1158 }
1108 case GCSsweeplocal: { 1159 case GCSsweeplocal: {
1160 return sweepstep(L, g, GCSsweeplocfin, &g->localfin);
1161 }
1162 case GCSsweeplocfin: {
1109 return sweepstep(L, g, GCSsweepfin, &g->finobj); 1163 return sweepstep(L, g, GCSsweepfin, &g->finobj);
1110 } 1164 }
1111 case GCSsweepfin: { 1165 case GCSsweepfin: {
diff --git a/lgc.h b/lgc.h
index db309360..7e385136 100644
--- a/lgc.h
+++ b/lgc.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.h,v 2.69 2013/08/29 13:49:57 roberto Exp roberto $ 2** $Id: lgc.h,v 2.70 2013/08/30 19:14:26 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*/
@@ -39,10 +39,11 @@
39#define GCSpropagate 0 39#define GCSpropagate 0
40#define GCSatomic 1 40#define GCSatomic 1
41#define GCSsweeplocal 2 41#define GCSsweeplocal 2
42#define GCSsweepfin 3 42#define GCSsweeplocfin 3
43#define GCSsweepall 4 43#define GCSsweepfin 4
44#define GCSsweepmainth 5 44#define GCSsweepall 5
45#define GCSpause 6 45#define GCSsweepmainth 6
46#define GCSpause 7
46 47
47 48
48#define issweepphase(g) \ 49#define issweepphase(g) \
diff --git a/lstate.c b/lstate.c
index 842f6a42..e81d968d 100644
--- a/lstate.c
+++ b/lstate.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.c,v 2.108 2013/08/28 18:30:26 roberto Exp roberto $ 2** $Id: lstate.c,v 2.109 2013/08/30 19:14:26 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*/
@@ -296,9 +296,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
296 g->panic = NULL; 296 g->panic = NULL;
297 g->version = lua_version(NULL); 297 g->version = lua_version(NULL);
298 g->gcstate = GCSpause; 298 g->gcstate = GCSpause;
299 g->allgc = NULL; 299 g->localgc = g->localfin = g->allgc = g->finobj = NULL;
300 g->localgc = NULL;
301 g->finobj = NULL;
302 g->tobefnz = NULL; 300 g->tobefnz = NULL;
303 g->fixedgc = NULL; 301 g->fixedgc = NULL;
304 g->sweepgc = NULL; 302 g->sweepgc = NULL;
diff --git a/lstate.h b/lstate.h
index e03b75f2..38bbb982 100644
--- a/lstate.h
+++ b/lstate.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.h,v 2.91 2013/08/27 18:53:35 roberto Exp roberto $ 2** $Id: lstate.h,v 2.92 2013/08/30 19:14:26 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*/
@@ -121,8 +121,9 @@ typedef struct global_State {
121 lu_byte gcrunning; /* true if GC is running */ 121 lu_byte gcrunning; /* true if GC is running */
122 GCObject *allgc; /* list of all collectable objects */ 122 GCObject *allgc; /* list of all collectable objects */
123 GCObject *localgc; /* list of local objects */ 123 GCObject *localgc; /* list of local objects */
124 GCObject *finobj; /* list of collectable objects with finalizers */ 124 GCObject *localfin; /* list of local objects with finalizers */
125 GCObject **sweepgc; /* current position of sweep in list */ 125 GCObject **sweepgc; /* current position of sweep in list */
126 GCObject *finobj; /* list of collectable objects with finalizers */
126 GCObject *gray; /* list of gray objects */ 127 GCObject *gray; /* list of gray objects */
127 GCObject *grayagain; /* list of objects to be traversed atomically */ 128 GCObject *grayagain; /* list of objects to be traversed atomically */
128 GCObject *weak; /* list of tables with weak values */ 129 GCObject *weak; /* list of tables with weak values */
diff --git a/ltests.c b/ltests.c
index ec7631e7..a8890328 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ltests.c,v 2.151 2013/08/27 20:04:00 roberto Exp roberto $ 2** $Id: ltests.c,v 2.152 2013/08/30 19:14:26 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*/
@@ -202,17 +202,8 @@ static int testobjref2 (GCObject *f, GCObject *t) {
202 202
203 203
204static void printobj (global_State *g, GCObject *o) { 204static void printobj (global_State *g, GCObject *o) {
205 int i = 1; 205 printf("||%s(%p)-%s-%c(%02X)||",
206 GCObject *p; 206 ttypename(novariant(gch(o)->tt)), (void *)o,
207 for (p = g->allgc; p != o && p != NULL; p = gch(p)->next) i++;
208 if (p == NULL) {
209 i = 1;
210 for (p = g->finobj; p != o && p != NULL; p = gch(p)->next) i++;
211 if (p == NULL) i = 0; /* zero means 'not found' */
212 else i = -i; /* negative means 'found in findobj list */
213 }
214 printf("||%d:%s(%p)-%s-%c(%02X)||",
215 i, ttypename(novariant(gch(o)->tt)), (void *)o,
216 islocal(o)?"L":"NL", 207 islocal(o)?"L":"NL",
217 isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', gch(o)->marked); 208 isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', gch(o)->marked);
218} 209}
@@ -344,9 +335,10 @@ static void checkstack (global_State *g, lua_State *L1) {
344 335
345static void checkobject (global_State *g, GCObject *o, int maybedead) { 336static void checkobject (global_State *g, GCObject *o, int maybedead) {
346 if (isdead(g, o)) 337 if (isdead(g, o))
347 lua_assert(maybedead); 338 lua_assert(maybedead && issweepphase(g));
348 else { 339 else {
349 lua_assert(g->gcstate != GCSpause || iswhite(o)); 340 lua_assert(g->gcstate != GCSpause || iswhite(o));
341 lua_assert(!islocal(o) || !testbit(gch(o)->marked, LOCALMARK));
350 switch (gch(o)->tt) { 342 switch (gch(o)->tt) {
351 case LUA_TUSERDATA: { 343 case LUA_TUSERDATA: {
352 Table *mt = gco2u(o)->metatable; 344 Table *mt = gco2u(o)->metatable;
@@ -384,18 +376,18 @@ static void checkobject (global_State *g, GCObject *o, int maybedead) {
384 376
385#define TESTGRAYBIT 7 377#define TESTGRAYBIT 7
386 378
387static void checkgraylist (global_State *g, GCObject *l) { 379static void checkgraylist (global_State *g, GCObject *o) {
388 UNUSED(g); /* better to keep it available if we need to print an object */ 380 ((void)g); /* better to keep it available if we need to print an object */
389 while (l) { 381 while (o) {
390 lua_assert(isgray(l)); 382 lua_assert(isgray(o));
391 lua_assert(!testbit(l->gch.marked, TESTGRAYBIT)); 383 lua_assert(!testbit(o->gch.marked, TESTGRAYBIT));
392 l_setbit(l->gch.marked, TESTGRAYBIT); 384 l_setbit(o->gch.marked, TESTGRAYBIT);
393 switch (gch(l)->tt) { 385 switch (gch(o)->tt) {
394 case LUA_TTABLE: l = gco2t(l)->gclist; break; 386 case LUA_TTABLE: o = gco2t(o)->gclist; break;
395 case LUA_TLCL: l = gco2lcl(l)->gclist; break; 387 case LUA_TLCL: o = gco2lcl(o)->gclist; break;
396 case LUA_TCCL: l = gco2ccl(l)->gclist; break; 388 case LUA_TCCL: o = gco2ccl(o)->gclist; break;
397 case LUA_TTHREAD: l = gco2th(l)->gclist; break; 389 case LUA_TTHREAD: o = gco2th(o)->gclist; break;
398 case LUA_TPROTO: l = gco2p(l)->gclist; break; 390 case LUA_TPROTO: o = gco2p(o)->gclist; break;
399 default: lua_assert(0); /* other objects cannot be gray */ 391 default: lua_assert(0); /* other objects cannot be gray */
400 } 392 }
401 } 393 }
@@ -451,30 +443,35 @@ int lua_checkmemory (lua_State *L) {
451 if (gch(o)->tt == LUA_TTHREAD) isthread = 1; /* now travesing threads... */ 443 if (gch(o)->tt == LUA_TTHREAD) isthread = 1; /* now travesing threads... */
452 else lua_assert(!isthread); /* ... and only threads */ 444 else lua_assert(!isthread); /* ... and only threads */
453 checkobject(g, o, maybedead); 445 checkobject(g, o, maybedead);
454 lua_assert(!tofinalize(o)); 446 lua_assert(!tofinalize(o) && testbit(o->gch.marked, LOCALMARK));
455 lua_assert(testbit(o->gch.marked, LOCALMARK));
456 } 447 }
457 /* check 'finobj' list */ 448 /* check 'finobj' list */
458 checkgray(g, g->finobj); 449 checkgray(g, g->finobj);
459 for (o = g->finobj; o != NULL; o = gch(o)->next) { 450 for (o = g->finobj; o != NULL; o = gch(o)->next) {
460 lua_assert(tofinalize(o)); 451 checkobject(g, o, 0);
452 lua_assert(tofinalize(o) && testbit(o->gch.marked, LOCALMARK));
461 lua_assert(gch(o)->tt == LUA_TUSERDATA || 453 lua_assert(gch(o)->tt == LUA_TUSERDATA ||
462 gch(o)->tt == LUA_TTABLE); 454 gch(o)->tt == LUA_TTABLE);
463 checkobject(g, o, 0);
464 } 455 }
465 /* check 'tobefnz' list */ 456 /* check 'tobefnz' list */
466 checkgray(g, g->tobefnz); 457 checkgray(g, g->tobefnz);
467 for (o = g->tobefnz; o != NULL; o = gch(o)->next) { 458 for (o = g->tobefnz; o != NULL; o = gch(o)->next) {
468 lua_assert(!iswhite(o) || g->gcstate == GCSpause); 459 lua_assert(!iswhite(o) || g->gcstate == GCSpause);
469 lua_assert(!isdead(g, o) && tofinalize(o)); 460 lua_assert(!isdead(g, o) && tofinalize(o));
470 lua_assert(gch(o)->tt == LUA_TUSERDATA || 461 lua_assert(gch(o)->tt == LUA_TUSERDATA || gch(o)->tt == LUA_TTABLE);
471 gch(o)->tt == LUA_TTABLE);
472 } 462 }
473 /* check 'localgc' list */ 463 /* check 'localgc' list */
474 checkgray(g, g->localgc); 464 checkgray(g, g->localgc);
475 for (o = g->localgc; o != NULL; o = gch(o)->next) { 465 for (o = g->localgc; o != NULL; o = gch(o)->next) {
476 checkobject(g, o, 1); 466 checkobject(g, o, 1);
477 lua_assert(!testbit(o->gch.marked, LOCALMARK)); 467 lua_assert(!tofinalize(o) && !testbit(o->gch.marked, LOCALMARK));
468 }
469 /* check 'localfin' list */
470 checkgray(g, g->localfin);
471 for (o = g->localfin; o != NULL; o = gch(o)->next) {
472 checkobject(g, o, 0);
473 lua_assert(tofinalize(o) && !testbit(o->gch.marked, LOCALMARK));
474 lua_assert(gch(o)->tt == LUA_TUSERDATA || gch(o)->tt == LUA_TTABLE);
478 } 475 }
479 return 0; 476 return 0;
480} 477}
@@ -653,7 +650,7 @@ static int gc_local (lua_State *L) {
653 650
654static int gc_state (lua_State *L) { 651static int gc_state (lua_State *L) {
655 static const char *statenames[] = {"propagate", "atomic", 652 static const char *statenames[] = {"propagate", "atomic",
656 "sweeplocal", "sweepfin", "sweepall", "sweepmainth", 653 "sweeplocal", "sweeplocfin", "sweepfin", "sweepall", "sweepmainth",
657 "pause", ""}; 654 "pause", ""};
658 int option = luaL_checkoption(L, 1, "", statenames); 655 int option = luaL_checkoption(L, 1, "", statenames);
659 if (option == GCSpause + 1) { 656 if (option == GCSpause + 1) {