2 ** $Id: lgc.c,v 1.171a 2003/04/03 13:35:34 roberto Exp $
4 ** See Copyright Notice in lua.h
25 typedef struct GCState
{
26 GCObject
*tmark
; /* list of marked objects to be traversed */
27 GCObject
*wk
; /* list of traversed key-weak tables (to be cleared) */
28 GCObject
*wv
; /* list of traversed value-weak tables */
29 GCObject
*wkv
; /* list of traversed key-value weak tables */
35 ** some userful bit tricks
37 #define setbit(x,b) ((x) |= (1<<(b)))
38 #define resetbit(x,b) ((x) &= cast(lu_byte, ~(1<<(b))))
39 #define testbit(x,b) ((x) & (1<<(b)))
41 #define unmark(x) resetbit((x)->gch.marked, 0)
42 #define ismarked(x) ((x)->gch.marked & ((1<<4)|1))
44 #define stringmark(s) setbit((s)->tsv.marked, 0)
47 #define isfinalized(u) (!testbit((u)->uv.marked, 1))
48 #define markfinalized(u) resetbit((u)->uv.marked, 1)
52 #define VALUEWEAKBIT 2
53 #define KEYWEAK (1<<KEYWEAKBIT)
54 #define VALUEWEAK (1<<VALUEWEAKBIT)
58 #define markobject(st,o) { checkconsistency(o); \
59 if (iscollectable(o) && !ismarked(gcvalue(o))) reallymarkobject(st,gcvalue(o)); }
61 #define condmarkobject(st,o,c) { checkconsistency(o); \
62 if (iscollectable(o) && !ismarked(gcvalue(o)) && (c)) \
63 reallymarkobject(st,gcvalue(o)); }
65 #define markvalue(st,t) { if (!ismarked(valtogco(t))) \
66 reallymarkobject(st, valtogco(t)); }
70 static void reallymarkobject (GCState
*st
, GCObject
*o
) {
71 lua_assert(!ismarked(o
));
72 setbit(o
->gch
.marked
, 0); /* mark object */
75 markvalue(st
, gcotou(o
)->uv
.metatable
);
79 gcotocl(o
)->c
.gclist
= st
->tmark
;
84 gcotoh(o
)->gclist
= st
->tmark
;
89 gcototh(o
)->gclist
= st
->tmark
;
94 gcotop(o
)->gclist
= st
->tmark
;
98 default: lua_assert(o
->gch
.tt
== LUA_TSTRING
);
103 static void marktmu (GCState
*st
) {
105 for (u
= st
->g
->tmudata
; u
; u
= u
->gch
.next
) {
106 unmark(u
); /* may be marked, if left from previous GC */
107 reallymarkobject(st
, u
);
112 /* move `dead' udata that need finalization to list `tmudata' */
113 size_t luaC_separateudata (lua_State
*L
) {
115 GCObject
**p
= &G(L
)->rootudata
;
117 GCObject
*collected
= NULL
; /* to collect udata with gc event */
118 GCObject
**lastcollected
= &collected
;
119 while ((curr
= *p
) != NULL
) {
120 lua_assert(curr
->gch
.tt
== LUA_TUSERDATA
);
121 if (ismarked(curr
) || isfinalized(gcotou(curr
)))
122 p
= &curr
->gch
.next
; /* don't bother with them */
124 else if (fasttm(L
, gcotou(curr
)->uv
.metatable
, TM_GC
) == NULL
) {
125 markfinalized(gcotou(curr
)); /* don't need finalization */
128 else { /* must call its gc method */
129 deadmem
+= sizeudata(gcotou(curr
)->uv
.len
);
131 curr
->gch
.next
= NULL
; /* link `curr' at the end of `collected' list */
132 *lastcollected
= curr
;
133 lastcollected
= &curr
->gch
.next
;
136 /* insert collected udata with gc event into `tmudata' list */
137 *lastcollected
= G(L
)->tmudata
;
138 G(L
)->tmudata
= collected
;
143 static void removekey (Node
*n
) {
144 setnilvalue(gval(n
)); /* remove corresponding value ... */
145 if (iscollectable(gkey(n
)))
146 setttype(gkey(n
), LUA_TNONE
); /* dead key; remove it */
150 static void traversetable (GCState
*st
, Table
*h
) {
155 markvalue(st
, h
->metatable
);
156 lua_assert(h
->lsizenode
|| h
->node
== st
->g
->dummynode
);
157 mode
= gfasttm(st
->g
, h
->metatable
, TM_MODE
);
158 if (mode
&& ttisstring(mode
)) { /* is there a weak mode? */
159 weakkey
= (strchr(svalue(mode
), 'k') != NULL
);
160 weakvalue
= (strchr(svalue(mode
), 'v') != NULL
);
161 if (weakkey
|| weakvalue
) { /* is really weak? */
163 h
->marked
&= ~(KEYWEAK
| VALUEWEAK
); /* clear bits */
164 h
->marked
|= cast(lu_byte
, (weakkey
<< KEYWEAKBIT
) |
165 (weakvalue
<< VALUEWEAKBIT
));
166 weaklist
= (weakkey
&& weakvalue
) ? &st
->wkv
:
167 (weakkey
) ? &st
->wk
:
169 h
->gclist
= *weaklist
; /* must be cleared after GC, ... */
170 *weaklist
= valtogco(h
); /* ... so put in the appropriate list */
176 markobject(st
, &h
->array
[i
]);
180 Node
*n
= gnode(h
, i
);
181 if (!ttisnil(gval(n
))) {
182 lua_assert(!ttisnil(gkey(n
)));
183 condmarkobject(st
, gkey(n
), !weakkey
);
184 condmarkobject(st
, gval(n
), !weakvalue
);
190 static void traverseproto (GCState
*st
, Proto
*f
) {
192 stringmark(f
->source
);
193 for (i
=0; i
<f
->sizek
; i
++) { /* mark literal strings */
194 if (ttisstring(f
->k
+i
))
195 stringmark(tsvalue(f
->k
+i
));
197 for (i
=0; i
<f
->sizeupvalues
; i
++) /* mark upvalue names */
198 stringmark(f
->upvalues
[i
]);
199 for (i
=0; i
<f
->sizep
; i
++) /* mark nested protos */
200 markvalue(st
, f
->p
[i
]);
201 for (i
=0; i
<f
->sizelocvars
; i
++) /* mark local-variable names */
202 stringmark(f
->locvars
[i
].varname
);
203 lua_assert(luaG_checkcode(f
));
208 static void traverseclosure (GCState
*st
, Closure
*cl
) {
211 for (i
=0; i
<cl
->c
.nupvalues
; i
++) /* mark its upvalues */
212 markobject(st
, &cl
->c
.upvalue
[i
]);
216 lua_assert(cl
->l
.nupvalues
== cl
->l
.p
->nups
);
217 markvalue(st
, hvalue(&cl
->l
.g
));
218 markvalue(st
, cl
->l
.p
);
219 for (i
=0; i
<cl
->l
.nupvalues
; i
++) { /* mark its upvalues */
220 UpVal
*u
= cl
->l
.upvals
[i
];
222 markobject(st
, &u
->value
);
230 static void checkstacksizes (lua_State
*L
, StkId max
) {
231 int used
= L
->ci
- L
->base_ci
; /* number of `ci' in use */
232 if (4*used
< L
->size_ci
&& 2*BASIC_CI_SIZE
< L
->size_ci
)
233 luaD_reallocCI(L
, L
->size_ci
/2); /* still big enough... */
234 else condhardstacktests(luaD_reallocCI(L
, L
->size_ci
));
235 used
= max
- L
->stack
; /* part of stack in use */
236 if (4*used
< L
->stacksize
&& 2*(BASIC_STACK_SIZE
+EXTRA_STACK
) < L
->stacksize
)
237 luaD_reallocstack(L
, L
->stacksize
/2); /* still big enough... */
238 else condhardstacktests(luaD_reallocstack(L
, L
->stacksize
));
242 static void traversestack (GCState
*st
, lua_State
*L1
) {
245 markobject(st
, gt(L1
));
247 for (ci
= L1
->base_ci
; ci
<= L1
->ci
; ci
++) {
248 lua_assert(ci
->top
<= L1
->stack_last
);
249 lua_assert(ci
->state
& (CI_C
| CI_HASFRAME
| CI_SAVEDPC
));
253 for (o
= L1
->stack
; o
< L1
->top
; o
++)
255 for (; o
<= lim
; o
++)
257 checkstacksizes(L1
, lim
);
261 static void propagatemarks (GCState
*st
) {
262 while (st
->tmark
) { /* traverse marked objects */
263 switch (st
->tmark
->gch
.tt
) {
265 Table
*h
= gcotoh(st
->tmark
);
266 st
->tmark
= h
->gclist
;
267 traversetable(st
, h
);
270 case LUA_TFUNCTION
: {
271 Closure
*cl
= gcotocl(st
->tmark
);
272 st
->tmark
= cl
->c
.gclist
;
273 traverseclosure(st
, cl
);
277 lua_State
*th
= gcototh(st
->tmark
);
278 st
->tmark
= th
->gclist
;
279 traversestack(st
, th
);
283 Proto
*p
= gcotop(st
->tmark
);
284 st
->tmark
= p
->gclist
;
285 traverseproto(st
, p
);
288 default: lua_assert(0);
294 static int valismarked (const TObject
*o
) {
296 stringmark(tsvalue(o
)); /* strings are `values', so are never weak */
297 return !iscollectable(o
) || testbit(o
->value
.gc
->gch
.marked
, 0);
302 ** clear collected keys from weaktables
304 static void cleartablekeys (GCObject
*l
) {
306 Table
*h
= gcotoh(l
);
308 lua_assert(h
->marked
& KEYWEAK
);
310 Node
*n
= gnode(h
, i
);
311 if (!valismarked(gkey(n
))) /* key was collected? */
312 removekey(n
); /* remove entry from table */
320 ** clear collected values from weaktables
322 static void cleartablevalues (GCObject
*l
) {
324 Table
*h
= gcotoh(l
);
325 int i
= h
->sizearray
;
326 lua_assert(h
->marked
& VALUEWEAK
);
328 TObject
*o
= &h
->array
[i
];
329 if (!valismarked(o
)) /* value was collected? */
330 setnilvalue(o
); /* remove value */
334 Node
*n
= gnode(h
, i
);
335 if (!valismarked(gval(n
))) /* value was collected? */
336 removekey(n
); /* remove entry from table */
343 static void freeobj (lua_State
*L
, GCObject
*o
) {
345 case LUA_TPROTO
: luaF_freeproto(L
, gcotop(o
)); break;
346 case LUA_TFUNCTION
: luaF_freeclosure(L
, gcotocl(o
)); break;
347 case LUA_TUPVAL
: luaM_freelem(L
, gcotouv(o
)); break;
348 case LUA_TTABLE
: luaH_free(L
, gcotoh(o
)); break;
350 lua_assert(gcototh(o
) != L
&& gcototh(o
) != G(L
)->mainthread
);
351 luaE_freethread(L
, gcototh(o
));
355 luaM_free(L
, o
, sizestring(gcotots(o
)->tsv
.len
));
358 case LUA_TUSERDATA
: {
359 luaM_free(L
, o
, sizeudata(gcotou(o
)->uv
.len
));
362 default: lua_assert(0);
367 static int sweeplist (lua_State
*L
, GCObject
**p
, int limit
) {
369 int count
= 0; /* number of collected items */
370 while ((curr
= *p
) != NULL
) {
371 if (curr
->gch
.marked
> limit
) {
385 static void sweepstrings (lua_State
*L
, int all
) {
387 for (i
=0; i
<G(L
)->strt
.size
; i
++) { /* for each list */
388 G(L
)->strt
.nuse
-= sweeplist(L
, &G(L
)->strt
.hash
[i
], all
);
393 static void checkSizes (lua_State
*L
, size_t deadmem
) {
394 /* check size of string hash */
395 if (G(L
)->strt
.nuse
< cast(ls_nstr
, G(L
)->strt
.size
/4) &&
396 G(L
)->strt
.size
> MINSTRTABSIZE
*2)
397 luaS_resize(L
, G(L
)->strt
.size
/2); /* table is too big */
398 /* check size of buffer */
399 if (luaZ_sizebuffer(&G(L
)->buff
) > LUA_MINBUFFER
*2) { /* buffer too big? */
400 size_t newsize
= luaZ_sizebuffer(&G(L
)->buff
) / 2;
401 luaZ_resizebuffer(L
, &G(L
)->buff
, newsize
);
403 G(L
)->GCthreshold
= 2*G(L
)->nblocks
- deadmem
; /* new threshold */
407 static void do1gcTM (lua_State
*L
, Udata
*udata
) {
408 const TObject
*tm
= fasttm(L
, udata
->uv
.metatable
, TM_GC
);
410 setobj2s(L
->top
, tm
);
411 setuvalue(L
->top
+1, udata
);
413 luaD_call(L
, L
->top
- 2, 0);
418 void luaC_callGCTM (lua_State
*L
) {
419 lu_byte oldah
= L
->allowhook
;
420 L
->allowhook
= 0; /* stop debug hooks during GC tag methods */
421 L
->top
++; /* reserve space to keep udata while runs its gc method */
422 while (G(L
)->tmudata
!= NULL
) {
423 GCObject
*o
= G(L
)->tmudata
;
424 Udata
*udata
= gcotou(o
);
425 G(L
)->tmudata
= udata
->uv
.next
; /* remove udata from `tmudata' */
426 udata
->uv
.next
= G(L
)->rootudata
; /* return it to `root' list */
428 setuvalue(L
->top
- 1, udata
); /* keep a reference to it */
430 markfinalized(udata
);
434 L
->allowhook
= oldah
; /* restore hooks */
438 void luaC_sweep (lua_State
*L
, int all
) {
439 if (all
) all
= 256; /* larger than any mark */
440 sweeplist(L
, &G(L
)->rootudata
, all
);
441 sweepstrings(L
, all
);
442 sweeplist(L
, &G(L
)->rootgc
, all
);
447 static void markroot (GCState
*st
, lua_State
*L
) {
448 global_State
*g
= st
->g
;
449 markobject(st
, defaultmeta(L
));
450 markobject(st
, registry(L
));
451 traversestack(st
, g
->mainthread
);
452 if (L
!= g
->mainthread
) /* another thread is running? */
453 markvalue(st
, L
); /* cannot collect it */
457 static size_t mark (lua_State
*L
) {
463 st
.wkv
= st
.wk
= st
.wv
= NULL
;
465 propagatemarks(&st
); /* mark all reachable objects */
466 cleartablevalues(st
.wkv
);
467 cleartablevalues(st
.wv
);
468 wkv
= st
.wkv
; /* keys must be cleared after preserving udata */
471 deadmem
= luaC_separateudata(L
); /* separate userdata to be preserved */
472 marktmu(&st
); /* mark `preserved' userdata */
473 propagatemarks(&st
); /* remark, to propagate `preserveness' */
475 /* `propagatemarks' may resuscitate some weak tables; clear them too */
476 cleartablekeys(st
.wk
);
477 cleartablevalues(st
.wv
);
478 cleartablekeys(st
.wkv
);
479 cleartablevalues(st
.wkv
);
484 void luaC_collectgarbage (lua_State
*L
) {
485 size_t deadmem
= mark(L
);
487 checkSizes(L
, deadmem
);
492 void luaC_link (lua_State
*L
, GCObject
*o
, lu_byte tt
) {
493 o
->gch
.next
= G(L
)->rootgc
;