aboutsummaryrefslogtreecommitdiff
path: root/lgc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lgc.c')
-rw-r--r--lgc.c416
1 files changed, 175 insertions, 241 deletions
diff --git a/lgc.c b/lgc.c
index 253a2892..81682454 100644
--- a/lgc.c
+++ b/lgc.c
@@ -9,7 +9,6 @@
9 9
10#include "lprefix.h" 10#include "lprefix.h"
11 11
12#include <stdio.h>
13#include <string.h> 12#include <string.h>
14 13
15 14
@@ -19,6 +18,7 @@
19#include "ldo.h" 18#include "ldo.h"
20#include "lfunc.h" 19#include "lfunc.h"
21#include "lgc.h" 20#include "lgc.h"
21#include "llex.h"
22#include "lmem.h" 22#include "lmem.h"
23#include "lobject.h" 23#include "lobject.h"
24#include "lstate.h" 24#include "lstate.h"
@@ -28,36 +28,18 @@
28 28
29 29
30/* 30/*
31** Maximum number of elements to sweep in each single step. 31** Number of fixed (luaC_fix) objects in a Lua state: metafield names,
32** (Large enough to dissipate fixed overheads but small enough 32** plus reserved words, plus "_ENV", plus the memory-error message.
33** to allow small steps for the collector.)
34*/
35#define GCSWEEPMAX 100
36
37/*
38** Maximum number of finalizers to call in each single step.
39*/
40#define GCFINMAX 10
41
42
43/*
44** Cost of calling one finalizer.
45*/
46#define GCFINALIZECOST 50
47
48
49/*
50** The equivalent, in bytes, of one unit of "work" (visiting a slot,
51** sweeping an object, etc.)
52*/ 33*/
53#define WORK2MEM sizeof(TValue) 34#define NFIXED (TM_N + NUM_RESERVED + 2)
54 35
55 36
56/* 37/*
57** macro to adjust 'pause': 'pause' is actually used like 38** Maximum number of elements to sweep in each single step.
58** 'pause / PAUSEADJ' (value chosen by tests) 39** (Large enough to dissipate fixed overheads but small enough
40** to allow small steps for the collector.)
59*/ 41*/
60#define PAUSEADJ 100 42#define GCSWEEPMAX 20
61 43
62 44
63/* mask with all color bits */ 45/* mask with all color bits */
@@ -105,7 +87,7 @@
105#define markobjectN(g,t) { if (t) markobject(g,t); } 87#define markobjectN(g,t) { if (t) markobject(g,t); }
106 88
107static void reallymarkobject (global_State *g, GCObject *o); 89static void reallymarkobject (global_State *g, GCObject *o);
108static lu_mem atomic (lua_State *L); 90static l_obj atomic (lua_State *L);
109static void entersweep (lua_State *L); 91static void entersweep (lua_State *L);
110 92
111 93
@@ -217,7 +199,7 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
217 } 199 }
218 else { /* sweep phase */ 200 else { /* sweep phase */
219 lua_assert(issweepphase(g)); 201 lua_assert(issweepphase(g));
220 if (g->gckind == KGC_INC) /* incremental mode? */ 202 if (g->gckind != KGC_GEN) /* incremental mode? */
221 makewhite(g, o); /* mark 'o' as white to avoid other barriers */ 203 makewhite(g, o); /* mark 'o' as white to avoid other barriers */
222 } 204 }
223} 205}
@@ -259,6 +241,7 @@ GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
259 global_State *g = G(L); 241 global_State *g = G(L);
260 char *p = cast_charp(luaM_newobject(L, novariant(tt), sz)); 242 char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
261 GCObject *o = cast(GCObject *, p + offset); 243 GCObject *o = cast(GCObject *, p + offset);
244 g->GCdebt--;
262 o->marked = luaC_white(g); 245 o->marked = luaC_white(g);
263 o->tt = tt; 246 o->tt = tt;
264 o->next = g->allgc; 247 o->next = g->allgc;
@@ -267,6 +250,9 @@ GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
267} 250}
268 251
269 252
253/*
254** create a new collectable object with no offset.
255*/
270GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { 256GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
271 return luaC_newobjdt(L, tt, sz, 0); 257 return luaC_newobjdt(L, tt, sz, 0);
272} 258}
@@ -295,6 +281,7 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
295** (only closures can), and a userdata's metatable must be a table. 281** (only closures can), and a userdata's metatable must be a table.
296*/ 282*/
297static void reallymarkobject (global_State *g, GCObject *o) { 283static void reallymarkobject (global_State *g, GCObject *o) {
284 g->marked++;
298 switch (o->tt) { 285 switch (o->tt) {
299 case LUA_VSHRSTR: 286 case LUA_VSHRSTR:
300 case LUA_VLNGSTR: { 287 case LUA_VLNGSTR: {
@@ -342,9 +329,9 @@ static void markmt (global_State *g) {
342/* 329/*
343** mark all objects in list of being-finalized 330** mark all objects in list of being-finalized
344*/ 331*/
345static lu_mem markbeingfnz (global_State *g) { 332static l_obj markbeingfnz (global_State *g) {
346 GCObject *o; 333 GCObject *o;
347 lu_mem count = 0; 334 l_obj count = 0;
348 for (o = g->tobefnz; o != NULL; o = o->next) { 335 for (o = g->tobefnz; o != NULL; o = o->next) {
349 count++; 336 count++;
350 markobject(g, o); 337 markobject(g, o);
@@ -364,12 +351,11 @@ static lu_mem markbeingfnz (global_State *g) {
364** upvalues, as they have nothing to be checked. (If the thread gets an 351** upvalues, as they have nothing to be checked. (If the thread gets an
365** upvalue later, it will be linked in the list again.) 352** upvalue later, it will be linked in the list again.)
366*/ 353*/
367static int remarkupvals (global_State *g) { 354static l_obj remarkupvals (global_State *g) {
355 l_obj work = 0;
368 lua_State *thread; 356 lua_State *thread;
369 lua_State **p = &g->twups; 357 lua_State **p = &g->twups;
370 int work = 0; /* estimate of how much work was done here */
371 while ((thread = *p) != NULL) { 358 while ((thread = *p) != NULL) {
372 work++;
373 if (!iswhite(thread) && thread->openupval != NULL) 359 if (!iswhite(thread) && thread->openupval != NULL)
374 p = &thread->twups; /* keep marked thread with upvalues in the list */ 360 p = &thread->twups; /* keep marked thread with upvalues in the list */
375 else { /* thread is not marked or without upvalues */ 361 else { /* thread is not marked or without upvalues */
@@ -379,13 +365,13 @@ static int remarkupvals (global_State *g) {
379 thread->twups = thread; /* mark that it is out of list */ 365 thread->twups = thread; /* mark that it is out of list */
380 for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { 366 for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) {
381 lua_assert(getage(uv) <= getage(thread)); 367 lua_assert(getage(uv) <= getage(thread));
382 work++;
383 if (!iswhite(uv)) { /* upvalue already visited? */ 368 if (!iswhite(uv)) { /* upvalue already visited? */
384 lua_assert(upisopen(uv) && isgray(uv)); 369 lua_assert(upisopen(uv) && isgray(uv));
385 markvalue(g, uv->v.p); /* mark its value */ 370 markvalue(g, uv->v.p); /* mark its value */
386 } 371 }
387 } 372 }
388 } 373 }
374 work++;
389 } 375 }
390 return work; 376 return work;
391} 377}
@@ -398,10 +384,15 @@ static void cleargraylists (global_State *g) {
398 384
399 385
400/* 386/*
401** mark root set and reset all gray lists, to start a new collection 387** mark root set and reset all gray lists, to start a new collection.
388** 'marked' is initialized with the number of fixed objects in the state,
389** to count the total number of live objects during a cycle. (That is
390** the metafield names, plus the reserved words, plus "_ENV" plus the
391** memory-error message.)
402*/ 392*/
403static void restartcollection (global_State *g) { 393static void restartcollection (global_State *g) {
404 cleargraylists(g); 394 cleargraylists(g);
395 g->marked = NFIXED;
405 markobject(g, g->mainthread); 396 markobject(g, g->mainthread);
406 markvalue(g, &g->l_registry); 397 markvalue(g, &g->l_registry);
407 markmt(g); 398 markmt(g);
@@ -539,7 +530,7 @@ static void traversestrongtable (global_State *g, Table *h) {
539} 530}
540 531
541 532
542static lu_mem traversetable (global_State *g, Table *h) { 533static void traversetable (global_State *g, Table *h) {
543 const char *weakkey, *weakvalue; 534 const char *weakkey, *weakvalue;
544 const TValue *mode = gfasttm(g, h->metatable, TM_MODE); 535 const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
545 TString *smode; 536 TString *smode;
@@ -558,17 +549,15 @@ static lu_mem traversetable (global_State *g, Table *h) {
558 } 549 }
559 else /* not weak */ 550 else /* not weak */
560 traversestrongtable(g, h); 551 traversestrongtable(g, h);
561 return 1 + h->alimit + 2 * allocsizenode(h);
562} 552}
563 553
564 554
565static int traverseudata (global_State *g, Udata *u) { 555static void traverseudata (global_State *g, Udata *u) {
566 int i; 556 int i;
567 markobjectN(g, u->metatable); /* mark its metatable */ 557 markobjectN(g, u->metatable); /* mark its metatable */
568 for (i = 0; i < u->nuvalue; i++) 558 for (i = 0; i < u->nuvalue; i++)
569 markvalue(g, &u->uv[i].uv); 559 markvalue(g, &u->uv[i].uv);
570 genlink(g, obj2gco(u)); 560 genlink(g, obj2gco(u));
571 return 1 + u->nuvalue;
572} 561}
573 562
574 563
@@ -577,7 +566,7 @@ static int traverseudata (global_State *g, Udata *u) {
577** arrays can be larger than needed; the extra slots are filled with 566** arrays can be larger than needed; the extra slots are filled with
578** NULL, so the use of 'markobjectN') 567** NULL, so the use of 'markobjectN')
579*/ 568*/
580static int traverseproto (global_State *g, Proto *f) { 569static void traverseproto (global_State *g, Proto *f) {
581 int i; 570 int i;
582 markobjectN(g, f->source); 571 markobjectN(g, f->source);
583 for (i = 0; i < f->sizek; i++) /* mark literals */ 572 for (i = 0; i < f->sizek; i++) /* mark literals */
@@ -588,29 +577,26 @@ static int traverseproto (global_State *g, Proto *f) {
588 markobjectN(g, f->p[i]); 577 markobjectN(g, f->p[i]);
589 for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ 578 for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
590 markobjectN(g, f->locvars[i].varname); 579 markobjectN(g, f->locvars[i].varname);
591 return 1 + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars;
592} 580}
593 581
594 582
595static int traverseCclosure (global_State *g, CClosure *cl) { 583static void traverseCclosure (global_State *g, CClosure *cl) {
596 int i; 584 int i;
597 for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ 585 for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */
598 markvalue(g, &cl->upvalue[i]); 586 markvalue(g, &cl->upvalue[i]);
599 return 1 + cl->nupvalues;
600} 587}
601 588
602/* 589/*
603** Traverse a Lua closure, marking its prototype and its upvalues. 590** Traverse a Lua closure, marking its prototype and its upvalues.
604** (Both can be NULL while closure is being created.) 591** (Both can be NULL while closure is being created.)
605*/ 592*/
606static int traverseLclosure (global_State *g, LClosure *cl) { 593static void traverseLclosure (global_State *g, LClosure *cl) {
607 int i; 594 int i;
608 markobjectN(g, cl->p); /* mark its prototype */ 595 markobjectN(g, cl->p); /* mark its prototype */
609 for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ 596 for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */
610 UpVal *uv = cl->upvals[i]; 597 UpVal *uv = cl->upvals[i];
611 markobjectN(g, uv); /* mark upvalue */ 598 markobjectN(g, uv); /* mark upvalue */
612 } 599 }
613 return 1 + cl->nupvalues;
614} 600}
615 601
616 602
@@ -626,13 +612,13 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
626** (which can only happen in generational mode) or if the traverse is in 612** (which can only happen in generational mode) or if the traverse is in
627** the propagate phase (which can only happen in incremental mode). 613** the propagate phase (which can only happen in incremental mode).
628*/ 614*/
629static int traversethread (global_State *g, lua_State *th) { 615static void traversethread (global_State *g, lua_State *th) {
630 UpVal *uv; 616 UpVal *uv;
631 StkId o = th->stack.p; 617 StkId o = th->stack.p;
632 if (isold(th) || g->gcstate == GCSpropagate) 618 if (isold(th) || g->gcstate == GCSpropagate)
633 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ 619 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
634 if (o == NULL) 620 if (o == NULL)
635 return 1; /* stack not completely built yet */ 621 return; /* stack not completely built yet */
636 lua_assert(g->gcstate == GCSatomic || 622 lua_assert(g->gcstate == GCSatomic ||
637 th->openupval == NULL || isintwups(th)); 623 th->openupval == NULL || isintwups(th));
638 for (; o < th->top.p; o++) /* mark live elements in the stack */ 624 for (; o < th->top.p; o++) /* mark live elements in the stack */
@@ -650,34 +636,35 @@ static int traversethread (global_State *g, lua_State *th) {
650 g->twups = th; 636 g->twups = th;
651 } 637 }
652 } 638 }
653 return 1 + stacksize(th);
654} 639}
655 640
656 641
657/* 642/*
658** traverse one gray object, turning it to black. 643** traverse one gray object, turning it to black.
659*/ 644*/
660static lu_mem propagatemark (global_State *g) { 645static void propagatemark (global_State *g) {
661 GCObject *o = g->gray; 646 GCObject *o = g->gray;
662 nw2black(o); 647 nw2black(o);
663 g->gray = *getgclist(o); /* remove from 'gray' list */ 648 g->gray = *getgclist(o); /* remove from 'gray' list */
664 switch (o->tt) { 649 switch (o->tt) {
665 case LUA_VTABLE: return traversetable(g, gco2t(o)); 650 case LUA_VTABLE: traversetable(g, gco2t(o)); break;
666 case LUA_VUSERDATA: return traverseudata(g, gco2u(o)); 651 case LUA_VUSERDATA: traverseudata(g, gco2u(o)); break;
667 case LUA_VLCL: return traverseLclosure(g, gco2lcl(o)); 652 case LUA_VLCL: traverseLclosure(g, gco2lcl(o)); break;
668 case LUA_VCCL: return traverseCclosure(g, gco2ccl(o)); 653 case LUA_VCCL: traverseCclosure(g, gco2ccl(o)); break;
669 case LUA_VPROTO: return traverseproto(g, gco2p(o)); 654 case LUA_VPROTO: traverseproto(g, gco2p(o)); break;
670 case LUA_VTHREAD: return traversethread(g, gco2th(o)); 655 case LUA_VTHREAD: traversethread(g, gco2th(o)); break;
671 default: lua_assert(0); return 0; 656 default: lua_assert(0);
672 } 657 }
673} 658}
674 659
675 660
676static lu_mem propagateall (global_State *g) { 661static l_obj propagateall (global_State *g) {
677 lu_mem tot = 0; 662 l_obj work = 0;
678 while (g->gray) 663 while (g->gray) {
679 tot += propagatemark(g); 664 propagatemark(g);
680 return tot; 665 work++;
666 }
667 return work;
681} 668}
682 669
683 670
@@ -686,10 +673,10 @@ static lu_mem propagateall (global_State *g) {
686** Repeat until it converges, that is, nothing new is marked. 'dir' 673** Repeat until it converges, that is, nothing new is marked. 'dir'
687** inverts the direction of the traversals, trying to speed up 674** inverts the direction of the traversals, trying to speed up
688** convergence on chains in the same table. 675** convergence on chains in the same table.
689**
690*/ 676*/
691static void convergeephemerons (global_State *g) { 677static l_obj convergeephemerons (global_State *g) {
692 int changed; 678 int changed;
679 l_obj work = 0;
693 int dir = 0; 680 int dir = 0;
694 do { 681 do {
695 GCObject *w; 682 GCObject *w;
@@ -704,9 +691,11 @@ static void convergeephemerons (global_State *g) {
704 propagateall(g); /* propagate changes */ 691 propagateall(g); /* propagate changes */
705 changed = 1; /* will have to revisit all ephemeron tables */ 692 changed = 1; /* will have to revisit all ephemeron tables */
706 } 693 }
694 work++;
707 } 695 }
708 dir = !dir; /* invert direction next time */ 696 dir = !dir; /* invert direction next time */
709 } while (changed); /* repeat until no more changes */ 697 } while (changed); /* repeat until no more changes */
698 return work;
710} 699}
711 700
712/* }====================================================== */ 701/* }====================================================== */
@@ -722,7 +711,8 @@ static void convergeephemerons (global_State *g) {
722/* 711/*
723** clear entries with unmarked keys from all weaktables in list 'l' 712** clear entries with unmarked keys from all weaktables in list 'l'
724*/ 713*/
725static void clearbykeys (global_State *g, GCObject *l) { 714static l_obj clearbykeys (global_State *g, GCObject *l) {
715 l_obj work = 0;
726 for (; l; l = gco2t(l)->gclist) { 716 for (; l; l = gco2t(l)->gclist) {
727 Table *h = gco2t(l); 717 Table *h = gco2t(l);
728 Node *limit = gnodelast(h); 718 Node *limit = gnodelast(h);
@@ -733,7 +723,9 @@ static void clearbykeys (global_State *g, GCObject *l) {
733 if (isempty(gval(n))) /* is entry empty? */ 723 if (isempty(gval(n))) /* is entry empty? */
734 clearkey(n); /* clear its key */ 724 clearkey(n); /* clear its key */
735 } 725 }
726 work++;
736 } 727 }
728 return work;
737} 729}
738 730
739 731
@@ -741,7 +733,8 @@ static void clearbykeys (global_State *g, GCObject *l) {
741** clear entries with unmarked values from all weaktables in list 'l' up 733** clear entries with unmarked values from all weaktables in list 'l' up
742** to element 'f' 734** to element 'f'
743*/ 735*/
744static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { 736static l_obj clearbyvalues (global_State *g, GCObject *l, GCObject *f) {
737 l_obj work = 0;
745 for (; l != f; l = gco2t(l)->gclist) { 738 for (; l != f; l = gco2t(l)->gclist) {
746 Table *h = gco2t(l); 739 Table *h = gco2t(l);
747 Node *n, *limit = gnodelast(h); 740 Node *n, *limit = gnodelast(h);
@@ -758,7 +751,9 @@ static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) {
758 if (isempty(gval(n))) /* is entry empty? */ 751 if (isempty(gval(n))) /* is entry empty? */
759 clearkey(n); /* clear its key */ 752 clearkey(n); /* clear its key */
760 } 753 }
754 work++;
761 } 755 }
756 return work;
762} 757}
763 758
764 759
@@ -770,6 +765,7 @@ static void freeupval (lua_State *L, UpVal *uv) {
770 765
771 766
772static void freeobj (lua_State *L, GCObject *o) { 767static void freeobj (lua_State *L, GCObject *o) {
768 G(L)->totalobjs--;
773 switch (o->tt) { 769 switch (o->tt) {
774 case LUA_VPROTO: 770 case LUA_VPROTO:
775 luaF_freeproto(L, gco2p(o)); 771 luaF_freeproto(L, gco2p(o));
@@ -819,10 +815,9 @@ static void freeobj (lua_State *L, GCObject *o) {
819** objects, where a dead object is one marked with the old (non current) 815** 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 816** white; change all non-dead objects back to white, preparing for next
821** collection cycle. Return where to continue the traversal or NULL if 817** collection cycle. Return where to continue the traversal or NULL if
822** list is finished. ('*countout' gets the number of elements traversed.) 818** list is finished.
823*/ 819*/
824static GCObject **sweeplist (lua_State *L, GCObject **p, int countin, 820static GCObject **sweeplist (lua_State *L, GCObject **p, int countin) {
825 int *countout) {
826 global_State *g = G(L); 821 global_State *g = G(L);
827 int ow = otherwhite(g); 822 int ow = otherwhite(g);
828 int i; 823 int i;
@@ -839,8 +834,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int countin,
839 p = &curr->next; /* go to next element */ 834 p = &curr->next; /* go to next element */
840 } 835 }
841 } 836 }
842 if (countout)
843 *countout = i; /* number of elements traversed */
844 return (*p == NULL) ? NULL : p; 837 return (*p == NULL) ? NULL : p;
845} 838}
846 839
@@ -851,7 +844,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int countin,
851static GCObject **sweeptolive (lua_State *L, GCObject **p) { 844static GCObject **sweeptolive (lua_State *L, GCObject **p) {
852 GCObject **old = p; 845 GCObject **old = p;
853 do { 846 do {
854 p = sweeplist(L, p, 1, NULL); 847 p = sweeplist(L, p, 1);
855 } while (p == old); 848 } while (p == old);
856 return p; 849 return p;
857} 850}
@@ -870,11 +863,8 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p) {
870*/ 863*/
871static void checkSizes (lua_State *L, global_State *g) { 864static void checkSizes (lua_State *L, global_State *g) {
872 if (!g->gcemergency) { 865 if (!g->gcemergency) {
873 if (g->strt.nuse < g->strt.size / 4) { /* string table too big? */ 866 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); 867 luaS_resize(L, g->strt.size / 2);
876 g->GCestimate += g->GCdebt - olddebt; /* correct estimate */
877 }
878 } 868 }
879} 869}
880 870
@@ -933,18 +923,6 @@ static void GCTM (lua_State *L) {
933 923
934 924
935/* 925/*
936** Call a few finalizers
937*/
938static int runafewfinalizers (lua_State *L, int n) {
939 global_State *g = G(L);
940 int i;
941 for (i = 0; i < n && g->tobefnz; i++)
942 GCTM(L); /* call one finalizer */
943 return i;
944}
945
946
947/*
948** call all pending finalizers 926** call all pending finalizers
949*/ 927*/
950static void callallpendingfinalizers (lua_State *L) { 928static void callallpendingfinalizers (lua_State *L) {
@@ -1052,20 +1030,13 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
1052 1030
1053/* 1031/*
1054** Set the "time" to wait before starting a new GC cycle; cycle will 1032** Set the "time" to wait before starting a new GC cycle; cycle will
1055** start when memory use hits the threshold of ('estimate' * pause / 1033** start when number of objects in use hits the threshold of
1056** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero, 1034** approximately (marked * pause / 100).
1057** because Lua cannot even start with less than PAUSEADJ bytes).
1058*/ 1035*/
1059static void setpause (global_State *g) { 1036static void setpause (global_State *g) {
1060 l_mem threshold, debt; 1037 l_obj threshold = applygcparam(g, gcpause, g->marked);
1061 int pause = getgcparam(g->gcpause); 1038 l_obj debt = threshold - gettotalobjs(g);
1062 l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ 1039 if (debt < 0) debt = 0;
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;
1069 luaE_setdebt(g, debt); 1040 luaE_setdebt(g, debt);
1070} 1041}
1071 1042
@@ -1305,18 +1276,17 @@ static void atomic2gen (lua_State *L, global_State *g) {
1305 sweep2old(L, &g->tobefnz); 1276 sweep2old(L, &g->tobefnz);
1306 1277
1307 g->gckind = KGC_GEN; 1278 g->gckind = KGC_GEN;
1308 g->lastatomic = 0; 1279 g->GClastmajor = gettotalobjs(g); /* base for memory control */
1309 g->GCestimate = gettotalbytes(g); /* base for memory control */
1310 finishgencycle(L, g); 1280 finishgencycle(L, g);
1311} 1281}
1312 1282
1313 1283
1314/* 1284/*
1315** Set debt for the next minor collection, which will happen when 1285** Set debt for the next minor collection, which will happen when
1316** memory grows 'genminormul'%. 1286** total number of objects grows 'genminormul'%.
1317*/ 1287*/
1318static void setminordebt (global_State *g) { 1288static void setminordebt (global_State *g) {
1319 luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul)); 1289 luaE_setdebt(g, applygcparam(g, genminormul, gettotalobjs(g)));
1320} 1290}
1321 1291
1322 1292
@@ -1326,14 +1296,12 @@ static void setminordebt (global_State *g) {
1326** are cleared. Then, turn all objects into old and finishes the 1296** are cleared. Then, turn all objects into old and finishes the
1327** collection. 1297** collection.
1328*/ 1298*/
1329static lu_mem entergen (lua_State *L, global_State *g) { 1299static void entergen (lua_State *L, global_State *g) {
1330 lu_mem numobjs;
1331 luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ 1300 luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */
1332 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ 1301 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
1333 numobjs = atomic(L); /* propagates all and then do the atomic stuff */ 1302 atomic(L); /* propagates all and then do the atomic stuff */
1334 atomic2gen(L, g); 1303 atomic2gen(L, g);
1335 setminordebt(g); /* set debt assuming next cycle will be minor */ 1304 setminordebt(g); /* set debt assuming next cycle will be minor */
1336 return numobjs;
1337} 1305}
1338 1306
1339 1307
@@ -1350,7 +1318,6 @@ static void enterinc (global_State *g) {
1350 g->finobjrold = g->finobjold1 = g->finobjsur = NULL; 1318 g->finobjrold = g->finobjold1 = g->finobjsur = NULL;
1351 g->gcstate = GCSpause; 1319 g->gcstate = GCSpause;
1352 g->gckind = KGC_INC; 1320 g->gckind = KGC_INC;
1353 g->lastatomic = 0;
1354} 1321}
1355 1322
1356 1323
@@ -1359,111 +1326,75 @@ static void enterinc (global_State *g) {
1359*/ 1326*/
1360void luaC_changemode (lua_State *L, int newmode) { 1327void luaC_changemode (lua_State *L, int newmode) {
1361 global_State *g = G(L); 1328 global_State *g = G(L);
1362 if (newmode != g->gckind) { 1329 if (newmode != g->gckind) { /* does it need to change? */
1363 if (newmode == KGC_GEN) /* entering generational mode? */ 1330 if (newmode == KGC_INC) { /* entering incremental mode? */
1331 if (g->gckind == KGC_GENMAJOR)
1332 g->gckind = KGC_INC; /* already incremental but in name */
1333 else
1334 enterinc(g); /* entering incremental mode */
1335 }
1336 else {
1337 lua_assert(newmode == KGC_GEN);
1364 entergen(L, g); 1338 entergen(L, g);
1365 else 1339 }
1366 enterinc(g); /* entering incremental mode */
1367 } 1340 }
1368 g->lastatomic = 0;
1369} 1341}
1370 1342
1371 1343
1372/* 1344/*
1373** Does a full collection in generational mode. 1345** Does a full collection in generational mode.
1374*/ 1346*/
1375static lu_mem fullgen (lua_State *L, global_State *g) { 1347static void fullgen (lua_State *L, global_State *g) {
1376 enterinc(g); 1348 enterinc(g);
1377 return entergen(L, g); 1349 entergen(L, g);
1378} 1350}
1379 1351
1380 1352
1381/* 1353/*
1382** Does a major collection after last collection was a "bad collection". 1354** Does a major collector up to the atomic phase and then either
1383** 1355** returns to minor collections or stays doing major ones. If the
1384** When the program is building a big structure, it allocates lots of 1356** number of objects collected this time (numobjs - marked) is more than
1385** memory but generates very little garbage. In those scenarios, 1357** half the number of objects created since the last major collection
1386** the generational mode just wastes time doing small collections, and 1358** (numobjs - lastmajor), it goes back to minor collections.
1387** major collections are frequently what we call a "bad collection", a 1359*/
1388** collection that frees too few objects. To avoid the cost of switching 1360static void genmajorstep (lua_State *L, global_State *g) {
1389** between generational mode and the incremental mode needed for full 1361 l_obj lastmajor = g->GClastmajor; /* count from last collection */
1390** (major) collections, the collector tries to stay in incremental mode 1362 l_obj numobjs = gettotalobjs(g); /* current count */
1391** after a bad collection, and to switch back to generational mode only
1392** after a "good" collection (one that traverses less than 9/8 objects
1393** of the previous one).
1394** The collector must choose whether to stay in incremental mode or to
1395** switch back to generational mode before sweeping. At this point, it
1396** does not know the real memory in use, so it cannot use memory to
1397** decide whether to return to generational mode. Instead, it uses the
1398** number of objects traversed (returned by 'atomic') as a proxy. The
1399** field 'g->lastatomic' keeps this count from the last collection.
1400** ('g->lastatomic != 0' also means that the last collection was bad.)
1401*/
1402static 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 */
1405 if (g->gckind == KGC_GEN) /* still in generational mode? */
1406 enterinc(g); /* enter incremental mode */
1407 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ 1363 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
1408 newatomic = atomic(L); /* mark everybody */ 1364 atomic(L); /* mark everybody */
1409 if (newatomic < lastatomic + (lastatomic >> 3)) { /* good collection? */ 1365 if ((numobjs - g->marked) > ((numobjs - lastmajor) >> 1)) {
1410 atomic2gen(L, g); /* return to generational mode */ 1366 atomic2gen(L, g); /* return to generational mode */
1411 setminordebt(g); 1367 setminordebt(g);
1412 } 1368 }
1413 else { /* another bad collection; stay in incremental mode */ 1369 else { /* bad collection; stay in major mode */
1414 g->GCestimate = gettotalbytes(g); /* first estimate */
1415 entersweep(L); 1370 entersweep(L);
1416 luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ 1371 luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */
1417 setpause(g); 1372 setpause(g);
1418 g->lastatomic = newatomic; 1373 g->GClastmajor = gettotalobjs(g);
1419 } 1374 }
1420} 1375}
1421 1376
1422 1377
1423/* 1378/*
1424** Does a generational "step". 1379** Does a generational "step". If the total number of objects grew
1425** Usually, this means doing a minor collection and setting the debt to 1380** more than 'majormul'% since the last major collection, does a
1426** make another collection when memory grows 'genminormul'% larger. 1381** major collection. Otherwise, does a minor collection.
1427**
1428** However, there are exceptions. If memory grows 'genmajormul'%
1429** larger than it was at the end of the last major collection (kept
1430** in 'g->GCestimate'), the function does a major collection. At the
1431** end, it checks whether the major collection was able to free a
1432** decent amount of memory (at least half the growth in memory since
1433** previous major collection). If so, the collector keeps its state,
1434** and the next collection will probably be minor again. Otherwise,
1435** we have what we call a "bad collection". In that case, set the field
1436** 'g->lastatomic' to signal that fact, so that the next collection will
1437** go to 'stepgenfull'.
1438**
1439** 'GCdebt <= 0' means an explicit call to GC step with "size" zero;
1440** in that case, do a minor collection.
1441*/ 1382*/
1442static void genstep (lua_State *L, global_State *g) { 1383static void genstep (lua_State *L, global_State *g) {
1443 if (g->lastatomic != 0) /* last collection was a bad one? */ 1384 l_obj majorbase = g->GClastmajor; /* count after last major collection */
1444 stepgenfull(L, g); /* do a full step */ 1385 l_obj majorinc = applygcparam(g, genmajormul, majorbase);
1445 else { 1386 if (gettotalobjs(g) > majorbase + majorinc && 0) {
1446 lu_mem majorbase = g->GCestimate; /* memory after last major collection */ 1387 /* do a major collection */
1447 lu_mem majorinc = (majorbase / 100) * getgcparam(g->genmajormul); 1388 enterinc(g);
1448 if (g->GCdebt > 0 && gettotalbytes(g) > majorbase + majorinc) { 1389 g->gckind = KGC_GENMAJOR;
1449 lu_mem numobjs = fullgen(L, g); /* do a major collection */ 1390 genmajorstep(L, g);
1450 if (gettotalbytes(g) < majorbase + (majorinc / 2)) { 1391 }
1451 /* collected at least half of memory growth since last major 1392 else { /* regular case; do a minor collection */
1452 collection; keep doing minor collections. */ 1393 g->marked = 0;
1453 lua_assert(g->lastatomic == 0); 1394 youngcollection(L, g);
1454 } 1395 setminordebt(g);
1455 else { /* bad collection */ 1396 lua_assert(g->GClastmajor == majorbase);
1456 g->lastatomic = numobjs; /* signal that last collection was bad */
1457 setpause(g); /* do a long wait for next (major) collection */
1458 }
1459 }
1460 else { /* regular case; do a minor collection */
1461 youngcollection(L, g);
1462 setminordebt(g);
1463 g->GCestimate = majorbase; /* preserve base value */
1464 }
1465 } 1397 }
1466 lua_assert(isdecGCmodegen(g));
1467} 1398}
1468 1399
1469/* }====================================================== */ 1400/* }====================================================== */
@@ -1522,9 +1453,9 @@ void luaC_freeallobjects (lua_State *L) {
1522} 1453}
1523 1454
1524 1455
1525static lu_mem atomic (lua_State *L) { 1456static l_obj atomic (lua_State *L) {
1457 l_obj work = 0;
1526 global_State *g = G(L); 1458 global_State *g = G(L);
1527 lu_mem work = 0;
1528 GCObject *origweak, *origall; 1459 GCObject *origweak, *origall;
1529 GCObject *grayagain = g->grayagain; /* save original list */ 1460 GCObject *grayagain = g->grayagain; /* save original list */
1530 g->grayagain = NULL; 1461 g->grayagain = NULL;
@@ -1541,50 +1472,44 @@ static lu_mem atomic (lua_State *L) {
1541 work += propagateall(g); /* propagate changes */ 1472 work += propagateall(g); /* propagate changes */
1542 g->gray = grayagain; 1473 g->gray = grayagain;
1543 work += propagateall(g); /* traverse 'grayagain' list */ 1474 work += propagateall(g); /* traverse 'grayagain' list */
1544 convergeephemerons(g); 1475 work += convergeephemerons(g);
1545 /* at this point, all strongly accessible objects are marked. */ 1476 /* at this point, all strongly accessible objects are marked. */
1546 /* Clear values from weak tables, before checking finalizers */ 1477 /* Clear values from weak tables, before checking finalizers */
1547 clearbyvalues(g, g->weak, NULL); 1478 work += clearbyvalues(g, g->weak, NULL);
1548 clearbyvalues(g, g->allweak, NULL); 1479 work += clearbyvalues(g, g->allweak, NULL);
1549 origweak = g->weak; origall = g->allweak; 1480 origweak = g->weak; origall = g->allweak;
1550 separatetobefnz(g, 0); /* separate objects to be finalized */ 1481 separatetobefnz(g, 0); /* separate objects to be finalized */
1551 work += markbeingfnz(g); /* mark objects that will be finalized */ 1482 work += markbeingfnz(g); /* mark objects that will be finalized */
1552 work += propagateall(g); /* remark, to propagate 'resurrection' */ 1483 work += propagateall(g); /* remark, to propagate 'resurrection' */
1553 convergeephemerons(g); 1484 work += convergeephemerons(g);
1554 /* at this point, all resurrected objects are marked. */ 1485 /* at this point, all resurrected objects are marked. */
1555 /* remove dead objects from weak tables */ 1486 /* remove dead objects from weak tables */
1556 clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron tables */ 1487 work += clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron */
1557 clearbykeys(g, g->allweak); /* clear keys from all 'allweak' tables */ 1488 work += clearbykeys(g, g->allweak); /* clear keys from all 'allweak' */
1558 /* clear values from resurrected weak tables */ 1489 /* clear values from resurrected weak tables */
1559 clearbyvalues(g, g->weak, origweak); 1490 work += clearbyvalues(g, g->weak, origweak);
1560 clearbyvalues(g, g->allweak, origall); 1491 work += clearbyvalues(g, g->allweak, origall);
1561 luaS_clearcache(g); 1492 luaS_clearcache(g);
1562 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ 1493 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
1563 lua_assert(g->gray == NULL); 1494 lua_assert(g->gray == NULL);
1564 return work; /* estimate of slots marked by 'atomic' */ 1495 return work;
1565} 1496}
1566 1497
1567 1498
1568static int sweepstep (lua_State *L, global_State *g, 1499static void sweepstep (lua_State *L, global_State *g,
1569 int nextstate, GCObject **nextlist) { 1500 int nextstate, GCObject **nextlist) {
1570 if (g->sweepgc) { 1501 if (g->sweepgc)
1571 l_mem olddebt = g->GCdebt; 1502 g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
1572 int count;
1573 g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX, &count);
1574 g->GCestimate += g->GCdebt - olddebt; /* update estimate */
1575 return count;
1576 }
1577 else { /* enter next state */ 1503 else { /* enter next state */
1578 g->gcstate = nextstate; 1504 g->gcstate = nextstate;
1579 g->sweepgc = nextlist; 1505 g->sweepgc = nextlist;
1580 return 0; /* no work done */
1581 } 1506 }
1582} 1507}
1583 1508
1584 1509
1585static lu_mem singlestep (lua_State *L) { 1510static l_obj singlestep (lua_State *L) {
1586 global_State *g = G(L); 1511 global_State *g = G(L);
1587 lu_mem work; 1512 l_obj work;
1588 lua_assert(!g->gcstopem); /* collector is not reentrant */ 1513 lua_assert(!g->gcstopem); /* collector is not reentrant */
1589 g->gcstopem = 1; /* no emergency collections while collecting */ 1514 g->gcstopem = 1; /* no emergency collections while collecting */
1590 switch (g->gcstate) { 1515 switch (g->gcstate) {
@@ -1599,26 +1524,30 @@ static lu_mem singlestep (lua_State *L) {
1599 g->gcstate = GCSenteratomic; /* finish propagate phase */ 1524 g->gcstate = GCSenteratomic; /* finish propagate phase */
1600 work = 0; 1525 work = 0;
1601 } 1526 }
1602 else 1527 else {
1603 work = propagatemark(g); /* traverse one gray object */ 1528 propagatemark(g); /* traverse one gray object */
1529 work = 1;
1530 }
1604 break; 1531 break;
1605 } 1532 }
1606 case GCSenteratomic: { 1533 case GCSenteratomic: {
1607 work = atomic(L); /* work is what was traversed by 'atomic' */ 1534 work = atomic(L);
1608 entersweep(L); 1535 entersweep(L);
1609 g->GCestimate = gettotalbytes(g); /* first estimate */
1610 break; 1536 break;
1611 } 1537 }
1612 case GCSswpallgc: { /* sweep "regular" objects */ 1538 case GCSswpallgc: { /* sweep "regular" objects */
1613 work = sweepstep(L, g, GCSswpfinobj, &g->finobj); 1539 sweepstep(L, g, GCSswpfinobj, &g->finobj);
1540 work = GCSWEEPMAX;
1614 break; 1541 break;
1615 } 1542 }
1616 case GCSswpfinobj: { /* sweep objects with finalizers */ 1543 case GCSswpfinobj: { /* sweep objects with finalizers */
1617 work = sweepstep(L, g, GCSswptobefnz, &g->tobefnz); 1544 sweepstep(L, g, GCSswptobefnz, &g->tobefnz);
1545 work = GCSWEEPMAX;
1618 break; 1546 break;
1619 } 1547 }
1620 case GCSswptobefnz: { /* sweep objects to be finalized */ 1548 case GCSswptobefnz: { /* sweep objects to be finalized */
1621 work = sweepstep(L, g, GCSswpend, NULL); 1549 sweepstep(L, g, GCSswpend, NULL);
1550 work = GCSWEEPMAX;
1622 break; 1551 break;
1623 } 1552 }
1624 case GCSswpend: { /* finish sweeps */ 1553 case GCSswpend: { /* finish sweeps */
@@ -1627,10 +1556,11 @@ static lu_mem singlestep (lua_State *L) {
1627 work = 0; 1556 work = 0;
1628 break; 1557 break;
1629 } 1558 }
1630 case GCScallfin: { /* call remaining finalizers */ 1559 case GCScallfin: { /* call finalizers */
1631 if (g->tobefnz && !g->gcemergency) { 1560 if (g->tobefnz && !g->gcemergency) {
1632 g->gcstopem = 0; /* ok collections during finalizers */ 1561 g->gcstopem = 0; /* ok collections during finalizers */
1633 work = runafewfinalizers(L, GCFINMAX) * GCFINALIZECOST; 1562 GCTM(L); /* call one finalizer */
1563 work = 1;
1634 } 1564 }
1635 else { /* emergency mode or no more finalizers */ 1565 else { /* emergency mode or no more finalizers */
1636 g->gcstate = GCSpause; /* finish collection */ 1566 g->gcstate = GCSpause; /* finish collection */
@@ -1665,20 +1595,16 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
1665** controls when next step will be performed. 1595** controls when next step will be performed.
1666*/ 1596*/
1667static void incstep (lua_State *L, global_State *g) { 1597static void incstep (lua_State *L, global_State *g) {
1668 int stepmul = (getgcparam(g->gcstepmul) | 1); /* avoid division by 0 */ 1598 l_obj stepsize = cast(l_obj, 1) << g->gcstepsize;
1669 l_mem debt = (g->GCdebt / WORK2MEM) * stepmul; 1599 l_obj work2do = applygcparam(g, gcstepmul, stepsize);
1670 l_mem stepsize = (g->gcstepsize <= log2maxs(l_mem))
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) */ 1600 do { /* repeat until pause or enough "credit" (negative debt) */
1674 lu_mem work = singlestep(L); /* perform one single step */ 1601 l_obj work = singlestep(L); /* perform one single step */
1675 debt -= work; 1602 work2do -= work;
1676 } while (debt > -stepsize && g->gcstate != GCSpause); 1603 } while (work2do > 0 && g->gcstate != GCSpause);
1677 if (g->gcstate == GCSpause) 1604 if (g->gcstate == GCSpause)
1678 setpause(g); /* pause until next cycle */ 1605 setpause(g); /* pause until next cycle */
1679 else { 1606 else {
1680 debt = (debt / stepmul) * WORK2MEM; /* convert 'work units' to bytes */ 1607 luaE_setdebt(g, stepsize);
1681 luaE_setdebt(g, debt);
1682 } 1608 }
1683} 1609}
1684 1610
@@ -1689,13 +1615,21 @@ static void incstep (lua_State *L, global_State *g) {
1689*/ 1615*/
1690void luaC_step (lua_State *L) { 1616void luaC_step (lua_State *L) {
1691 global_State *g = G(L); 1617 global_State *g = G(L);
1618 lua_assert(!g->gcemergency);
1692 if (!gcrunning(g)) /* not running? */ 1619 if (!gcrunning(g)) /* not running? */
1693 luaE_setdebt(g, -2000); 1620 luaE_setdebt(g, 2000);
1694 else { 1621 else {
1695 if(isdecGCmodegen(g)) 1622 switch (g->gckind) {
1696 genstep(L, g); 1623 case KGC_INC:
1697 else 1624 incstep(L, g);
1698 incstep(L, g); 1625 break;
1626 case KGC_GEN:
1627 genstep(L, g);
1628 break;
1629 case KGC_GENMAJOR:
1630 genmajorstep(L, g);
1631 break;
1632 }
1699 } 1633 }
1700} 1634}
1701 1635
@@ -1715,8 +1649,8 @@ static void fullinc (lua_State *L, global_State *g) {
1715 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ 1649 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
1716 g->gcstate = GCSenteratomic; /* go straight to atomic phase ??? */ 1650 g->gcstate = GCSenteratomic; /* go straight to atomic phase ??? */
1717 luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ 1651 luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */
1718 /* estimate must be correct after a full GC cycle */ 1652 /* 'marked' must be correct after a full GC cycle */
1719 lua_assert(g->GCestimate == gettotalbytes(g)); 1653 lua_assert(g->marked == gettotalobjs(g));
1720 luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ 1654 luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */
1721 setpause(g); 1655 setpause(g);
1722} 1656}
@@ -1731,10 +1665,10 @@ void luaC_fullgc (lua_State *L, int isemergency) {
1731 global_State *g = G(L); 1665 global_State *g = G(L);
1732 lua_assert(!g->gcemergency); 1666 lua_assert(!g->gcemergency);
1733 g->gcemergency = isemergency; /* set flag */ 1667 g->gcemergency = isemergency; /* set flag */
1734 if (g->gckind == KGC_INC) 1668 if (g->gckind == KGC_GEN)
1735 fullinc(L, g);
1736 else
1737 fullgen(L, g); 1669 fullgen(L, g);
1670 else
1671 fullinc(L, g);
1738 g->gcemergency = 0; 1672 g->gcemergency = 0;
1739} 1673}
1740 1674