aboutsummaryrefslogtreecommitdiff
path: root/lgc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lgc.c')
-rw-r--r--lgc.c253
1 files changed, 121 insertions, 132 deletions
diff --git a/lgc.c b/lgc.c
index 20e9b4aa..9c5cc2e3 100644
--- a/lgc.c
+++ b/lgc.c
@@ -19,6 +19,7 @@
19#include "ldo.h" 19#include "ldo.h"
20#include "lfunc.h" 20#include "lfunc.h"
21#include "lgc.h" 21#include "lgc.h"
22#include "llex.h"
22#include "lmem.h" 23#include "lmem.h"
23#include "lobject.h" 24#include "lobject.h"
24#include "lstate.h" 25#include "lstate.h"
@@ -32,7 +33,7 @@
32** (Large enough to dissipate fixed overheads but small enough 33** (Large enough to dissipate fixed overheads but small enough
33** to allow small steps for the collector.) 34** to allow small steps for the collector.)
34*/ 35*/
35#define GCSWEEPMAX 100 36#define GCSWEEPMAX 20
36 37
37/* 38/*
38** Maximum number of finalizers to call in each single step. 39** Maximum number of finalizers to call in each single step.
@@ -46,19 +47,6 @@
46#define GCFINALIZECOST 50 47#define GCFINALIZECOST 50
47 48
48 49
49/*
50** The equivalent, in bytes, of one unit of "work" (visiting a slot,
51** sweeping an object, etc.)
52*/
53#define WORK2MEM sizeof(TValue)
54
55
56/*
57** macro to adjust 'pause': 'pause' is actually used like
58** 'pause / PAUSEADJ' (value chosen by tests)
59*/
60#define PAUSEADJ 100
61
62 50
63/* mask with all color bits */ 51/* mask with all color bits */
64#define maskcolors (bitmask(BLACKBIT) | WHITEBITS) 52#define maskcolors (bitmask(BLACKBIT) | WHITEBITS)
@@ -105,7 +93,7 @@
105#define markobjectN(g,t) { if (t) markobject(g,t); } 93#define markobjectN(g,t) { if (t) markobject(g,t); }
106 94
107static void reallymarkobject (global_State *g, GCObject *o); 95static void reallymarkobject (global_State *g, GCObject *o);
108static lu_mem atomic (lua_State *L); 96static l_mem atomic (lua_State *L);
109static void entersweep (lua_State *L); 97static void entersweep (lua_State *L);
110 98
111 99
@@ -259,7 +247,7 @@ GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
259 global_State *g = G(L); 247 global_State *g = G(L);
260 char *p = cast_charp(luaM_newobject(L, novariant(tt), sz)); 248 char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
261 GCObject *o = cast(GCObject *, p + offset); 249 GCObject *o = cast(GCObject *, p + offset);
262 g->totalobjs++; 250 g->GCdebt++;
263 o->marked = luaC_white(g); 251 o->marked = luaC_white(g);
264 o->tt = tt; 252 o->tt = tt;
265 o->next = g->allgc; 253 o->next = g->allgc;
@@ -268,6 +256,9 @@ GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
268} 256}
269 257
270 258
259/*
260** create a new collectable object with no offset.
261*/
271GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { 262GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
272 return luaC_newobjdt(L, tt, sz, 0); 263 return luaC_newobjdt(L, tt, sz, 0);
273} 264}
@@ -296,6 +287,7 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
296** (only closures can), and a userdata's metatable must be a table. 287** (only closures can), and a userdata's metatable must be a table.
297*/ 288*/
298static void reallymarkobject (global_State *g, GCObject *o) { 289static void reallymarkobject (global_State *g, GCObject *o) {
290 g->marked++;
299 switch (o->tt) { 291 switch (o->tt) {
300 case LUA_VSHRSTR: 292 case LUA_VSHRSTR:
301 case LUA_VLNGSTR: { 293 case LUA_VLNGSTR: {
@@ -343,9 +335,9 @@ static void markmt (global_State *g) {
343/* 335/*
344** mark all objects in list of being-finalized 336** mark all objects in list of being-finalized
345*/ 337*/
346static lu_mem markbeingfnz (global_State *g) { 338static l_mem markbeingfnz (global_State *g) {
347 GCObject *o; 339 GCObject *o;
348 lu_mem count = 0; 340 l_mem count = 0;
349 for (o = g->tobefnz; o != NULL; o = o->next) { 341 for (o = g->tobefnz; o != NULL; o = o->next) {
350 count++; 342 count++;
351 markobject(g, o); 343 markobject(g, o);
@@ -365,12 +357,11 @@ static lu_mem markbeingfnz (global_State *g) {
365** upvalues, as they have nothing to be checked. (If the thread gets an 357** upvalues, as they have nothing to be checked. (If the thread gets an
366** upvalue later, it will be linked in the list again.) 358** upvalue later, it will be linked in the list again.)
367*/ 359*/
368static int remarkupvals (global_State *g) { 360static l_mem remarkupvals (global_State *g) {
361 l_mem work = 0;
369 lua_State *thread; 362 lua_State *thread;
370 lua_State **p = &g->twups; 363 lua_State **p = &g->twups;
371 int work = 0; /* estimate of how much work was done here */
372 while ((thread = *p) != NULL) { 364 while ((thread = *p) != NULL) {
373 work++;
374 if (!iswhite(thread) && thread->openupval != NULL) 365 if (!iswhite(thread) && thread->openupval != NULL)
375 p = &thread->twups; /* keep marked thread with upvalues in the list */ 366 p = &thread->twups; /* keep marked thread with upvalues in the list */
376 else { /* thread is not marked or without upvalues */ 367 else { /* thread is not marked or without upvalues */
@@ -380,13 +371,13 @@ static int remarkupvals (global_State *g) {
380 thread->twups = thread; /* mark that it is out of list */ 371 thread->twups = thread; /* mark that it is out of list */
381 for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { 372 for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) {
382 lua_assert(getage(uv) <= getage(thread)); 373 lua_assert(getage(uv) <= getage(thread));
383 work++;
384 if (!iswhite(uv)) { /* upvalue already visited? */ 374 if (!iswhite(uv)) { /* upvalue already visited? */
385 lua_assert(upisopen(uv) && isgray(uv)); 375 lua_assert(upisopen(uv) && isgray(uv));
386 markvalue(g, uv->v.p); /* mark its value */ 376 markvalue(g, uv->v.p); /* mark its value */
387 } 377 }
388 } 378 }
389 } 379 }
380 work++;
390 } 381 }
391 return work; 382 return work;
392} 383}
@@ -399,10 +390,15 @@ static void cleargraylists (global_State *g) {
399 390
400 391
401/* 392/*
402** mark root set and reset all gray lists, to start a new collection 393** mark root set and reset all gray lists, to start a new collection.
394** 'marked' is initialized with the number of fixed objects in the state,
395** to count the total number of live objects during a cycle. (That is
396** the metafield names, plus the reserved words, plus "_ENV" plus the
397** memory-error message.)
403*/ 398*/
404static void restartcollection (global_State *g) { 399static void restartcollection (global_State *g) {
405 cleargraylists(g); 400 cleargraylists(g);
401 g->marked = TM_N + NUM_RESERVED + 2;
406 markobject(g, g->mainthread); 402 markobject(g, g->mainthread);
407 markvalue(g, &g->l_registry); 403 markvalue(g, &g->l_registry);
408 markmt(g); 404 markmt(g);
@@ -540,7 +536,7 @@ static void traversestrongtable (global_State *g, Table *h) {
540} 536}
541 537
542 538
543static lu_mem traversetable (global_State *g, Table *h) { 539static void traversetable (global_State *g, Table *h) {
544 const char *weakkey, *weakvalue; 540 const char *weakkey, *weakvalue;
545 const TValue *mode = gfasttm(g, h->metatable, TM_MODE); 541 const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
546 markobjectN(g, h->metatable); 542 markobjectN(g, h->metatable);
@@ -557,17 +553,15 @@ static lu_mem traversetable (global_State *g, Table *h) {
557 } 553 }
558 else /* not weak */ 554 else /* not weak */
559 traversestrongtable(g, h); 555 traversestrongtable(g, h);
560 return 1 + h->alimit + 2 * allocsizenode(h);
561} 556}
562 557
563 558
564static int traverseudata (global_State *g, Udata *u) { 559static void traverseudata (global_State *g, Udata *u) {
565 int i; 560 int i;
566 markobjectN(g, u->metatable); /* mark its metatable */ 561 markobjectN(g, u->metatable); /* mark its metatable */
567 for (i = 0; i < u->nuvalue; i++) 562 for (i = 0; i < u->nuvalue; i++)
568 markvalue(g, &u->uv[i].uv); 563 markvalue(g, &u->uv[i].uv);
569 genlink(g, obj2gco(u)); 564 genlink(g, obj2gco(u));
570 return 1 + u->nuvalue;
571} 565}
572 566
573 567
@@ -576,7 +570,7 @@ static int traverseudata (global_State *g, Udata *u) {
576** arrays can be larger than needed; the extra slots are filled with 570** arrays can be larger than needed; the extra slots are filled with
577** NULL, so the use of 'markobjectN') 571** NULL, so the use of 'markobjectN')
578*/ 572*/
579static int traverseproto (global_State *g, Proto *f) { 573static void traverseproto (global_State *g, Proto *f) {
580 int i; 574 int i;
581 markobjectN(g, f->source); 575 markobjectN(g, f->source);
582 for (i = 0; i < f->sizek; i++) /* mark literals */ 576 for (i = 0; i < f->sizek; i++) /* mark literals */
@@ -587,29 +581,26 @@ static int traverseproto (global_State *g, Proto *f) {
587 markobjectN(g, f->p[i]); 581 markobjectN(g, f->p[i]);
588 for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ 582 for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
589 markobjectN(g, f->locvars[i].varname); 583 markobjectN(g, f->locvars[i].varname);
590 return 1 + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars;
591} 584}
592 585
593 586
594static int traverseCclosure (global_State *g, CClosure *cl) { 587static void traverseCclosure (global_State *g, CClosure *cl) {
595 int i; 588 int i;
596 for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ 589 for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */
597 markvalue(g, &cl->upvalue[i]); 590 markvalue(g, &cl->upvalue[i]);
598 return 1 + cl->nupvalues;
599} 591}
600 592
601/* 593/*
602** Traverse a Lua closure, marking its prototype and its upvalues. 594** Traverse a Lua closure, marking its prototype and its upvalues.
603** (Both can be NULL while closure is being created.) 595** (Both can be NULL while closure is being created.)
604*/ 596*/
605static int traverseLclosure (global_State *g, LClosure *cl) { 597static void traverseLclosure (global_State *g, LClosure *cl) {
606 int i; 598 int i;
607 markobjectN(g, cl->p); /* mark its prototype */ 599 markobjectN(g, cl->p); /* mark its prototype */
608 for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ 600 for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */
609 UpVal *uv = cl->upvals[i]; 601 UpVal *uv = cl->upvals[i];
610 markobjectN(g, uv); /* mark upvalue */ 602 markobjectN(g, uv); /* mark upvalue */
611 } 603 }
612 return 1 + cl->nupvalues;
613} 604}
614 605
615 606
@@ -625,13 +616,13 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
625** (which can only happen in generational mode) or if the traverse is in 616** (which can only happen in generational mode) or if the traverse is in
626** the propagate phase (which can only happen in incremental mode). 617** the propagate phase (which can only happen in incremental mode).
627*/ 618*/
628static int traversethread (global_State *g, lua_State *th) { 619static void traversethread (global_State *g, lua_State *th) {
629 UpVal *uv; 620 UpVal *uv;
630 StkId o = th->stack.p; 621 StkId o = th->stack.p;
631 if (isold(th) || g->gcstate == GCSpropagate) 622 if (isold(th) || g->gcstate == GCSpropagate)
632 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ 623 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
633 if (o == NULL) 624 if (o == NULL)
634 return 1; /* stack not completely built yet */ 625 return; /* stack not completely built yet */
635 lua_assert(g->gcstate == GCSatomic || 626 lua_assert(g->gcstate == GCSatomic ||
636 th->openupval == NULL || isintwups(th)); 627 th->openupval == NULL || isintwups(th));
637 for (; o < th->top.p; o++) /* mark live elements in the stack */ 628 for (; o < th->top.p; o++) /* mark live elements in the stack */
@@ -649,34 +640,35 @@ static int traversethread (global_State *g, lua_State *th) {
649 } 640 }
650 else if (!g->gcemergency) 641 else if (!g->gcemergency)
651 luaD_shrinkstack(th); /* do not change stack in emergency cycle */ 642 luaD_shrinkstack(th); /* do not change stack in emergency cycle */
652 return 1 + stacksize(th);
653} 643}
654 644
655 645
656/* 646/*
657** traverse one gray object, turning it to black. 647** traverse one gray object, turning it to black.
658*/ 648*/
659static lu_mem propagatemark (global_State *g) { 649static void propagatemark (global_State *g) {
660 GCObject *o = g->gray; 650 GCObject *o = g->gray;
661 nw2black(o); 651 nw2black(o);
662 g->gray = *getgclist(o); /* remove from 'gray' list */ 652 g->gray = *getgclist(o); /* remove from 'gray' list */
663 switch (o->tt) { 653 switch (o->tt) {
664 case LUA_VTABLE: return traversetable(g, gco2t(o)); 654 case LUA_VTABLE: traversetable(g, gco2t(o)); break;
665 case LUA_VUSERDATA: return traverseudata(g, gco2u(o)); 655 case LUA_VUSERDATA: traverseudata(g, gco2u(o)); break;
666 case LUA_VLCL: return traverseLclosure(g, gco2lcl(o)); 656 case LUA_VLCL: traverseLclosure(g, gco2lcl(o)); break;
667 case LUA_VCCL: return traverseCclosure(g, gco2ccl(o)); 657 case LUA_VCCL: traverseCclosure(g, gco2ccl(o)); break;
668 case LUA_VPROTO: return traverseproto(g, gco2p(o)); 658 case LUA_VPROTO: traverseproto(g, gco2p(o)); break;
669 case LUA_VTHREAD: return traversethread(g, gco2th(o)); 659 case LUA_VTHREAD: traversethread(g, gco2th(o)); break;
670 default: lua_assert(0); return 0; 660 default: lua_assert(0);
671 } 661 }
672} 662}
673 663
674 664
675static lu_mem propagateall (global_State *g) { 665static l_mem propagateall (global_State *g) {
676 lu_mem tot = 0; 666 l_mem work = 0;
677 while (g->gray) 667 while (g->gray) {
678 tot += propagatemark(g); 668 propagatemark(g);
679 return tot; 669 work++;
670 }
671 return work;
680} 672}
681 673
682 674
@@ -685,10 +677,10 @@ static lu_mem propagateall (global_State *g) {
685** Repeat until it converges, that is, nothing new is marked. 'dir' 677** Repeat until it converges, that is, nothing new is marked. 'dir'
686** inverts the direction of the traversals, trying to speed up 678** inverts the direction of the traversals, trying to speed up
687** convergence on chains in the same table. 679** convergence on chains in the same table.
688**
689*/ 680*/
690static void convergeephemerons (global_State *g) { 681static l_mem convergeephemerons (global_State *g) {
691 int changed; 682 int changed;
683 l_mem work = 0;
692 int dir = 0; 684 int dir = 0;
693 do { 685 do {
694 GCObject *w; 686 GCObject *w;
@@ -703,9 +695,11 @@ static void convergeephemerons (global_State *g) {
703 propagateall(g); /* propagate changes */ 695 propagateall(g); /* propagate changes */
704 changed = 1; /* will have to revisit all ephemeron tables */ 696 changed = 1; /* will have to revisit all ephemeron tables */
705 } 697 }
698 work++;
706 } 699 }
707 dir = !dir; /* invert direction next time */ 700 dir = !dir; /* invert direction next time */
708 } while (changed); /* repeat until no more changes */ 701 } while (changed); /* repeat until no more changes */
702 return work;
709} 703}
710 704
711/* }====================================================== */ 705/* }====================================================== */
@@ -721,7 +715,8 @@ static void convergeephemerons (global_State *g) {
721/* 715/*
722** clear entries with unmarked keys from all weaktables in list 'l' 716** clear entries with unmarked keys from all weaktables in list 'l'
723*/ 717*/
724static void clearbykeys (global_State *g, GCObject *l) { 718static l_mem clearbykeys (global_State *g, GCObject *l) {
719 l_mem work = 0;
725 for (; l; l = gco2t(l)->gclist) { 720 for (; l; l = gco2t(l)->gclist) {
726 Table *h = gco2t(l); 721 Table *h = gco2t(l);
727 Node *limit = gnodelast(h); 722 Node *limit = gnodelast(h);
@@ -732,7 +727,9 @@ static void clearbykeys (global_State *g, GCObject *l) {
732 if (isempty(gval(n))) /* is entry empty? */ 727 if (isempty(gval(n))) /* is entry empty? */
733 clearkey(n); /* clear its key */ 728 clearkey(n); /* clear its key */
734 } 729 }
730 work++;
735 } 731 }
732 return work;
736} 733}
737 734
738 735
@@ -740,7 +737,8 @@ static void clearbykeys (global_State *g, GCObject *l) {
740** clear entries with unmarked values from all weaktables in list 'l' up 737** clear entries with unmarked values from all weaktables in list 'l' up
741** to element 'f' 738** to element 'f'
742*/ 739*/
743static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { 740static l_mem clearbyvalues (global_State *g, GCObject *l, GCObject *f) {
741 l_mem work = 0;
744 for (; l != f; l = gco2t(l)->gclist) { 742 for (; l != f; l = gco2t(l)->gclist) {
745 Table *h = gco2t(l); 743 Table *h = gco2t(l);
746 Node *n, *limit = gnodelast(h); 744 Node *n, *limit = gnodelast(h);
@@ -757,7 +755,9 @@ static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) {
757 if (isempty(gval(n))) /* is entry empty? */ 755 if (isempty(gval(n))) /* is entry empty? */
758 clearkey(n); /* clear its key */ 756 clearkey(n); /* clear its key */
759 } 757 }
758 work++;
760 } 759 }
760 return work;
761} 761}
762 762
763 763
@@ -819,10 +819,9 @@ static void freeobj (lua_State *L, GCObject *o) {
819** objects, where a dead object is one marked with the old (non current) 819** objects, where a dead object is one marked with the old (non current)
820** white; change all non-dead objects back to white, preparing for next 820** white; change all non-dead objects back to white, preparing for next
821** collection cycle. Return where to continue the traversal or NULL if 821** collection cycle. Return where to continue the traversal or NULL if
822** list is finished. ('*countout' gets the number of elements traversed.) 822** list is finished.
823*/ 823*/
824static GCObject **sweeplist (lua_State *L, GCObject **p, int countin, 824static GCObject **sweeplist (lua_State *L, GCObject **p, int countin) {
825 int *countout) {
826 global_State *g = G(L); 825 global_State *g = G(L);
827 int ow = otherwhite(g); 826 int ow = otherwhite(g);
828 int i; 827 int i;
@@ -839,8 +838,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int countin,
839 p = &curr->next; /* go to next element */ 838 p = &curr->next; /* go to next element */
840 } 839 }
841 } 840 }
842 if (countout)
843 *countout = i; /* number of elements traversed */
844 return (*p == NULL) ? NULL : p; 841 return (*p == NULL) ? NULL : p;
845} 842}
846 843
@@ -851,7 +848,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int countin,
851static GCObject **sweeptolive (lua_State *L, GCObject **p) { 848static GCObject **sweeptolive (lua_State *L, GCObject **p) {
852 GCObject **old = p; 849 GCObject **old = p;
853 do { 850 do {
854 p = sweeplist(L, p, 1, NULL); 851 p = sweeplist(L, p, 1);
855 } while (p == old); 852 } while (p == old);
856 return p; 853 return p;
857} 854}
@@ -870,11 +867,8 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p) {
870*/ 867*/
871static void checkSizes (lua_State *L, global_State *g) { 868static void checkSizes (lua_State *L, global_State *g) {
872 if (!g->gcemergency) { 869 if (!g->gcemergency) {
873 if (g->strt.nuse < g->strt.size / 4) { /* string table too big? */ 870 if (g->strt.nuse < g->strt.size / 4) /* string table too big? */
874 l_mem olddebt = g->GCdebt;
875 luaS_resize(L, g->strt.size / 2); 871 luaS_resize(L, g->strt.size / 2);
876 g->GCestimate += g->GCdebt - olddebt; /* correct estimate */
877 }
878 } 872 }
879} 873}
880 874
@@ -935,12 +929,11 @@ static void GCTM (lua_State *L) {
935/* 929/*
936** Call a few finalizers 930** Call a few finalizers
937*/ 931*/
938static int runafewfinalizers (lua_State *L, int n) { 932static void runafewfinalizers (lua_State *L, int n) {
939 global_State *g = G(L); 933 global_State *g = G(L);
940 int i; 934 int i;
941 for (i = 0; i < n && g->tobefnz; i++) 935 for (i = 0; i < n && g->tobefnz; i++)
942 GCTM(L); /* call one finalizer */ 936 GCTM(L); /* call one finalizer */
943 return i;
944} 937}
945 938
946 939
@@ -1052,19 +1045,16 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
1052 1045
1053/* 1046/*
1054** Set the "time" to wait before starting a new GC cycle; cycle will 1047** Set the "time" to wait before starting a new GC cycle; cycle will
1055** start when memory use hits the threshold of ('estimate' * pause / 1048** start when number of objects in use hits the threshold of
1056** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero, 1049** approximately ('marked' * pause / 100). (A direct multiplication
1057** because Lua cannot even start with less than PAUSEADJ bytes). 1050** by 'pause' may overflow, and a direct division by 100 may undeflow
1051** to zero. So, the division is done in two steps. 8 * 12 is near 100
1052** and the division by 8 is cheap.)
1058*/ 1053*/
1059static void setpause (global_State *g) { 1054static void setpause (global_State *g) {
1060 l_mem threshold, debt; 1055 unsigned int pause = getgcparam(g->gcpause);
1061 int pause = getgcparam(g->gcpause); 1056 lu_mem threshold = g->marked / 8 * pause / 12;
1062 l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ 1057 l_mem debt = gettotalobjs(g) - threshold;
1063 lua_assert(estimate > 0);
1064 threshold = (pause < MAX_LMEM / estimate) /* overflow? */
1065 ? estimate * pause /* no overflow */
1066 : MAX_LMEM; /* overflow; truncate to maximum */
1067 debt = gettotalbytes(g) - threshold;
1068 if (debt > 0) debt = 0; 1058 if (debt > 0) debt = 0;
1069 luaE_setdebt(g, debt); 1059 luaE_setdebt(g, debt);
1070} 1060}
@@ -1306,17 +1296,17 @@ static void atomic2gen (lua_State *L, global_State *g) {
1306 1296
1307 g->gckind = KGC_GEN; 1297 g->gckind = KGC_GEN;
1308 g->lastatomic = 0; 1298 g->lastatomic = 0;
1309 g->GCestimate = gettotalbytes(g); /* base for memory control */ 1299 g->GCestimate = gettotalobjs(g); /* base for memory control */
1310 finishgencycle(L, g); 1300 finishgencycle(L, g);
1311} 1301}
1312 1302
1313 1303
1314/* 1304/*
1315** Set debt for the next minor collection, which will happen when 1305** Set debt for the next minor collection, which will happen when
1316** memory grows 'genminormul'%. 1306** total number of objects grows 'genminormul'%.
1317*/ 1307*/
1318static void setminordebt (global_State *g) { 1308static void setminordebt (global_State *g) {
1319 luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul)); 1309 luaE_setdebt(g, -(cast(l_mem, (gettotalobjs(g) / 100)) * g->genminormul));
1320} 1310}
1321 1311
1322 1312
@@ -1326,14 +1316,12 @@ static void setminordebt (global_State *g) {
1326** are cleared. Then, turn all objects into old and finishes the 1316** are cleared. Then, turn all objects into old and finishes the
1327** collection. 1317** collection.
1328*/ 1318*/
1329static lu_mem entergen (lua_State *L, global_State *g) { 1319static void entergen (lua_State *L, global_State *g) {
1330 lu_mem numobjs;
1331 luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ 1320 luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */
1332 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ 1321 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
1333 numobjs = atomic(L); /* propagates all and then do the atomic stuff */ 1322 atomic(L); /* propagates all and then do the atomic stuff */
1334 atomic2gen(L, g); 1323 atomic2gen(L, g);
1335 setminordebt(g); /* set debt assuming next cycle will be minor */ 1324 setminordebt(g); /* set debt assuming next cycle will be minor */
1336 return numobjs;
1337} 1325}
1338 1326
1339 1327
@@ -1372,9 +1360,9 @@ void luaC_changemode (lua_State *L, int newmode) {
1372/* 1360/*
1373** Does a full collection in generational mode. 1361** Does a full collection in generational mode.
1374*/ 1362*/
1375static lu_mem fullgen (lua_State *L, global_State *g) { 1363static void fullgen (lua_State *L, global_State *g) {
1376 enterinc(g); 1364 enterinc(g);
1377 return entergen(L, g); 1365 entergen(L, g);
1378} 1366}
1379 1367
1380 1368
@@ -1400,22 +1388,22 @@ static lu_mem fullgen (lua_State *L, global_State *g) {
1400** ('g->lastatomic != 0' also means that the last collection was bad.) 1388** ('g->lastatomic != 0' also means that the last collection was bad.)
1401*/ 1389*/
1402static void stepgenfull (lua_State *L, global_State *g) { 1390static void stepgenfull (lua_State *L, global_State *g) {
1403 lu_mem newatomic; /* count of traversed objects */
1404 lu_mem lastatomic = g->lastatomic; /* count from last collection */ 1391 lu_mem lastatomic = g->lastatomic; /* count from last collection */
1405 if (g->gckind == KGC_GEN) /* still in generational mode? */ 1392 if (g->gckind == KGC_GEN) /* still in generational mode? */
1406 enterinc(g); /* enter incremental mode */ 1393 enterinc(g); /* enter incremental mode */
1407 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ 1394 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
1408 newatomic = atomic(L); /* mark everybody */ 1395 g->marked = 0;
1409 if (newatomic < lastatomic + (lastatomic >> 3)) { /* good collection? */ 1396 atomic(L); /* mark everybody */
1397 if (g->marked < lastatomic + (lastatomic >> 3)) { /* good collection? */
1410 atomic2gen(L, g); /* return to generational mode */ 1398 atomic2gen(L, g); /* return to generational mode */
1411 setminordebt(g); 1399 setminordebt(g);
1412 } 1400 }
1413 else { /* another bad collection; stay in incremental mode */ 1401 else { /* another bad collection; stay in incremental mode */
1414 g->GCestimate = gettotalbytes(g); /* first estimate */; 1402 g->GCestimate = gettotalobjs(g); /* first estimate */;
1403 g->lastatomic = g->marked;
1415 entersweep(L); 1404 entersweep(L);
1416 luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ 1405 luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */
1417 setpause(g); 1406 setpause(g);
1418 g->lastatomic = newatomic;
1419 } 1407 }
1420} 1408}
1421 1409
@@ -1443,21 +1431,23 @@ static void genstep (lua_State *L, global_State *g) {
1443 if (g->lastatomic != 0) /* last collection was a bad one? */ 1431 if (g->lastatomic != 0) /* last collection was a bad one? */
1444 stepgenfull(L, g); /* do a full step */ 1432 stepgenfull(L, g); /* do a full step */
1445 else { 1433 else {
1446 lu_mem majorbase = g->GCestimate; /* memory after last major collection */ 1434 l_mem majorbase = g->GCestimate; /* objects after last major collection */
1447 lu_mem majorinc = (majorbase / 100) * getgcparam(g->genmajormul); 1435 l_mem majorinc = (majorbase / 100) * getgcparam(g->genmajormul);
1448 if (g->GCdebt > 0 && gettotalbytes(g) > majorbase + majorinc) { 1436 if (g->GCdebt > 0 && gettotalobjs(g) > majorbase + majorinc) {
1449 lu_mem numobjs = fullgen(L, g); /* do a major collection */ 1437 g->marked = 0;
1450 if (gettotalbytes(g) < majorbase + (majorinc / 2)) { 1438 fullgen(L, g); /* do a major collection */
1451 /* collected at least half of memory growth since last major 1439 if (gettotalobjs(g) < majorbase + (majorinc / 2)) {
1440 /* collected at least half of object growth since last major
1452 collection; keep doing minor collections. */ 1441 collection; keep doing minor collections. */
1453 lua_assert(g->lastatomic == 0); 1442 lua_assert(g->lastatomic == 0);
1454 } 1443 }
1455 else { /* bad collection */ 1444 else { /* bad collection */
1456 g->lastatomic = numobjs; /* signal that last collection was bad */ 1445 g->lastatomic = g->marked; /* signal that last collection was bad */
1457 setpause(g); /* do a long wait for next (major) collection */ 1446 setpause(g); /* do a long wait for next (major) collection */
1458 } 1447 }
1459 } 1448 }
1460 else { /* regular case; do a minor collection */ 1449 else { /* regular case; do a minor collection */
1450 g->marked = 0;
1461 youngcollection(L, g); 1451 youngcollection(L, g);
1462 setminordebt(g); 1452 setminordebt(g);
1463 g->GCestimate = majorbase; /* preserve base value */ 1453 g->GCestimate = majorbase; /* preserve base value */
@@ -1522,9 +1512,9 @@ void luaC_freeallobjects (lua_State *L) {
1522} 1512}
1523 1513
1524 1514
1525static lu_mem atomic (lua_State *L) { 1515static l_mem atomic (lua_State *L) {
1516 l_mem work = 0;
1526 global_State *g = G(L); 1517 global_State *g = G(L);
1527 lu_mem work = 0;
1528 GCObject *origweak, *origall; 1518 GCObject *origweak, *origall;
1529 GCObject *grayagain = g->grayagain; /* save original list */ 1519 GCObject *grayagain = g->grayagain; /* save original list */
1530 g->grayagain = NULL; 1520 g->grayagain = NULL;
@@ -1541,50 +1531,47 @@ static lu_mem atomic (lua_State *L) {
1541 work += propagateall(g); /* propagate changes */ 1531 work += propagateall(g); /* propagate changes */
1542 g->gray = grayagain; 1532 g->gray = grayagain;
1543 work += propagateall(g); /* traverse 'grayagain' list */ 1533 work += propagateall(g); /* traverse 'grayagain' list */
1544 convergeephemerons(g); 1534 work += convergeephemerons(g);
1545 /* at this point, all strongly accessible objects are marked. */ 1535 /* at this point, all strongly accessible objects are marked. */
1546 /* Clear values from weak tables, before checking finalizers */ 1536 /* Clear values from weak tables, before checking finalizers */
1547 clearbyvalues(g, g->weak, NULL); 1537 work += clearbyvalues(g, g->weak, NULL);
1548 clearbyvalues(g, g->allweak, NULL); 1538 work += clearbyvalues(g, g->allweak, NULL);
1549 origweak = g->weak; origall = g->allweak; 1539 origweak = g->weak; origall = g->allweak;
1550 separatetobefnz(g, 0); /* separate objects to be finalized */ 1540 separatetobefnz(g, 0); /* separate objects to be finalized */
1551 work += markbeingfnz(g); /* mark objects that will be finalized */ 1541 work += markbeingfnz(g); /* mark objects that will be finalized */
1552 work += propagateall(g); /* remark, to propagate 'resurrection' */ 1542 work += propagateall(g); /* remark, to propagate 'resurrection' */
1553 convergeephemerons(g); 1543 work += convergeephemerons(g);
1554 /* at this point, all resurrected objects are marked. */ 1544 /* at this point, all resurrected objects are marked. */
1555 /* remove dead objects from weak tables */ 1545 /* remove dead objects from weak tables */
1556 clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron tables */ 1546 work += clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron */
1557 clearbykeys(g, g->allweak); /* clear keys from all 'allweak' tables */ 1547 work += clearbykeys(g, g->allweak); /* clear keys from all 'allweak' */
1558 /* clear values from resurrected weak tables */ 1548 /* clear values from resurrected weak tables */
1559 clearbyvalues(g, g->weak, origweak); 1549 work += clearbyvalues(g, g->weak, origweak);
1560 clearbyvalues(g, g->allweak, origall); 1550 work += clearbyvalues(g, g->allweak, origall);
1561 luaS_clearcache(g); 1551 luaS_clearcache(g);
1562 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ 1552 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
1563 lua_assert(g->gray == NULL); 1553 lua_assert(g->gray == NULL);
1564 return work; /* estimate of slots marked by 'atomic' */ 1554 return work;
1565} 1555}
1566 1556
1567 1557
1568static int sweepstep (lua_State *L, global_State *g, 1558static void sweepstep (lua_State *L, global_State *g,
1569 int nextstate, GCObject **nextlist) { 1559 int nextstate, GCObject **nextlist) {
1570 if (g->sweepgc) { 1560 if (g->sweepgc) {
1571 l_mem olddebt = g->GCdebt; 1561 l_mem olddebt = g->GCdebt;
1572 int count; 1562 g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
1573 g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX, &count);
1574 g->GCestimate += g->GCdebt - olddebt; /* update estimate */ 1563 g->GCestimate += g->GCdebt - olddebt; /* update estimate */
1575 return count;
1576 } 1564 }
1577 else { /* enter next state */ 1565 else { /* enter next state */
1578 g->gcstate = nextstate; 1566 g->gcstate = nextstate;
1579 g->sweepgc = nextlist; 1567 g->sweepgc = nextlist;
1580 return 0; /* no work done */
1581 } 1568 }
1582} 1569}
1583 1570
1584 1571
1585static lu_mem singlestep (lua_State *L) { 1572static l_mem singlestep (lua_State *L) {
1586 global_State *g = G(L); 1573 global_State *g = G(L);
1587 lu_mem work; 1574 l_mem work;
1588 lua_assert(!g->gcstopem); /* collector is not reentrant */ 1575 lua_assert(!g->gcstopem); /* collector is not reentrant */
1589 g->gcstopem = 1; /* no emergency collections while collecting */ 1576 g->gcstopem = 1; /* no emergency collections while collecting */
1590 switch (g->gcstate) { 1577 switch (g->gcstate) {
@@ -1599,26 +1586,30 @@ static lu_mem singlestep (lua_State *L) {
1599 g->gcstate = GCSenteratomic; /* finish propagate phase */ 1586 g->gcstate = GCSenteratomic; /* finish propagate phase */
1600 work = 0; 1587 work = 0;
1601 } 1588 }
1602 else 1589 else {
1603 work = propagatemark(g); /* traverse one gray object */ 1590 propagatemark(g); /* traverse one gray object */
1591 work = 1;
1592 }
1604 break; 1593 break;
1605 } 1594 }
1606 case GCSenteratomic: { 1595 case GCSenteratomic: {
1607 work = atomic(L); /* work is what was traversed by 'atomic' */ 1596 work = atomic(L);
1608 entersweep(L); 1597 entersweep(L);
1609 g->GCestimate = gettotalbytes(g); /* first estimate */;
1610 break; 1598 break;
1611 } 1599 }
1612 case GCSswpallgc: { /* sweep "regular" objects */ 1600 case GCSswpallgc: { /* sweep "regular" objects */
1613 work = sweepstep(L, g, GCSswpfinobj, &g->finobj); 1601 sweepstep(L, g, GCSswpfinobj, &g->finobj);
1602 work = GCSWEEPMAX;
1614 break; 1603 break;
1615 } 1604 }
1616 case GCSswpfinobj: { /* sweep objects with finalizers */ 1605 case GCSswpfinobj: { /* sweep objects with finalizers */
1617 work = sweepstep(L, g, GCSswptobefnz, &g->tobefnz); 1606 sweepstep(L, g, GCSswptobefnz, &g->tobefnz);
1607 work = GCSWEEPMAX;
1618 break; 1608 break;
1619 } 1609 }
1620 case GCSswptobefnz: { /* sweep objects to be finalized */ 1610 case GCSswptobefnz: { /* sweep objects to be finalized */
1621 work = sweepstep(L, g, GCSswpend, NULL); 1611 sweepstep(L, g, GCSswpend, NULL);
1612 work = GCSWEEPMAX;
1622 break; 1613 break;
1623 } 1614 }
1624 case GCSswpend: { /* finish sweeps */ 1615 case GCSswpend: { /* finish sweeps */
@@ -1630,7 +1621,8 @@ static lu_mem singlestep (lua_State *L) {
1630 case GCScallfin: { /* call remaining finalizers */ 1621 case GCScallfin: { /* call remaining finalizers */
1631 if (g->tobefnz && !g->gcemergency) { 1622 if (g->tobefnz && !g->gcemergency) {
1632 g->gcstopem = 0; /* ok collections during finalizers */ 1623 g->gcstopem = 0; /* ok collections during finalizers */
1633 work = runafewfinalizers(L, GCFINMAX) * GCFINALIZECOST; 1624 runafewfinalizers(L, GCFINMAX);
1625 work = GCFINMAX * GCFINALIZECOST;
1634 } 1626 }
1635 else { /* emergency mode or no more finalizers */ 1627 else { /* emergency mode or no more finalizers */
1636 g->gcstate = GCSpause; /* finish collection */ 1628 g->gcstate = GCSpause; /* finish collection */
@@ -1666,18 +1658,16 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
1666*/ 1658*/
1667static void incstep (lua_State *L, global_State *g) { 1659static void incstep (lua_State *L, global_State *g) {
1668 int stepmul = (getgcparam(g->gcstepmul) | 1); /* avoid division by 0 */ 1660 int stepmul = (getgcparam(g->gcstepmul) | 1); /* avoid division by 0 */
1669 l_mem debt = (g->GCdebt / WORK2MEM) * stepmul; 1661 l_mem debt = (g->GCdebt / 100) * stepmul;
1670 l_mem stepsize = (g->gcstepsize <= log2maxs(l_mem)) 1662 l_mem stepsize = cast(l_mem, 1) << g->gcstepsize;
1671 ? ((cast(l_mem, 1) << g->gcstepsize) / WORK2MEM) * stepmul
1672 : MAX_LMEM; /* overflow; keep maximum value */
1673 do { /* repeat until pause or enough "credit" (negative debt) */ 1663 do { /* repeat until pause or enough "credit" (negative debt) */
1674 lu_mem work = singlestep(L); /* perform one single step */ 1664 l_mem work = singlestep(L); /* perform one single step */
1675 debt -= work; 1665 debt -= work;
1676 } while (debt > -stepsize && g->gcstate != GCSpause); 1666 } while (debt > -stepsize && g->gcstate != GCSpause);
1677 if (g->gcstate == GCSpause) 1667 if (g->gcstate == GCSpause)
1678 setpause(g); /* pause until next cycle */ 1668 setpause(g); /* pause until next cycle */
1679 else { 1669 else {
1680 debt = (debt / stepmul) * WORK2MEM; /* convert 'work units' to bytes */ 1670 debt = (debt / stepmul) * 100; /* apply step multiplier */
1681 luaE_setdebt(g, debt); 1671 luaE_setdebt(g, debt);
1682 } 1672 }
1683} 1673}
@@ -1710,9 +1700,8 @@ static void fullinc (lua_State *L, global_State *g) {
1710 /* finish any pending sweep phase to start a new cycle */ 1700 /* finish any pending sweep phase to start a new cycle */
1711 luaC_runtilstate(L, bitmask(GCSpause)); 1701 luaC_runtilstate(L, bitmask(GCSpause));
1712 luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ 1702 luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */
1713 /* estimate must be correct after a full GC cycle */
1714 lua_assert(g->GCestimate == gettotalbytes(g));
1715 luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ 1703 luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */
1704 /* estimate must be correct after a full GC cycle */
1716 setpause(g); 1705 setpause(g);
1717} 1706}
1718 1707