aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2010-03-24 10:07:01 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2010-03-24 10:07:01 -0300
commit4433dbb5f5ac0bb6118bc49ddf061f194c070814 (patch)
tree628f9da77c0cf6a80556a9c189f2528a3d7d7ca4
parent5cb128ea540b33dbc6be659d5dfc3c64c57d78d9 (diff)
downloadlua-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.c56
-rw-r--r--lgc.h12
-rw-r--r--lstate.c5
-rw-r--r--lstate.h11
-rw-r--r--ltests.c8
5 files changed, 48 insertions, 44 deletions
diff --git a/lgc.c b/lgc.c
index 0ae5aafd..f19ca70b 100644
--- a/lgc.c
+++ b/lgc.c
@@ -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,
139void luaC_linkupval (lua_State *L, UpVal *uv) { 141void 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) {
549static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { 551static 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) {
597static Udata *udata2finalize (global_State *g) { 600static 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' */
644void luaC_separateudata (lua_State *L, int all) { 647void 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));
diff --git a/lgc.h b/lgc.h
index aa969b38..c01a8cc8 100644
--- a/lgc.h
+++ b/lgc.h
@@ -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
diff --git a/lstate.c b/lstate.c
index c2fe534a..200ddd69 100644
--- a/lstate.c
+++ b/lstate.c
@@ -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;
diff --git a/lstate.h b/lstate.h
index ebf4e4af..45eccf8a 100644
--- a/lstate.h
+++ b/lstate.h
@@ -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 */
diff --git a/ltests.c b/ltests.c
index 3d0fa117..123ff64e 100644
--- a/ltests.c
+++ b/ltests.c
@@ -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) {
188static void printobj (global_State *g, GCObject *o) { 188static 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));