xref: /netbsd-src/external/mit/lua/dist/src/lgc.c (revision 80d9064ac03cbb6a4174695f0d5b237c8766d3d0)
1 /*	$NetBSD: lgc.c,v 1.2 2014/07/19 18:38:34 lneto Exp $	*/
2 
3 /*
4 ** $Id: lgc.c,v 1.2 2014/07/19 18:38:34 lneto Exp $
5 ** Garbage Collector
6 ** See Copyright Notice in lua.h
7 */
8 
9 #ifndef _KERNEL
10 #include <string.h>
11 #endif
12 
13 #define lgc_c
14 #define LUA_CORE
15 
16 #include "lua.h"
17 
18 #include "ldebug.h"
19 #include "ldo.h"
20 #include "lfunc.h"
21 #include "lgc.h"
22 #include "lmem.h"
23 #include "lobject.h"
24 #include "lstate.h"
25 #include "lstring.h"
26 #include "ltable.h"
27 #include "ltm.h"
28 
29 
30 /*
31 ** internal state for collector while inside the atomic phase. The
32 ** collector should never be in this state while running regular code.
33 */
34 #define GCSinsideatomic		(GCSpause + 1)
35 
36 /*
37 ** cost of sweeping one element (the size of a small object divided
38 ** by some adjust for the sweep speed)
39 */
40 #define GCSWEEPCOST	((sizeof(TString) + 4) / 4)
41 
42 /* maximum number of elements to sweep in each single step */
43 #define GCSWEEPMAX	(cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4))
44 
45 /* cost of calling one finalizer */
46 #define GCFINALIZECOST	GCSWEEPCOST
47 
48 
49 /*
50 ** macro to adjust 'stepmul': 'stepmul' is actually used like
51 ** 'stepmul / STEPMULADJ' (value chosen by tests)
52 */
53 #define STEPMULADJ		200
54 
55 
56 /*
57 ** macro to adjust 'pause': 'pause' is actually used like
58 ** 'pause / PAUSEADJ' (value chosen by tests)
59 */
60 #define PAUSEADJ		100
61 
62 
63 /*
64 ** 'makewhite' erases all color bits then sets only the current white
65 ** bit
66 */
67 #define maskcolors	(~(bitmask(BLACKBIT) | WHITEBITS))
68 #define makewhite(g,x)	\
69  (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g)))
70 
71 #define white2gray(x)	resetbits(gch(x)->marked, WHITEBITS)
72 #define black2gray(x)	resetbit(gch(x)->marked, BLACKBIT)
73 
74 
75 #define valiswhite(x)   (iscollectable(x) && iswhite(gcvalue(x)))
76 
77 #define checkdeadkey(n)	lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n)))
78 
79 
80 #define checkconsistency(obj)  \
81   lua_longassert(!iscollectable(obj) || righttt(obj))
82 
83 
84 #define markvalue(g,o) { checkconsistency(o); \
85   if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
86 
87 #define markobject(g,t) \
88   { if ((t) && iswhite(obj2gco(t))) reallymarkobject(g, obj2gco(t)); }
89 
90 static void reallymarkobject (global_State *g, GCObject *o);
91 
92 
93 /*
94 ** {======================================================
95 ** Generic functions
96 ** =======================================================
97 */
98 
99 
100 /*
101 ** one after last element in a hash array
102 */
103 #define gnodelast(h)	gnode(h, cast(size_t, sizenode(h)))
104 
105 
106 /*
107 ** link table 'h' into list pointed by 'p'
108 */
109 #define linktable(h,p)	((h)->gclist = *(p), *(p) = obj2gco(h))
110 
111 
112 /*
113 ** if key is not marked, mark its entry as dead (therefore removing it
114 ** from the table)
115 */
116 static void removeentry (Node *n) {
117   lua_assert(ttisnil(gval(n)));
118   if (valiswhite(gkey(n)))
119     setdeadvalue(gkey(n));  /* unused and unmarked key; remove it */
120 }
121 
122 
123 /*
124 ** tells whether a key or value can be cleared from a weak
125 ** table. Non-collectable objects are never removed from weak
126 ** tables. Strings behave as `values', so are never removed too. for
127 ** other objects: if really collected, cannot keep them; for objects
128 ** being finalized, keep them in keys, but not in values
129 */
130 static int iscleared (global_State *g, const TValue *o) {
131   if (!iscollectable(o)) return 0;
132   else if (ttisstring(o)) {
133     markobject(g, rawtsvalue(o));  /* strings are `values', so are never weak */
134     return 0;
135   }
136   else return iswhite(gcvalue(o));
137 }
138 
139 
140 /*
141 ** barrier that moves collector forward, that is, mark the white object
142 ** being pointed by a black object.
143 */
144 void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
145   global_State *g = G(L);
146   lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
147   lua_assert(g->gcstate != GCSpause);
148   lua_assert(gch(o)->tt != LUA_TTABLE);  /* tables use a back barrier */
149   if (keepinvariant(g))  /* must keep invariant? */
150     reallymarkobject(g, v);  /* restore invariant */
151   else {  /* sweep phase */
152     lua_assert(issweepphase(g));
153     makewhite(g, o);  /* mark main obj. as white to avoid other barriers */
154   }
155 }
156 
157 
158 /*
159 ** barrier that moves collector backward, that is, mark the black object
160 ** pointing to a white object as gray again. (Current implementation
161 ** only works for tables; access to 'gclist' is not uniform across
162 ** different types.)
163 */
164 void luaC_barrierback_ (lua_State *L, GCObject *o) {
165   global_State *g = G(L);
166   lua_assert(isblack(o) && !isdead(g, o) && gch(o)->tt == LUA_TTABLE);
167   black2gray(o);  /* make object gray (again) */
168   gco2t(o)->gclist = g->grayagain;
169   g->grayagain = o;
170 }
171 
172 
173 /*
174 ** barrier for assignments to closed upvalues. Because upvalues are
175 ** shared among closures, it is impossible to know the color of all
176 ** closures pointing to it. So, we assume that the object being assigned
177 ** must be marked.
178 */
179 void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) {
180   global_State *g = G(L);
181   GCObject *o = gcvalue(uv->v);
182   lua_assert(!upisopen(uv));  /* ensured by macro luaC_upvalbarrier */
183   if (keepinvariant(g))
184     markobject(g, o);
185 }
186 
187 
188 void luaC_fix (lua_State *L, GCObject *o) {
189   global_State *g = G(L);
190   lua_assert(g->allgc == o);  /* object must be 1st in 'allgc' list! */
191   white2gray(o);  /* they will be gray forever */
192   g->allgc = o->gch.next;  /* remove object from 'allgc' list */
193   o->gch.next = g->fixedgc;  /* link it to 'fixedgc' list */
194   g->fixedgc = o;
195 }
196 
197 
198 /*
199 ** create a new collectable object (with given type and size) and link
200 ** it to 'allgc' list.
201 */
202 GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
203   global_State *g = G(L);
204   GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz));
205   gch(o)->marked = luaC_white(g);
206   gch(o)->tt = tt;
207   gch(o)->next = g->allgc;
208   g->allgc = o;
209   return o;
210 }
211 
212 /* }====================================================== */
213 
214 
215 
216 /*
217 ** {======================================================
218 ** Mark functions
219 ** =======================================================
220 */
221 
222 
223 /*
224 ** mark an object. Userdata, strings, and closed upvalues are visited
225 ** and turned black here. Other objects are marked gray and added
226 ** to appropriate list to be visited (and turned black) later. (Open
227 ** upvalues are already linked in 'headuv' list.)
228 */
229 static void reallymarkobject (global_State *g, GCObject *o) {
230  reentry:
231   white2gray(o);
232   switch (gch(o)->tt) {
233     case LUA_TSHRSTR:
234     case LUA_TLNGSTR: {
235       gray2black(o);
236       g->GCmemtrav += sizestring(gco2ts(o));
237       break;
238     }
239     case LUA_TUSERDATA: {
240       TValue uvalue;
241       markobject(g, gco2u(o)->metatable);  /* mark its metatable */
242       gray2black(o);
243       g->GCmemtrav += sizeudata(gco2u(o));
244       getuservalue(g->mainthread, rawgco2u(o), &uvalue);
245       if (valiswhite(&uvalue)) {  /* markvalue(g, &uvalue); */
246         o = gcvalue(&uvalue);
247         goto reentry;
248       }
249       break;
250     }
251     case LUA_TLCL: {
252       gco2lcl(o)->gclist = g->gray;
253       g->gray = o;
254       break;
255     }
256     case LUA_TCCL: {
257       gco2ccl(o)->gclist = g->gray;
258       g->gray = o;
259       break;
260     }
261     case LUA_TTABLE: {
262       linktable(gco2t(o), &g->gray);
263       break;
264     }
265     case LUA_TTHREAD: {
266       gco2th(o)->gclist = g->gray;
267       g->gray = o;
268       break;
269     }
270     case LUA_TPROTO: {
271       gco2p(o)->gclist = g->gray;
272       g->gray = o;
273       break;
274     }
275     default: lua_assert(0); break;
276   }
277 }
278 
279 
280 /*
281 ** mark metamethods for basic types
282 */
283 static void markmt (global_State *g) {
284   int i;
285   for (i=0; i < LUA_NUMTAGS; i++)
286     markobject(g, g->mt[i]);
287 }
288 
289 
290 /*
291 ** mark all objects in list of being-finalized
292 */
293 static void markbeingfnz (global_State *g) {
294   GCObject *o;
295   for (o = g->tobefnz; o != NULL; o = gch(o)->next)
296     markobject(g, o);
297 }
298 
299 
300 /*
301 ** Mark all values stored in marked open upvalues from non-marked threads.
302 ** (Values from marked threads were already marked when traversing the
303 ** thread.) Remove from the list threads that no longer have upvalues and
304 ** not-marked threads.
305 */
306 static void remarkupvals (global_State *g) {
307   lua_State *thread;
308   lua_State **p = &g->twups;
309   while ((thread = *p) != NULL) {
310     lua_assert(!isblack(obj2gco(thread)));  /* threads are never black */
311     if (isgray(obj2gco(thread)) && thread->openupval != NULL)
312       p = &thread->twups;  /* keep marked thread with upvalues in the list */
313     else {  /* thread is not marked or without upvalues */
314       UpVal *uv;
315       *p = thread->twups;  /* remove thread from the list */
316       thread->twups = thread;  /* mark that it is out of list */
317       for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) {
318         if (uv->u.open.touched) {
319           markvalue(g, uv->v);  /* remark upvalue's value */
320           uv->u.open.touched = 0;
321         }
322       }
323     }
324   }
325 }
326 
327 
328 /*
329 ** mark root set and reset all gray lists, to start a new collection
330 */
331 static void restartcollection (global_State *g) {
332   g->gray = g->grayagain = NULL;
333   g->weak = g->allweak = g->ephemeron = NULL;
334   markobject(g, g->mainthread);
335   markvalue(g, &g->l_registry);
336   markmt(g);
337   markbeingfnz(g);  /* mark any finalizing object left from previous cycle */
338 }
339 
340 /* }====================================================== */
341 
342 
343 /*
344 ** {======================================================
345 ** Traverse functions
346 ** =======================================================
347 */
348 
349 static void traverseweakvalue (global_State *g, Table *h) {
350   Node *n, *limit = gnodelast(h);
351   /* if there is array part, assume it may have white values (do not
352      traverse it just to check) */
353   int hasclears = (h->sizearray > 0);
354   for (n = gnode(h, 0); n < limit; n++) {
355     checkdeadkey(n);
356     if (ttisnil(gval(n)))  /* entry is empty? */
357       removeentry(n);  /* remove it */
358     else {
359       lua_assert(!ttisnil(gkey(n)));
360       markvalue(g, gkey(n));  /* mark key */
361       if (!hasclears && iscleared(g, gval(n)))  /* is there a white value? */
362         hasclears = 1;  /* table will have to be cleared */
363     }
364   }
365   if (hasclears)
366     linktable(h, &g->weak);  /* has to be cleared later */
367   else  /* no white values */
368     linktable(h, &g->grayagain);  /* no need to clean */
369 }
370 
371 
372 static int traverseephemeron (global_State *g, Table *h) {
373   int marked = 0;  /* true if an object is marked in this traversal */
374   int hasclears = 0;  /* true if table has white keys */
375   int prop = 0;  /* true if table has entry "white-key -> white-value" */
376   Node *n, *limit = gnodelast(h);
377   int i;
378   /* traverse array part (numeric keys are 'strong') */
379   for (i = 0; i < h->sizearray; i++) {
380     if (valiswhite(&h->array[i])) {
381       marked = 1;
382       reallymarkobject(g, gcvalue(&h->array[i]));
383     }
384   }
385   /* traverse hash part */
386   for (n = gnode(h, 0); n < limit; n++) {
387     checkdeadkey(n);
388     if (ttisnil(gval(n)))  /* entry is empty? */
389       removeentry(n);  /* remove it */
390     else if (iscleared(g, gkey(n))) {  /* key is not marked (yet)? */
391       hasclears = 1;  /* table must be cleared */
392       if (valiswhite(gval(n)))  /* value not marked yet? */
393         prop = 1;  /* must propagate again */
394     }
395     else if (valiswhite(gval(n))) {  /* value not marked yet? */
396       marked = 1;
397       reallymarkobject(g, gcvalue(gval(n)));  /* mark it now */
398     }
399   }
400   if (prop)
401     linktable(h, &g->ephemeron);  /* have to propagate again */
402   else if (hasclears)  /* does table have white keys? */
403     linktable(h, &g->allweak);  /* may have to clean white keys */
404   else  /* no white keys */
405     linktable(h, &g->grayagain);  /* no need to clean */
406   return marked;
407 }
408 
409 
410 static void traversestrongtable (global_State *g, Table *h) {
411   Node *n, *limit = gnodelast(h);
412   int i;
413   for (i = 0; i < h->sizearray; i++)  /* traverse array part */
414     markvalue(g, &h->array[i]);
415   for (n = gnode(h, 0); n < limit; n++) {  /* traverse hash part */
416     checkdeadkey(n);
417     if (ttisnil(gval(n)))  /* entry is empty? */
418       removeentry(n);  /* remove it */
419     else {
420       lua_assert(!ttisnil(gkey(n)));
421       markvalue(g, gkey(n));  /* mark key */
422       markvalue(g, gval(n));  /* mark value */
423     }
424   }
425 }
426 
427 
428 static lu_mem traversetable (global_State *g, Table *h) {
429   const char *weakkey, *weakvalue;
430   const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
431   markobject(g, h->metatable);
432   if (mode && ttisstring(mode) &&  /* is there a weak mode? */
433       ((weakkey = strchr(svalue(mode), 'k')),
434        (weakvalue = strchr(svalue(mode), 'v')),
435        (weakkey || weakvalue))) {  /* is really weak? */
436     black2gray(obj2gco(h));  /* keep table gray */
437     if (!weakkey)  /* strong keys? */
438       traverseweakvalue(g, h);
439     else if (!weakvalue)  /* strong values? */
440       traverseephemeron(g, h);
441     else  /* all weak */
442       linktable(h, &g->allweak);  /* nothing to traverse now */
443   }
444   else  /* not weak */
445     traversestrongtable(g, h);
446   return sizeof(Table) + sizeof(TValue) * h->sizearray +
447                          sizeof(Node) * cast(size_t, sizenode(h));
448 }
449 
450 
451 static int traverseproto (global_State *g, Proto *f) {
452   int i;
453   if (f->cache && iswhite(obj2gco(f->cache)))
454     f->cache = NULL;  /* allow cache to be collected */
455   markobject(g, f->source);
456   for (i = 0; i < f->sizek; i++)  /* mark literals */
457     markvalue(g, &f->k[i]);
458   for (i = 0; i < f->sizeupvalues; i++)  /* mark upvalue names */
459     markobject(g, f->upvalues[i].name);
460   for (i = 0; i < f->sizep; i++)  /* mark nested protos */
461     markobject(g, f->p[i]);
462   for (i = 0; i < f->sizelocvars; i++)  /* mark local-variable names */
463     markobject(g, f->locvars[i].varname);
464   return sizeof(Proto) + sizeof(Instruction) * f->sizecode +
465                          sizeof(Proto *) * f->sizep +
466                          sizeof(TValue) * f->sizek +
467                          sizeof(int) * f->sizelineinfo +
468                          sizeof(LocVar) * f->sizelocvars +
469                          sizeof(Upvaldesc) * f->sizeupvalues;
470 }
471 
472 
473 static lu_mem traverseCclosure (global_State *g, CClosure *cl) {
474   int i;
475   for (i = 0; i < cl->nupvalues; i++)  /* mark its upvalues */
476     markvalue(g, &cl->upvalue[i]);
477   return sizeCclosure(cl->nupvalues);
478 }
479 
480 /*
481 ** open upvalues point to values in a thread, so those values should
482 ** be marked when the thread is traversed except in the atomic phase
483 ** (because then the value cannot be changed by the thread and the
484 ** thread may not be traversed again)
485 */
486 static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
487   int i;
488   markobject(g, cl->p);  /* mark its prototype */
489   for (i = 0; i < cl->nupvalues; i++) {  /* mark its upvalues */
490     UpVal *uv = cl->upvals[i];
491     if (uv != NULL) {
492       if (upisopen(uv) && g->gcstate != GCSinsideatomic)
493         uv->u.open.touched = 1;  /* can be marked in 'remarkupvals' */
494       else
495         markvalue(g, uv->v);
496     }
497   }
498   return sizeLclosure(cl->nupvalues);
499 }
500 
501 
502 static lu_mem traversethread (global_State *g, lua_State *th) {
503   StkId o = th->stack;
504   if (o == NULL)
505     return 1;  /* stack not completely built yet */
506   lua_assert(g->gcstate == GCSinsideatomic ||
507              th->openupval == NULL || isintwups(th));
508   for (; o < th->top; o++)  /* mark live elements in the stack */
509     markvalue(g, o);
510   if (g->gcstate == GCSinsideatomic) {  /* final traversal? */
511     StkId lim = th->stack + th->stacksize;  /* real end of stack */
512     for (; o < lim; o++)  /* clear not-marked stack slice */
513       setnilvalue(o);
514     /* 'remarkupvals' may have removed thread from 'twups' list */
515     if (!isintwups(th) && th->openupval != NULL) {
516       th->twups = g->twups;  /* link it back to the list */
517       g->twups = th;
518     }
519   }
520   else if (g->gckind != KGC_EMERGENCY)
521     luaD_shrinkstack(th); /* do not change stack in emergency cycle */
522   return (sizeof(lua_State) + sizeof(TValue) * th->stacksize);
523 }
524 
525 
526 /*
527 ** traverse one gray object, turning it to black (except for threads,
528 ** which are always gray).
529 */
530 static void propagatemark (global_State *g) {
531   lu_mem size;
532   GCObject *o = g->gray;
533   lua_assert(isgray(o));
534   gray2black(o);
535   switch (gch(o)->tt) {
536     case LUA_TTABLE: {
537       Table *h = gco2t(o);
538       g->gray = h->gclist;  /* remove from 'gray' list */
539       size = traversetable(g, h);
540       break;
541     }
542     case LUA_TLCL: {
543       LClosure *cl = gco2lcl(o);
544       g->gray = cl->gclist;  /* remove from 'gray' list */
545       size = traverseLclosure(g, cl);
546       break;
547     }
548     case LUA_TCCL: {
549       CClosure *cl = gco2ccl(o);
550       g->gray = cl->gclist;  /* remove from 'gray' list */
551       size = traverseCclosure(g, cl);
552       break;
553     }
554     case LUA_TTHREAD: {
555       lua_State *th = gco2th(o);
556       g->gray = th->gclist;  /* remove from 'gray' list */
557       th->gclist = g->grayagain;
558       g->grayagain = o;  /* insert into 'grayagain' list */
559       black2gray(o);
560       size = traversethread(g, th);
561       break;
562     }
563     case LUA_TPROTO: {
564       Proto *p = gco2p(o);
565       g->gray = p->gclist;  /* remove from 'gray' list */
566       size = traverseproto(g, p);
567       break;
568     }
569     default: lua_assert(0); return;
570   }
571   g->GCmemtrav += size;
572 }
573 
574 
575 static void propagateall (global_State *g) {
576   while (g->gray) propagatemark(g);
577 }
578 
579 
580 static void propagatelist (global_State *g, GCObject *l) {
581   lua_assert(g->gray == NULL);  /* no grays left */
582   g->gray = l;
583   propagateall(g);  /* traverse all elements from 'l' */
584 }
585 
586 /*
587 ** retraverse all gray lists. Because tables may be reinserted in other
588 ** lists when traversed, traverse the original lists to avoid traversing
589 ** twice the same table (which is not wrong, but inefficient)
590 */
591 static void retraversegrays (global_State *g) {
592   GCObject *weak = g->weak;  /* save original lists */
593   GCObject *grayagain = g->grayagain;
594   GCObject *ephemeron = g->ephemeron;
595   g->weak = g->grayagain = g->ephemeron = NULL;
596   propagateall(g);  /* traverse main gray list */
597   propagatelist(g, grayagain);
598   propagatelist(g, weak);
599   propagatelist(g, ephemeron);
600 }
601 
602 
603 static void convergeephemerons (global_State *g) {
604   int changed;
605   do {
606     GCObject *w;
607     GCObject *next = g->ephemeron;  /* get ephemeron list */
608     g->ephemeron = NULL;  /* tables will return to this list when traversed */
609     changed = 0;
610     while ((w = next) != NULL) {
611       next = gco2t(w)->gclist;
612       if (traverseephemeron(g, gco2t(w))) {  /* traverse marked some value? */
613         propagateall(g);  /* propagate changes */
614         changed = 1;  /* will have to revisit all ephemeron tables */
615       }
616     }
617   } while (changed);
618 }
619 
620 /* }====================================================== */
621 
622 
623 /*
624 ** {======================================================
625 ** Sweep Functions
626 ** =======================================================
627 */
628 
629 
630 /*
631 ** clear entries with unmarked keys from all weaktables in list 'l' up
632 ** to element 'f'
633 */
634 static void clearkeys (global_State *g, GCObject *l, GCObject *f) {
635   for (; l != f; l = gco2t(l)->gclist) {
636     Table *h = gco2t(l);
637     Node *n, *limit = gnodelast(h);
638     for (n = gnode(h, 0); n < limit; n++) {
639       if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) {
640         setnilvalue(gval(n));  /* remove value ... */
641         removeentry(n);  /* and remove entry from table */
642       }
643     }
644   }
645 }
646 
647 
648 /*
649 ** clear entries with unmarked values from all weaktables in list 'l' up
650 ** to element 'f'
651 */
652 static void clearvalues (global_State *g, GCObject *l, GCObject *f) {
653   for (; l != f; l = gco2t(l)->gclist) {
654     Table *h = gco2t(l);
655     Node *n, *limit = gnodelast(h);
656     int i;
657     for (i = 0; i < h->sizearray; i++) {
658       TValue *o = &h->array[i];
659       if (iscleared(g, o))  /* value was collected? */
660         setnilvalue(o);  /* remove value */
661     }
662     for (n = gnode(h, 0); n < limit; n++) {
663       if (!ttisnil(gval(n)) && iscleared(g, gval(n))) {
664         setnilvalue(gval(n));  /* remove value ... */
665         removeentry(n);  /* and remove entry from table */
666       }
667     }
668   }
669 }
670 
671 
672 void luaC_upvdeccount (lua_State *L, UpVal *uv) {
673   lua_assert(uv->refcount > 0);
674   uv->refcount--;
675   if (uv->refcount == 0 && !upisopen(uv))
676     luaM_free(L, uv);
677 }
678 
679 
680 static void freeLclosure (lua_State *L, LClosure *cl) {
681   int i;
682   for (i = 0; i < cl->nupvalues; i++) {
683     UpVal *uv = cl->upvals[i];
684     if (uv)
685       luaC_upvdeccount(L, uv);
686   }
687   luaM_freemem(L, cl, sizeLclosure(cl->nupvalues));
688 }
689 
690 
691 static void freeobj (lua_State *L, GCObject *o) {
692   switch (gch(o)->tt) {
693     case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
694     case LUA_TLCL: {
695       freeLclosure(L, gco2lcl(o));
696       break;
697     }
698     case LUA_TCCL: {
699       luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues));
700       break;
701     }
702     case LUA_TTABLE: luaH_free(L, gco2t(o)); break;
703     case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break;
704     case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;
705     case LUA_TSHRSTR:
706       luaS_remove(L, rawgco2ts(o));  /* remove it from hash table */
707       /* go through */
708     case LUA_TLNGSTR: {
709       luaM_freemem(L, o, sizestring(gco2ts(o)));
710       break;
711     }
712     default: lua_assert(0);
713   }
714 }
715 
716 
717 #define sweepwholelist(L,p)	sweeplist(L,p,MAX_LUMEM)
718 static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count);
719 
720 
721 /*
722 ** sweep at most 'count' elements from a list of GCObjects erasing dead
723 ** objects, where a dead (not alive) object is one marked with the "old"
724 ** (non current) white and not fixed; change all non-dead objects back
725 ** to white, preparing for next collection cycle.
726 ** When object is a thread, sweep its list of open upvalues too.
727 */
728 static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
729   global_State *g = G(L);
730   int ow = otherwhite(g);
731   int white = luaC_white(g);  /* current white */
732   while (*p != NULL && count-- > 0) {
733     GCObject *curr = *p;
734     int marked = gch(curr)->marked;
735     if (isdeadm(ow, marked)) {  /* is 'curr' dead? */
736       *p = gch(curr)->next;  /* remove 'curr' from list */
737       freeobj(L, curr);  /* erase 'curr' */
738     }
739     else {  /* update marks */
740       gch(curr)->marked = cast_byte((marked & maskcolors) | white);
741       p = &gch(curr)->next;  /* go to next element */
742     }
743   }
744   return (*p == NULL) ? NULL : p;
745 }
746 
747 
748 /*
749 ** sweep a list until a live object (or end of list)
750 */
751 static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
752   GCObject **old = p;
753   int i = 0;
754   do {
755     i++;
756     p = sweeplist(L, p, 1);
757   } while (p == old);
758   if (n) *n += i;
759   return p;
760 }
761 
762 /* }====================================================== */
763 
764 
765 /*
766 ** {======================================================
767 ** Finalization
768 ** =======================================================
769 */
770 
771 /*
772 ** If possible, free concatenation buffer and shrink string table
773 */
774 static void checkSizes (lua_State *L, global_State *g) {
775   if (g->gckind != KGC_EMERGENCY) {
776     l_mem olddebt = g->GCdebt;
777     luaZ_freebuffer(L, &g->buff);  /* free concatenation buffer */
778     if (g->strt.nuse < g->strt.size / 4)  /* string table too big? */
779       luaS_resize(L, g->strt.size / 2);  /* shrink it a little */
780     g->GCestimate += g->GCdebt - olddebt;  /* update estimate */
781   }
782 }
783 
784 
785 static GCObject *udata2finalize (global_State *g) {
786   GCObject *o = g->tobefnz;  /* get first element */
787   lua_assert(tofinalize(o));
788   g->tobefnz = gch(o)->next;  /* remove it from 'tobefnz' list */
789   gch(o)->next = g->allgc;  /* return it to 'allgc' list */
790   g->allgc = o;
791   resetbit(gch(o)->marked, FINALIZEDBIT);  /* object is "normal" again */
792   if (issweepphase(g))
793     makewhite(g, o);  /* "sweep" object */
794   return o;
795 }
796 
797 
798 static void dothecall (lua_State *L, void *ud) {
799   UNUSED(ud);
800   luaD_call(L, L->top - 2, 0, 0);
801 }
802 
803 
804 static void GCTM (lua_State *L, int propagateerrors) {
805   global_State *g = G(L);
806   const TValue *tm;
807   TValue v;
808   setgcovalue(L, &v, udata2finalize(g));
809   tm = luaT_gettmbyobj(L, &v, TM_GC);
810   if (tm != NULL && ttisfunction(tm)) {  /* is there a finalizer? */
811     int status;
812     lu_byte oldah = L->allowhook;
813     int running  = g->gcrunning;
814     L->allowhook = 0;  /* stop debug hooks during GC metamethod */
815     g->gcrunning = 0;  /* avoid GC steps */
816     setobj2s(L, L->top, tm);  /* push finalizer... */
817     setobj2s(L, L->top + 1, &v);  /* ... and its argument */
818     L->top += 2;  /* and (next line) call the finalizer */
819     status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
820     L->allowhook = oldah;  /* restore hooks */
821     g->gcrunning = running;  /* restore state */
822     if (status != LUA_OK && propagateerrors) {  /* error while running __gc? */
823       if (status == LUA_ERRRUN) {  /* is there an error object? */
824         const char *msg = (ttisstring(L->top - 1))
825                             ? svalue(L->top - 1)
826                             : "no message";
827         luaO_pushfstring(L, "error in __gc metamethod (%s)", msg);
828         status = LUA_ERRGCMM;  /* error in __gc metamethod */
829       }
830       luaD_throw(L, status);  /* re-throw error */
831     }
832   }
833 }
834 
835 
836 /*
837 ** call a few (up to 'g->gcfinnum') finalizers
838 */
839 static int runafewfinalizers (lua_State *L) {
840   global_State *g = G(L);
841   unsigned int i;
842   lua_assert(!g->tobefnz || g->gcfinnum > 0);
843   for (i = 0; g->tobefnz && i < g->gcfinnum; i++)
844     GCTM(L, 1);  /* call one finalizer */
845   g->gcfinnum = (!g->tobefnz) ? 0  /* nothing more to finalize? */
846                     : g->gcfinnum * 2;  /* else call a few more next time */
847   return i;
848 }
849 
850 
851 /*
852 ** call all pending finalizers
853 */
854 static void callallpendingfinalizers (lua_State *L, int propagateerrors) {
855   global_State *g = G(L);
856   while (g->tobefnz)
857     GCTM(L, propagateerrors);
858 }
859 
860 
861 /*
862 ** find last 'next' field in list 'p' list (to add elements in its end)
863 */
864 static GCObject **findlast (GCObject **p) {
865   while (*p != NULL)
866     p = &gch(*p)->next;
867   return p;
868 }
869 
870 
871 /*
872 ** move all unreachable objects (or 'all' objects) that need
873 ** finalization from list 'p' to list 'tobefnz' (to be finalized)
874 */
875 static void separatetobefnz (global_State *g, int all) {
876   GCObject *curr;
877   GCObject **p = &g->finobj;
878   GCObject **lastnext = findlast(&g->tobefnz);
879   while ((curr = *p) != NULL) {  /* traverse all finalizable objects */
880     lua_assert(tofinalize(curr));
881     if (!(iswhite(curr) || all))  /* not being collected? */
882       p = &gch(curr)->next;  /* don't bother with it */
883     else {
884       *p = gch(curr)->next;  /* remove 'curr' from "fin" list */
885       gch(curr)->next = *lastnext;  /* link at the end of 'tobefnz' list */
886       *lastnext = curr;
887       lastnext = &gch(curr)->next;
888     }
889   }
890 }
891 
892 
893 /*
894 ** if object 'o' has a finalizer, remove it from 'allgc' list (must
895 ** search the list to find it) and link it in 'finobj' list.
896 */
897 void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
898   global_State *g = G(L);
899   if (tofinalize(o) ||                 /* obj. is already marked... */
900       gfasttm(g, mt, TM_GC) == NULL)   /* or has no finalizer? */
901     return;  /* nothing to be done */
902   else {  /* move 'o' to 'finobj' list */
903     GCObject **p;
904     if (issweepphase(g)) {
905       makewhite(g, o);  /* "sweep" object 'o' */
906       if (g->sweepgc == &o->gch.next)  /* shoud not remove 'sweepgc' object */
907         g->sweepgc = sweeptolive(L, g->sweepgc, NULL);  /* change 'sweepgc' */
908     }
909     /* search for pointer pointing to 'o' */
910     for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ }
911     *p = o->gch.next;  /* remove 'o' from 'allgc' list */
912     o->gch.next = g->finobj;  /* link it in "fin" list */
913     g->finobj = o;
914     l_setbit(o->gch.marked, FINALIZEDBIT);  /* mark it as such */
915   }
916 }
917 
918 /* }====================================================== */
919 
920 
921 
922 /*
923 ** {======================================================
924 ** GC control
925 ** =======================================================
926 */
927 
928 
929 /*
930 ** set a reasonable "time" to wait before starting a new GC cycle;
931 ** cycle will start when memory use hits threshold
932 */
933 static void setpause (global_State *g) {
934   l_mem threshold, debt;
935   l_mem estimate = g->GCestimate / PAUSEADJ;  /* adjust 'estimate' */
936   threshold = (g->gcpause < MAX_LMEM / estimate)  /* overflow? */
937             ? estimate * g->gcpause  /* no overflow */
938             : MAX_LMEM;  /* overflow; truncate to maximum */
939   debt = gettotalbytes(g) - threshold;
940   luaE_setdebt(g, debt);
941 }
942 
943 
944 /*
945 ** Enter first sweep phase.
946 ** The call to 'sweeptolive' makes pointer point to an object inside
947 ** the list (instead of to the header), so that the real sweep do not
948 ** need to skip objects created between "now" and the start of the real
949 ** sweep.
950 ** Returns how many objects it swept.
951 */
952 static int entersweep (lua_State *L) {
953   global_State *g = G(L);
954   int n = 0;
955   g->gcstate = GCSswpallgc;
956   lua_assert(g->sweepgc == NULL);
957   g->sweepgc = sweeptolive(L, &g->allgc, &n);
958   return n;
959 }
960 
961 
962 void luaC_freeallobjects (lua_State *L) {
963   global_State *g = G(L);
964   separatetobefnz(g, 1);  /* separate all objects with finalizers */
965   lua_assert(g->finobj == NULL);
966   callallpendingfinalizers(L, 0);
967   lua_assert(g->tobefnz == NULL);
968   g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */
969   g->gckind = KGC_NORMAL;
970   sweepwholelist(L, &g->finobj);
971   sweepwholelist(L, &g->allgc);
972   sweepwholelist(L, &g->fixedgc);  /* collect fixed objects */
973   lua_assert(g->strt.nuse == 0);
974 }
975 
976 
977 static l_mem atomic (lua_State *L) {
978   global_State *g = G(L);
979   l_mem work;
980   GCObject *origweak, *origall;
981   g->GCmemtrav = 0;  /* start counting work */
982   lua_assert(!iswhite(obj2gco(g->mainthread)));
983   g->gcstate = GCSinsideatomic;
984   markobject(g, L);  /* mark running thread */
985   /* registry and global metatables may be changed by API */
986   markvalue(g, &g->l_registry);
987   markmt(g);  /* mark basic metatables */
988   /* remark occasional upvalues of (maybe) dead threads */
989   remarkupvals(g);
990   propagateall(g);  /* propagate changes */
991   work = g->GCmemtrav;  /* stop counting (do not (re)count grays) */
992   /* traverse objects caught by write barrier and by 'remarkupvals' */
993   retraversegrays(g);
994   g->GCmemtrav = 0;  /* restart counting */
995   convergeephemerons(g);
996   /* at this point, all strongly accessible objects are marked. */
997   /* Clear values from weak tables, before checking finalizers */
998   clearvalues(g, g->weak, NULL);
999   clearvalues(g, g->allweak, NULL);
1000   origweak = g->weak; origall = g->allweak;
1001   work += g->GCmemtrav;  /* stop counting (objects being finalized) */
1002   separatetobefnz(g, 0);  /* separate objects to be finalized */
1003   g->gcfinnum = 1;  /* there may be objects to be finalized */
1004   markbeingfnz(g);  /* mark objects that will be finalized */
1005   propagateall(g);  /* remark, to propagate 'resurrection' */
1006   g->GCmemtrav = 0;  /* restart counting */
1007   convergeephemerons(g);
1008   /* at this point, all resurrected objects are marked. */
1009   /* remove dead objects from weak tables */
1010   clearkeys(g, g->ephemeron, NULL);  /* clear keys from all ephemeron tables */
1011   clearkeys(g, g->allweak, NULL);  /* clear keys from all allweak tables */
1012   /* clear values from resurrected weak tables */
1013   clearvalues(g, g->weak, origweak);
1014   clearvalues(g, g->allweak, origall);
1015   g->currentwhite = cast_byte(otherwhite(g));  /* flip current white */
1016   work += g->GCmemtrav;  /* complete counting */
1017   return work;  /* estimate of memory marked by 'atomic' */
1018 }
1019 
1020 
1021 static lu_mem sweepstep (lua_State *L, global_State *g,
1022                          int nextstate, GCObject **nextlist) {
1023   if (g->sweepgc) {
1024     l_mem olddebt = g->GCdebt;
1025     g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
1026     g->GCestimate += g->GCdebt - olddebt;  /* update estimate */
1027     if (g->sweepgc)  /* is there still something to sweep? */
1028       return (GCSWEEPMAX * GCSWEEPCOST);
1029   }
1030   /* else enter next state */
1031   g->gcstate = nextstate;
1032   g->sweepgc = nextlist;
1033   return 0;
1034 }
1035 
1036 
1037 static lu_mem singlestep (lua_State *L) {
1038   global_State *g = G(L);
1039   switch (g->gcstate) {
1040     case GCSpause: {
1041       g->GCmemtrav = g->strt.size * sizeof(GCObject*);
1042       restartcollection(g);
1043       g->gcstate = GCSpropagate;
1044       return g->GCmemtrav;
1045     }
1046     case GCSpropagate: {
1047       g->GCmemtrav = 0;
1048       lua_assert(g->gray);
1049       propagatemark(g);
1050        if (g->gray == NULL)  /* no more `gray' objects? */
1051         g->gcstate = GCSatomic;  /* finish propagate phase */
1052       return g->GCmemtrav;  /* memory traversed in this step */
1053     }
1054     case GCSatomic: {
1055       lu_mem work;
1056       int sw;
1057       propagateall(g);  /* make sure gray list is empty */
1058       work = atomic(L);  /* work is what was traversed by 'atomic' */
1059       sw = entersweep(L);
1060       g->GCestimate = gettotalbytes(g);  /* first estimate */;
1061       return work + sw * GCSWEEPCOST;
1062     }
1063     case GCSswpallgc: {  /* sweep "regular" objects */
1064       return sweepstep(L, g, GCSswpfinobj, &g->finobj);
1065     }
1066     case GCSswpfinobj: {  /* sweep objects with finalizers */
1067       return sweepstep(L, g, GCSswptobefnz, &g->tobefnz);
1068     }
1069     case GCSswptobefnz: {  /* sweep objects to be finalized */
1070       return sweepstep(L, g, GCSswpend, NULL);
1071     }
1072     case GCSswpend: {  /* finish sweeps */
1073       makewhite(g, obj2gco(g->mainthread));  /* sweep main thread */
1074       checkSizes(L, g);
1075       g->gcstate = GCScallfin;
1076       return 0;
1077     }
1078     case GCScallfin: {  /* call remaining finalizers */
1079       if (g->tobefnz && g->gckind != KGC_EMERGENCY) {
1080         int n = runafewfinalizers(L);
1081         return (n * GCFINALIZECOST);
1082       }
1083       else {  /* emergency mode or no more finalizers */
1084         g->gcstate = GCSpause;  /* finish collection */
1085         return 0;
1086       }
1087     }
1088     default: lua_assert(0); return 0;
1089   }
1090 }
1091 
1092 
1093 /*
1094 ** advances the garbage collector until it reaches a state allowed
1095 ** by 'statemask'
1096 */
1097 void luaC_runtilstate (lua_State *L, int statesmask) {
1098   global_State *g = G(L);
1099   while (!testbit(statesmask, g->gcstate))
1100     singlestep(L);
1101 }
1102 
1103 
1104 /*
1105 ** get GC debt and convert it from Kb to 'work units' (avoid zero debt
1106 ** and overflows)
1107 */
1108 static l_mem getdebt (global_State *g) {
1109   l_mem debt = g->GCdebt;
1110   int stepmul = g->gcstepmul;
1111   debt = (debt / STEPMULADJ) + 1;
1112   debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
1113   return debt;
1114 }
1115 
1116 /*
1117 ** performs a basic GC step when collector is running
1118 */
1119 void luaC_step (lua_State *L) {
1120   global_State *g = G(L);
1121   l_mem debt = getdebt(g);  /* GC deficit (be paid now) */
1122   if (!g->gcrunning) {  /* not running? */
1123     luaE_setdebt(g, -GCSTEPSIZE * 10);  /* avoid being called too often */
1124     return;
1125   }
1126   do {  /* repeat until pause or enough "credit" (negative debt) */
1127     lu_mem work = singlestep(L);  /* perform one single step */
1128     debt -= work;
1129   } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause);
1130   if (g->gcstate == GCSpause)
1131     setpause(g);  /* pause until next cycle */
1132   else {
1133     debt = (debt / g->gcstepmul) * STEPMULADJ;  /* convert 'work units' to Kb */
1134     luaE_setdebt(g, debt);
1135     runafewfinalizers(L);
1136   }
1137 }
1138 
1139 
1140 /*
1141 ** Performs a full GC cycle; if "isemergency", set a flag to avoid
1142 ** some operations which could change the interpreter state in some
1143 ** unexpected ways (running finalizers and shrinking some structures).
1144 ** Before running the collection, check 'keepinvariant'; if it is true,
1145 ** there may be some objects marked as black, so the collector has
1146 ** to sweep all objects to turn them back to white (as white has not
1147 ** changed, nothing will be collected).
1148 */
1149 void luaC_fullgc (lua_State *L, int isemergency) {
1150   global_State *g = G(L);
1151   lua_assert(g->gckind == KGC_NORMAL);
1152   if (isemergency) g->gckind = KGC_EMERGENCY;  /* set flag */
1153   if (keepinvariant(g)) {  /* black objects? */
1154     entersweep(L); /* sweep everything to turn them back to white */
1155   }
1156   /* finish any pending sweep phase to start a new cycle */
1157   luaC_runtilstate(L, bitmask(GCSpause));
1158   luaC_runtilstate(L, ~bitmask(GCSpause));  /* start new collection */
1159   luaC_runtilstate(L, bitmask(GCScallfin));  /* run up to finalizers */
1160   /* estimate must be correct after a full GC cycle */
1161   lua_assert(g->GCestimate == gettotalbytes(g));
1162   luaC_runtilstate(L, bitmask(GCSpause));  /* finish collection */
1163   g->gckind = KGC_NORMAL;
1164   setpause(g);
1165 }
1166 
1167 /* }====================================================== */
1168 
1169 
1170