summaryrefslogtreecommitdiff
path: root/lgc.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2002-11-13 09:49:19 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2002-11-13 09:49:19 -0200
commit3010eb05365e77065009db39d20ef9a4110479a6 (patch)
treed880230c27289095a21a7350568b114b8c743242 /lgc.c
parent2f91f95d94d3a27fee6b45c31ea9ab631924a8bf (diff)
downloadlua-3010eb05365e77065009db39d20ef9a4110479a6.tar.gz
lua-3010eb05365e77065009db39d20ef9a4110479a6.tar.bz2
lua-3010eb05365e77065009db39d20ef9a4110479a6.zip
all objects with several children (tables, closures, stacks, prototypes)
go to `gray' queue
Diffstat (limited to 'lgc.c')
-rw-r--r--lgc.c288
1 files changed, 162 insertions, 126 deletions
diff --git a/lgc.c b/lgc.c
index 6fd41d34..72984d2a 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 1.155 2002/11/07 15:37:10 roberto Exp roberto $ 2** $Id: lgc.c,v 1.156 2002/11/11 11:52:43 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*/
@@ -21,11 +21,11 @@
21 21
22 22
23typedef struct GCState { 23typedef struct GCState {
24 Table *tmark; /* list of marked tables to be visited */ 24 GCObject *tmark; /* list of marked objects to be traversed */
25 Table *wk; /* list of visited key-weak tables (to be cleared after GC) */ 25 GCObject *wk; /* list of traversed key-weak tables (to be cleared) */
26 Table *wv; /* list of visited value-weak tables */ 26 GCObject *wv; /* list of traversed value-weak tables */
27 Table *wkv; /* list of visited key-value weak tables */ 27 GCObject *wkv; /* list of traversed key-value weak tables */
28 lua_State *L; 28 global_State *G;
29} GCState; 29} GCState;
30 30
31 31
@@ -47,8 +47,6 @@ typedef struct GCState {
47#define markfinalized(u) resetbit((u)->uv.marked, 1) 47#define markfinalized(u) resetbit((u)->uv.marked, 1)
48 48
49 49
50static void reallymarkobject (GCState *st, GCObject *o);
51
52#define markobject(st,o) { checkconsistency(o); \ 50#define markobject(st,o) { checkconsistency(o); \
53 if (iscollectable(o) && !ismarked(gcvalue(o))) reallymarkobject(st,gcvalue(o)); } 51 if (iscollectable(o) && !ismarked(gcvalue(o))) reallymarkobject(st,gcvalue(o)); }
54 52
@@ -56,105 +54,50 @@ static void reallymarkobject (GCState *st, GCObject *o);
56 if (iscollectable(o) && !ismarked(gcvalue(o)) && (c)) \ 54 if (iscollectable(o) && !ismarked(gcvalue(o)) && (c)) \
57 reallymarkobject(st,gcvalue(o)); } 55 reallymarkobject(st,gcvalue(o)); }
58 56
59#define marktable(st,t) { if (!ismarked(cast(GCObject *, t))) \ 57#define markvalue(st,t) { if (!ismarked(valtogco(t))) \
60 reallymarkobject(st, cast(GCObject *, (t))); } 58 reallymarkobject(st, valtogco(t)); }
61
62
63static void markproto (Proto *f) {
64 if (!f->marked) {
65 int i;
66 f->marked = 1;
67 strmark(f->source);
68 for (i=0; i<f->sizek; i++) {
69 if (ttisstring(f->k+i))
70 strmark(tsvalue(f->k+i));
71 }
72 for (i=0; i<f->sizep; i++)
73 markproto(f->p[i]);
74 for (i=0; i<f->sizelocvars; i++) /* mark local-variable names */
75 strmark(f->locvars[i].varname);
76 }
77 lua_assert(luaG_checkcode(f));
78}
79 59
80 60
81 61
82static void markclosure (GCState *st, Closure *cl) {
83 if (cl->c.isC) {
84 int i;
85 for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */
86 markobject(st, &cl->c.upvalue[i]);
87 }
88 else {
89 int i;
90 lua_assert(cl->l.nupvalues == cl->l.p->nupvalues);
91 marktable(st, hvalue(&cl->l.g));
92 markproto(cl->l.p);
93 for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */
94 UpVal *u = cl->l.upvals[i];
95 if (!u->marked) {
96 markobject(st, &u->value);
97 u->marked = 1;
98 }
99 }
100 }
101}
102
103
104static void checkstacksizes (lua_State *L, StkId max) {
105 int used = L->ci - L->base_ci; /* number of `ci' in use */
106 if (4*used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci)
107 luaD_reallocCI(L, L->size_ci/2); /* still big enough... */
108 used = max - L->stack; /* part of stack in use */
109 if (4*used < L->stacksize && 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize)
110 luaD_reallocstack(L, L->stacksize/2); /* still big enough... */
111}
112
113
114static void markstack (GCState *st, lua_State *L1) {
115 StkId o, lim;
116 CallInfo *ci;
117 markobject(st, gt(L1));
118 for (o=L1->stack; o<L1->top; o++)
119 markobject(st, o);
120 lim = o;
121 for (ci = L1->base_ci; ci <= L1->ci; ci++) {
122 lua_assert(ci->top <= L1->stack_last);
123 if (lim < ci->top) lim = ci->top;
124 }
125 for (; o<=lim; o++) setnilvalue(o);
126 checkstacksizes(L1, lim);
127}
128
129
130static void reallymarkobject (GCState *st, GCObject *o) { 62static void reallymarkobject (GCState *st, GCObject *o) {
63 lua_assert(!ismarked(o));
131 setbit(o->gch.marked, 0); /* mark object */ 64 setbit(o->gch.marked, 0); /* mark object */
132 switch (o->gch.tt) { 65 switch (o->gch.tt) {
133 case LUA_TFUNCTION: { 66 case LUA_TUSERDATA: {
134 markclosure(st, &o->cl); 67 markvalue(st, gcotou(o)->uv.metatable);
135 break; 68 break;
136 } 69 }
137 case LUA_TUSERDATA: { 70 case LUA_TFUNCTION: {
138 marktable(st, (&o->u)->uv.metatable); 71 gcotocl(o)->c.gclist = st->tmark;
72 st->tmark = o;
139 break; 73 break;
140 } 74 }
141 case LUA_TTABLE: { 75 case LUA_TTABLE: {
142 (&o->h)->gclist = st->tmark; /* chain it for later traversal */ 76 gcotoh(o)->gclist = st->tmark;
143 st->tmark = &o->h; 77 st->tmark = o;
144 break; 78 break;
145 } 79 }
146 case LUA_TTHREAD: { 80 case LUA_TTHREAD: {
147 markstack(st, &o->th); 81 gcototh(o)->gclist = st->tmark;
82 st->tmark = o;
148 break; 83 break;
149 } 84 }
85 case LUA_TPROTO: {
86 gcotop(o)->gclist = st->tmark;
87 st->tmark = o;
88 break;
89 }
90 default: lua_assert(o->gch.tt == LUA_TSTRING);
150 } 91 }
151} 92}
152 93
153 94
154static void marktmu (GCState *st) { 95static void marktmu (GCState *st) {
155 GCObject *u; 96 GCObject *u;
156 for (u = G(st->L)->tmudata; u; u = u->uv.next) 97 for (u = st->G->tmudata; u; u = u->gch.next) {
98 unmark(u); /* may be marked, if left from previous GC */
157 reallymarkobject(st, u); 99 reallymarkobject(st, u);
100 }
158} 101}
159 102
160 103
@@ -166,18 +109,18 @@ static void separateudata (lua_State *L) {
166 GCObject **lastcollected = &collected; 109 GCObject **lastcollected = &collected;
167 while ((curr = *p) != NULL) { 110 while ((curr = *p) != NULL) {
168 lua_assert(curr->gch.tt == LUA_TUSERDATA); 111 lua_assert(curr->gch.tt == LUA_TUSERDATA);
169 if (ismarked(curr) || isfinalized(&curr->u)) 112 if (ismarked(curr) || isfinalized(gcotou(curr)))
170 p = &curr->uv.next; /* don't bother with them */ 113 p = &curr->gch.next; /* don't bother with them */
171 114
172 else if (fasttm(L, (&curr->u)->uv.metatable, TM_GC) == NULL) { 115 else if (fasttm(L, gcotou(curr)->uv.metatable, TM_GC) == NULL) {
173 markfinalized(&curr->u); /* don't need finalization */ 116 markfinalized(gcotou(curr)); /* don't need finalization */
174 p = &curr->uv.next; 117 p = &curr->gch.next;
175 } 118 }
176 else { /* must call its gc method */ 119 else { /* must call its gc method */
177 *p = curr->uv.next; 120 *p = curr->gch.next;
178 curr->uv.next = NULL; /* link `curr' at the end of `collected' list */ 121 curr->gch.next = NULL; /* link `curr' at the end of `collected' list */
179 *lastcollected = curr; 122 *lastcollected = curr;
180 lastcollected = &curr->uv.next; 123 lastcollected = &curr->gch.next;
181 } 124 }
182 } 125 }
183 /* insert collected udata with gc event into `tmudata' list */ 126 /* insert collected udata with gc event into `tmudata' list */
@@ -197,17 +140,17 @@ static void traversetable (GCState *st, Table *h) {
197 int i; 140 int i;
198 int weakkey = 0; 141 int weakkey = 0;
199 int weakvalue = 0; 142 int weakvalue = 0;
200 marktable(st, h->metatable); 143 markvalue(st, h->metatable);
201 lua_assert(h->lsizenode || h->node == G(st->L)->dummynode); 144 lua_assert(h->lsizenode || h->node == st->G->dummynode);
202 if (h->mode & (WEAKKEY | WEAKVALUE)) { /* weak table? */ 145 if (h->mode & (WEAKKEY | WEAKVALUE)) { /* weak table? */
203 Table **weaklist; 146 GCObject **weaklist;
204 weakkey = h->mode & WEAKKEY; 147 weakkey = h->mode & WEAKKEY;
205 weakvalue = h->mode & WEAKVALUE; 148 weakvalue = h->mode & WEAKVALUE;
206 weaklist = (weakkey && weakvalue) ? &st->wkv : 149 weaklist = (weakkey && weakvalue) ? &st->wkv :
207 (weakkey) ? &st->wk : 150 (weakkey) ? &st->wk :
208 &st->wv; 151 &st->wv;
209 h->gclist = *weaklist; /* must be cleared after GC, ... */ 152 h->gclist = *weaklist; /* must be cleared after GC, ... */
210 *weaklist = h; /* ... so put in the appropriate list */ 153 *weaklist = valtogco(h); /* ... so put in the appropriate list */
211 } 154 }
212 if (!weakvalue) { 155 if (!weakvalue) {
213 i = sizearray(h); 156 i = sizearray(h);
@@ -226,11 +169,99 @@ static void traversetable (GCState *st, Table *h) {
226} 169}
227 170
228 171
172static void traverseproto (GCState *st, Proto *f) {
173 int i;
174 strmark(f->source);
175 for (i=0; i<f->sizek; i++) {
176 if (ttisstring(f->k+i))
177 strmark(tsvalue(f->k+i));
178 }
179 for (i=0; i<f->sizep; i++)
180 markvalue(st, f->p[i]);
181 for (i=0; i<f->sizelocvars; i++) /* mark local-variable names */
182 strmark(f->locvars[i].varname);
183 lua_assert(luaG_checkcode(f));
184}
185
186
187
188static void traverseclosure (GCState *st, Closure *cl) {
189 if (cl->c.isC) {
190 int i;
191 for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */
192 markobject(st, &cl->c.upvalue[i]);
193 }
194 else {
195 int i;
196 lua_assert(cl->l.nupvalues == cl->l.p->nupvalues);
197 markvalue(st, hvalue(&cl->l.g));
198 markvalue(st, cl->l.p);
199 for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */
200 UpVal *u = cl->l.upvals[i];
201 if (!u->marked) {
202 markobject(st, &u->value);
203 u->marked = 1;
204 }
205 }
206 }
207}
208
209
210static void checkstacksizes (lua_State *L, StkId max) {
211 int used = L->ci - L->base_ci; /* number of `ci' in use */
212 if (4*used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci)
213 luaD_reallocCI(L, L->size_ci/2); /* still big enough... */
214 used = max - L->stack; /* part of stack in use */
215 if (4*used < L->stacksize && 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize)
216 luaD_reallocstack(L, L->stacksize/2); /* still big enough... */
217}
218
219
220static void traversestack (GCState *st, lua_State *L1) {
221 StkId o, lim;
222 CallInfo *ci;
223 markobject(st, gt(L1));
224 for (o=L1->stack; o<L1->top; o++)
225 markobject(st, o);
226 lim = o;
227 for (ci = L1->base_ci; ci <= L1->ci; ci++) {
228 lua_assert(ci->top <= L1->stack_last);
229 if (lim < ci->top) lim = ci->top;
230 }
231 for (; o<=lim; o++) setnilvalue(o);
232 checkstacksizes(L1, lim);
233}
234
235
229static void propagatemarks (GCState *st) { 236static void propagatemarks (GCState *st) {
230 while (st->tmark) { /* traverse marked tables */ 237 while (st->tmark) { /* traverse marked objects */
231 Table *h = st->tmark; /* get first table from list */ 238 switch (st->tmark->gch.tt) {
232 st->tmark = h->gclist; /* remove it from list */ 239 case LUA_TTABLE: {
233 traversetable(st, h); 240 Table *h = gcotoh(st->tmark);
241 st->tmark = h->gclist;
242 traversetable(st, h);
243 break;
244 }
245 case LUA_TFUNCTION: {
246 Closure *cl = gcotocl(st->tmark);
247 st->tmark = cl->c.gclist;
248 traverseclosure(st, cl);
249 break;
250 }
251 case LUA_TTHREAD: {
252 lua_State *th = gcototh(st->tmark);
253 st->tmark = th->gclist;
254 traversestack(st, th);
255 break;
256 }
257 case LUA_TPROTO: {
258 Proto *p = gcotop(st->tmark);
259 st->tmark = p->gclist;
260 traverseproto(st, p);
261 break;
262 }
263 default: lua_assert(0);
264 }
234 } 265 }
235} 266}
236 267
@@ -245,8 +276,9 @@ static int valismarked (const TObject *o) {
245/* 276/*
246** clear collected keys from weaktables 277** clear collected keys from weaktables
247*/ 278*/
248static void cleartablekeys (Table *h) { 279static void cleartablekeys (GCObject *l) {
249 for (; h; h = h->gclist) { 280 while (l) {
281 Table *h = gcotoh(l);
250 int i = sizenode(h); 282 int i = sizenode(h);
251 lua_assert(h->mode & WEAKKEY); 283 lua_assert(h->mode & WEAKKEY);
252 while (i--) { 284 while (i--) {
@@ -254,6 +286,7 @@ static void cleartablekeys (Table *h) {
254 if (!valismarked(key(n))) /* key was collected? */ 286 if (!valismarked(key(n))) /* key was collected? */
255 removekey(n); /* remove entry from table */ 287 removekey(n); /* remove entry from table */
256 } 288 }
289 l = h->gclist;
257 } 290 }
258} 291}
259 292
@@ -261,8 +294,9 @@ static void cleartablekeys (Table *h) {
261/* 294/*
262** clear collected values from weaktables 295** clear collected values from weaktables
263*/ 296*/
264static void cleartablevalues (Table *h) { 297static void cleartablevalues (GCObject *l) {
265 for (; h; h = h->gclist) { 298 while (l) {
299 Table *h = gcotoh(l);
266 int i = sizearray(h); 300 int i = sizearray(h);
267 lua_assert(h->mode & WEAKVALUE); 301 lua_assert(h->mode & WEAKVALUE);
268 while (i--) { 302 while (i--) {
@@ -276,27 +310,28 @@ static void cleartablevalues (Table *h) {
276 if (!valismarked(val(n))) /* value was collected? */ 310 if (!valismarked(val(n))) /* value was collected? */
277 removekey(n); /* remove entry from table */ 311 removekey(n); /* remove entry from table */
278 } 312 }
313 l = h->gclist;
279 } 314 }
280} 315}
281 316
282 317
283static void freeobj (lua_State *L, GCObject *o) { 318static void freeobj (lua_State *L, GCObject *o) {
284 switch (o->gch.tt) { 319 switch (o->gch.tt) {
285 case LUA_TPROTO: luaF_freeproto(L, &o->p); break; 320 case LUA_TPROTO: luaF_freeproto(L, gcotop(o)); break;
286 case LUA_TFUNCTION: luaF_freeclosure(L, &o->cl); break; 321 case LUA_TFUNCTION: luaF_freeclosure(L, gcotocl(o)); break;
287 case LUA_TUPVAL: luaM_freelem(L, &o->uv); break; 322 case LUA_TUPVAL: luaM_freelem(L, gcotouv(o)); break;
288 case LUA_TTABLE: luaH_free(L, &o->h); break; 323 case LUA_TTABLE: luaH_free(L, gcotoh(o)); break;
289 case LUA_TTHREAD: { 324 case LUA_TTHREAD: {
290 lua_assert(&o->th != L && &o->th != G(L)->mainthread); 325 lua_assert(gcototh(o) != L && gcototh(o) != G(L)->mainthread);
291 luaE_freethread(L, &o->th); 326 luaE_freethread(L, gcototh(o));
292 break; 327 break;
293 } 328 }
294 case LUA_TSTRING: { 329 case LUA_TSTRING: {
295 luaM_free(L, o, sizestring((&o->ts)->tsv.len)); 330 luaM_free(L, o, sizestring(gcotots(o)->tsv.len));
296 break; 331 break;
297 } 332 }
298 case LUA_TUSERDATA: { 333 case LUA_TUSERDATA: {
299 luaM_free(L, o, sizeudata((&o->u)->uv.len)); 334 luaM_free(L, o, sizeudata(gcotou(o)->uv.len));
300 break; 335 break;
301 } 336 }
302 default: lua_assert(0); 337 default: lua_assert(0);
@@ -360,14 +395,15 @@ static void callGCTM (lua_State *L) {
360 setallowhook(L, 0); /* stop debug hooks during GC tag methods */ 395 setallowhook(L, 0); /* stop debug hooks during GC tag methods */
361 L->top++; /* reserve space to keep udata while runs its gc method */ 396 L->top++; /* reserve space to keep udata while runs its gc method */
362 while (G(L)->tmudata != NULL) { 397 while (G(L)->tmudata != NULL) {
363 GCObject *udata = G(L)->tmudata; 398 GCObject *o = G(L)->tmudata;
399 Udata *udata = gcotou(o);
364 G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */ 400 G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */
365 udata->uv.next = G(L)->rootudata; /* return it to `root' list */ 401 udata->uv.next = G(L)->rootudata; /* return it to `root' list */
366 G(L)->rootudata = udata; 402 G(L)->rootudata = o;
367 setuvalue(L->top - 1, &udata->u); /* keep a reference to it */ 403 setuvalue(L->top - 1, udata); /* keep a reference to it */
368 unmark(udata); 404 unmark(o);
369 markfinalized(&udata->u); 405 markfinalized(udata);
370 do1gcTM(L, &udata->u); 406 do1gcTM(L, udata);
371 } 407 }
372 L->top--; 408 L->top--;
373 setallowhook(L, oldah); /* restore hooks */ 409 setallowhook(L, oldah); /* restore hooks */
@@ -389,23 +425,23 @@ void luaC_sweep (lua_State *L, int all) {
389 425
390 426
391/* mark root set */ 427/* mark root set */
392static void markroot (GCState *st) { 428static void markroot (GCState *st, lua_State *L) {
393 lua_State *L = st->L; 429 global_State *G = st->G;
394 markobject(st, defaultmeta(L)); 430 markobject(st, defaultmeta(L));
395 markobject(st, registry(L)); 431 markobject(st, registry(L));
396 markstack(st, G(L)->mainthread); 432 traversestack(st, G->mainthread);
397 if (L != G(L)->mainthread) /* another thread is running? */ 433 if (L != G->mainthread) /* another thread is running? */
398 reallymarkobject(st, cast(GCObject *, L)); /* cannot collect it */ 434 markvalue(st, L); /* cannot collect it */
399} 435}
400 436
401 437
402static void mark (lua_State *L) { 438static void mark (lua_State *L) {
403 GCState st; 439 GCState st;
404 Table *wkv; 440 GCObject *wkv;
405 st.L = L; 441 st.G = G(L);
406 st.tmark = NULL; 442 st.tmark = NULL;
407 st.wkv = st.wk = st.wv = NULL; 443 st.wkv = st.wk = st.wv = NULL;
408 markroot(&st); 444 markroot(&st, L);
409 propagatemarks(&st); /* mark all reachable objects */ 445 propagatemarks(&st); /* mark all reachable objects */
410 cleartablevalues(st.wkv); 446 cleartablevalues(st.wkv);
411 cleartablevalues(st.wv); 447 cleartablevalues(st.wv);