2 ** $Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 roberto Exp $
4 ** See Copyright Notice in lua.h
28 #define GCSTEPSIZE 1024u
30 #define GCSWEEPCOST 10
31 #define GCFINALIZECOST 100
34 #define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS))
36 #define makewhite(g,x) \
37 ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g)))
39 #define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT)
40 #define black2gray(x) resetbit((x)->gch.marked, BLACKBIT)
42 #define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT)
45 #define isfinalized(u) testbit((u)->marked, FINALIZEDBIT)
46 #define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT)
49 #define KEYWEAK bitmask(KEYWEAKBIT)
50 #define VALUEWEAK bitmask(VALUEWEAKBIT)
54 #define markvalue(g,o) { checkconsistency(o); \
55 if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); }
57 #define markobject(g,t) { if (iswhite(obj2gco(t))) \
58 reallymarkobject(g, obj2gco(t)); }
61 #define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause)
64 static void removeentry (Node
*n
) {
65 lua_assert(ttisnil(gval(n
)));
66 if (iscollectable(gkey(n
)))
67 setttype(gkey(n
), LUA_TDEADKEY
); /* dead key; remove it */
71 static void reallymarkobject (global_State
*g
, GCObject
*o
) {
72 lua_assert(iswhite(o
) && !isdead(g
, o
));
79 Table
*mt
= gco2u(o
)->metatable
;
80 gray2black(o
); /* udata are never gray */
81 if (mt
) markobject(g
, mt
);
82 markobject(g
, gco2u(o
)->env
);
86 UpVal
*uv
= gco2uv(o
);
88 if (uv
->v
== &uv
->u
.value
) /* closed? */
89 gray2black(o
); /* open upvalues are never black */
93 gco2cl(o
)->c
.gclist
= g
->gray
;
98 gco2h(o
)->gclist
= g
->gray
;
103 gco2th(o
)->gclist
= g
->gray
;
108 gco2p(o
)->gclist
= g
->gray
;
112 default: lua_assert(0);
117 static void marktmu (global_State
*g
) {
118 GCObject
*u
= g
->tmudata
;
122 makewhite(g
, u
); /* may be marked, if left from previous GC */
123 reallymarkobject(g
, u
);
124 } while (u
!= g
->tmudata
);
129 /* move `dead' udata that need finalization to list `tmudata' */
130 size_t luaC_separateudata (lua_State
*L
, int all
) {
131 global_State
*g
= G(L
);
133 GCObject
**p
= &g
->mainthread
->next
;
135 while ((curr
= *p
) != NULL
) {
136 if (!(iswhite(curr
) || all
) || isfinalized(gco2u(curr
)))
137 p
= &curr
->gch
.next
; /* don't bother with them */
138 else if (fasttm(L
, gco2u(curr
)->metatable
, TM_GC
) == NULL
) {
139 markfinalized(gco2u(curr
)); /* don't need finalization */
142 else { /* must call its gc method */
143 deadmem
+= sizeudata(gco2u(curr
));
144 markfinalized(gco2u(curr
));
146 /* link `curr' at the end of `tmudata' list */
147 if (g
->tmudata
== NULL
) /* list is empty? */
148 g
->tmudata
= curr
->gch
.next
= curr
; /* creates a circular list */
150 curr
->gch
.next
= g
->tmudata
->gch
.next
;
151 g
->tmudata
->gch
.next
= curr
;
160 static int traversetable (global_State
*g
, Table
*h
) {
166 markobject(g
, h
->metatable
);
167 mode
= gfasttm(g
, h
->metatable
, TM_MODE
);
168 if (mode
&& ttisstring(mode
)) { /* is there a weak mode? */
169 weakkey
= (strchr(svalue(mode
), 'k') != NULL
);
170 weakvalue
= (strchr(svalue(mode
), 'v') != NULL
);
171 if (weakkey
|| weakvalue
) { /* is really weak? */
172 h
->marked
&= ~(KEYWEAK
| VALUEWEAK
); /* clear bits */
173 h
->marked
|= cast_byte((weakkey
<< KEYWEAKBIT
) |
174 (weakvalue
<< VALUEWEAKBIT
));
175 h
->gclist
= g
->weak
; /* must be cleared after GC, ... */
176 g
->weak
= obj2gco(h
); /* ... so put in the appropriate list */
179 if (weakkey
&& weakvalue
) return 1;
183 markvalue(g
, &h
->array
[i
]);
187 Node
*n
= gnode(h
, i
);
188 lua_assert(ttype(gkey(n
)) != LUA_TDEADKEY
|| ttisnil(gval(n
)));
189 if (ttisnil(gval(n
)))
190 removeentry(n
); /* remove empty entries */
192 lua_assert(!ttisnil(gkey(n
)));
193 if (!weakkey
) markvalue(g
, gkey(n
));
194 if (!weakvalue
) markvalue(g
, gval(n
));
197 return weakkey
|| weakvalue
;
202 ** All marks are conditional because a GC may happen while the
203 ** prototype is still being created
205 static void traverseproto (global_State
*g
, Proto
*f
) {
207 if (f
->source
) stringmark(f
->source
);
208 for (i
=0; i
<f
->sizek
; i
++) /* mark literals */
209 markvalue(g
, &f
->k
[i
]);
210 for (i
=0; i
<f
->sizeupvalues
; i
++) { /* mark upvalue names */
212 stringmark(f
->upvalues
[i
]);
214 for (i
=0; i
<f
->sizep
; i
++) { /* mark nested protos */
216 markobject(g
, f
->p
[i
]);
218 for (i
=0; i
<f
->sizelocvars
; i
++) { /* mark local-variable names */
219 if (f
->locvars
[i
].varname
)
220 stringmark(f
->locvars
[i
].varname
);
226 static void traverseclosure (global_State
*g
, Closure
*cl
) {
227 markobject(g
, cl
->c
.env
);
230 for (i
=0; i
<cl
->c
.nupvalues
; i
++) /* mark its upvalues */
231 markvalue(g
, &cl
->c
.upvalue
[i
]);
235 lua_assert(cl
->l
.nupvalues
== cl
->l
.p
->nups
);
236 markobject(g
, cl
->l
.p
);
237 for (i
=0; i
<cl
->l
.nupvalues
; i
++) /* mark its upvalues */
238 markobject(g
, cl
->l
.upvals
[i
]);
243 static void checkstacksizes (lua_State
*L
, StkId max
) {
244 int ci_used
= cast_int(L
->ci
- L
->base_ci
); /* number of `ci' in use */
245 int s_used
= cast_int(max
- L
->stack
); /* part of stack in use */
246 if (L
->size_ci
> LUAI_MAXCALLS
) /* handling overflow? */
247 return; /* do not touch the stacks */
248 if (4*ci_used
< L
->size_ci
&& 2*BASIC_CI_SIZE
< L
->size_ci
)
249 luaD_reallocCI(L
, L
->size_ci
/2); /* still big enough... */
250 condhardstacktests(luaD_reallocCI(L
, ci_used
+ 1));
251 if (4*s_used
< L
->stacksize
&&
252 2*(BASIC_STACK_SIZE
+EXTRA_STACK
) < L
->stacksize
)
253 luaD_reallocstack(L
, L
->stacksize
/2); /* still big enough... */
254 condhardstacktests(luaD_reallocstack(L
, s_used
));
258 static void traversestack (global_State
*g
, lua_State
*l
) {
263 for (ci
= l
->base_ci
; ci
<= l
->ci
; ci
++) {
264 lua_assert(ci
->top
<= l
->stack_last
);
265 if (lim
< ci
->top
) lim
= ci
->top
;
267 for (o
= l
->stack
; o
< l
->top
; o
++)
269 for (; o
<= lim
; o
++)
271 checkstacksizes(l
, lim
);
276 ** traverse one gray object, turning it to black.
277 ** Returns `quantity' traversed.
279 static l_mem
propagatemark (global_State
*g
) {
280 GCObject
*o
= g
->gray
;
281 lua_assert(isgray(o
));
287 if (traversetable(g
, h
)) /* table is weak? */
288 black2gray(o
); /* keep it gray */
289 return sizeof(Table
) + sizeof(TValue
) * h
->sizearray
+
290 sizeof(Node
) * sizenode(h
);
292 case LUA_TFUNCTION
: {
293 Closure
*cl
= gco2cl(o
);
294 g
->gray
= cl
->c
.gclist
;
295 traverseclosure(g
, cl
);
296 return (cl
->c
.isC
) ? sizeCclosure(cl
->c
.nupvalues
) :
297 sizeLclosure(cl
->l
.nupvalues
);
300 lua_State
*th
= gco2th(o
);
301 g
->gray
= th
->gclist
;
302 th
->gclist
= g
->grayagain
;
305 traversestack(g
, th
);
306 return sizeof(lua_State
) + sizeof(TValue
) * th
->stacksize
+
307 sizeof(CallInfo
) * th
->size_ci
;
313 return sizeof(Proto
) + sizeof(Instruction
) * p
->sizecode
+
314 sizeof(Proto
*) * p
->sizep
+
315 sizeof(TValue
) * p
->sizek
+
316 sizeof(int) * p
->sizelineinfo
+
317 sizeof(LocVar
) * p
->sizelocvars
+
318 sizeof(TString
*) * p
->sizeupvalues
;
320 default: lua_assert(0); return 0;
325 static size_t propagateall (global_State
*g
) {
327 while (g
->gray
) m
+= propagatemark(g
);
333 ** The next function tells whether a key or value can be cleared from
334 ** a weak table. Non-collectable objects are never removed from weak
335 ** tables. Strings behave as `values', so are never removed too. for
336 ** other objects: if really collected, cannot keep them; for userdata
337 ** being finalized, keep them in keys, but not in values
339 static int iscleared (const TValue
*o
, int iskey
) {
340 if (!iscollectable(o
)) return 0;
342 stringmark(rawtsvalue(o
)); /* strings are `values', so are never weak */
345 return iswhite(gcvalue(o
)) ||
346 (ttisuserdata(o
) && (!iskey
&& isfinalized(uvalue(o
))));
351 ** clear collected entries from weaktables
353 static void cleartable (GCObject
*l
) {
356 int i
= h
->sizearray
;
357 lua_assert(testbit(h
->marked
, VALUEWEAKBIT
) ||
358 testbit(h
->marked
, KEYWEAKBIT
));
359 if (testbit(h
->marked
, VALUEWEAKBIT
)) {
361 TValue
*o
= &h
->array
[i
];
362 if (iscleared(o
, 0)) /* value was collected? */
363 setnilvalue(o
); /* remove value */
368 Node
*n
= gnode(h
, i
);
369 if (!ttisnil(gval(n
)) && /* non-empty entry? */
370 (iscleared(key2tval(n
), 1) || iscleared(gval(n
), 0))) {
371 setnilvalue(gval(n
)); /* remove value ... */
372 removeentry(n
); /* remove entry from table */
380 static void freeobj (lua_State
*L
, GCObject
*o
) {
382 case LUA_TPROTO
: luaF_freeproto(L
, gco2p(o
)); break;
383 case LUA_TFUNCTION
: luaF_freeclosure(L
, gco2cl(o
)); break;
384 case LUA_TUPVAL
: luaF_freeupval(L
, gco2uv(o
)); break;
385 case LUA_TTABLE
: luaH_free(L
, gco2h(o
)); break;
387 lua_assert(gco2th(o
) != L
&& gco2th(o
) != G(L
)->mainthread
);
388 luaE_freethread(L
, gco2th(o
));
393 luaM_freemem(L
, o
, sizestring(gco2ts(o
)));
396 case LUA_TUSERDATA
: {
397 luaM_freemem(L
, o
, sizeudata(gco2u(o
)));
400 default: lua_assert(0);
406 #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM)
409 static GCObject
**sweeplist (lua_State
*L
, GCObject
**p
, lu_mem count
) {
411 global_State
*g
= G(L
);
412 int deadmask
= otherwhite(g
);
413 while ((curr
= *p
) != NULL
&& count
-- > 0) {
414 if (curr
->gch
.tt
== LUA_TTHREAD
) /* sweep open upvalues of each thread */
415 sweepwholelist(L
, &gco2th(curr
)->openupval
);
416 if ((curr
->gch
.marked
^ WHITEBITS
) & deadmask
) { /* not dead? */
417 lua_assert(!isdead(g
, curr
) || testbit(curr
->gch
.marked
, FIXEDBIT
));
418 makewhite(g
, curr
); /* make it white (for next cycle) */
421 else { /* must erase `curr' */
422 lua_assert(isdead(g
, curr
) || deadmask
== bitmask(SFIXEDBIT
));
424 if (curr
== g
->rootgc
) /* is the first element of the list? */
425 g
->rootgc
= curr
->gch
.next
; /* adjust first */
433 static void checkSizes (lua_State
*L
) {
434 global_State
*g
= G(L
);
435 /* check size of string hash */
436 if (g
->strt
.nuse
< cast(lu_int32
, g
->strt
.size
/4) &&
437 g
->strt
.size
> MINSTRTABSIZE
*2)
438 luaS_resize(L
, g
->strt
.size
/2); /* table is too big */
439 /* check size of buffer */
440 if (luaZ_sizebuffer(&g
->buff
) > LUA_MINBUFFER
*2) { /* buffer too big? */
441 size_t newsize
= luaZ_sizebuffer(&g
->buff
) / 2;
442 luaZ_resizebuffer(L
, &g
->buff
, newsize
);
447 static void GCTM (lua_State
*L
) {
448 global_State
*g
= G(L
);
449 GCObject
*o
= g
->tmudata
->gch
.next
; /* get first element */
450 Udata
*udata
= rawgco2u(o
);
452 /* remove udata from `tmudata' */
453 if (o
== g
->tmudata
) /* last element? */
456 g
->tmudata
->gch
.next
= udata
->uv
.next
;
457 udata
->uv
.next
= g
->mainthread
->next
; /* return it to `root' list */
458 g
->mainthread
->next
= o
;
460 tm
= fasttm(L
, udata
->uv
.metatable
, TM_GC
);
462 lu_byte oldah
= L
->allowhook
;
463 lu_mem oldt
= g
->GCthreshold
;
464 L
->allowhook
= 0; /* stop debug hooks during GC tag method */
465 g
->GCthreshold
= 2*g
->totalbytes
; /* avoid GC steps */
466 setobj2s(L
, L
->top
, tm
);
467 setuvalue(L
, L
->top
+1, udata
);
469 luaD_call(L
, L
->top
- 2, 0);
470 L
->allowhook
= oldah
; /* restore hooks */
471 g
->GCthreshold
= oldt
; /* restore threshold */
477 ** Call all GC tag methods
479 void luaC_callGCTM (lua_State
*L
) {
480 while (G(L
)->tmudata
)
485 void luaC_freeall (lua_State
*L
) {
486 global_State
*g
= G(L
);
488 g
->currentwhite
= WHITEBITS
| bitmask(SFIXEDBIT
); /* mask to collect all elements */
489 sweepwholelist(L
, &g
->rootgc
);
490 for (i
= 0; i
< g
->strt
.size
; i
++) /* free all string lists */
491 sweepwholelist(L
, &g
->strt
.hash
[i
]);
495 static void markmt (global_State
*g
) {
497 for (i
=0; i
<NUM_TAGS
; i
++)
498 if (g
->mt
[i
]) markobject(g
, g
->mt
[i
]);
503 static void markroot (lua_State
*L
) {
504 global_State
*g
= G(L
);
508 markobject(g
, g
->mainthread
);
509 /* make global table be traversed before main stack */
510 markvalue(g
, gt(g
->mainthread
));
511 markvalue(g
, registry(L
));
513 g
->gcstate
= GCSpropagate
;
517 static void remarkupvals (global_State
*g
) {
519 for (uv
= g
->uvhead
.u
.l
.next
; uv
!= &g
->uvhead
; uv
= uv
->u
.l
.next
) {
520 lua_assert(uv
->u
.l
.next
->u
.l
.prev
== uv
&& uv
->u
.l
.prev
->u
.l
.next
== uv
);
521 if (isgray(obj2gco(uv
)))
527 static void atomic (lua_State
*L
) {
528 global_State
*g
= G(L
);
529 size_t udsize
; /* total size of userdata to be finalized */
530 /* remark occasional upvalues of (maybe) dead threads */
532 /* traverse objects cautch by write barrier and by 'remarkupvals' */
534 /* remark weak tables */
537 lua_assert(!iswhite(obj2gco(g
->mainthread
)));
538 markobject(g
, L
); /* mark running thread */
539 markmt(g
); /* mark basic metatables (again) */
541 /* remark gray again */
542 g
->gray
= g
->grayagain
;
545 udsize
= luaC_separateudata(L
, 0); /* separate userdata to be finalized */
546 marktmu(g
); /* mark `preserved' userdata */
547 udsize
+= propagateall(g
); /* remark, to propagate `preserveness' */
548 cleartable(g
->weak
); /* remove collected objects from weak tables */
549 /* flip current white */
550 g
->currentwhite
= cast_byte(otherwhite(g
));
552 g
->sweepgc
= &g
->rootgc
;
553 g
->gcstate
= GCSsweepstring
;
554 g
->estimate
= g
->totalbytes
- udsize
; /* first estimate */
558 static l_mem
singlestep (lua_State
*L
) {
559 global_State
*g
= G(L
);
560 /*lua_checkmemory(L);*/
561 switch (g
->gcstate
) {
563 markroot(L
); /* start a new collection */
568 return propagatemark(g
);
569 else { /* no more `gray' objects */
570 atomic(L
); /* finish mark phase */
574 case GCSsweepstring
: {
575 lu_mem old
= g
->totalbytes
;
576 sweepwholelist(L
, &g
->strt
.hash
[g
->sweepstrgc
++]);
577 if (g
->sweepstrgc
>= g
->strt
.size
) /* nothing more to sweep? */
578 g
->gcstate
= GCSsweep
; /* end sweep-string phase */
579 lua_assert(old
>= g
->totalbytes
);
580 g
->estimate
-= old
- g
->totalbytes
;
584 lu_mem old
= g
->totalbytes
;
585 g
->sweepgc
= sweeplist(L
, g
->sweepgc
, GCSWEEPMAX
);
586 if (*g
->sweepgc
== NULL
) { /* nothing more to sweep? */
588 g
->gcstate
= GCSfinalize
; /* end sweep phase */
590 lua_assert(old
>= g
->totalbytes
);
591 g
->estimate
-= old
- g
->totalbytes
;
592 return GCSWEEPMAX
*GCSWEEPCOST
;
597 if (g
->estimate
> GCFINALIZECOST
)
598 g
->estimate
-= GCFINALIZECOST
;
599 return GCFINALIZECOST
;
602 g
->gcstate
= GCSpause
; /* end collection */
607 default: lua_assert(0); return 0;
612 void luaC_step (lua_State
*L
) {
613 global_State
*g
= G(L
);
614 l_mem lim
= (GCSTEPSIZE
/100) * g
->gcstepmul
;
616 lim
= (MAX_LUMEM
-1)/2; /* no limit */
617 g
->gcdept
+= g
->totalbytes
- g
->GCthreshold
;
619 lim
-= singlestep(L
);
620 if (g
->gcstate
== GCSpause
)
623 if (g
->gcstate
!= GCSpause
) {
624 if (g
->gcdept
< GCSTEPSIZE
)
625 g
->GCthreshold
= g
->totalbytes
+ GCSTEPSIZE
; /* - lim/g->gcstepmul;*/
627 g
->gcdept
-= GCSTEPSIZE
;
628 g
->GCthreshold
= g
->totalbytes
;
632 lua_assert(g
->totalbytes
>= g
->estimate
);
638 void luaC_fullgc (lua_State
*L
) {
639 global_State
*g
= G(L
);
640 if (g
->gcstate
<= GCSpropagate
) {
641 /* reset sweep marks to sweep all elements (returning them to white) */
643 g
->sweepgc
= &g
->rootgc
;
644 /* reset other collector lists */
648 g
->gcstate
= GCSsweepstring
;
650 lua_assert(g
->gcstate
!= GCSpause
&& g
->gcstate
!= GCSpropagate
);
651 /* finish any pending sweep phase */
652 while (g
->gcstate
!= GCSfinalize
) {
653 lua_assert(g
->gcstate
== GCSsweepstring
|| g
->gcstate
== GCSsweep
);
657 while (g
->gcstate
!= GCSpause
) {
664 void luaC_barrierf (lua_State
*L
, GCObject
*o
, GCObject
*v
) {
665 global_State
*g
= G(L
);
666 lua_assert(isblack(o
) && iswhite(v
) && !isdead(g
, v
) && !isdead(g
, o
));
667 lua_assert(g
->gcstate
!= GCSfinalize
&& g
->gcstate
!= GCSpause
);
668 lua_assert(ttype(&o
->gch
) != LUA_TTABLE
);
669 /* must keep invariant? */
670 if (g
->gcstate
== GCSpropagate
)
671 reallymarkobject(g
, v
); /* restore invariant */
672 else /* don't mind */
673 makewhite(g
, o
); /* mark as white just to avoid other barriers */
677 void luaC_barrierback (lua_State
*L
, Table
*t
) {
678 global_State
*g
= G(L
);
679 GCObject
*o
= obj2gco(t
);
680 lua_assert(isblack(o
) && !isdead(g
, o
));
681 lua_assert(g
->gcstate
!= GCSfinalize
&& g
->gcstate
!= GCSpause
);
682 black2gray(o
); /* make table gray (again) */
683 t
->gclist
= g
->grayagain
;
688 void luaC_link (lua_State
*L
, GCObject
*o
, lu_byte tt
) {
689 global_State
*g
= G(L
);
690 o
->gch
.next
= g
->rootgc
;
692 o
->gch
.marked
= luaC_white(g
);
697 void luaC_linkupval (lua_State
*L
, UpVal
*uv
) {
698 global_State
*g
= G(L
);
699 GCObject
*o
= obj2gco(uv
);
700 o
->gch
.next
= g
->rootgc
; /* link upvalue into `rootgc' list */
703 if (g
->gcstate
== GCSpropagate
) {
704 gray2black(o
); /* closed upvalues need barrier */
705 luaC_barrier(L
, uv
, uv
->v
);
707 else { /* sweep phase: sweep it (turning it into white) */
709 lua_assert(g
->gcstate
!= GCSfinalize
&& g
->gcstate
!= GCSpause
);