Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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