~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to tests/lua/src/lgc.c

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-02 13:11:51 UTC
  • Revision ID: package-import@ubuntu.com-20130502131151-q8dvteqr1ef2x7xz
Tags: upstream-1.4.1~20130504~adb56cb
ImportĀ upstreamĀ versionĀ 1.4.1~20130504~adb56cb

Show diffs side-by-side

added added

removed removed

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