aboutsummaryrefslogtreecommitdiff
path: root/lgc.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2003-12-01 14:33:30 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2003-12-01 14:33:30 -0200
commit1d10acb35500df47d6052164e6c56476f520232e (patch)
treec6e4983bff097a53b0d73820506ec13ceb8887f5 /lgc.c
parentda61624756a9a64df4aa7e45e9f4013c1b76c293 (diff)
downloadlua-1d10acb35500df47d6052164e6c56476f520232e.tar.gz
lua-1d10acb35500df47d6052164e6c56476f520232e.tar.bz2
lua-1d10acb35500df47d6052164e6c56476f520232e.zip
incremental GC phases
Diffstat (limited to 'lgc.c')
-rw-r--r--lgc.c242
1 files changed, 174 insertions, 68 deletions
diff --git a/lgc.c b/lgc.c
index b60b9d3a..cb9fa289 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 1.179 2003/11/18 14:55:11 roberto Exp roberto $ 2** $Id: lgc.c,v 1.180 2003/11/19 19:41:57 roberto Exp roberto $
3** Garbage Collector 3** Garbage Collector
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -22,6 +22,9 @@
22#include "ltm.h" 22#include "ltm.h"
23 23
24 24
25#define GCSTEPSIZE (20*sizeof(TObject))
26
27
25 28
26#define isblack(x) testbit((x)->gch.marked, BLACKBIT) 29#define isblack(x) testbit((x)->gch.marked, BLACKBIT)
27#define gray2black(x) ((x)->gch.marked++) 30#define gray2black(x) ((x)->gch.marked++)
@@ -40,6 +43,9 @@
40#define markfinalized(u) setbit((u)->uv.marked, FINALIZEDBIT) 43#define markfinalized(u) setbit((u)->uv.marked, FINALIZEDBIT)
41 44
42 45
46#define maskbf bit2mask(BLACKBIT, FIXEDBIT)
47
48
43#define KEYWEAK bitmask(KEYWEAKBIT) 49#define KEYWEAK bitmask(KEYWEAKBIT)
44#define VALUEWEAK bitmask(VALUEWEAKBIT) 50#define VALUEWEAK bitmask(VALUEWEAKBIT)
45 51
@@ -57,6 +63,49 @@
57 63
58 64
59 65
66/*
67** computes the size of a collectible object
68*/
69static size_t objsize (GCObject *o) {
70 switch (o->gch.tt) {
71 case LUA_TSTRING: {
72 TString *ts = gcotots(o);
73 return sizestring(ts->tsv.len);
74 }
75 case LUA_TUSERDATA: {
76 Udata *u = gcotou(o);
77 return sizeudata(u->uv.len);
78 }
79 case LUA_TTABLE: {
80 Table *h = gcotoh(o);
81 return sizeof(Table) + sizeof(TObject) * h->sizearray +
82 sizeof(Node) * sizenode(h);
83 }
84 case LUA_TUPVAL:
85 return sizeof(UpVal);
86 case LUA_TFUNCTION: {
87 Closure *cl = gcotocl(o);
88 return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) :
89 sizeLclosure(cl->l.nupvalues);
90 }
91 case LUA_TTHREAD: {
92 lua_State *th = gcototh(o);
93 return sizeof(lua_State) + sizeof(TObject) * th->stacksize +
94 sizeof(CallInfo) * th->size_ci;
95 }
96 case LUA_TPROTO: {
97 Proto *p = gcotop(o);
98 return sizeof(Proto) + sizeof(Instruction) * p->sizecode +
99 sizeof(Proto *) * p->sizep + sizeof(TObject) * p->sizek +
100 sizeof(int) * p->sizelineinfo + sizeof(LocVar) * p->sizelocvars +
101 sizeof(TString *) * p->sizeupvalues;
102 }
103 }
104 lua_assert(0);
105 return 0; /* to avoid warnings */
106}
107
108
60static void reallymarkobject (global_State *g, GCObject *o) { 109static void reallymarkobject (global_State *g, GCObject *o) {
61 lua_assert(iswhite(o)); 110 lua_assert(iswhite(o));
62 switch (o->gch.tt) { 111 switch (o->gch.tt) {
@@ -248,44 +297,53 @@ static void traversestack (global_State *g, lua_State *L1) {
248} 297}
249 298
250 299
251static void propagatemarks (global_State *g) { 300/*
252 while (g->gray) { /* traverse marked objects */ 301** traverse a given `quantity' of gray objects,
253 lua_assert(isgray(g->gray)); 302** turning them to black. Returns extra `quantity' traversed.
254 gray2black(g->gray); 303*/
255 switch (g->gray->gch.tt) { 304static l_mem propagatemarks (global_State *g, l_mem lim) {
305 GCObject *o;
306 while ((o = g->gray) != NULL) {
307 lua_assert(isgray(o));
308 gray2black(o);
309 switch (o->gch.tt) {
256 case LUA_TTABLE: { 310 case LUA_TTABLE: {
257 Table *h = gcotoh(g->gray); 311 Table *h = gcotoh(o);
258 g->gray = h->gclist; 312 g->gray = h->gclist;
259 traversetable(g, h); 313 traversetable(g, h);
260 break; 314 break;
261 } 315 }
262 case LUA_TFUNCTION: { 316 case LUA_TFUNCTION: {
263 Closure *cl = gcotocl(g->gray); 317 Closure *cl = gcotocl(o);
264 g->gray = cl->c.gclist; 318 g->gray = cl->c.gclist;
265 traverseclosure(g, cl); 319 traverseclosure(g, cl);
266 break; 320 break;
267 } 321 }
268 case LUA_TTHREAD: { 322 case LUA_TTHREAD: {
269 lua_State *th = gcototh(g->gray); 323 lua_State *th = gcototh(o);
270 g->gray = th->gclist; 324 g->gray = th->gclist;
271 traversestack(g, th); 325 traversestack(g, th);
272 break; 326 break;
273 } 327 }
274 case LUA_TPROTO: { 328 case LUA_TPROTO: {
275 Proto *p = gcotop(g->gray); 329 Proto *p = gcotop(o);
276 g->gray = p->gclist; 330 g->gray = p->gclist;
277 traverseproto(g, p); 331 traverseproto(g, p);
278 break; 332 break;
279 } 333 }
280 case LUA_TUPVAL: { 334 case LUA_TUPVAL: {
281 UpVal *uv = gcotouv(g->gray); 335 UpVal *uv = gcotouv(o);
282 g->gray = uv->gclist; 336 g->gray = uv->gclist;
283 markvalue(g, &uv->value); 337 markvalue(g, &uv->value);
284 break; 338 break;
285 } 339 }
286 default: lua_assert(0); 340 default: lua_assert(0);
287 } 341 }
342 lim -= objsize(o);
343 if (lim <= 0) return lim;
288 } 344 }
345 g->gcstate = GCSatomic;
346 return lim;
289} 347}
290 348
291 349
@@ -366,116 +424,164 @@ static void freeobj (lua_State *L, GCObject *o) {
366} 424}
367 425
368 426
369static int sweeplist (lua_State *L, GCObject **p, int mask) { 427static GCObject **sweeplist (lua_State *L, GCObject **p, int mask,
428 l_mem *plim) {
370 GCObject *curr; 429 GCObject *curr;
371 int count = 0; /* number of collected items */ 430 l_mem lim = *plim;
372 while ((curr = *p) != NULL) { 431 while ((curr = *p) != NULL) {
373 lua_assert(!isgray(curr)); 432 lua_assert(!isgray(curr));
374 if (curr->gch.marked & mask) { 433 if (curr->gch.marked & mask) {
434 lim -= objsize(curr);
375 makewhite(curr); 435 makewhite(curr);
376 p = &curr->gch.next; 436 p = &curr->gch.next;
377 } 437 }
378 else { 438 else {
379 count++;
380 *p = curr->gch.next; 439 *p = curr->gch.next;
381 freeobj(L, curr); 440 freeobj(L, curr);
382 } 441 }
442 if (lim <= 0) break;
383 } 443 }
384 return count; 444 *plim = lim;
445 return p;
385} 446}
386 447
387 448
388static void sweepstrings (lua_State *L, int mask) { 449static void sweepstrings (lua_State *L, int mask) {
389 int i; 450 int i;
390 for (i=0; i<G(L)->strt.size; i++) { /* for each list */ 451 global_State *g = G(L);
391 G(L)->strt.nuse -= sweeplist(L, &G(L)->strt.hash[i], mask); 452 for (i = 0; i < g->strt.size; i++) { /* for each list */
453 GCObject *curr;
454 GCObject **p = &G(L)->strt.hash[i];
455 while ((curr = *p) != NULL) {
456 lua_assert(!isgray(curr) && curr->gch.tt == LUA_TSTRING);
457 if (curr->gch.marked & mask) {
458 makewhite(curr);
459 p = &curr->gch.next;
460 }
461 else {
462 g->strt.nuse--;
463 *p = curr->gch.next;
464 luaM_free(L, curr, sizestring(gcotots(curr)->tsv.len));
465 }
466 }
392 } 467 }
393} 468}
394 469
395 470
396static void checkSizes (lua_State *L, size_t deadmem) { 471static void checkSizes (lua_State *L) {
472 global_State *g = G(L);
397 /* check size of string hash */ 473 /* check size of string hash */
398 if (G(L)->strt.nuse < cast(lu_int32, G(L)->strt.size/4) && 474 if (g->strt.nuse < cast(lu_int32, G(L)->strt.size/4) &&
399 G(L)->strt.size > MINSTRTABSIZE*2) 475 g->strt.size > MINSTRTABSIZE*2)
400 luaS_resize(L, G(L)->strt.size/2); /* table is too big */ 476 luaS_resize(L, g->strt.size/2); /* table is too big */
401 /* check size of buffer */ 477 /* check size of buffer */
402 if (luaZ_sizebuffer(&G(L)->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ 478 if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */
403 size_t newsize = luaZ_sizebuffer(&G(L)->buff) / 2; 479 size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
404 luaZ_resizebuffer(L, &G(L)->buff, newsize); 480 luaZ_resizebuffer(L, &g->buff, newsize);
405 } 481 }
406 lua_assert(G(L)->nblocks > deadmem); 482 lua_assert(g->nblocks > g->GCthreshold);
407 G(L)->GCthreshold = 2*G(L)->nblocks - deadmem; /* new threshold */ 483 g->GCthreshold = 2*G(L)->nblocks - g->GCthreshold; /* new threshold */
408} 484}
409 485
410 486
411static void do1gcTM (lua_State *L, Udata *udata) { 487static void GCTM (lua_State *L) {
412 const TObject *tm = fasttm(L, udata->uv.metatable, TM_GC); 488 global_State *g = G(L);
413 if (tm != NULL) { 489 if (g->tmudata == NULL)
414 setobj2s(L->top, tm); 490 g->gcstate = GCSroot; /* will restart GC */
415 setuvalue(L->top+1, udata); 491 else {
416 L->top += 2; 492 GCObject *o = g->tmudata;
417 luaD_call(L, L->top - 2, 0); 493 Udata *udata = gcotou(o);
494 const TObject *tm;
495 g->tmudata = udata->uv.next; /* remove udata from `tmudata' */
496 udata->uv.next = g->rootudata; /* return it to `root' list */
497 g->rootudata = o;
498 makewhite(o);
499 tm = fasttm(L, udata->uv.metatable, TM_GC);
500 if (tm != NULL) {
501 lu_byte oldah = L->allowhook;
502 L->allowhook = 0; /* stop debug hooks during GC tag method */
503 setobj2s(L->top, tm);
504 setuvalue(L->top+1, udata);
505 L->top += 2;
506 luaD_call(L, L->top - 2, 0);
507 L->allowhook = oldah; /* restore hooks */
508 }
418 } 509 }
419} 510}
420 511
421 512
513/*
514** Call all GC tag methods
515*/
422void luaC_callGCTM (lua_State *L) { 516void luaC_callGCTM (lua_State *L) {
423 lu_byte oldah = L->allowhook; 517 while (G(L)->tmudata)
424 L->allowhook = 0; /* stop debug hooks during GC tag methods */ 518 GCTM(L);
425 L->top++; /* reserve space to keep udata while runs its gc method */
426 while (G(L)->tmudata != NULL) {
427 GCObject *o = G(L)->tmudata;
428 Udata *udata = gcotou(o);
429 G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */
430 udata->uv.next = G(L)->rootudata; /* return it to `root' list */
431 G(L)->rootudata = o;
432 setuvalue(L->top - 1, udata); /* keep a reference to it */
433 makewhite(o);
434 do1gcTM(L, udata);
435 }
436 L->top--;
437 L->allowhook = oldah; /* restore hooks */
438} 519}
439 520
440 521
441void luaC_sweep (lua_State *L, int all) { 522void luaC_sweepall (lua_State *L) {
442 int mask = (all) ? 0 : bit2mask(BLACKBIT, FIXEDBIT); 523 l_mem dummy = MAXLMEM;
443 sweeplist(L, &G(L)->rootudata, mask); 524 sweepstrings(L, 0);
444 sweepstrings(L, mask); 525 sweeplist(L, &G(L)->rootudata, 0, &dummy);
445 sweeplist(L, &G(L)->rootgc, mask); 526 sweeplist(L, &G(L)->rootgc, 0, &dummy);
446} 527}
447 528
448 529
449/* mark root set */ 530/* mark root set */
450static void markroot (global_State *g, lua_State *L) { 531static void markroot (lua_State *L) {
532 global_State *g = G(L);
533 lua_assert(g->gray == NULL);
534 g->weak = NULL;
535 makewhite(valtogco(g->mainthread));
536 markobject(g, g->mainthread);
451 markvalue(g, defaultmeta(L)); 537 markvalue(g, defaultmeta(L));
452 markvalue(g, registry(L)); 538 markvalue(g, registry(L));
453 traversestack(g, g->mainthread);
454 if (L != g->mainthread) /* another thread is running? */ 539 if (L != g->mainthread) /* another thread is running? */
455 markobject(g, L); /* cannot collect it */ 540 markobject(g, L); /* cannot collect it */
541 g->gcstate = GCSpropagate;
456} 542}
457 543
458 544
459static size_t mark (lua_State *L) { 545static void atomic (lua_State *L) {
460 size_t deadmem;
461 global_State *g = G(L); 546 global_State *g = G(L);
462 lua_assert(g->gray == NULL); 547 g->GCthreshold = luaC_separateudata(L); /* separate userdata to be preserved */
463 g->weak = NULL;
464 markroot(g, L);
465 propagatemarks(g); /* mark all reachable objects */
466 deadmem = luaC_separateudata(L); /* separate userdata to be preserved */
467 marktmu(g); /* mark `preserved' userdata */ 548 marktmu(g); /* mark `preserved' userdata */
468 propagatemarks(g); /* remark, to propagate `preserveness' */ 549 propagatemarks(g, MAXLMEM); /* remark, to propagate `preserveness' */
469 cleartable(g->weak); /* remove collected objects from weak tables */ 550 cleartable(g->weak); /* remove collected objects from weak tables */
470 return deadmem; 551 g->sweepgc = &g->rootgc;
552 g->sweepudata = &g->rootudata;
553 sweepstrings(L, maskbf);
554 g->gcstate = GCSsweep;
555}
556
557
558static void sweepstep (lua_State *L) {
559 global_State *g = G(L);
560 l_mem lim = GCSTEPSIZE;
561 g->sweepudata = sweeplist(L, g->sweepudata, maskbf, &lim);
562 g->sweepgc = sweeplist(L, g->sweepgc, maskbf, &lim);
563 if (lim == GCSTEPSIZE) { /* nothing more to sweep? */
564 g->gcstate = GCSfinalize; /* end sweep phase */
565 }
471} 566}
472 567
473 568
474void luaC_collectgarbage (lua_State *L) { 569void luaC_collectgarbage (lua_State *L) {
475 size_t deadmem = mark(L); 570 global_State *g = G(L);
476 luaC_sweep(L, 0); 571 /* GCSroot */
477 checkSizes(L, deadmem); 572 markroot(L);
478 luaC_callGCTM(L); 573 /* GCSpropagate */
574 while (g->gcstate == GCSpropagate)
575 propagatemarks(g, GCSTEPSIZE);
576 /* atomic */
577 atomic(L);
578 /* GCSsweep */
579 while (g->gcstate == GCSsweep)
580 sweepstep(L);
581 /* GCSfinalize */
582 checkSizes(L);
583 while (g->gcstate == GCSfinalize)
584 GCTM(L);
479} 585}
480 586
481 587