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