diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2003-11-19 17:41:57 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2003-11-19 17:41:57 -0200 |
commit | 57b6ed68151c965b48f662828c50264c50e81d73 (patch) | |
tree | 2a3e133e49d9cc52b738fea5383b90c8574caff5 /lgc.c | |
parent | 9b9cdfee8b38feb4b94a3750f7539087d020850c (diff) | |
download | lua-57b6ed68151c965b48f662828c50264c50e81d73.tar.gz lua-57b6ed68151c965b48f662828c50264c50e81d73.tar.bz2 lua-57b6ed68151c965b48f662828c50264c50e81d73.zip |
initial implementation of white/gray/black coloring
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 89 |
1 files changed, 53 insertions, 36 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 1.178 2003/11/17 19:50:05 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 1.179 2003/11/18 14:55:11 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 | */ |
@@ -23,9 +23,15 @@ | |||
23 | 23 | ||
24 | 24 | ||
25 | 25 | ||
26 | #define unblack(x) resetbit((x)->gch.marked, BLACKBIT) | ||
27 | #define isblack(x) testbit((x)->gch.marked, BLACKBIT) | 26 | #define isblack(x) testbit((x)->gch.marked, BLACKBIT) |
28 | #define blacken(x) setbit((x)->gch.marked, BLACKBIT) | 27 | #define gray2black(x) ((x)->gch.marked++) |
28 | #define white2black(x) setbit((x)->gch.marked, BLACKBIT) | ||
29 | |||
30 | #define iswhite(x) (!test2bits((x)->gch.marked, GRAYBIT, BLACKBIT)) | ||
31 | #define makewhite(x) reset2bits((x)->gch.marked, GRAYBIT, BLACKBIT) | ||
32 | |||
33 | #define isgray(x) testbit((x)->gch.marked, GRAYBIT) | ||
34 | #define white2gray(x) setbit((x)->gch.marked, GRAYBIT) | ||
29 | 35 | ||
30 | #define stringmark(s) setbit((s)->tsv.marked, BLACKBIT) | 36 | #define stringmark(s) setbit((s)->tsv.marked, BLACKBIT) |
31 | 37 | ||
@@ -39,55 +45,61 @@ | |||
39 | 45 | ||
40 | 46 | ||
41 | 47 | ||
42 | #define markobject(g,o) { checkconsistency(o); \ | 48 | #define markvalue(g,o) { checkconsistency(o); \ |
43 | if (iscollectable(o) && !isblack(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } | 49 | if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } |
44 | 50 | ||
45 | #define condmarkobject(g,o,c) { checkconsistency(o); \ | 51 | #define condmarkobject(g,o,c) { checkconsistency(o); \ |
46 | if (iscollectable(o) && !isblack(gcvalue(o)) && (c)) \ | 52 | if (iscollectable(o) && iswhite(gcvalue(o)) && (c)) \ |
47 | reallymarkobject(g,gcvalue(o)); } | 53 | reallymarkobject(g,gcvalue(o)); } |
48 | 54 | ||
49 | #define markvalue(g,t) { if (!isblack(valtogco(t))) \ | 55 | #define markobject(g,t) { if (iswhite(valtogco(t))) \ |
50 | reallymarkobject(g, valtogco(t)); } | 56 | reallymarkobject(g, valtogco(t)); } |
51 | 57 | ||
52 | 58 | ||
53 | 59 | ||
54 | static void reallymarkobject (global_State *g, GCObject *o) { | 60 | static void reallymarkobject (global_State *g, GCObject *o) { |
55 | lua_assert(!isblack(o)); | 61 | lua_assert(iswhite(o)); |
56 | blacken(o); | ||
57 | switch (o->gch.tt) { | 62 | switch (o->gch.tt) { |
63 | case LUA_TSTRING: { | ||
64 | white2black(o); /* strings do not go to gray list */ | ||
65 | return; | ||
66 | } | ||
58 | case LUA_TUSERDATA: { | 67 | case LUA_TUSERDATA: { |
59 | markvalue(g, gcotou(o)->uv.metatable); | 68 | white2black(o); /* userdata do not go to gray list */ |
60 | break; | 69 | markobject(g, gcotou(o)->uv.metatable); |
70 | return; | ||
61 | } | 71 | } |
62 | case LUA_TFUNCTION: { | 72 | case LUA_TFUNCTION: { |
63 | gcotocl(o)->c.gclist = g->gray; | 73 | gcotocl(o)->c.gclist = g->gray; |
64 | g->gray = o; | ||
65 | break; | 74 | break; |
66 | } | 75 | } |
67 | case LUA_TTABLE: { | 76 | case LUA_TTABLE: { |
68 | gcotoh(o)->gclist = g->gray; | 77 | gcotoh(o)->gclist = g->gray; |
69 | g->gray = o; | ||
70 | break; | 78 | break; |
71 | } | 79 | } |
72 | case LUA_TTHREAD: { | 80 | case LUA_TTHREAD: { |
73 | gcototh(o)->gclist = g->gray; | 81 | gcototh(o)->gclist = g->gray; |
74 | g->gray = o; | ||
75 | break; | 82 | break; |
76 | } | 83 | } |
77 | case LUA_TPROTO: { | 84 | case LUA_TPROTO: { |
78 | gcotop(o)->gclist = g->gray; | 85 | gcotop(o)->gclist = g->gray; |
79 | g->gray = o; | ||
80 | break; | 86 | break; |
81 | } | 87 | } |
82 | default: lua_assert(o->gch.tt == LUA_TSTRING); | 88 | case LUA_TUPVAL: { |
89 | gcotouv(o)->gclist = g->gray; | ||
90 | break; | ||
91 | } | ||
92 | default: lua_assert(0); | ||
83 | } | 93 | } |
94 | g->gray = o; /* finish list linking */ | ||
95 | white2gray(o); | ||
84 | } | 96 | } |
85 | 97 | ||
86 | 98 | ||
87 | static void marktmu (global_State *g) { | 99 | static void marktmu (global_State *g) { |
88 | GCObject *u; | 100 | GCObject *u; |
89 | for (u = g->tmudata; u; u = u->gch.next) { | 101 | for (u = g->tmudata; u; u = u->gch.next) { |
90 | unblack(u); /* may be marked, if left from previous GC */ | 102 | makewhite(u); /* may be marked, if left from previous GC */ |
91 | reallymarkobject(g, u); | 103 | reallymarkobject(g, u); |
92 | } | 104 | } |
93 | } | 105 | } |
@@ -130,7 +142,7 @@ static void traversetable (global_State *g, Table *h) { | |||
130 | int weakkey = 0; | 142 | int weakkey = 0; |
131 | int weakvalue = 0; | 143 | int weakvalue = 0; |
132 | const TObject *mode; | 144 | const TObject *mode; |
133 | markvalue(g, h->metatable); | 145 | markobject(g, h->metatable); |
134 | lua_assert(h->lsizenode || h->node == g->dummynode); | 146 | lua_assert(h->lsizenode || h->node == g->dummynode); |
135 | mode = gfasttm(g, h->metatable, TM_MODE); | 147 | mode = gfasttm(g, h->metatable, TM_MODE); |
136 | if (mode && ttisstring(mode)) { /* is there a weak mode? */ | 148 | if (mode && ttisstring(mode)) { /* is there a weak mode? */ |
@@ -148,7 +160,7 @@ static void traversetable (global_State *g, Table *h) { | |||
148 | if (!weakvalue) { | 160 | if (!weakvalue) { |
149 | i = h->sizearray; | 161 | i = h->sizearray; |
150 | while (i--) | 162 | while (i--) |
151 | markobject(g, &h->array[i]); | 163 | markvalue(g, &h->array[i]); |
152 | } | 164 | } |
153 | i = sizenode(h); | 165 | i = sizenode(h); |
154 | while (i--) { | 166 | while (i--) { |
@@ -179,7 +191,7 @@ static void traverseproto (global_State *g, Proto *f) { | |||
179 | } | 191 | } |
180 | for (i=0; i<f->sizep; i++) { /* mark nested protos */ | 192 | for (i=0; i<f->sizep; i++) { /* mark nested protos */ |
181 | if (f->p[i]) | 193 | if (f->p[i]) |
182 | markvalue(g, f->p[i]); | 194 | markobject(g, f->p[i]); |
183 | } | 195 | } |
184 | for (i=0; i<f->sizelocvars; i++) { /* mark local-variable names */ | 196 | for (i=0; i<f->sizelocvars; i++) { /* mark local-variable names */ |
185 | if (f->locvars[i].varname) | 197 | if (f->locvars[i].varname) |
@@ -193,19 +205,15 @@ static void traverseclosure (global_State *g, Closure *cl) { | |||
193 | if (cl->c.isC) { | 205 | if (cl->c.isC) { |
194 | int i; | 206 | int i; |
195 | for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */ | 207 | for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */ |
196 | markobject(g, &cl->c.upvalue[i]); | 208 | markvalue(g, &cl->c.upvalue[i]); |
197 | } | 209 | } |
198 | else { | 210 | else { |
199 | int i; | 211 | int i; |
200 | lua_assert(cl->l.nupvalues == cl->l.p->nups); | 212 | lua_assert(cl->l.nupvalues == cl->l.p->nups); |
201 | markvalue(g, hvalue(&cl->l.g)); | 213 | markobject(g, hvalue(&cl->l.g)); |
202 | markvalue(g, cl->l.p); | 214 | markobject(g, cl->l.p); |
203 | for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */ | 215 | for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */ |
204 | UpVal *u = cl->l.upvals[i]; | 216 | markobject(g, cl->l.upvals[i]); |
205 | if (!isblack(valtogco(u))) { | ||
206 | blacken(valtogco(u)); | ||
207 | markobject(g, &u->value); | ||
208 | } | ||
209 | } | 217 | } |
210 | } | 218 | } |
211 | } | 219 | } |
@@ -226,14 +234,14 @@ static void checkstacksizes (lua_State *L, StkId max) { | |||
226 | static void traversestack (global_State *g, lua_State *L1) { | 234 | static void traversestack (global_State *g, lua_State *L1) { |
227 | StkId o, lim; | 235 | StkId o, lim; |
228 | CallInfo *ci; | 236 | CallInfo *ci; |
229 | markobject(g, gt(L1)); | 237 | markvalue(g, gt(L1)); |
230 | lim = L1->top; | 238 | lim = L1->top; |
231 | for (ci = L1->base_ci; ci <= L1->ci; ci++) { | 239 | for (ci = L1->base_ci; ci <= L1->ci; ci++) { |
232 | lua_assert(ci->top <= L1->stack_last); | 240 | lua_assert(ci->top <= L1->stack_last); |
233 | if (lim < ci->top) lim = ci->top; | 241 | if (lim < ci->top) lim = ci->top; |
234 | } | 242 | } |
235 | for (o = L1->stack; o < L1->top; o++) | 243 | for (o = L1->stack; o < L1->top; o++) |
236 | markobject(g, o); | 244 | markvalue(g, o); |
237 | for (; o <= lim; o++) | 245 | for (; o <= lim; o++) |
238 | setnilvalue(o); | 246 | setnilvalue(o); |
239 | checkstacksizes(L1, lim); | 247 | checkstacksizes(L1, lim); |
@@ -242,6 +250,8 @@ static void traversestack (global_State *g, lua_State *L1) { | |||
242 | 250 | ||
243 | static void propagatemarks (global_State *g) { | 251 | static void propagatemarks (global_State *g) { |
244 | while (g->gray) { /* traverse marked objects */ | 252 | while (g->gray) { /* traverse marked objects */ |
253 | lua_assert(isgray(g->gray)); | ||
254 | gray2black(g->gray); | ||
245 | switch (g->gray->gch.tt) { | 255 | switch (g->gray->gch.tt) { |
246 | case LUA_TTABLE: { | 256 | case LUA_TTABLE: { |
247 | Table *h = gcotoh(g->gray); | 257 | Table *h = gcotoh(g->gray); |
@@ -267,6 +277,12 @@ static void propagatemarks (global_State *g) { | |||
267 | traverseproto(g, p); | 277 | traverseproto(g, p); |
268 | break; | 278 | break; |
269 | } | 279 | } |
280 | case LUA_TUPVAL: { | ||
281 | UpVal *uv = gcotouv(g->gray); | ||
282 | g->gray = uv->gclist; | ||
283 | markvalue(g, &uv->value); | ||
284 | break; | ||
285 | } | ||
270 | default: lua_assert(0); | 286 | default: lua_assert(0); |
271 | } | 287 | } |
272 | } | 288 | } |
@@ -354,8 +370,9 @@ static int sweeplist (lua_State *L, GCObject **p, int mask) { | |||
354 | GCObject *curr; | 370 | GCObject *curr; |
355 | int count = 0; /* number of collected items */ | 371 | int count = 0; /* number of collected items */ |
356 | while ((curr = *p) != NULL) { | 372 | while ((curr = *p) != NULL) { |
373 | lua_assert(!isgray(curr)); | ||
357 | if (curr->gch.marked & mask) { | 374 | if (curr->gch.marked & mask) { |
358 | unblack(curr); | 375 | makewhite(curr); |
359 | p = &curr->gch.next; | 376 | p = &curr->gch.next; |
360 | } | 377 | } |
361 | else { | 378 | else { |
@@ -413,7 +430,7 @@ void luaC_callGCTM (lua_State *L) { | |||
413 | udata->uv.next = G(L)->rootudata; /* return it to `root' list */ | 430 | udata->uv.next = G(L)->rootudata; /* return it to `root' list */ |
414 | G(L)->rootudata = o; | 431 | G(L)->rootudata = o; |
415 | setuvalue(L->top - 1, udata); /* keep a reference to it */ | 432 | setuvalue(L->top - 1, udata); /* keep a reference to it */ |
416 | unblack(o); | 433 | makewhite(o); |
417 | do1gcTM(L, udata); | 434 | do1gcTM(L, udata); |
418 | } | 435 | } |
419 | L->top--; | 436 | L->top--; |
@@ -422,7 +439,7 @@ void luaC_callGCTM (lua_State *L) { | |||
422 | 439 | ||
423 | 440 | ||
424 | void luaC_sweep (lua_State *L, int all) { | 441 | void luaC_sweep (lua_State *L, int all) { |
425 | int mask = (all) ? 0 : (bitmask(BLACKBIT) | bitmask(FIXEDBIT)); | 442 | int mask = (all) ? 0 : bit2mask(BLACKBIT, FIXEDBIT); |
426 | sweeplist(L, &G(L)->rootudata, mask); | 443 | sweeplist(L, &G(L)->rootudata, mask); |
427 | sweepstrings(L, mask); | 444 | sweepstrings(L, mask); |
428 | sweeplist(L, &G(L)->rootgc, mask); | 445 | sweeplist(L, &G(L)->rootgc, mask); |
@@ -431,11 +448,11 @@ void luaC_sweep (lua_State *L, int all) { | |||
431 | 448 | ||
432 | /* mark root set */ | 449 | /* mark root set */ |
433 | static void markroot (global_State *g, lua_State *L) { | 450 | static void markroot (global_State *g, lua_State *L) { |
434 | markobject(g, defaultmeta(L)); | 451 | markvalue(g, defaultmeta(L)); |
435 | markobject(g, registry(L)); | 452 | markvalue(g, registry(L)); |
436 | traversestack(g, g->mainthread); | 453 | traversestack(g, g->mainthread); |
437 | if (L != g->mainthread) /* another thread is running? */ | 454 | if (L != g->mainthread) /* another thread is running? */ |
438 | markvalue(g, L); /* cannot collect it */ | 455 | markobject(g, L); /* cannot collect it */ |
439 | } | 456 | } |
440 | 457 | ||
441 | 458 | ||