diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-08-30 16:09:21 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-08-30 16:09:21 -0300 |
commit | fdafd4f4a88d1584dea900517445a17d87f8b82f (patch) | |
tree | 52e38e886d569e77c1df82ebe2bcfbaafd4c6f75 /lgc.c | |
parent | beeff4ccafe5877d00119cb3d93f1f937d46dcfb (diff) | |
download | lua-fdafd4f4a88d1584dea900517445a17d87f8b82f.tar.gz lua-fdafd4f4a88d1584dea900517445a17d87f8b82f.tar.bz2 lua-fdafd4f4a88d1584dea900517445a17d87f8b82f.zip |
new structure for collectable objects, sharing a common header
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 279 |
1 files changed, 103 insertions, 176 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 1.146 2002/08/16 14:45:55 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 1.147 2002/08/16 20:00:28 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 | */ |
@@ -34,28 +34,24 @@ typedef struct GCState { | |||
34 | #define resetbit(x,b) ((x) &= cast(lu_byte, ~(1<<(b)))) | 34 | #define resetbit(x,b) ((x) &= cast(lu_byte, ~(1<<(b)))) |
35 | #define testbit(x,b) ((x) & (1<<(b))) | 35 | #define testbit(x,b) ((x) & (1<<(b))) |
36 | 36 | ||
37 | #define mark(x) setbit((x)->gch.marked, 0) | ||
38 | #define unmark(x) resetbit((x)->gch.marked, 0) | ||
39 | #define ismarked(x) ((x)->gch.marked & ((1<<4)|1)) | ||
37 | 40 | ||
38 | #define strmark(s) setbit((s)->tsv.marked, 0) | 41 | #define strmark(s) setbit((s)->tsv.marked, 0) |
39 | #define strunmark(s) resetbit((s)->tsv.marked, 0) | 42 | #define strunmark(s) resetbit((s)->tsv.marked, 0) |
40 | 43 | ||
41 | 44 | ||
45 | #define isfinalized(u) (!testbit((u)->uv.marked, 1)) | ||
46 | #define markfinalized(u) resetbit((u)->uv.marked, 1) | ||
42 | 47 | ||
43 | /* mark tricks for userdata */ | ||
44 | #define isudmarked(u) testbit(u->uv.marked, 0) | ||
45 | #define markud(u) setbit(u->uv.marked, 0) | ||
46 | #define unmarkud(u) resetbit(u->uv.marked, 0) | ||
47 | 48 | ||
48 | #define isfinalized(u) testbit(u->uv.marked, 1) | 49 | static void reallymarkobject (GCState *st, GCObject *o); |
49 | #define markfinalized(u) setbit(u->uv.marked, 1) | ||
50 | 50 | ||
51 | #define markobject(st,o) \ | ||
52 | if (iscollectable(o)) reallymarkobject(st,(o)->value.gc) | ||
51 | 53 | ||
52 | #define ismarkable(o) (!((1 << ttype(o)) & \ | 54 | #define marktable(st,t) reallymarkobject(st, cast(GCObject *, (t))) |
53 | ((1 << LUA_TNIL) | (1 << LUA_TNUMBER) | \ | ||
54 | (1 << LUA_TBOOLEAN) | (1 << LUA_TLIGHTUSERDATA)))) | ||
55 | |||
56 | static void reallymarkobject (GCState *st, TObject *o); | ||
57 | |||
58 | #define markobject(st,o) if (ismarkable(o)) reallymarkobject(st,o) | ||
59 | 55 | ||
60 | 56 | ||
61 | static void markproto (Proto *f) { | 57 | static void markproto (Proto *f) { |
@@ -76,63 +72,46 @@ static void markproto (Proto *f) { | |||
76 | } | 72 | } |
77 | 73 | ||
78 | 74 | ||
79 | static void marktable (GCState *st, Table *h) { | ||
80 | if (!h->marked) { | ||
81 | h->marked = 1; | ||
82 | h->gclist = st->tmark; /* chain it for later traversal */ | ||
83 | st->tmark = h; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | 75 | ||
88 | static void markclosure (GCState *st, Closure *cl) { | 76 | static void markclosure (GCState *st, Closure *cl) { |
89 | if (!cl->c.marked) { | 77 | if (cl->c.isC) { |
90 | cl->c.marked = 1; | 78 | int i; |
91 | if (cl->c.isC) { | 79 | for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */ |
92 | int i; | 80 | markobject(st, &cl->c.upvalue[i]); |
93 | for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */ | 81 | } |
94 | markobject(st, &cl->c.upvalue[i]); | 82 | else { |
95 | } | 83 | int i; |
96 | else { | 84 | lua_assert(cl->l.nupvalues == cl->l.p->nupvalues); |
97 | int i; | 85 | marktable(st, hvalue(&cl->l.g)); |
98 | lua_assert(cl->l.nupvalues == cl->l.p->nupvalues); | 86 | markproto(cl->l.p); |
99 | marktable(st, hvalue(&cl->l.g)); | 87 | for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */ |
100 | markproto(cl->l.p); | 88 | UpVal *u = cl->l.upvals[i]; |
101 | for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */ | 89 | if (!u->marked) { |
102 | UpVal *u = cl->l.upvals[i]; | 90 | markobject(st, &u->value); |
103 | if (!u->marked) { | 91 | u->marked = 1; |
104 | markobject(st, &u->value); | ||
105 | u->marked = 1; | ||
106 | } | ||
107 | } | 92 | } |
108 | } | 93 | } |
109 | } | 94 | } |
110 | } | 95 | } |
111 | 96 | ||
112 | 97 | ||
113 | static void markudata (GCState *st, Udata *u) { | 98 | static void reallymarkobject (GCState *st, GCObject *o) { |
114 | markud(u); | 99 | if (ismarked(o)) return; |
115 | marktable(st, u->uv.metatable); | 100 | mark(o); |
116 | } | 101 | switch (o->gch.tt) { |
117 | 102 | case LUA_TFUNCTION: { | |
118 | 103 | markclosure(st, &o->cl); | |
119 | static void reallymarkobject (GCState *st, TObject *o) { | ||
120 | switch (ttype(o)) { | ||
121 | case LUA_TSTRING: | ||
122 | strmark(tsvalue(o)); | ||
123 | break; | ||
124 | case LUA_TUSERDATA: | ||
125 | if (!isudmarked(uvalue(o))) | ||
126 | markudata(st, uvalue(o)); | ||
127 | break; | 104 | break; |
128 | case LUA_TFUNCTION: | 105 | } |
129 | markclosure(st, clvalue(o)); | 106 | case LUA_TUSERDATA: { |
107 | marktable(st, (&o->u)->uv.metatable); | ||
130 | break; | 108 | break; |
109 | } | ||
131 | case LUA_TTABLE: { | 110 | case LUA_TTABLE: { |
132 | marktable(st, hvalue(o)); | 111 | (&o->h)->gclist = st->tmark; /* chain it for later traversal */ |
112 | st->tmark = &o->h; | ||
133 | break; | 113 | break; |
134 | } | 114 | } |
135 | default: lua_assert(0); /* should not be called with other types */ | ||
136 | } | 115 | } |
137 | } | 116 | } |
138 | 117 | ||
@@ -177,22 +156,29 @@ static void traversestacks (GCState *st) { | |||
177 | 156 | ||
178 | 157 | ||
179 | static void marktmu (GCState *st) { | 158 | static void marktmu (GCState *st) { |
180 | Udata *u; | 159 | GCObject *u; |
181 | for (u = G(st->L)->tmudata; u; u = u->uv.next) | 160 | for (u = G(st->L)->tmudata; u; u = u->uv.next) { |
182 | markudata(st, u); | 161 | mark(u); |
162 | marktable(st, (&u->u)->uv.metatable); | ||
163 | } | ||
183 | } | 164 | } |
184 | 165 | ||
185 | 166 | ||
186 | /* move `dead' udata that need finalization to list `tmudata' */ | 167 | /* move `dead' udata that need finalization to list `tmudata' */ |
187 | static void separateudata (lua_State *L) { | 168 | static void separateudata (lua_State *L) { |
188 | Udata **p = &G(L)->rootudata; | 169 | GCObject **p = &G(L)->rootudata; |
189 | Udata *curr; | 170 | GCObject *curr; |
190 | Udata *collected = NULL; /* to collect udata with gc event */ | 171 | GCObject *collected = NULL; /* to collect udata with gc event */ |
191 | Udata **lastcollected = &collected; | 172 | GCObject **lastcollected = &collected; |
192 | while ((curr = *p) != NULL) { | 173 | while ((curr = *p) != NULL) { |
193 | if (isudmarked(curr) || isfinalized(curr) || | 174 | lua_assert(curr->gch.tt == LUA_TUSERDATA); |
194 | (fasttm(L, curr->uv.metatable, TM_GC) == NULL)) | 175 | if (ismarked(curr) || isfinalized(&curr->u)) |
176 | p = &curr->uv.next; /* don't bother with them */ | ||
177 | |||
178 | else if (fasttm(L, (&curr->u)->uv.metatable, TM_GC) == NULL) { | ||
179 | markfinalized(&curr->u); /* don't need finalization */ | ||
195 | p = &curr->uv.next; | 180 | p = &curr->uv.next; |
181 | } | ||
196 | else { /* must call its gc method */ | 182 | else { /* must call its gc method */ |
197 | *p = curr->uv.next; | 183 | *p = curr->uv.next; |
198 | curr->uv.next = NULL; /* link `curr' at the end of `collected' list */ | 184 | curr->uv.next = NULL; /* link `curr' at the end of `collected' list */ |
@@ -208,7 +194,7 @@ static void separateudata (lua_State *L) { | |||
208 | 194 | ||
209 | static void removekey (Node *n) { | 195 | static void removekey (Node *n) { |
210 | setnilvalue(val(n)); /* remove corresponding value ... */ | 196 | setnilvalue(val(n)); /* remove corresponding value ... */ |
211 | if (ismarkable(key(n))) | 197 | if (iscollectable(key(n))) |
212 | setttype(key(n), LUA_TNONE); /* dead key; remove it */ | 198 | setttype(key(n), LUA_TNONE); /* dead key; remove it */ |
213 | } | 199 | } |
214 | 200 | ||
@@ -251,20 +237,10 @@ static void propagatemarks (GCState *st) { | |||
251 | } | 237 | } |
252 | 238 | ||
253 | 239 | ||
254 | static int ismarked (const TObject *o) { | 240 | static int valismarked (const TObject *o) { |
255 | switch (ttype(o)) { | 241 | if (ttisstring(o)) |
256 | case LUA_TUSERDATA: | 242 | strmark(tsvalue(o)); /* strings are `values', so are never weak */ |
257 | return isudmarked(uvalue(o)); | 243 | return !iscollectable(o) || testbit(o->value.gc->gch.marked, 0); |
258 | case LUA_TTABLE: | ||
259 | return hvalue(o)->marked; | ||
260 | case LUA_TFUNCTION: | ||
261 | return clvalue(o)->c.marked; | ||
262 | case LUA_TSTRING: | ||
263 | strmark(tsvalue(o)); /* strings are `values', so are never weak */ | ||
264 | /* go through */ | ||
265 | default: /* number, nil, boolean, udataval */ | ||
266 | return 1; | ||
267 | } | ||
268 | } | 244 | } |
269 | 245 | ||
270 | 246 | ||
@@ -279,7 +255,7 @@ static void cleartablekeys (GCState *st) { | |||
279 | int i = sizenode(h); | 255 | int i = sizenode(h); |
280 | while (i--) { | 256 | while (i--) { |
281 | Node *n = node(h, i); | 257 | Node *n = node(h, i); |
282 | if (!ismarked(key(n))) /* key was collected? */ | 258 | if (!valismarked(key(n))) /* key was collected? */ |
283 | removekey(n); /* remove entry from table */ | 259 | removekey(n); /* remove entry from table */ |
284 | } | 260 | } |
285 | } | 261 | } |
@@ -297,13 +273,13 @@ static void cleartablevalues (GCState *st) { | |||
297 | int i = sizearray(h); | 273 | int i = sizearray(h); |
298 | while (i--) { | 274 | while (i--) { |
299 | TObject *o = &h->array[i]; | 275 | TObject *o = &h->array[i]; |
300 | if (!ismarked(o)) /* value was collected? */ | 276 | if (!valismarked(o)) /* value was collected? */ |
301 | setnilvalue(o); /* remove value */ | 277 | setnilvalue(o); /* remove value */ |
302 | } | 278 | } |
303 | i = sizenode(h); | 279 | i = sizenode(h); |
304 | while (i--) { | 280 | while (i--) { |
305 | Node *n = node(h, i); | 281 | Node *n = node(h, i); |
306 | if (!ismarked(val(n))) /* value was collected? */ | 282 | if (!valismarked(val(n))) /* value was collected? */ |
307 | removekey(n); /* remove entry from table */ | 283 | removekey(n); /* remove entry from table */ |
308 | } | 284 | } |
309 | } | 285 | } |
@@ -311,103 +287,47 @@ static void cleartablevalues (GCState *st) { | |||
311 | } | 287 | } |
312 | 288 | ||
313 | 289 | ||
314 | static void sweepproto (lua_State *L) { | 290 | static void freeobj (lua_State *L, GCObject *o) { |
315 | Proto **p = &G(L)->rootproto; | 291 | switch (o->gch.tt) { |
316 | Proto *curr; | 292 | case LUA_TPROTO: luaF_freeproto(L, &o->p); break; |
317 | while ((curr = *p) != NULL) { | 293 | case LUA_TFUNCTION: luaF_freeclosure(L, &o->cl); break; |
318 | if (curr->marked) { | 294 | case LUA_TUPVAL: luaM_freelem(L, &o->uv); break; |
319 | curr->marked = 0; | 295 | case LUA_TTABLE: luaH_free(L, &o->h); break; |
320 | p = &curr->next; | 296 | case LUA_TSTRING: { |
321 | } | 297 | luaM_free(L, o, sizestring((&o->ts)->tsv.len)); |
322 | else { | 298 | break; |
323 | *p = curr->next; | ||
324 | luaF_freeproto(L, curr); | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | |||
329 | |||
330 | static void sweepclosures (lua_State *L) { | ||
331 | Closure **p = &G(L)->rootcl; | ||
332 | Closure *curr; | ||
333 | while ((curr = *p) != NULL) { | ||
334 | if (curr->c.marked) { | ||
335 | curr->c.marked = 0; | ||
336 | p = &curr->c.next; | ||
337 | } | ||
338 | else { | ||
339 | *p = curr->c.next; | ||
340 | luaF_freeclosure(L, curr); | ||
341 | } | ||
342 | } | ||
343 | } | ||
344 | |||
345 | |||
346 | static void sweepupval (lua_State *L) { | ||
347 | UpVal **v = &G(L)->rootupval; | ||
348 | UpVal *curr; | ||
349 | while ((curr = *v) != NULL) { | ||
350 | if (curr->marked) { | ||
351 | curr->marked = 0; /* unmark */ | ||
352 | v = &curr->next; /* next */ | ||
353 | } | ||
354 | else { | ||
355 | *v = curr->next; /* next */ | ||
356 | luaM_freelem(L, curr); | ||
357 | } | ||
358 | } | ||
359 | } | ||
360 | |||
361 | |||
362 | static void sweeptable (lua_State *L) { | ||
363 | Table **p = &G(L)->roottable; | ||
364 | Table *curr; | ||
365 | while ((curr = *p) != NULL) { | ||
366 | if (curr->marked) { | ||
367 | curr->marked = 0; | ||
368 | p = &curr->next; | ||
369 | } | 299 | } |
370 | else { | 300 | case LUA_TUSERDATA: { |
371 | *p = curr->next; | 301 | luaM_free(L, o, sizeudata((&o->u)->uv.len)); |
372 | luaH_free(L, curr); | 302 | break; |
373 | } | 303 | } |
304 | default: lua_assert(0); | ||
374 | } | 305 | } |
375 | } | 306 | } |
376 | 307 | ||
377 | 308 | ||
378 | 309 | static int sweeplist (lua_State *L, GCObject **p, int limit) { | |
379 | static void sweepudata (lua_State *L) { | 310 | GCObject *curr; |
380 | Udata **p = &G(L)->rootudata; | 311 | int count = 0; /* number of collected items */ |
381 | Udata *curr; | ||
382 | while ((curr = *p) != NULL) { | 312 | while ((curr = *p) != NULL) { |
383 | if (isudmarked(curr)) { | 313 | if (curr->gch.marked > limit) { |
384 | unmarkud(curr); | 314 | unmark(curr); |
385 | p = &curr->uv.next; | 315 | p = &curr->gch.next; |
386 | } | 316 | } |
387 | else { | 317 | else { |
388 | *p = curr->uv.next; | 318 | count++; |
389 | luaM_free(L, curr, sizeudata(curr->uv.len)); | 319 | *p = curr->gch.next; |
320 | freeobj(L, curr); | ||
390 | } | 321 | } |
391 | } | 322 | } |
323 | return count; | ||
392 | } | 324 | } |
393 | 325 | ||
394 | 326 | ||
395 | static void sweepstrings (lua_State *L, int all) { | 327 | static void sweepstrings (lua_State *L, int all) { |
396 | int i; | 328 | int i; |
397 | for (i=0; i<G(L)->strt.size; i++) { /* for each list */ | 329 | for (i=0; i<G(L)->strt.size; i++) { /* for each list */ |
398 | TString **p = &G(L)->strt.hash[i]; | 330 | G(L)->strt.nuse -= sweeplist(L, &G(L)->strt.hash[i], all); |
399 | TString *curr; | ||
400 | while ((curr = *p) != NULL) { | ||
401 | if (curr->tsv.marked && !all) { /* preserve? */ | ||
402 | strunmark(curr); | ||
403 | p = &curr->tsv.nexthash; | ||
404 | } | ||
405 | else { /* collect */ | ||
406 | *p = curr->tsv.nexthash; | ||
407 | G(L)->strt.nuse--; | ||
408 | luaM_free(L, curr, sizestring(curr->tsv.len)); | ||
409 | } | ||
410 | } | ||
411 | } | 331 | } |
412 | if (G(L)->strt.nuse < cast(ls_nstr, G(L)->strt.size/4) && | 332 | if (G(L)->strt.nuse < cast(ls_nstr, G(L)->strt.size/4) && |
413 | G(L)->strt.size > MINSTRTABSIZE*2) | 333 | G(L)->strt.size > MINSTRTABSIZE*2) |
@@ -442,14 +362,14 @@ static void callGCTM (lua_State *L) { | |||
442 | setallowhook(L, 0); /* stop debug hooks during GC tag methods */ | 362 | setallowhook(L, 0); /* stop debug hooks during GC tag methods */ |
443 | L->top++; /* reserve space to keep udata while runs its gc method */ | 363 | L->top++; /* reserve space to keep udata while runs its gc method */ |
444 | while (G(L)->tmudata != NULL) { | 364 | while (G(L)->tmudata != NULL) { |
445 | Udata *udata = G(L)->tmudata; | 365 | GCObject *udata = G(L)->tmudata; |
446 | G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */ | 366 | G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */ |
447 | udata->uv.next = G(L)->rootudata; /* return it to `root' list */ | 367 | udata->uv.next = G(L)->rootudata; /* return it to `root' list */ |
448 | G(L)->rootudata = udata; | 368 | G(L)->rootudata = udata; |
449 | setuvalue(L->top - 1, udata); /* keep a reference to it */ | 369 | setuvalue(L->top - 1, &udata->u); /* keep a reference to it */ |
450 | unmarkud(udata); | 370 | unmark(udata); |
451 | markfinalized(udata); | 371 | markfinalized(&udata->u); |
452 | do1gcTM(L, udata); | 372 | do1gcTM(L, &udata->u); |
453 | } | 373 | } |
454 | L->top--; | 374 | L->top--; |
455 | setallowhook(L, oldah); /* restore hooks */ | 375 | setallowhook(L, oldah); /* restore hooks */ |
@@ -463,12 +383,10 @@ void luaC_callallgcTM (lua_State *L) { | |||
463 | 383 | ||
464 | 384 | ||
465 | void luaC_sweep (lua_State *L, int all) { | 385 | void luaC_sweep (lua_State *L, int all) { |
466 | sweepudata(L); | 386 | if (all) all = 256; /* larger than any mark */ |
387 | sweeplist(L, &G(L)->rootudata, all); | ||
467 | sweepstrings(L, all); | 388 | sweepstrings(L, all); |
468 | sweeptable(L); | 389 | sweeplist(L, &G(L)->rootgc, all); |
469 | sweepproto(L); | ||
470 | sweepupval(L); | ||
471 | sweepclosures(L); | ||
472 | } | 390 | } |
473 | 391 | ||
474 | 392 | ||
@@ -482,7 +400,8 @@ void luaC_collectgarbage (lua_State *L) { | |||
482 | cleartablevalues(&st); | 400 | cleartablevalues(&st); |
483 | separateudata(L); /* separate userdata to be preserved */ | 401 | separateudata(L); /* separate userdata to be preserved */ |
484 | marktmu(&st); /* mark `preserved' userdata */ | 402 | marktmu(&st); /* mark `preserved' userdata */ |
485 | propagatemarks(&st); /* remark */ | 403 | propagatemarks(&st); /* remark, to propagate `preserveness' */ |
404 | cleartablevalues(&st); /* again, for eventual weak preserved tables */ | ||
486 | cleartablekeys(&st); | 405 | cleartablekeys(&st); |
487 | luaC_sweep(L, 0); | 406 | luaC_sweep(L, 0); |
488 | checkMbuffer(L); | 407 | checkMbuffer(L); |
@@ -490,3 +409,11 @@ void luaC_collectgarbage (lua_State *L) { | |||
490 | callGCTM(L); | 409 | callGCTM(L); |
491 | } | 410 | } |
492 | 411 | ||
412 | |||
413 | void luaC_link (lua_State *L, GCObject *o, int tt) { | ||
414 | o->gch.next = G(L)->rootgc; | ||
415 | G(L)->rootgc = o; | ||
416 | o->gch.marked = 0; | ||
417 | o->gch.tt = tt; | ||
418 | } | ||
419 | |||