/src/testdir/build/lua-master/source/lgc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | ** $Id: lgc.c $ |
3 | | ** Garbage Collector |
4 | | ** See Copyright Notice in lua.h |
5 | | */ |
6 | | |
7 | | #define lgc_c |
8 | | #define LUA_CORE |
9 | | |
10 | | #include "lprefix.h" |
11 | | |
12 | | #include <string.h> |
13 | | |
14 | | |
15 | | #include "lua.h" |
16 | | |
17 | | #include "ldebug.h" |
18 | | #include "ldo.h" |
19 | | #include "lfunc.h" |
20 | | #include "lgc.h" |
21 | | #include "lmem.h" |
22 | | #include "lobject.h" |
23 | | #include "lstate.h" |
24 | | #include "lstring.h" |
25 | | #include "ltable.h" |
26 | | #include "ltm.h" |
27 | | |
28 | | |
29 | | /* |
30 | | ** Maximum number of elements to sweep in each single step. |
31 | | ** (Large enough to dissipate fixed overheads but small enough |
32 | | ** to allow small steps for the collector.) |
33 | | */ |
34 | 24.9M | #define GCSWEEPMAX 20 |
35 | | |
36 | | |
37 | | /* |
38 | | ** Cost (in work units) of running one finalizer. |
39 | | */ |
40 | 1.88M | #define CWUFIN 10 |
41 | | |
42 | | |
43 | | /* mask with all color bits */ |
44 | 4.72M | #define maskcolors (bitmask(BLACKBIT) | WHITEBITS) |
45 | | |
46 | | /* mask with all GC bits */ |
47 | 4.72M | #define maskgcbits (maskcolors | AGEBITS) |
48 | | |
49 | | |
50 | | /* macro to erase all color bits then set only the current white bit */ |
51 | | #define makewhite(g,x) \ |
52 | 825k | (x->marked = cast_byte((x->marked & ~maskcolors) | luaC_white(g))) |
53 | | |
54 | | /* make an object gray (neither white nor black) */ |
55 | 76.6M | #define set2gray(x) resetbits(x->marked, maskcolors) |
56 | | |
57 | | |
58 | | /* make an object black (coming from any color) */ |
59 | | #define set2black(x) \ |
60 | 135M | (x->marked = cast_byte((x->marked & ~WHITEBITS) | bitmask(BLACKBIT))) |
61 | | |
62 | | |
63 | 811M | #define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) |
64 | | |
65 | 176M | #define keyiswhite(n) (keyiscollectable(n) && iswhite(gckey(n))) |
66 | | |
67 | | |
68 | | /* |
69 | | ** Protected access to objects in values |
70 | | */ |
71 | 15.2k | #define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL) |
72 | | |
73 | | |
74 | | /* |
75 | | ** Access to collectable objects in array part of tables |
76 | | */ |
77 | | #define gcvalarr(t,i) \ |
78 | 540M | ((*getArrTag(t,i) & BIT_ISCOLLECTABLE) ? getArrVal(t,i)->gc : NULL) |
79 | | |
80 | | |
81 | 824M | #define markvalue(g,o) { checkliveness(mainthread(g),o); \ |
82 | 824M | if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } |
83 | | |
84 | 176M | #define markkey(g, n) { if keyiswhite(n) reallymarkobject(g,gckey(n)); } |
85 | | |
86 | 141M | #define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); } |
87 | | |
88 | | /* |
89 | | ** mark an object that can be NULL (either because it is really optional, |
90 | | ** or it was stripped as debug info, or inside an uncompleted structure) |
91 | | */ |
92 | 182M | #define markobjectN(g,t) { if (t) markobject(g,t); } |
93 | | |
94 | | |
95 | | static void reallymarkobject (global_State *g, GCObject *o); |
96 | | static void atomic (lua_State *L); |
97 | | static void entersweep (lua_State *L); |
98 | | |
99 | | |
100 | | /* |
101 | | ** {====================================================== |
102 | | ** Generic functions |
103 | | ** ======================================================= |
104 | | */ |
105 | | |
106 | | |
107 | | /* |
108 | | ** one after last element in a hash array |
109 | | */ |
110 | 19.8M | #define gnodelast(h) gnode(h, cast_sizet(sizenode(h))) |
111 | | |
112 | | |
113 | 341M | static l_mem objsize (GCObject *o) { |
114 | 341M | lu_mem res; |
115 | 341M | switch (o->tt) { |
116 | 61.6M | case LUA_VTABLE: { |
117 | 61.6M | res = luaH_size(gco2t(o)); |
118 | 0 | break; |
119 | 61.6M | } |
120 | 42.1M | case LUA_VLCL: { |
121 | 42.1M | LClosure *cl = gco2lcl(o); |
122 | 42.1M | res = sizeLclosure(cl->nupvalues); |
123 | 42.1M | break; |
124 | 42.1M | } |
125 | 4.38M | case LUA_VCCL: { |
126 | 4.38M | CClosure *cl = gco2ccl(o); |
127 | 4.38M | res = sizeCclosure(cl->nupvalues); |
128 | 4.38M | break; |
129 | 4.38M | } |
130 | 7.79M | case LUA_VUSERDATA: { |
131 | 7.79M | Udata *u = gco2u(o); |
132 | 7.79M | res = sizeudata(u->nuvalue, u->len); |
133 | 7.79M | break; |
134 | 7.79M | } |
135 | 21.3M | case LUA_VPROTO: { |
136 | 21.3M | res = luaF_protosize(gco2p(o)); |
137 | 0 | break; |
138 | 21.3M | } |
139 | 2.40M | case LUA_VTHREAD: { |
140 | 2.40M | res = luaE_threadsize(gco2th(o)); |
141 | 0 | break; |
142 | 2.40M | } |
143 | 136M | case LUA_VSHRSTR: { |
144 | 136M | TString *ts = gco2ts(o); |
145 | 136M | res = sizestrshr(cast_uint(ts->shrlen)); |
146 | 136M | break; |
147 | 136M | } |
148 | 44.3M | case LUA_VLNGSTR: { |
149 | 44.3M | TString *ts = gco2ts(o); |
150 | 0 | res = luaS_sizelngstr(ts->u.lnglen, ts->shrlen); |
151 | 44.3M | break; |
152 | 44.3M | } |
153 | 20.2M | case LUA_VUPVAL: { |
154 | 20.2M | res = sizeof(UpVal); |
155 | 20.2M | break; |
156 | 44.3M | } |
157 | 0 | default: res = 0; lua_assert(0); |
158 | 341M | } |
159 | 341M | return cast(l_mem, res); |
160 | 341M | } |
161 | | |
162 | | |
163 | 118M | static GCObject **getgclist (GCObject *o) { |
164 | 118M | switch (o->tt) { |
165 | 40.7M | case LUA_VTABLE: return &gco2t(o)->gclist; |
166 | 40.5M | case LUA_VLCL: return &gco2lcl(o)->gclist; |
167 | 7.20M | case LUA_VCCL: return &gco2ccl(o)->gclist; |
168 | 10.0M | case LUA_VTHREAD: return &gco2th(o)->gclist; |
169 | 19.8M | case LUA_VPROTO: return &gco2p(o)->gclist; |
170 | 22 | case LUA_VUSERDATA: { |
171 | 22 | Udata *u = gco2u(o); |
172 | 22 | lua_assert(u->nuvalue > 0); |
173 | 22 | return &u->gclist; |
174 | 22 | } |
175 | 0 | default: lua_assert(0); return 0; |
176 | 118M | } |
177 | 118M | } |
178 | | |
179 | | |
180 | | /* |
181 | | ** Link a collectable object 'o' with a known type into the list 'p'. |
182 | | ** (Must be a macro to access the 'gclist' field in different types.) |
183 | | */ |
184 | 3.90M | #define linkgclist(o,p) linkgclist_(obj2gco(o), &(o)->gclist, &(p)) |
185 | | |
186 | 60.6M | static void linkgclist_ (GCObject *o, GCObject **pnext, GCObject **list) { |
187 | 60.6M | lua_assert(!isgray(o)); /* cannot be in a gray list */ |
188 | 60.6M | *pnext = *list; |
189 | 60.6M | *list = o; |
190 | 60.6M | set2gray(o); /* now it is */ |
191 | 60.6M | } |
192 | | |
193 | | |
194 | | /* |
195 | | ** Link a generic collectable object 'o' into the list 'p'. |
196 | | */ |
197 | 56.7M | #define linkobjgclist(o,p) linkgclist_(obj2gco(o), getgclist(o), &(p)) |
198 | | |
199 | | |
200 | | |
201 | | /* |
202 | | ** Clear keys for empty entries in tables. If entry is empty, mark its |
203 | | ** entry as dead. This allows the collection of the key, but keeps its |
204 | | ** entry in the table: its removal could break a chain and could break |
205 | | ** a table traversal. Other places never manipulate dead keys, because |
206 | | ** its associated empty value is enough to signal that the entry is |
207 | | ** logically empty. |
208 | | */ |
209 | 75.5M | static void clearkey (Node *n) { |
210 | 75.5M | lua_assert(isempty(gval(n))); |
211 | 75.5M | if (keyiscollectable(n)) |
212 | 28.7k | setdeadkey(n); /* unused key; remove it */ |
213 | 75.5M | } |
214 | | |
215 | | |
216 | | /* |
217 | | ** tells whether a key or value can be cleared from a weak |
218 | | ** table. Non-collectable objects are never removed from weak |
219 | | ** tables. Strings behave as 'values', so are never removed too. for |
220 | | ** other objects: if really collected, cannot keep them; for objects |
221 | | ** being finalized, keep them in keys, but not in values |
222 | | */ |
223 | 1.19M | static int iscleared (global_State *g, const GCObject *o) { |
224 | 1.19M | if (o == NULL) return 0; /* non-collectable value */ |
225 | 1.18M | else if (novariant(o->tt) == LUA_TSTRING) { |
226 | 275k | markobject(g, o); /* strings are 'values', so are never weak */ |
227 | 275k | return 0; |
228 | 275k | } |
229 | 907k | else return iswhite(o); |
230 | 1.19M | } |
231 | | |
232 | | |
233 | | /* |
234 | | ** Barrier that moves collector forward, that is, marks the white object |
235 | | ** 'v' being pointed by the black object 'o'. In the generational |
236 | | ** mode, 'v' must also become old, if 'o' is old; however, it cannot |
237 | | ** be changed directly to OLD, because it may still point to non-old |
238 | | ** objects. So, it is marked as OLD0. In the next cycle it will become |
239 | | ** OLD1, and in the next it will finally become OLD (regular old). By |
240 | | ** then, any object it points to will also be old. If called in the |
241 | | ** incremental sweep phase, it clears the black object to white (sweep |
242 | | ** it) to avoid other barrier calls for this same object. (That cannot |
243 | | ** be done is generational mode, as its sweep does not distinguish |
244 | | ** white from dead.) |
245 | | */ |
246 | 507k | void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { |
247 | 507k | global_State *g = G(L); |
248 | 507k | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); |
249 | 507k | if (keepinvariant(g)) { /* must keep invariant? */ |
250 | 308k | reallymarkobject(g, v); /* restore invariant */ |
251 | 308k | if (isold(o)) { |
252 | 104k | lua_assert(!isold(v)); /* white object could not be old */ |
253 | 104k | setage(v, G_OLD0); /* restore generational invariant */ |
254 | 104k | } |
255 | 308k | } |
256 | 199k | else { /* sweep phase */ |
257 | 199k | lua_assert(issweepphase(g)); |
258 | 199k | if (g->gckind != KGC_GENMINOR) /* incremental mode? */ |
259 | 199k | makewhite(g, o); /* mark 'o' as white to avoid other barriers */ |
260 | 199k | } |
261 | 507k | } |
262 | | |
263 | | |
264 | | /* |
265 | | ** barrier that moves collector backward, that is, mark the black object |
266 | | ** pointing to a white object as gray again. |
267 | | */ |
268 | 612k | void luaC_barrierback_ (lua_State *L, GCObject *o) { |
269 | 612k | global_State *g = G(L); |
270 | 612k | lua_assert(isblack(o) && !isdead(g, o)); |
271 | 612k | lua_assert((g->gckind != KGC_GENMINOR) |
272 | 612k | || (isold(o) && getage(o) != G_TOUCHED1)); |
273 | 612k | if (getage(o) == G_TOUCHED2) /* already in gray list? */ |
274 | 612k | set2gray(o); /* make it gray to become touched1 */ |
275 | 542k | else /* link it in 'grayagain' and paint it gray */ |
276 | 542k | linkobjgclist(o, g->grayagain); |
277 | 612k | if (isold(o)) /* generational mode? */ |
278 | 131k | setage(o, G_TOUCHED1); /* touched in current cycle */ |
279 | 612k | } |
280 | | |
281 | | |
282 | 2.97M | void luaC_fix (lua_State *L, GCObject *o) { |
283 | 2.97M | global_State *g = G(L); |
284 | 2.97M | lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ |
285 | 2.97M | set2gray(o); /* they will be gray forever */ |
286 | 2.97M | setage(o, G_OLD); /* and old forever */ |
287 | 2.97M | g->allgc = o->next; /* remove object from 'allgc' list */ |
288 | 2.97M | o->next = g->fixedgc; /* link it to 'fixedgc' list */ |
289 | 2.97M | g->fixedgc = o; |
290 | 2.97M | } |
291 | | |
292 | | |
293 | | /* |
294 | | ** create a new collectable object (with given type, size, and offset) |
295 | | ** and link it to 'allgc' list. |
296 | | */ |
297 | 137M | GCObject *luaC_newobjdt (lua_State *L, lu_byte tt, size_t sz, size_t offset) { |
298 | 137M | global_State *g = G(L); |
299 | 137M | char *p = cast_charp(luaM_newobject(L, novariant(tt), sz)); |
300 | 137M | GCObject *o = cast(GCObject *, p + offset); |
301 | 137M | o->marked = luaC_white(g); |
302 | 137M | o->tt = tt; |
303 | 137M | o->next = g->allgc; |
304 | 137M | g->allgc = o; |
305 | 137M | return o; |
306 | 137M | } |
307 | | |
308 | | |
309 | | /* |
310 | | ** create a new collectable object with no offset. |
311 | | */ |
312 | 137M | GCObject *luaC_newobj (lua_State *L, lu_byte tt, size_t sz) { |
313 | 137M | return luaC_newobjdt(L, tt, sz, 0); |
314 | 137M | } |
315 | | |
316 | | /* }====================================================== */ |
317 | | |
318 | | |
319 | | |
320 | | /* |
321 | | ** {====================================================== |
322 | | ** Mark functions |
323 | | ** ======================================================= |
324 | | */ |
325 | | |
326 | | |
327 | | /* |
328 | | ** Mark an object. Userdata with no user values, strings, and closed |
329 | | ** upvalues are visited and turned black here. Open upvalues are |
330 | | ** already indirectly linked through their respective threads in the |
331 | | ** 'twups' list, so they don't go to the gray list; nevertheless, they |
332 | | ** are kept gray to avoid barriers, as their values will be revisited |
333 | | ** by the thread or by 'remarkupvals'. Other objects are added to the |
334 | | ** gray list to be visited (and turned black) later. Both userdata and |
335 | | ** upvalues can call this function recursively, but this recursion goes |
336 | | ** for at most two levels: An upvalue cannot refer to another upvalue |
337 | | ** (only closures can), and a userdata's metatable must be a table. |
338 | | */ |
339 | 201M | static void reallymarkobject (global_State *g, GCObject *o) { |
340 | 201M | g->GCmarked += objsize(o); |
341 | 201M | switch (o->tt) { |
342 | 109M | case LUA_VSHRSTR: |
343 | 128M | case LUA_VLNGSTR: { |
344 | 128M | set2black(o); /* nothing to visit */ |
345 | 128M | break; |
346 | 109M | } |
347 | 11.6M | case LUA_VUPVAL: { |
348 | 11.6M | UpVal *uv = gco2upv(o); |
349 | 11.6M | if (upisopen(uv)) |
350 | 11.6M | set2gray(uv); /* open upvalues are kept gray */ |
351 | 2.35M | else |
352 | 2.35M | set2black(uv); /* closed upvalues are visited here */ |
353 | 11.6M | markvalue(g, uv->v.p); /* mark its content */ |
354 | 11.6M | break; |
355 | 11.6M | } |
356 | 4.78M | case LUA_VUSERDATA: { |
357 | 4.78M | Udata *u = gco2u(o); |
358 | 4.78M | if (u->nuvalue == 0) { /* no user values? */ |
359 | 4.78M | markobjectN(g, u->metatable); /* mark its metatable */ |
360 | 4.78M | set2black(u); /* nothing else to mark */ |
361 | 4.78M | break; |
362 | 4.78M | } |
363 | | /* else... */ |
364 | 4.78M | } /* FALLTHROUGH */ |
365 | 43.7M | case LUA_VLCL: case LUA_VCCL: case LUA_VTABLE: |
366 | 56.1M | case LUA_VTHREAD: case LUA_VPROTO: { |
367 | 56.1M | linkobjgclist(o, g->gray); /* to be visited later */ |
368 | 0 | break; |
369 | 56.1M | } |
370 | 0 | default: lua_assert(0); break; |
371 | 201M | } |
372 | 201M | } |
373 | | |
374 | | |
375 | | /* |
376 | | ** mark metamethods for basic types |
377 | | */ |
378 | 1.66M | static void markmt (global_State *g) { |
379 | 1.66M | int i; |
380 | 16.6M | for (i=0; i < LUA_NUMTYPES; i++) |
381 | 15.0M | markobjectN(g, g->mt[i]); |
382 | 1.66M | } |
383 | | |
384 | | |
385 | | /* |
386 | | ** mark all objects in list of being-finalized |
387 | | */ |
388 | 1.66M | static void markbeingfnz (global_State *g) { |
389 | 1.66M | GCObject *o; |
390 | 4.16M | for (o = g->tobefnz; o != NULL; o = o->next) |
391 | 2.49M | markobject(g, o); |
392 | 1.66M | } |
393 | | |
394 | | |
395 | | /* |
396 | | ** For each non-marked thread, simulates a barrier between each open |
397 | | ** upvalue and its value. (If the thread is collected, the value will be |
398 | | ** assigned to the upvalue, but then it can be too late for the barrier |
399 | | ** to act. The "barrier" does not need to check colors: A non-marked |
400 | | ** thread must be young; upvalues cannot be older than their threads; so |
401 | | ** any visited upvalue must be young too.) Also removes the thread from |
402 | | ** the list, as it was already visited. Removes also threads with no |
403 | | ** upvalues, as they have nothing to be checked. (If the thread gets an |
404 | | ** upvalue later, it will be linked in the list again.) |
405 | | */ |
406 | 1.11M | static void remarkupvals (global_State *g) { |
407 | 1.11M | lua_State *thread; |
408 | 1.11M | lua_State **p = &g->twups; |
409 | 2.50M | while ((thread = *p) != NULL) { |
410 | 1.39M | if (!iswhite(thread) && thread->openupval != NULL) |
411 | 1.35M | p = &thread->twups; /* keep marked thread with upvalues in the list */ |
412 | 32.8k | else { /* thread is not marked or without upvalues */ |
413 | 32.8k | UpVal *uv; |
414 | 32.8k | lua_assert(!isold(thread) || thread->openupval == NULL); |
415 | 32.8k | *p = thread->twups; /* remove thread from the list */ |
416 | 32.8k | thread->twups = thread; /* mark that it is out of list */ |
417 | 33.4k | for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { |
418 | 561 | lua_assert(getage(uv) <= getage(thread)); |
419 | 561 | if (!iswhite(uv)) { /* upvalue already visited? */ |
420 | 262 | lua_assert(upisopen(uv) && isgray(uv)); |
421 | 524 | markvalue(g, uv->v.p); /* mark its value */ |
422 | 262 | } |
423 | 561 | } |
424 | 32.8k | } |
425 | 1.39M | } |
426 | 1.11M | } |
427 | | |
428 | | |
429 | 608k | static void cleargraylists (global_State *g) { |
430 | 608k | g->gray = g->grayagain = NULL; |
431 | 608k | g->weak = g->allweak = g->ephemeron = NULL; |
432 | 608k | } |
433 | | |
434 | | |
435 | | /* |
436 | | ** mark root set and reset all gray lists, to start a new collection. |
437 | | ** 'GCmarked' is initialized to count the total number of live bytes |
438 | | ** during a cycle. |
439 | | */ |
440 | 555k | static void restartcollection (global_State *g) { |
441 | 555k | cleargraylists(g); |
442 | 555k | g->GCmarked = 0; |
443 | 555k | markobject(g, mainthread(g)); |
444 | 555k | markvalue(g, &g->l_registry); |
445 | 555k | markmt(g); |
446 | 555k | markbeingfnz(g); /* mark any finalizing object left from previous cycle */ |
447 | 555k | } |
448 | | |
449 | | /* }====================================================== */ |
450 | | |
451 | | |
452 | | /* |
453 | | ** {====================================================== |
454 | | ** Traverse functions |
455 | | ** ======================================================= |
456 | | */ |
457 | | |
458 | | |
459 | | /* |
460 | | ** Check whether object 'o' should be kept in the 'grayagain' list for |
461 | | ** post-processing by 'correctgraylist'. (It could put all old objects |
462 | | ** in the list and leave all the work to 'correctgraylist', but it is |
463 | | ** more efficient to avoid adding elements that will be removed.) Only |
464 | | ** TOUCHED1 objects need to be in the list. TOUCHED2 doesn't need to go |
465 | | ** back to a gray list, but then it must become OLD. (That is what |
466 | | ** 'correctgraylist' does when it finds a TOUCHED2 object.) |
467 | | ** This function is a no-op in incremental mode, as objects cannot be |
468 | | ** marked as touched in that mode. |
469 | | */ |
470 | 20.0M | static void genlink (global_State *g, GCObject *o) { |
471 | 20.0M | lua_assert(isblack(o)); |
472 | 20.0M | if (getage(o) == G_TOUCHED1) { /* touched in this cycle? */ |
473 | 120k | linkobjgclist(o, g->grayagain); /* link it back in 'grayagain' */ |
474 | 120k | } /* everything else do not need to be linked back */ |
475 | 19.9M | else if (getage(o) == G_TOUCHED2) |
476 | 46.5k | setage(o, G_OLD); /* advance age */ |
477 | 20.0M | } |
478 | | |
479 | | |
480 | | /* |
481 | | ** Traverse a table with weak values and link it to proper list. During |
482 | | ** propagate phase, keep it in 'grayagain' list, to be revisited in the |
483 | | ** atomic phase. In the atomic phase, if table has any white value, |
484 | | ** put it in 'weak' list, to be cleared; otherwise, call 'genlink' |
485 | | ** to check table age in generational mode. |
486 | | */ |
487 | 0 | static void traverseweakvalue (global_State *g, Table *h) { |
488 | 0 | Node *n, *limit = gnodelast(h); |
489 | | /* if there is array part, assume it may have white values (it is not |
490 | | worth traversing it now just to check) */ |
491 | 0 | int hasclears = (h->asize > 0); |
492 | 0 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ |
493 | 0 | if (isempty(gval(n))) /* entry is empty? */ |
494 | 0 | clearkey(n); /* clear its key */ |
495 | 0 | else { |
496 | 0 | lua_assert(!keyisnil(n)); |
497 | 0 | markkey(g, n); |
498 | 0 | if (!hasclears && iscleared(g, gcvalueN(gval(n)))) /* a white value? */ |
499 | 0 | hasclears = 1; /* table will have to be cleared */ |
500 | 0 | } |
501 | 0 | } |
502 | 0 | if (g->gcstate == GCSpropagate) |
503 | 0 | linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ |
504 | 0 | else if (hasclears) |
505 | 0 | linkgclist(h, g->weak); /* has to be cleared later */ |
506 | 0 | else |
507 | 0 | genlink(g, obj2gco(h)); |
508 | 0 | } |
509 | | |
510 | | |
511 | | /* |
512 | | ** Traverse the array part of a table. |
513 | | */ |
514 | 20.1M | static int traversearray (global_State *g, Table *h) { |
515 | 20.1M | unsigned asize = h->asize; |
516 | 20.1M | int marked = 0; /* true if some object is marked in this traversal */ |
517 | 20.1M | unsigned i; |
518 | 560M | for (i = 0; i < asize; i++) { |
519 | 540M | GCObject *o = gcvalarr(h, i); |
520 | 540M | if (o != NULL && iswhite(o)) { |
521 | 12.0M | marked = 1; |
522 | 12.0M | reallymarkobject(g, o); |
523 | 12.0M | } |
524 | 540M | } |
525 | 20.1M | return marked; |
526 | 20.1M | } |
527 | | |
528 | | |
529 | | /* |
530 | | ** Traverse an ephemeron table and link it to proper list. Returns true |
531 | | ** iff any object was marked during this traversal (which implies that |
532 | | ** convergence has to continue). During propagation phase, keep table |
533 | | ** in 'grayagain' list, to be visited again in the atomic phase. In |
534 | | ** the atomic phase, if table has any white->white entry, it has to |
535 | | ** be revisited during ephemeron convergence (as that key may turn |
536 | | ** black). Otherwise, if it has any white key, table has to be cleared |
537 | | ** (in the atomic phase). In generational mode, some tables |
538 | | ** must be kept in some gray list for post-processing; this is done |
539 | | ** by 'genlink'. |
540 | | */ |
541 | 275k | static int traverseephemeron (global_State *g, Table *h, int inv) { |
542 | 275k | int hasclears = 0; /* true if table has white keys */ |
543 | 275k | int hasww = 0; /* true if table has entry "white-key -> white-value" */ |
544 | 275k | unsigned int i; |
545 | 275k | unsigned int nsize = sizenode(h); |
546 | 275k | int marked = traversearray(g, h); /* traverse array part */ |
547 | | /* traverse hash part; if 'inv', traverse descending |
548 | | (see 'convergeephemerons') */ |
549 | 1.72M | for (i = 0; i < nsize; i++) { |
550 | 1.44M | Node *n = inv ? gnode(h, nsize - 1 - i) : gnode(h, i); |
551 | 1.44M | if (isempty(gval(n))) /* entry is empty? */ |
552 | 288k | clearkey(n); /* clear its key */ |
553 | 1.16M | else if (iscleared(g, gckeyN(n))) { /* key is not marked (yet)? */ |
554 | 31.2k | hasclears = 1; /* table must be cleared */ |
555 | 31.2k | if (valiswhite(gval(n))) /* value not marked yet? */ |
556 | 27.9k | hasww = 1; /* white-white entry */ |
557 | 31.2k | } |
558 | 1.13M | else if (valiswhite(gval(n))) { /* value not marked yet? */ |
559 | 344k | marked = 1; |
560 | 344k | reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ |
561 | 344k | } |
562 | 1.44M | } |
563 | | /* link table into proper list */ |
564 | 275k | if (g->gcstate == GCSpropagate) |
565 | 107k | linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ |
566 | 167k | else if (hasww) /* table has white->white entries? */ |
567 | 466 | linkgclist(h, g->ephemeron); /* have to propagate again */ |
568 | 167k | else if (hasclears) /* table has white keys? */ |
569 | 98 | linkgclist(h, g->allweak); /* may have to clean white keys */ |
570 | 167k | else |
571 | 167k | genlink(g, obj2gco(h)); /* check whether collector still needs to see it */ |
572 | 275k | return marked; |
573 | 275k | } |
574 | | |
575 | | |
576 | 19.8M | static void traversestrongtable (global_State *g, Table *h) { |
577 | 19.8M | Node *n, *limit = gnodelast(h); |
578 | 19.8M | traversearray(g, h); |
579 | 271M | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ |
580 | 251M | if (isempty(gval(n))) /* entry is empty? */ |
581 | 75.2M | clearkey(n); /* clear its key */ |
582 | 176M | else { |
583 | 176M | lua_assert(!keyisnil(n)); |
584 | 176M | markkey(g, n); |
585 | 176M | markvalue(g, gval(n)); |
586 | 176M | } |
587 | 251M | } |
588 | 19.8M | genlink(g, obj2gco(h)); |
589 | 19.8M | } |
590 | | |
591 | | |
592 | | /* |
593 | | ** (result & 1) iff weak values; (result & 2) iff weak keys. |
594 | | */ |
595 | 20.1M | static int getmode (global_State *g, Table *h) { |
596 | 20.1M | const TValue *mode = gfasttm(g, h->metatable, TM_MODE); |
597 | 20.1M | if (mode == NULL || !ttisshrstring(mode)) |
598 | 19.8M | return 0; /* ignore non-(short)string modes */ |
599 | 274k | else { |
600 | 274k | const char *smode = getshrstr(tsvalue(mode)); |
601 | 0 | const char *weakkey = strchr(smode, 'k'); |
602 | 274k | const char *weakvalue = strchr(smode, 'v'); |
603 | 274k | return ((weakkey != NULL) << 1) | (weakvalue != NULL); |
604 | 549k | } |
605 | 20.1M | } |
606 | | |
607 | | |
608 | 20.1M | static l_mem traversetable (global_State *g, Table *h) { |
609 | 20.1M | markobjectN(g, h->metatable); |
610 | 20.1M | switch (getmode(g, h)) { |
611 | 19.8M | case 0: /* not weak */ |
612 | 19.8M | traversestrongtable(g, h); |
613 | 19.8M | break; |
614 | 0 | case 1: /* weak values */ |
615 | 0 | traverseweakvalue(g, h); |
616 | 0 | break; |
617 | 274k | case 2: /* weak keys */ |
618 | 274k | traverseephemeron(g, h, 0); |
619 | 274k | break; |
620 | 0 | case 3: /* all weak; nothing to traverse */ |
621 | 0 | if (g->gcstate == GCSpropagate) |
622 | 0 | linkgclist(h, g->grayagain); /* must visit again its metatable */ |
623 | 0 | else |
624 | 0 | linkgclist(h, g->allweak); /* must clear collected entries */ |
625 | 0 | break; |
626 | 20.1M | } |
627 | 20.1M | return 1 + 2*sizenode(h) + h->asize; |
628 | 20.1M | } |
629 | | |
630 | | |
631 | 11 | static l_mem traverseudata (global_State *g, Udata *u) { |
632 | 11 | int i; |
633 | 11 | markobjectN(g, u->metatable); /* mark its metatable */ |
634 | 22 | for (i = 0; i < u->nuvalue; i++) |
635 | 11 | markvalue(g, &u->uv[i].uv); |
636 | 11 | genlink(g, obj2gco(u)); |
637 | 0 | return 1 + u->nuvalue; |
638 | 11 | } |
639 | | |
640 | | |
641 | | /* |
642 | | ** Traverse a prototype. (While a prototype is being build, its |
643 | | ** arrays can be larger than needed; the extra slots are filled with |
644 | | ** NULL, so the use of 'markobjectN') |
645 | | */ |
646 | 9.91M | static l_mem traverseproto (global_State *g, Proto *f) { |
647 | 9.91M | int i; |
648 | 9.91M | markobjectN(g, f->source); |
649 | 104M | for (i = 0; i < f->sizek; i++) /* mark literals */ |
650 | 94.9M | markvalue(g, &f->k[i]); |
651 | 24.8M | for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ |
652 | 14.8M | markobjectN(g, f->upvalues[i].name); |
653 | 18.4M | for (i = 0; i < f->sizep; i++) /* mark nested protos */ |
654 | 9.91M | markobjectN(g, f->p[i]); |
655 | 42.8M | for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ |
656 | 32.9M | markobjectN(g, f->locvars[i].varname); |
657 | 9.91M | return 1 + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars; |
658 | 9.91M | } |
659 | | |
660 | | |
661 | 3.60M | static l_mem traverseCclosure (global_State *g, CClosure *cl) { |
662 | 3.60M | int i; |
663 | 7.48M | for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ |
664 | 3.88M | markvalue(g, &cl->upvalue[i]); |
665 | 3.60M | return 1 + cl->nupvalues; |
666 | 3.60M | } |
667 | | |
668 | | /* |
669 | | ** Traverse a Lua closure, marking its prototype and its upvalues. |
670 | | ** (Both can be NULL while closure is being created.) |
671 | | */ |
672 | 20.2M | static l_mem traverseLclosure (global_State *g, LClosure *cl) { |
673 | 20.2M | int i; |
674 | 20.2M | markobjectN(g, cl->p); /* mark its prototype */ |
675 | 46.8M | for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ |
676 | 26.5M | UpVal *uv = cl->upvals[i]; |
677 | 26.5M | markobjectN(g, uv); /* mark upvalue */ |
678 | 26.5M | } |
679 | 20.2M | return 1 + cl->nupvalues; |
680 | 20.2M | } |
681 | | |
682 | | |
683 | | /* |
684 | | ** Traverse a thread, marking the elements in the stack up to its top |
685 | | ** and cleaning the rest of the stack in the final traversal. That |
686 | | ** ensures that the entire stack have valid (non-dead) objects. |
687 | | ** Threads have no barriers. In gen. mode, old threads must be visited |
688 | | ** at every cycle, because they might point to young objects. In inc. |
689 | | ** mode, the thread can still be modified before the end of the cycle, |
690 | | ** and therefore it must be visited again in the atomic phase. To ensure |
691 | | ** these visits, threads must return to a gray list if they are not new |
692 | | ** (which can only happen in generational mode) or if the traverse is in |
693 | | ** the propagate phase (which can only happen in incremental mode). |
694 | | */ |
695 | 4.31M | static l_mem traversethread (global_State *g, lua_State *th) { |
696 | 4.31M | UpVal *uv; |
697 | 4.31M | StkId o = th->stack.p; |
698 | 4.31M | if (isold(th) || g->gcstate == GCSpropagate) |
699 | 1.93M | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ |
700 | 4.31M | if (o == NULL) |
701 | 0 | return 0; /* stack not completely built yet */ |
702 | 4.31M | lua_assert(g->gcstate == GCSatomic || |
703 | 4.31M | th->openupval == NULL || isintwups(th)); |
704 | 526M | for (; o < th->top.p; o++) /* mark live elements in the stack */ |
705 | 521M | markvalue(g, s2v(o)); |
706 | 19.4M | for (uv = th->openupval; uv != NULL; uv = uv->u.open.next) |
707 | 15.1M | markobject(g, uv); /* open upvalues cannot be collected */ |
708 | 4.31M | if (g->gcstate == GCSatomic) { /* final traversal? */ |
709 | 3.86M | if (!g->gcemergency) |
710 | 3.86M | luaD_shrinkstack(th); /* do not change stack in emergency cycle */ |
711 | 253M | for (o = th->top.p; o < th->stack_last.p + EXTRA_STACK; o++) |
712 | 249M | setnilvalue(s2v(o)); /* clear dead stack slice */ |
713 | | /* 'remarkupvals' may have removed thread from 'twups' list */ |
714 | 3.86M | if (!isintwups(th) && th->openupval != NULL) { |
715 | 433 | th->twups = g->twups; /* link it back to the list */ |
716 | 433 | g->twups = th; |
717 | 433 | } |
718 | 3.86M | } |
719 | 4.31M | return 1 + (th->top.p - th->stack.p); |
720 | 4.31M | } |
721 | | |
722 | | |
723 | | /* |
724 | | ** traverse one gray object, turning it to black. Return an estimate |
725 | | ** of the number of slots traversed. |
726 | | */ |
727 | 58.1M | static l_mem propagatemark (global_State *g) { |
728 | 58.1M | GCObject *o = g->gray; |
729 | 58.1M | nw2black(o); |
730 | 0 | g->gray = *getgclist(o); /* remove from 'gray' list */ |
731 | 58.1M | switch (o->tt) { |
732 | 20.1M | case LUA_VTABLE: return traversetable(g, gco2t(o)); |
733 | 11 | case LUA_VUSERDATA: return traverseudata(g, gco2u(o)); |
734 | 20.2M | case LUA_VLCL: return traverseLclosure(g, gco2lcl(o)); |
735 | 3.60M | case LUA_VCCL: return traverseCclosure(g, gco2ccl(o)); |
736 | 9.91M | case LUA_VPROTO: return traverseproto(g, gco2p(o)); |
737 | 4.31M | case LUA_VTHREAD: return traversethread(g, gco2th(o)); |
738 | 0 | default: lua_assert(0); return 0; |
739 | 58.1M | } |
740 | 58.1M | } |
741 | | |
742 | | |
743 | 4.44M | static void propagateall (global_State *g) { |
744 | 27.8M | while (g->gray) |
745 | 23.3M | propagatemark(g); |
746 | 4.44M | } |
747 | | |
748 | | |
749 | | /* |
750 | | ** Traverse all ephemeron tables propagating marks from keys to values. |
751 | | ** Repeat until it converges, that is, nothing new is marked. 'dir' |
752 | | ** inverts the direction of the traversals, trying to speed up |
753 | | ** convergence on chains in the same table. |
754 | | */ |
755 | 2.22M | static void convergeephemerons (global_State *g) { |
756 | 2.22M | int changed; |
757 | 2.22M | int dir = 0; |
758 | 2.22M | do { |
759 | 2.22M | GCObject *w; |
760 | 2.22M | GCObject *next = g->ephemeron; /* get ephemeron list */ |
761 | 2.22M | g->ephemeron = NULL; /* tables may return to this list when traversed */ |
762 | 2.22M | changed = 0; |
763 | 2.22M | while ((w = next) != NULL) { /* for each ephemeron table */ |
764 | 465 | Table *h = gco2t(w); |
765 | 0 | next = h->gclist; /* list is rebuilt during loop */ |
766 | 465 | nw2black(h); /* out of the list (for now) */ |
767 | 465 | if (traverseephemeron(g, h, dir)) { /* marked some value? */ |
768 | 434 | propagateall(g); /* propagate changes */ |
769 | 434 | changed = 1; /* will have to revisit all ephemeron tables */ |
770 | 434 | } |
771 | 465 | } |
772 | 2.22M | dir = !dir; /* invert direction next time */ |
773 | 2.22M | } while (changed); /* repeat until no more changes */ |
774 | 2.22M | } |
775 | | |
776 | | /* }====================================================== */ |
777 | | |
778 | | |
779 | | /* |
780 | | ** {====================================================== |
781 | | ** Sweep Functions |
782 | | ** ======================================================= |
783 | | */ |
784 | | |
785 | | |
786 | | /* |
787 | | ** clear entries with unmarked keys from all weaktables in list 'l' |
788 | | */ |
789 | 2.22M | static void clearbykeys (global_State *g, GCObject *l) { |
790 | 2.22M | for (; l; l = gco2t(l)->gclist) { |
791 | 99 | Table *h = gco2t(l); |
792 | 99 | Node *limit = gnodelast(h); |
793 | 99 | Node *n; |
794 | 15.6k | for (n = gnode(h, 0); n < limit; n++) { |
795 | 15.5k | if (iscleared(g, gckeyN(n))) /* unmarked key? */ |
796 | 15.5k | setempty(gval(n)); /* remove entry */ |
797 | 15.5k | if (isempty(gval(n))) /* is entry empty? */ |
798 | 4.68k | clearkey(n); /* clear its key */ |
799 | 15.5k | } |
800 | 99 | } |
801 | 2.22M | } |
802 | | |
803 | | |
804 | | /* |
805 | | ** clear entries with unmarked values from all weaktables in list 'l' up |
806 | | ** to element 'f' |
807 | | */ |
808 | 4.44M | static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { |
809 | 4.44M | for (; l != f; l = gco2t(l)->gclist) { |
810 | 98 | Table *h = gco2t(l); |
811 | 98 | Node *n, *limit = gnodelast(h); |
812 | 98 | unsigned int i; |
813 | 98 | unsigned int asize = h->asize; |
814 | 98 | for (i = 0; i < asize; i++) { |
815 | 0 | GCObject *o = gcvalarr(h, i); |
816 | 0 | if (iscleared(g, o)) /* value was collected? */ |
817 | 0 | *getArrTag(h, i) = LUA_VEMPTY; /* remove entry */ |
818 | 0 | } |
819 | 15.3k | for (n = gnode(h, 0); n < limit; n++) { |
820 | 15.2k | if (iscleared(g, gcvalueN(gval(n)))) /* unmarked value? */ |
821 | 15.2k | setempty(gval(n)); /* remove entry */ |
822 | 15.2k | if (isempty(gval(n))) /* is entry empty? */ |
823 | 4.60k | clearkey(n); /* clear its key */ |
824 | 15.2k | } |
825 | 98 | } |
826 | 4.44M | } |
827 | | |
828 | | |
829 | 8.50M | static void freeupval (lua_State *L, UpVal *uv) { |
830 | 8.50M | if (upisopen(uv)) |
831 | 4.62k | luaF_unlinkupval(uv); |
832 | 8.50M | luaM_free(L, uv); |
833 | 8.50M | } |
834 | | |
835 | | |
836 | 137M | static void freeobj (lua_State *L, GCObject *o) { |
837 | 137M | assert_code(l_mem newmem = gettotalbytes(G(L)) - objsize(o)); |
838 | 137M | switch (o->tt) { |
839 | 11.1M | case LUA_VPROTO: |
840 | 11.1M | luaF_freeproto(L, gco2p(o)); |
841 | 0 | break; |
842 | 8.50M | case LUA_VUPVAL: |
843 | 8.50M | freeupval(L, gco2upv(o)); |
844 | 0 | break; |
845 | 21.6M | case LUA_VLCL: { |
846 | 21.6M | LClosure *cl = gco2lcl(o); |
847 | 21.6M | luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); |
848 | 21.6M | break; |
849 | 21.6M | } |
850 | 779k | case LUA_VCCL: { |
851 | 779k | CClosure *cl = gco2ccl(o); |
852 | 779k | luaM_freemem(L, cl, sizeCclosure(cl->nupvalues)); |
853 | 779k | break; |
854 | 779k | } |
855 | 41.5M | case LUA_VTABLE: |
856 | 41.5M | luaH_free(L, gco2t(o)); |
857 | 0 | break; |
858 | 9.00k | case LUA_VTHREAD: |
859 | 9.00k | luaE_freethread(L, gco2th(o)); |
860 | 0 | break; |
861 | 2.96M | case LUA_VUSERDATA: { |
862 | 2.96M | Udata *u = gco2u(o); |
863 | 2.96M | luaM_freemem(L, o, sizeudata(u->nuvalue, u->len)); |
864 | 2.96M | break; |
865 | 2.96M | } |
866 | 26.3M | case LUA_VSHRSTR: { |
867 | 26.3M | TString *ts = gco2ts(o); |
868 | 0 | luaS_remove(L, ts); /* remove it from hash table */ |
869 | 26.3M | luaM_freemem(L, ts, sizestrshr(cast_uint(ts->shrlen))); |
870 | 26.3M | break; |
871 | 26.3M | } |
872 | 24.8M | case LUA_VLNGSTR: { |
873 | 24.8M | TString *ts = gco2ts(o); |
874 | 24.8M | if (ts->shrlen == LSTRMEM) /* must free external string? */ |
875 | 999k | (*ts->falloc)(ts->ud, ts->contents, ts->u.lnglen + 1, 0); |
876 | 24.8M | luaM_freemem(L, ts, luaS_sizelngstr(ts->u.lnglen, ts->shrlen)); |
877 | 24.8M | break; |
878 | 24.8M | } |
879 | 0 | default: lua_assert(0); |
880 | 137M | } |
881 | 137M | lua_assert(gettotalbytes(G(L)) == newmem); |
882 | 137M | } |
883 | | |
884 | | |
885 | | /* |
886 | | ** sweep at most 'countin' elements from a list of GCObjects erasing dead |
887 | | ** objects, where a dead object is one marked with the old (non current) |
888 | | ** white; change all non-dead objects back to white (and new), preparing |
889 | | ** for next collection cycle. Return where to continue the traversal or |
890 | | ** NULL if list is finished. |
891 | | */ |
892 | 16.5M | static GCObject **sweeplist (lua_State *L, GCObject **p, l_mem countin) { |
893 | 16.5M | global_State *g = G(L); |
894 | 16.5M | int ow = otherwhite(g); |
895 | 16.5M | int white = luaC_white(g); /* current white */ |
896 | 285M | while (*p != NULL && countin-- > 0) { |
897 | 269M | GCObject *curr = *p; |
898 | 269M | int marked = curr->marked; |
899 | 269M | if (isdeadm(ow, marked)) { /* is 'curr' dead? */ |
900 | 77.0M | *p = curr->next; /* remove 'curr' from list */ |
901 | 77.0M | freeobj(L, curr); /* erase 'curr' */ |
902 | 77.0M | } |
903 | 192M | else { /* change mark to 'white' and age to 'new' */ |
904 | 192M | curr->marked = cast_byte((marked & ~maskgcbits) | white | G_NEW); |
905 | 192M | p = &curr->next; /* go to next element */ |
906 | 192M | } |
907 | 269M | } |
908 | 16.5M | return (*p == NULL) ? NULL : p; |
909 | 16.5M | } |
910 | | |
911 | | |
912 | | /* |
913 | | ** sweep a list until a live object (or end of list) |
914 | | */ |
915 | 558k | static GCObject **sweeptolive (lua_State *L, GCObject **p) { |
916 | 558k | GCObject **old = p; |
917 | 4.91M | do { |
918 | 4.91M | p = sweeplist(L, p, 1); |
919 | 4.91M | } while (p == old); |
920 | 558k | return p; |
921 | 558k | } |
922 | | |
923 | | /* }====================================================== */ |
924 | | |
925 | | |
926 | | /* |
927 | | ** {====================================================== |
928 | | ** Finalization |
929 | | ** ======================================================= |
930 | | */ |
931 | | |
932 | | /* |
933 | | ** If possible, shrink string table. |
934 | | */ |
935 | 1.12M | static void checkSizes (lua_State *L, global_State *g) { |
936 | 1.12M | if (!g->gcemergency) { |
937 | 1.12M | if (g->strt.nuse < g->strt.size / 4) /* string table too big? */ |
938 | 4.95k | luaS_resize(L, g->strt.size / 2); |
939 | 1.12M | } |
940 | 1.12M | } |
941 | | |
942 | | |
943 | | /* |
944 | | ** Get the next udata to be finalized from the 'tobefnz' list, and |
945 | | ** link it back into the 'allgc' list. |
946 | | */ |
947 | 2.70M | static GCObject *udata2finalize (global_State *g) { |
948 | 2.70M | GCObject *o = g->tobefnz; /* get first element */ |
949 | 2.70M | lua_assert(tofinalize(o)); |
950 | 2.70M | g->tobefnz = o->next; /* remove it from 'tobefnz' list */ |
951 | 2.70M | o->next = g->allgc; /* return it to 'allgc' list */ |
952 | 2.70M | g->allgc = o; |
953 | 2.70M | resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */ |
954 | 2.70M | if (issweepphase(g)) |
955 | 104k | makewhite(g, o); /* "sweep" object */ |
956 | 2.60M | else if (getage(o) == G_OLD1) |
957 | 25.0k | g->firstold1 = o; /* it is the first OLD1 object in the list */ |
958 | 2.70M | return o; |
959 | 2.70M | } |
960 | | |
961 | | |
962 | 2.69M | static void dothecall (lua_State *L, void *ud) { |
963 | 2.69M | UNUSED(ud); |
964 | 2.69M | luaD_callnoyield(L, L->top.p - 2, 0); |
965 | 2.69M | } |
966 | | |
967 | | |
968 | 2.70M | static void GCTM (lua_State *L) { |
969 | 2.70M | global_State *g = G(L); |
970 | 2.70M | const TValue *tm; |
971 | 2.70M | TValue v; |
972 | 2.70M | lua_assert(!g->gcemergency); |
973 | 2.70M | setgcovalue(L, &v, udata2finalize(g)); |
974 | 2.70M | tm = luaT_gettmbyobj(L, &v, TM_GC); |
975 | 2.70M | if (!notm(tm)) { /* is there a finalizer? */ |
976 | 2.69M | TStatus status; |
977 | 2.69M | lu_byte oldah = L->allowhook; |
978 | 2.69M | lu_byte oldgcstp = g->gcstp; |
979 | 2.69M | g->gcstp |= GCSTPGC; /* avoid GC steps */ |
980 | 2.69M | L->allowhook = 0; /* stop debug hooks during GC metamethod */ |
981 | 2.69M | setobj2s(L, L->top.p++, tm); /* push finalizer... */ |
982 | 2.69M | setobj2s(L, L->top.p++, &v); /* ... and its argument */ |
983 | 2.69M | L->ci->callstatus |= CIST_FIN; /* will run a finalizer */ |
984 | 2.69M | status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0); |
985 | 2.69M | L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ |
986 | 2.69M | L->allowhook = oldah; /* restore hooks */ |
987 | 2.69M | g->gcstp = oldgcstp; /* restore state */ |
988 | 2.69M | if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */ |
989 | 4.76k | luaE_warnerror(L, "__gc"); |
990 | 4.76k | L->top.p--; /* pops error object */ |
991 | 4.76k | } |
992 | 2.69M | } |
993 | 2.70M | } |
994 | | |
995 | | |
996 | | /* |
997 | | ** call all pending finalizers |
998 | | */ |
999 | 659k | static void callallpendingfinalizers (lua_State *L) { |
1000 | 659k | global_State *g = G(L); |
1001 | 1.48M | while (g->tobefnz) |
1002 | 829k | GCTM(L); |
1003 | 659k | } |
1004 | | |
1005 | | |
1006 | | /* |
1007 | | ** find last 'next' field in list 'p' list (to add elements in its end) |
1008 | | */ |
1009 | 1.17M | static GCObject **findlast (GCObject **p) { |
1010 | 1.23M | while (*p != NULL) |
1011 | 64.3k | p = &(*p)->next; |
1012 | 1.17M | return p; |
1013 | 1.17M | } |
1014 | | |
1015 | | |
1016 | | /* |
1017 | | ** Move all unreachable objects (or 'all' objects) that need |
1018 | | ** finalization from list 'finobj' to list 'tobefnz' (to be finalized). |
1019 | | ** (Note that objects after 'finobjold1' cannot be white, so they |
1020 | | ** don't need to be traversed. In incremental mode, 'finobjold1' is NULL, |
1021 | | ** so the whole list is traversed.) |
1022 | | */ |
1023 | 1.17M | static void separatetobefnz (global_State *g, int all) { |
1024 | 1.17M | GCObject *curr; |
1025 | 1.17M | GCObject **p = &g->finobj; |
1026 | 1.17M | GCObject **lastnext = findlast(&g->tobefnz); |
1027 | 6.11M | while ((curr = *p) != g->finobjold1) { /* traverse all finalizable objects */ |
1028 | 4.94M | lua_assert(tofinalize(curr)); |
1029 | 4.94M | if (!(iswhite(curr) || all)) /* not being collected? */ |
1030 | 2.23M | p = &curr->next; /* don't bother with it */ |
1031 | 2.70M | else { |
1032 | 2.70M | if (curr == g->finobjsur) /* removing 'finobjsur'? */ |
1033 | 21.7k | g->finobjsur = curr->next; /* correct it */ |
1034 | 2.70M | *p = curr->next; /* remove 'curr' from 'finobj' list */ |
1035 | 2.70M | curr->next = *lastnext; /* link at the end of 'tobefnz' list */ |
1036 | 2.70M | *lastnext = curr; |
1037 | 2.70M | lastnext = &curr->next; |
1038 | 2.70M | } |
1039 | 4.94M | } |
1040 | 1.17M | } |
1041 | | |
1042 | | |
1043 | | /* |
1044 | | ** If pointer 'p' points to 'o', move it to the next element. |
1045 | | */ |
1046 | 8.75M | static void checkpointer (GCObject **p, GCObject *o) { |
1047 | 8.75M | if (o == *p) |
1048 | 4.49k | *p = o->next; |
1049 | 8.75M | } |
1050 | | |
1051 | | |
1052 | | /* |
1053 | | ** Correct pointers to objects inside 'allgc' list when |
1054 | | ** object 'o' is being removed from the list. |
1055 | | */ |
1056 | 2.18M | static void correctpointers (global_State *g, GCObject *o) { |
1057 | 2.18M | checkpointer(&g->survival, o); |
1058 | 2.18M | checkpointer(&g->old1, o); |
1059 | 2.18M | checkpointer(&g->reallyold, o); |
1060 | 2.18M | checkpointer(&g->firstold1, o); |
1061 | 2.18M | } |
1062 | | |
1063 | | |
1064 | | /* |
1065 | | ** if object 'o' has a finalizer, remove it from 'allgc' list (must |
1066 | | ** search the list to find it) and link it in 'finobj' list. |
1067 | | */ |
1068 | 5.00M | void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { |
1069 | 5.00M | global_State *g = G(L); |
1070 | 5.00M | if (tofinalize(o) || /* obj. is already marked... */ |
1071 | 5.00M | gfasttm(g, mt, TM_GC) == NULL || /* or has no finalizer... */ |
1072 | 5.00M | (g->gcstp & GCSTPCLS)) /* or closing state? */ |
1073 | 2.29M | return; /* nothing to be done */ |
1074 | 2.70M | else { /* move 'o' to 'finobj' list */ |
1075 | 2.70M | GCObject **p; |
1076 | 2.70M | if (issweepphase(g)) { |
1077 | 522k | makewhite(g, o); /* "sweep" object 'o' */ |
1078 | 522k | if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ |
1079 | 3.41k | g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ |
1080 | 522k | } |
1081 | 2.18M | else |
1082 | 2.18M | correctpointers(g, o); |
1083 | | /* search for pointer pointing to 'o' */ |
1084 | 3.08M | for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } |
1085 | 2.70M | *p = o->next; /* remove 'o' from 'allgc' list */ |
1086 | 2.70M | o->next = g->finobj; /* link it in 'finobj' list */ |
1087 | 2.70M | g->finobj = o; |
1088 | 2.70M | l_setbit(o->marked, FINALIZEDBIT); /* mark it as such */ |
1089 | 2.70M | } |
1090 | 5.00M | } |
1091 | | |
1092 | | /* }====================================================== */ |
1093 | | |
1094 | | |
1095 | | /* |
1096 | | ** {====================================================== |
1097 | | ** Generational Collector |
1098 | | ** ======================================================= |
1099 | | */ |
1100 | | |
1101 | | /* |
1102 | | ** Fields 'GCmarked' and 'GCmajorminor' are used to control the pace and |
1103 | | ** the mode of the collector. They play several roles, depending on the |
1104 | | ** mode of the collector: |
1105 | | ** * KGC_INC: |
1106 | | ** GCmarked: number of marked bytes during a cycle. |
1107 | | ** GCmajorminor: not used. |
1108 | | ** * KGC_GENMINOR |
1109 | | ** GCmarked: number of bytes that became old since last major collection. |
1110 | | ** GCmajorminor: number of bytes marked in last major collection. |
1111 | | ** * KGC_GENMAJOR |
1112 | | ** GCmarked: number of bytes that became old since last major collection. |
1113 | | ** GCmajorminor: number of bytes marked in last major collection. |
1114 | | */ |
1115 | | |
1116 | | |
1117 | | /* |
1118 | | ** Set the "time" to wait before starting a new incremental cycle; |
1119 | | ** cycle will start when number of bytes in use hits the threshold of |
1120 | | ** approximately (marked * pause / 100). |
1121 | | */ |
1122 | 474k | static void setpause (global_State *g) { |
1123 | 474k | l_mem threshold = applygcparam(g, PAUSE, g->GCmarked); |
1124 | 474k | l_mem debt = threshold - gettotalbytes(g); |
1125 | 474k | if (debt < 0) debt = 0; |
1126 | 474k | luaE_setdebt(g, debt); |
1127 | 474k | } |
1128 | | |
1129 | | |
1130 | | /* |
1131 | | ** Sweep a list of objects to enter generational mode. Deletes dead |
1132 | | ** objects and turns the non dead to old. All non-dead threads---which |
1133 | | ** are now old---must be in a gray list. Everything else is not in a |
1134 | | ** gray list. Open upvalues are also kept gray. |
1135 | | */ |
1136 | 159k | static void sweep2old (lua_State *L, GCObject **p) { |
1137 | 159k | GCObject *curr; |
1138 | 159k | global_State *g = G(L); |
1139 | 37.6M | while ((curr = *p) != NULL) { |
1140 | 37.4M | if (iswhite(curr)) { /* is 'curr' dead? */ |
1141 | 4.29M | lua_assert(isdead(g, curr)); |
1142 | 4.29M | *p = curr->next; /* remove 'curr' from list */ |
1143 | 4.29M | freeobj(L, curr); /* erase 'curr' */ |
1144 | 4.29M | } |
1145 | 33.1M | else { /* all surviving objects become old */ |
1146 | 33.1M | setage(curr, G_OLD); |
1147 | 33.1M | if (curr->tt == LUA_VTHREAD) { /* threads must be watched */ |
1148 | 1.86M | lua_State *th = gco2th(curr); |
1149 | 1.86M | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ |
1150 | 1.86M | } |
1151 | 31.2M | else if (curr->tt == LUA_VUPVAL && upisopen(gco2upv(curr))) |
1152 | 31.2M | set2gray(curr); /* open upvalues are always gray */ |
1153 | 27.6M | else /* everything else is black */ |
1154 | 27.6M | nw2black(curr); |
1155 | 33.1M | p = &curr->next; /* go to next element */ |
1156 | 33.1M | } |
1157 | 37.4M | } |
1158 | 159k | } |
1159 | | |
1160 | | |
1161 | | /* |
1162 | | ** Sweep for generational mode. Delete dead objects. (Because the |
1163 | | ** collection is not incremental, there are no "new white" objects |
1164 | | ** during the sweep. So, any white object must be dead.) For |
1165 | | ** non-dead objects, advance their ages and clear the color of |
1166 | | ** new objects. (Old objects keep their colors.) |
1167 | | ** The ages of G_TOUCHED1 and G_TOUCHED2 objects cannot be advanced |
1168 | | ** here, because these old-generation objects are usually not swept |
1169 | | ** here. They will all be advanced in 'correctgraylist'. That function |
1170 | | ** will also remove objects turned white here from any gray list. |
1171 | | */ |
1172 | | static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, |
1173 | | GCObject *limit, GCObject **pfirstold1, |
1174 | 2.79M | l_mem *paddedold) { |
1175 | 2.79M | static const lu_byte nextage[] = { |
1176 | 2.79M | G_SURVIVAL, /* from G_NEW */ |
1177 | 2.79M | G_OLD1, /* from G_SURVIVAL */ |
1178 | 2.79M | G_OLD1, /* from G_OLD0 */ |
1179 | 2.79M | G_OLD, /* from G_OLD1 */ |
1180 | 2.79M | G_OLD, /* from G_OLD (do not change) */ |
1181 | 2.79M | G_TOUCHED1, /* from G_TOUCHED1 (do not change) */ |
1182 | 2.79M | G_TOUCHED2 /* from G_TOUCHED2 (do not change) */ |
1183 | 2.79M | }; |
1184 | 2.79M | l_mem addedold = 0; |
1185 | 2.79M | int white = luaC_white(g); |
1186 | 2.79M | GCObject *curr; |
1187 | 31.9M | while ((curr = *p) != limit) { |
1188 | 29.1M | if (iswhite(curr)) { /* is 'curr' dead? */ |
1189 | 22.0M | lua_assert(!isold(curr) && isdead(g, curr)); |
1190 | 22.0M | *p = curr->next; /* remove 'curr' from list */ |
1191 | 22.0M | freeobj(L, curr); /* erase 'curr' */ |
1192 | 22.0M | } |
1193 | 7.13M | else { /* correct mark and age */ |
1194 | 7.13M | int age = getage(curr); |
1195 | 7.13M | if (age == G_NEW) { /* new objects go back to white */ |
1196 | 4.72M | int marked = curr->marked & ~maskgcbits; /* erase GC bits */ |
1197 | 4.72M | curr->marked = cast_byte(marked | G_SURVIVAL | white); |
1198 | 4.72M | } |
1199 | 2.40M | else { /* all other objects will be old, and so keep their color */ |
1200 | 2.40M | lua_assert(age != G_OLD1); /* advanced in 'markold' */ |
1201 | 2.40M | setage(curr, nextage[age]); |
1202 | 2.40M | if (getage(curr) == G_OLD1) { |
1203 | 2.23M | addedold += objsize(curr); /* bytes becoming old */ |
1204 | 2.23M | if (*pfirstold1 == NULL) |
1205 | 229k | *pfirstold1 = curr; /* first OLD1 object in the list */ |
1206 | 2.23M | } |
1207 | 2.40M | } |
1208 | 7.13M | p = &curr->next; /* go to next element */ |
1209 | 7.13M | } |
1210 | 29.1M | } |
1211 | 2.79M | *paddedold += addedold; |
1212 | 2.79M | return p; |
1213 | 2.79M | } |
1214 | | |
1215 | | |
1216 | | /* |
1217 | | ** Correct a list of gray objects. Return a pointer to the last element |
1218 | | ** left on the list, so that we can link another list to the end of |
1219 | | ** this one. |
1220 | | ** Because this correction is done after sweeping, young objects might |
1221 | | ** be turned white and still be in the list. They are only removed. |
1222 | | ** 'TOUCHED1' objects are advanced to 'TOUCHED2' and remain on the list; |
1223 | | ** Non-white threads also remain on the list. 'TOUCHED2' objects and |
1224 | | ** anything else become regular old, are marked black, and are removed |
1225 | | ** from the list. |
1226 | | */ |
1227 | 2.40M | static GCObject **correctgraylist (GCObject **p) { |
1228 | 2.40M | GCObject *curr; |
1229 | 5.85M | while ((curr = *p) != NULL) { |
1230 | 3.45M | GCObject **next = getgclist(curr); |
1231 | 3.45M | if (iswhite(curr)) |
1232 | 0 | goto remove; /* remove all white objects */ |
1233 | 3.45M | else if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */ |
1234 | 117k | lua_assert(isgray(curr)); |
1235 | 117k | nw2black(curr); /* make it black, for next barrier */ |
1236 | 117k | setage(curr, G_TOUCHED2); |
1237 | 117k | goto remain; /* keep it in the list and go to next element */ |
1238 | 117k | } |
1239 | 3.33M | else if (curr->tt == LUA_VTHREAD) { |
1240 | 3.33M | lua_assert(isgray(curr)); |
1241 | 3.33M | goto remain; /* keep non-white threads on the list */ |
1242 | 3.33M | } |
1243 | 14 | else { /* everything else is removed */ |
1244 | 14 | lua_assert(isold(curr)); /* young objects should be white here */ |
1245 | 14 | if (getage(curr) == G_TOUCHED2) /* advance from TOUCHED2... */ |
1246 | 14 | setage(curr, G_OLD); /* ... to OLD */ |
1247 | 14 | nw2black(curr); /* make object black (to be removed) */ |
1248 | 0 | goto remove; |
1249 | 14 | } |
1250 | 14 | remove: *p = *next; continue; |
1251 | 3.45M | remain: p = next; continue; |
1252 | 3.45M | } |
1253 | 2.40M | return p; |
1254 | 2.40M | } |
1255 | | |
1256 | | |
1257 | | /* |
1258 | | ** Correct all gray lists, coalescing them into 'grayagain'. |
1259 | | */ |
1260 | 600k | static void correctgraylists (global_State *g) { |
1261 | 600k | GCObject **list = correctgraylist(&g->grayagain); |
1262 | 600k | *list = g->weak; g->weak = NULL; |
1263 | 600k | list = correctgraylist(list); |
1264 | 600k | *list = g->allweak; g->allweak = NULL; |
1265 | 600k | list = correctgraylist(list); |
1266 | 600k | *list = g->ephemeron; g->ephemeron = NULL; |
1267 | 600k | correctgraylist(list); |
1268 | 600k | } |
1269 | | |
1270 | | |
1271 | | /* |
1272 | | ** Mark black 'OLD1' objects when starting a new young collection. |
1273 | | ** Gray objects are already in some gray list, and so will be visited in |
1274 | | ** the atomic step. |
1275 | | */ |
1276 | 1.31M | static void markold (global_State *g, GCObject *from, GCObject *to) { |
1277 | 1.31M | GCObject *p; |
1278 | 4.01M | for (p = from; p != to; p = p->next) { |
1279 | 2.70M | if (getage(p) == G_OLD1) { |
1280 | 1.97M | lua_assert(!iswhite(p)); |
1281 | 1.97M | setage(p, G_OLD); /* now they are old */ |
1282 | 1.97M | if (isblack(p)) |
1283 | 1.95M | reallymarkobject(g, p); |
1284 | 1.97M | } |
1285 | 2.70M | } |
1286 | 1.31M | } |
1287 | | |
1288 | | |
1289 | | /* |
1290 | | ** Finish a young-generation collection. |
1291 | | */ |
1292 | 600k | static void finishgencycle (lua_State *L, global_State *g) { |
1293 | 600k | correctgraylists(g); |
1294 | 600k | checkSizes(L, g); |
1295 | 600k | g->gcstate = GCSpropagate; /* skip restart */ |
1296 | 600k | if (!g->gcemergency) |
1297 | 600k | callallpendingfinalizers(L); |
1298 | 600k | } |
1299 | | |
1300 | | |
1301 | | /* |
1302 | | ** Shifts from a minor collection to major collections. It starts in |
1303 | | ** the "sweep all" state to clear all objects, which are mostly black |
1304 | | ** in generational mode. |
1305 | | */ |
1306 | 53.0k | static void minor2inc (lua_State *L, global_State *g, lu_byte kind) { |
1307 | 53.0k | g->GCmajorminor = g->GCmarked; /* number of live bytes */ |
1308 | 53.0k | g->gckind = kind; |
1309 | 53.0k | g->reallyold = g->old1 = g->survival = NULL; |
1310 | 53.0k | g->finobjrold = g->finobjold1 = g->finobjsur = NULL; |
1311 | 53.0k | entersweep(L); /* continue as an incremental cycle */ |
1312 | | /* set a debt equal to the step size */ |
1313 | 53.0k | luaE_setdebt(g, applygcparam(g, STEPSIZE, 100)); |
1314 | 53.0k | } |
1315 | | |
1316 | | |
1317 | | /* |
1318 | | ** Decide whether to shift to major mode. It shifts if the accumulated |
1319 | | ** number of added old bytes (counted in 'GCmarked') is larger than |
1320 | | ** 'minormajor'% of the number of lived bytes after the last major |
1321 | | ** collection. (This number is kept in 'GCmajorminor'.) |
1322 | | */ |
1323 | 559k | static int checkminormajor (global_State *g) { |
1324 | 559k | l_mem limit = applygcparam(g, MINORMAJOR, g->GCmajorminor); |
1325 | 559k | if (limit == 0) |
1326 | 0 | return 0; /* special case: 'minormajor' 0 stops major collections */ |
1327 | 559k | return (g->GCmarked >= limit); |
1328 | 559k | } |
1329 | | |
1330 | | /* |
1331 | | ** Does a young collection. First, mark 'OLD1' objects. Then does the |
1332 | | ** atomic step. Then, check whether to continue in minor mode. If so, |
1333 | | ** sweep all lists and advance pointers. Finally, finish the collection. |
1334 | | */ |
1335 | 559k | static void youngcollection (lua_State *L, global_State *g) { |
1336 | 559k | l_mem addedold1 = 0; |
1337 | 559k | l_mem marked = g->GCmarked; /* preserve 'g->GCmarked' */ |
1338 | 559k | GCObject **psurvival; /* to point to first non-dead survival object */ |
1339 | 559k | GCObject *dummy; /* dummy out parameter to 'sweepgen' */ |
1340 | 559k | lua_assert(g->gcstate == GCSpropagate); |
1341 | 559k | if (g->firstold1) { /* are there regular OLD1 objects? */ |
1342 | 192k | markold(g, g->firstold1, g->reallyold); /* mark them */ |
1343 | 192k | g->firstold1 = NULL; /* no more OLD1 objects (for now) */ |
1344 | 192k | } |
1345 | 559k | markold(g, g->finobj, g->finobjrold); |
1346 | 559k | markold(g, g->tobefnz, NULL); |
1347 | | |
1348 | 559k | atomic(L); /* will lose 'g->marked' */ |
1349 | | |
1350 | | /* sweep nursery and get a pointer to its last live element */ |
1351 | 559k | g->gcstate = GCSswpallgc; |
1352 | 559k | psurvival = sweepgen(L, g, &g->allgc, g->survival, &g->firstold1, &addedold1); |
1353 | | /* sweep 'survival' */ |
1354 | 559k | sweepgen(L, g, psurvival, g->old1, &g->firstold1, &addedold1); |
1355 | 559k | g->reallyold = g->old1; |
1356 | 559k | g->old1 = *psurvival; /* 'survival' survivals are old now */ |
1357 | 559k | g->survival = g->allgc; /* all news are survivals */ |
1358 | | |
1359 | | /* repeat for 'finobj' lists */ |
1360 | 559k | dummy = NULL; /* no 'firstold1' optimization for 'finobj' lists */ |
1361 | 559k | psurvival = sweepgen(L, g, &g->finobj, g->finobjsur, &dummy, &addedold1); |
1362 | | /* sweep 'survival' */ |
1363 | 559k | sweepgen(L, g, psurvival, g->finobjold1, &dummy, &addedold1); |
1364 | 559k | g->finobjrold = g->finobjold1; |
1365 | 559k | g->finobjold1 = *psurvival; /* 'survival' survivals are old now */ |
1366 | 559k | g->finobjsur = g->finobj; /* all news are survivals */ |
1367 | | |
1368 | 559k | sweepgen(L, g, &g->tobefnz, NULL, &dummy, &addedold1); |
1369 | | |
1370 | | /* keep total number of added old1 bytes */ |
1371 | 559k | g->GCmarked = marked + addedold1; |
1372 | | |
1373 | | /* decide whether to shift to major mode */ |
1374 | 559k | if (checkminormajor(g)) { |
1375 | 12.6k | minor2inc(L, g, KGC_GENMAJOR); /* go to major mode */ |
1376 | 12.6k | g->GCmarked = 0; /* avoid pause in first major cycle (see 'setpause') */ |
1377 | 12.6k | } |
1378 | 546k | else |
1379 | 546k | finishgencycle(L, g); /* still in minor mode; finish it */ |
1380 | 559k | } |
1381 | | |
1382 | | |
1383 | | /* |
1384 | | ** Clears all gray lists, sweeps objects, and prepare sublists to enter |
1385 | | ** generational mode. The sweeps remove dead objects and turn all |
1386 | | ** surviving objects to old. Threads go back to 'grayagain'; everything |
1387 | | ** else is turned black (not in any gray list). |
1388 | | */ |
1389 | 53.0k | static void atomic2gen (lua_State *L, global_State *g) { |
1390 | 53.0k | cleargraylists(g); |
1391 | | /* sweep all elements making them old */ |
1392 | 53.0k | g->gcstate = GCSswpallgc; |
1393 | 53.0k | sweep2old(L, &g->allgc); |
1394 | | /* everything alive now is old */ |
1395 | 53.0k | g->reallyold = g->old1 = g->survival = g->allgc; |
1396 | 53.0k | g->firstold1 = NULL; /* there are no OLD1 objects anywhere */ |
1397 | | |
1398 | | /* repeat for 'finobj' lists */ |
1399 | 53.0k | sweep2old(L, &g->finobj); |
1400 | 53.0k | g->finobjrold = g->finobjold1 = g->finobjsur = g->finobj; |
1401 | | |
1402 | 53.0k | sweep2old(L, &g->tobefnz); |
1403 | | |
1404 | 53.0k | g->gckind = KGC_GENMINOR; |
1405 | 53.0k | g->GCmajorminor = g->GCmarked; /* "base" for number of bytes */ |
1406 | 53.0k | g->GCmarked = 0; /* to count the number of added old1 bytes */ |
1407 | 53.0k | finishgencycle(L, g); |
1408 | 53.0k | } |
1409 | | |
1410 | | |
1411 | | /* |
1412 | | ** Set debt for the next minor collection, which will happen when |
1413 | | ** total number of bytes grows 'genminormul'% in relation to |
1414 | | ** the base, GCmajorminor, which is the number of bytes being used |
1415 | | ** after the last major collection. |
1416 | | */ |
1417 | 612k | static void setminordebt (global_State *g) { |
1418 | 612k | luaE_setdebt(g, applygcparam(g, MINORMUL, g->GCmajorminor)); |
1419 | 612k | } |
1420 | | |
1421 | | |
1422 | | /* |
1423 | | ** Enter generational mode. Must go until the end of an atomic cycle |
1424 | | ** to ensure that all objects are correctly marked and weak tables |
1425 | | ** are cleared. Then, turn all objects into old and finishes the |
1426 | | ** collection. |
1427 | | */ |
1428 | 46.0k | static void entergen (lua_State *L, global_State *g) { |
1429 | 46.0k | luaC_runtilstate(L, GCSpause, 1); /* prepare to start a new cycle */ |
1430 | 46.0k | luaC_runtilstate(L, GCSpropagate, 1); /* start new cycle */ |
1431 | 46.0k | atomic(L); /* propagates all and then do the atomic stuff */ |
1432 | 46.0k | atomic2gen(L, g); |
1433 | 46.0k | setminordebt(g); /* set debt assuming next cycle will be minor */ |
1434 | 46.0k | } |
1435 | | |
1436 | | |
1437 | | /* |
1438 | | ** Change collector mode to 'newmode'. |
1439 | | */ |
1440 | 348k | void luaC_changemode (lua_State *L, int newmode) { |
1441 | 348k | global_State *g = G(L); |
1442 | 348k | if (g->gckind == KGC_GENMAJOR) /* doing major collections? */ |
1443 | 5.55k | g->gckind = KGC_INC; /* already incremental but in name */ |
1444 | 348k | if (newmode != g->gckind) { /* does it need to change? */ |
1445 | 28.0k | if (newmode == KGC_INC) /* entering incremental mode? */ |
1446 | 11.2k | minor2inc(L, g, KGC_INC); /* entering incremental mode */ |
1447 | 16.8k | else { |
1448 | 16.8k | lua_assert(newmode == KGC_GENMINOR); |
1449 | 16.8k | entergen(L, g); |
1450 | 16.8k | } |
1451 | 28.0k | } |
1452 | 348k | } |
1453 | | |
1454 | | |
1455 | | /* |
1456 | | ** Does a full collection in generational mode. |
1457 | | */ |
1458 | 29.2k | static void fullgen (lua_State *L, global_State *g) { |
1459 | 29.2k | minor2inc(L, g, KGC_INC); |
1460 | 29.2k | entergen(L, g); |
1461 | 29.2k | } |
1462 | | |
1463 | | |
1464 | | /* |
1465 | | ** After an atomic incremental step from a major collection, |
1466 | | ** check whether collector could return to minor collections. |
1467 | | ** It checks whether the number of bytes 'tobecollected' |
1468 | | ** is greater than 'majorminor'% of the number of bytes added |
1469 | | ** since the last collection ('addedbytes'). |
1470 | | */ |
1471 | 506k | static int checkmajorminor (lua_State *L, global_State *g) { |
1472 | 506k | if (g->gckind == KGC_GENMAJOR) { /* generational mode? */ |
1473 | 9.16k | l_mem numbytes = gettotalbytes(g); |
1474 | 9.16k | l_mem addedbytes = numbytes - g->GCmajorminor; |
1475 | 9.16k | l_mem limit = applygcparam(g, MAJORMINOR, addedbytes); |
1476 | 9.16k | l_mem tobecollected = numbytes - g->GCmarked; |
1477 | 9.16k | if (tobecollected > limit) { |
1478 | 7.05k | atomic2gen(L, g); /* return to generational mode */ |
1479 | 7.05k | setminordebt(g); |
1480 | 7.05k | return 1; /* exit incremental collection */ |
1481 | 7.05k | } |
1482 | 9.16k | } |
1483 | 499k | g->GCmajorminor = g->GCmarked; /* prepare for next collection */ |
1484 | 499k | return 0; /* stay doing incremental collections */ |
1485 | 506k | } |
1486 | | |
1487 | | /* }====================================================== */ |
1488 | | |
1489 | | |
1490 | | /* |
1491 | | ** {====================================================== |
1492 | | ** GC control |
1493 | | ** ======================================================= |
1494 | | */ |
1495 | | |
1496 | | |
1497 | | /* |
1498 | | ** Enter first sweep phase. |
1499 | | ** The call to 'sweeptolive' makes the pointer point to an object |
1500 | | ** inside the list (instead of to the header), so that the real sweep do |
1501 | | ** not need to skip objects created between "now" and the start of the |
1502 | | ** real sweep. |
1503 | | */ |
1504 | 554k | static void entersweep (lua_State *L) { |
1505 | 554k | global_State *g = G(L); |
1506 | 554k | g->gcstate = GCSswpallgc; |
1507 | 554k | lua_assert(g->sweepgc == NULL); |
1508 | 554k | g->sweepgc = sweeptolive(L, &g->allgc); |
1509 | 554k | } |
1510 | | |
1511 | | |
1512 | | /* |
1513 | | ** Delete all objects in list 'p' until (but not including) object |
1514 | | ** 'limit'. |
1515 | | */ |
1516 | 119k | static void deletelist (lua_State *L, GCObject *p, GCObject *limit) { |
1517 | 34.5M | while (p != limit) { |
1518 | 34.4M | GCObject *next = p->next; |
1519 | 34.4M | freeobj(L, p); |
1520 | 34.4M | p = next; |
1521 | 34.4M | } |
1522 | 119k | } |
1523 | | |
1524 | | |
1525 | | /* |
1526 | | ** Call all finalizers of the objects in the given Lua state, and |
1527 | | ** then free all objects, except for the main thread. |
1528 | | */ |
1529 | 59.5k | void luaC_freeallobjects (lua_State *L) { |
1530 | 59.5k | global_State *g = G(L); |
1531 | 59.5k | g->gcstp = GCSTPCLS; /* no extra finalizers after here */ |
1532 | 59.5k | luaC_changemode(L, KGC_INC); |
1533 | 59.5k | separatetobefnz(g, 1); /* separate all objects with finalizers */ |
1534 | 59.5k | lua_assert(g->finobj == NULL); |
1535 | 59.5k | callallpendingfinalizers(L); |
1536 | 59.5k | deletelist(L, g->allgc, obj2gco(mainthread(g))); |
1537 | 59.5k | lua_assert(g->finobj == NULL); /* no new finalizers */ |
1538 | 59.5k | deletelist(L, g->fixedgc, NULL); /* collect fixed objects */ |
1539 | 59.5k | lua_assert(g->strt.nuse == 0); |
1540 | 59.5k | } |
1541 | | |
1542 | | |
1543 | 1.11M | static void atomic (lua_State *L) { |
1544 | 1.11M | global_State *g = G(L); |
1545 | 1.11M | GCObject *origweak, *origall; |
1546 | 1.11M | GCObject *grayagain = g->grayagain; /* save original list */ |
1547 | 1.11M | g->grayagain = NULL; |
1548 | 1.11M | lua_assert(g->ephemeron == NULL && g->weak == NULL); |
1549 | 1.11M | lua_assert(!iswhite(mainthread(g))); |
1550 | 1.11M | g->gcstate = GCSatomic; |
1551 | 1.11M | markobject(g, L); /* mark running thread */ |
1552 | | /* registry and global metatables may be changed by API */ |
1553 | 1.11M | markvalue(g, &g->l_registry); |
1554 | 1.11M | markmt(g); /* mark global metatables */ |
1555 | 1.11M | propagateall(g); /* empties 'gray' list */ |
1556 | | /* remark occasional upvalues of (maybe) dead threads */ |
1557 | 1.11M | remarkupvals(g); |
1558 | 1.11M | propagateall(g); /* propagate changes */ |
1559 | 1.11M | g->gray = grayagain; |
1560 | 1.11M | propagateall(g); /* traverse 'grayagain' list */ |
1561 | 1.11M | convergeephemerons(g); |
1562 | | /* at this point, all strongly accessible objects are marked. */ |
1563 | | /* Clear values from weak tables, before checking finalizers */ |
1564 | 1.11M | clearbyvalues(g, g->weak, NULL); |
1565 | 1.11M | clearbyvalues(g, g->allweak, NULL); |
1566 | 1.11M | origweak = g->weak; origall = g->allweak; |
1567 | 1.11M | separatetobefnz(g, 0); /* separate objects to be finalized */ |
1568 | 1.11M | markbeingfnz(g); /* mark objects that will be finalized */ |
1569 | 1.11M | propagateall(g); /* remark, to propagate 'resurrection' */ |
1570 | 1.11M | convergeephemerons(g); |
1571 | | /* at this point, all resurrected objects are marked. */ |
1572 | | /* remove dead objects from weak tables */ |
1573 | 1.11M | clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron */ |
1574 | 1.11M | clearbykeys(g, g->allweak); /* clear keys from all 'allweak' */ |
1575 | | /* clear values from resurrected weak tables */ |
1576 | 1.11M | clearbyvalues(g, g->weak, origweak); |
1577 | 1.11M | clearbyvalues(g, g->allweak, origall); |
1578 | 1.11M | luaS_clearcache(g); |
1579 | 1.11M | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ |
1580 | 1.11M | lua_assert(g->gray == NULL); |
1581 | 1.11M | } |
1582 | | |
1583 | | |
1584 | | /* |
1585 | | ** Do a sweep step. The normal case (not fast) sweeps at most GCSWEEPMAX |
1586 | | ** elements. The fast case sweeps the whole list. |
1587 | | */ |
1588 | | static void sweepstep (lua_State *L, global_State *g, |
1589 | 13.1M | lu_byte nextstate, GCObject **nextlist, int fast) { |
1590 | 13.1M | if (g->sweepgc) |
1591 | 11.5M | g->sweepgc = sweeplist(L, g->sweepgc, fast ? MAX_LMEM : GCSWEEPMAX); |
1592 | 1.57M | else { /* enter next state */ |
1593 | 1.57M | g->gcstate = nextstate; |
1594 | 1.57M | g->sweepgc = nextlist; |
1595 | 1.57M | } |
1596 | 13.1M | } |
1597 | | |
1598 | | |
1599 | | /* |
1600 | | ** Performs one incremental "step" in an incremental garbage collection. |
1601 | | ** For indivisible work, a step goes to the next state. When marking |
1602 | | ** (propagating), a step traverses one object. When sweeping, a step |
1603 | | ** sweeps GCSWEEPMAX objects, to avoid a big overhead for sweeping |
1604 | | ** objects one by one. (Sweeping is inexpensive, no matter the |
1605 | | ** object.) When 'fast' is true, 'singlestep' tries to finish a state |
1606 | | ** "as fast as possible". In particular, it skips the propagation |
1607 | | ** phase and leaves all objects to be traversed by the atomic phase: |
1608 | | ** That avoids traversing twice some objects, such as threads and |
1609 | | ** weak tables. |
1610 | | */ |
1611 | | |
1612 | 102M | #define step2pause -3 /* finished collection; entered pause state */ |
1613 | 101M | #define atomicstep -2 /* atomic step */ |
1614 | 50.7M | #define step2minor -1 /* moved to minor collections */ |
1615 | | |
1616 | | |
1617 | 52.4M | static l_mem singlestep (lua_State *L, int fast) { |
1618 | 52.4M | global_State *g = G(L); |
1619 | 52.4M | l_mem stepresult; |
1620 | 52.4M | lua_assert(!g->gcstopem); /* collector is not reentrant */ |
1621 | 52.4M | g->gcstopem = 1; /* no emergency collections while collecting */ |
1622 | 52.4M | switch (g->gcstate) { |
1623 | 555k | case GCSpause: { |
1624 | 555k | restartcollection(g); |
1625 | 555k | g->gcstate = GCSpropagate; |
1626 | 555k | stepresult = 1; |
1627 | 555k | break; |
1628 | 0 | } |
1629 | 35.3M | case GCSpropagate: { |
1630 | 35.3M | if (fast || g->gray == NULL) { |
1631 | 506k | g->gcstate = GCSenteratomic; /* finish propagate phase */ |
1632 | 506k | stepresult = 1; |
1633 | 506k | } |
1634 | 34.8M | else |
1635 | 34.8M | stepresult = propagatemark(g); /* traverse one gray object */ |
1636 | 35.3M | break; |
1637 | 0 | } |
1638 | 506k | case GCSenteratomic: { |
1639 | 506k | atomic(L); |
1640 | 506k | if (checkmajorminor(L, g)) |
1641 | 7.05k | stepresult = step2minor; |
1642 | 499k | else { |
1643 | 499k | entersweep(L); |
1644 | 499k | stepresult = atomicstep; |
1645 | 499k | } |
1646 | 506k | break; |
1647 | 0 | } |
1648 | 11.0M | case GCSswpallgc: { /* sweep "regular" objects */ |
1649 | 11.0M | sweepstep(L, g, GCSswpfinobj, &g->finobj, fast); |
1650 | 11.0M | stepresult = GCSWEEPMAX; |
1651 | 11.0M | break; |
1652 | 0 | } |
1653 | 1.05M | case GCSswpfinobj: { /* sweep objects with finalizers */ |
1654 | 1.05M | sweepstep(L, g, GCSswptobefnz, &g->tobefnz, fast); |
1655 | 1.05M | stepresult = GCSWEEPMAX; |
1656 | 1.05M | break; |
1657 | 0 | } |
1658 | 1.09M | case GCSswptobefnz: { /* sweep objects to be finalized */ |
1659 | 1.09M | sweepstep(L, g, GCSswpend, NULL, fast); |
1660 | 1.09M | stepresult = GCSWEEPMAX; |
1661 | 1.09M | break; |
1662 | 0 | } |
1663 | 523k | case GCSswpend: { /* finish sweeps */ |
1664 | 523k | checkSizes(L, g); |
1665 | 523k | g->gcstate = GCScallfin; |
1666 | 523k | stepresult = GCSWEEPMAX; |
1667 | 523k | break; |
1668 | 0 | } |
1669 | 2.40M | case GCScallfin: { /* call finalizers */ |
1670 | 2.40M | if (g->tobefnz && !g->gcemergency) { |
1671 | 1.88M | g->gcstopem = 0; /* ok collections during finalizers */ |
1672 | 1.88M | GCTM(L); /* call one finalizer */ |
1673 | 1.88M | stepresult = CWUFIN; |
1674 | 1.88M | } |
1675 | 523k | else { /* emergency mode or no more finalizers */ |
1676 | 523k | g->gcstate = GCSpause; /* finish collection */ |
1677 | 523k | stepresult = step2pause; |
1678 | 523k | } |
1679 | 2.40M | break; |
1680 | 0 | } |
1681 | 0 | default: lua_assert(0); return 0; |
1682 | 52.4M | } |
1683 | 52.4M | g->gcstopem = 0; |
1684 | 52.4M | return stepresult; |
1685 | 52.4M | } |
1686 | | |
1687 | | |
1688 | | /* |
1689 | | ** Advances the garbage collector until it reaches the given state. |
1690 | | ** (The option 'fast' is only for testing; in normal code, 'fast' |
1691 | | ** here is always true.) |
1692 | | */ |
1693 | 305k | void luaC_runtilstate (lua_State *L, int state, int fast) { |
1694 | 305k | global_State *g = G(L); |
1695 | 305k | lua_assert(g->gckind == KGC_INC); |
1696 | 1.99M | while (state != g->gcstate) |
1697 | 1.69M | singlestep(L, fast); |
1698 | 305k | } |
1699 | | |
1700 | | |
1701 | | |
1702 | | /* |
1703 | | ** Performs a basic incremental step. The step size is |
1704 | | ** converted from bytes to "units of work"; then the function loops |
1705 | | ** running single steps until adding that many units of work or |
1706 | | ** finishing a cycle (pause state). Finally, it sets the debt that |
1707 | | ** controls when next step will be performed. |
1708 | | */ |
1709 | 960k | static void incstep (lua_State *L, global_State *g) { |
1710 | 960k | l_mem stepsize = applygcparam(g, STEPSIZE, 100); |
1711 | 960k | l_mem work2do = applygcparam(g, STEPMUL, stepsize / cast_int(sizeof(void*))); |
1712 | 960k | l_mem stres; |
1713 | 960k | int fast = (work2do == 0); /* special case: do a full collection */ |
1714 | 50.7M | do { /* repeat until enough work */ |
1715 | 50.7M | stres = singlestep(L, fast); /* perform one single step */ |
1716 | 50.7M | if (stres == step2minor) /* returned to minor collections? */ |
1717 | 7.05k | return; /* nothing else to be done here */ |
1718 | 50.7M | else if (stres == step2pause || (stres == atomicstep && !fast)) |
1719 | 829k | break; /* end of cycle or atomic */ |
1720 | 49.9M | else |
1721 | 49.9M | work2do -= stres; |
1722 | 50.7M | } while (fast || work2do > 0); |
1723 | 953k | if (g->gcstate == GCSpause) |
1724 | 403k | setpause(g); /* pause until next cycle */ |
1725 | 550k | else |
1726 | 550k | luaE_setdebt(g, stepsize); |
1727 | 953k | } |
1728 | | |
1729 | | |
1730 | | #if !defined(luai_tracegc) |
1731 | 3.04M | #define luai_tracegc(L,f) ((void)0) |
1732 | | #endif |
1733 | | |
1734 | | /* |
1735 | | ** Performs a basic GC step if collector is running. (If collector was |
1736 | | ** stopped by the user, set a reasonable debt to avoid it being called |
1737 | | ** at every single check.) |
1738 | | */ |
1739 | 1.53M | void luaC_step (lua_State *L) { |
1740 | 1.53M | global_State *g = G(L); |
1741 | 1.53M | lua_assert(!g->gcemergency); |
1742 | 1.53M | if (!gcrunning(g)) { /* not running? */ |
1743 | 13.3k | if (g->gcstp & GCSTPUSR) /* stopped by the user? */ |
1744 | 9.08k | luaE_setdebt(g, 20000); |
1745 | 13.3k | } |
1746 | 1.52M | else { |
1747 | 1.52M | luai_tracegc(L, 1); /* for internal debugging */ |
1748 | 1.52M | switch (g->gckind) { |
1749 | 960k | case KGC_INC: case KGC_GENMAJOR: |
1750 | 960k | incstep(L, g); |
1751 | 960k | break; |
1752 | 559k | case KGC_GENMINOR: |
1753 | 559k | youngcollection(L, g); |
1754 | 559k | setminordebt(g); |
1755 | 559k | break; |
1756 | 1.52M | } |
1757 | 1.52M | luai_tracegc(L, 0); /* for internal debugging */ |
1758 | 1.52M | } |
1759 | 1.53M | } |
1760 | | |
1761 | | |
1762 | | /* |
1763 | | ** Perform a full collection in incremental mode. |
1764 | | ** Before running the collection, check 'keepinvariant'; if it is true, |
1765 | | ** there may be some objects marked as black, so the collector has |
1766 | | ** to sweep all objects to turn them back to white (as white has not |
1767 | | ** changed, nothing will be collected). |
1768 | | */ |
1769 | 71.0k | static void fullinc (lua_State *L, global_State *g) { |
1770 | 71.0k | if (keepinvariant(g)) /* black objects? */ |
1771 | 2.47k | entersweep(L); /* sweep everything to turn them back to white */ |
1772 | | /* finish any pending sweep phase to start a new cycle */ |
1773 | 71.0k | luaC_runtilstate(L, GCSpause, 1); |
1774 | 71.0k | luaC_runtilstate(L, GCScallfin, 1); /* run up to finalizers */ |
1775 | 71.0k | luaC_runtilstate(L, GCSpause, 1); /* finish collection */ |
1776 | 71.0k | setpause(g); |
1777 | 71.0k | } |
1778 | | |
1779 | | |
1780 | | /* |
1781 | | ** Performs a full GC cycle; if 'isemergency', set a flag to avoid |
1782 | | ** some operations which could change the interpreter state in some |
1783 | | ** unexpected ways (running finalizers and shrinking some structures). |
1784 | | */ |
1785 | 100k | void luaC_fullgc (lua_State *L, int isemergency) { |
1786 | 100k | global_State *g = G(L); |
1787 | 100k | lua_assert(!g->gcemergency); |
1788 | 100k | g->gcemergency = cast_byte(isemergency); /* set flag */ |
1789 | 100k | switch (g->gckind) { |
1790 | 29.2k | case KGC_GENMINOR: fullgen(L, g); break; |
1791 | 69.7k | case KGC_INC: fullinc(L, g); break; |
1792 | 1.32k | case KGC_GENMAJOR: |
1793 | 1.32k | g->gckind = KGC_INC; |
1794 | 1.32k | fullinc(L, g); |
1795 | 1.32k | g->gckind = KGC_GENMAJOR; |
1796 | 1.32k | break; |
1797 | 100k | } |
1798 | 100k | g->gcemergency = 0; |
1799 | 100k | } |
1800 | | |
1801 | | /* }====================================================== */ |
1802 | | |
1803 | | |