aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-09-19 19:02:14 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-09-19 19:02:14 -0300
commitddfa1fbccfe4c1ec69f7396a4f5842abe70927ba (patch)
treedf467dc5dc5c64a21bb976ec661796d17d37f791
parentb443145ff3415fcaee903a7d95fa7212df5a77db (diff)
downloadlua-ddfa1fbccfe4c1ec69f7396a4f5842abe70927ba.tar.gz
lua-ddfa1fbccfe4c1ec69f7396a4f5842abe70927ba.tar.bz2
lua-ddfa1fbccfe4c1ec69f7396a4f5842abe70927ba.zip
GC back to controling pace counting bytes
Memory is the resource we want to save. Still to be reviewed again.
-rw-r--r--lapi.c19
-rw-r--r--lauxlib.c1
-rw-r--r--lgc.c307
-rw-r--r--lgc.h34
-rw-r--r--llimits.h19
-rw-r--r--lmem.c8
-rw-r--r--lobject.c12
-rw-r--r--lobject.h2
-rw-r--r--lstate.c14
-rw-r--r--lstate.h15
-rw-r--r--ltests.c18
11 files changed, 247 insertions, 202 deletions
diff --git a/lapi.c b/lapi.c
index 4f4e3021..c493609a 100644
--- a/lapi.c
+++ b/lapi.c
@@ -53,16 +53,6 @@ const char lua_ident[] =
53#define isupvalue(i) ((i) < LUA_REGISTRYINDEX) 53#define isupvalue(i) ((i) < LUA_REGISTRYINDEX)
54 54
55 55
56/* Advance the garbage collector when creating large objects */
57static void advancegc (lua_State *L, size_t delta) {
58 delta >>= 5; /* one object for each 32 bytes (empirical) */
59 if (delta > 0) {
60 global_State *g = G(L);
61 luaE_setdebt(g, g->GCdebt - cast(l_obj, delta));
62 }
63}
64
65
66/* 56/*
67** Convert an acceptable index to a pointer to its respective value. 57** Convert an acceptable index to a pointer to its respective value.
68** Non-valid indices return the special nil value 'G(L)->nilvalue'. 58** Non-valid indices return the special nil value 'G(L)->nilvalue'.
@@ -540,7 +530,6 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
540 ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); 530 ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
541 setsvalue2s(L, L->top.p, ts); 531 setsvalue2s(L, L->top.p, ts);
542 api_incr_top(L); 532 api_incr_top(L);
543 advancegc(L, len);
544 luaC_checkGC(L); 533 luaC_checkGC(L);
545 lua_unlock(L); 534 lua_unlock(L);
546 return getstr(ts); 535 return getstr(ts);
@@ -557,7 +546,6 @@ LUA_API const char *lua_pushextlstring (lua_State *L,
557 setsvalue2s(L, L->top.p, ts); 546 setsvalue2s(L, L->top.p, ts);
558 api_incr_top(L); 547 api_incr_top(L);
559 if (falloc != NULL) /* non-static string? */ 548 if (falloc != NULL) /* non-static string? */
560 advancegc(L, len); /* count its memory */
561 luaC_checkGC(L); 549 luaC_checkGC(L);
562 lua_unlock(L); 550 lua_unlock(L);
563 return getstr(ts); 551 return getstr(ts);
@@ -1190,16 +1178,16 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
1190 } 1178 }
1191 case LUA_GCCOUNT: { 1179 case LUA_GCCOUNT: {
1192 /* GC values are expressed in Kbytes: #bytes/2^10 */ 1180 /* GC values are expressed in Kbytes: #bytes/2^10 */
1193 res = cast_int(g->GCtotalbytes >> 10); 1181 res = cast_int(gettotalbytes(g) >> 10);
1194 break; 1182 break;
1195 } 1183 }
1196 case LUA_GCCOUNTB: { 1184 case LUA_GCCOUNTB: {
1197 res = cast_int(g->GCtotalbytes & 0x3ff); 1185 res = cast_int(gettotalbytes(g) & 0x3ff);
1198 break; 1186 break;
1199 } 1187 }
1200 case LUA_GCSTEP: { 1188 case LUA_GCSTEP: {
1201 lu_byte oldstp = g->gcstp; 1189 lu_byte oldstp = g->gcstp;
1202 l_obj n = cast(l_obj, va_arg(argp, size_t)); 1190 l_mem n = cast(l_mem, va_arg(argp, size_t));
1203 int work = 0; /* true if GC did some work */ 1191 int work = 0; /* true if GC did some work */
1204 g->gcstp = 0; /* allow GC to run (other bits must be zero here) */ 1192 g->gcstp = 0; /* allow GC to run (other bits must be zero here) */
1205 if (n <= 0) 1193 if (n <= 0)
@@ -1356,7 +1344,6 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
1356 u = luaS_newudata(L, size, cast(unsigned short, nuvalue)); 1344 u = luaS_newudata(L, size, cast(unsigned short, nuvalue));
1357 setuvalue(L, s2v(L->top.p), u); 1345 setuvalue(L, s2v(L->top.p), u);
1358 api_incr_top(L); 1346 api_incr_top(L);
1359 advancegc(L, size);
1360 luaC_checkGC(L); 1347 luaC_checkGC(L);
1361 lua_unlock(L); 1348 lua_unlock(L);
1362 return getudatamem(u); 1349 return getudatamem(u);
diff --git a/lauxlib.c b/lauxlib.c
index b70b7ae6..defd4d57 100644
--- a/lauxlib.c
+++ b/lauxlib.c
@@ -618,6 +618,7 @@ LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
618 box->bsize = 0; box->box = NULL; 618 box->bsize = 0; box->box = NULL;
619 lua_pushextlstring(L, s, len, allocf, ud); 619 lua_pushextlstring(L, s, len, allocf, ud);
620 lua_closeslot(L, -2); /* close the box */ 620 lua_closeslot(L, -2); /* close the box */
621 lua_gc(L, LUA_GCSTEP, len);
621 } 622 }
622 lua_remove(L, -2); /* remove box or placeholder from the stack */ 623 lua_remove(L, -2); /* remove box or placeholder from the stack */
623} 624}
diff --git a/lgc.c b/lgc.c
index 92034635..a38d11b2 100644
--- a/lgc.c
+++ b/lgc.c
@@ -18,7 +18,6 @@
18#include "ldo.h" 18#include "ldo.h"
19#include "lfunc.h" 19#include "lfunc.h"
20#include "lgc.h" 20#include "lgc.h"
21#include "llex.h"
22#include "lmem.h" 21#include "lmem.h"
23#include "lobject.h" 22#include "lobject.h"
24#include "lstate.h" 23#include "lstate.h"
@@ -28,13 +27,6 @@
28 27
29 28
30/* 29/*
31** Number of fixed (luaC_fix) objects in a Lua state: metafield names,
32** plus reserved words, plus "_ENV", plus the memory-error message.
33*/
34#define NFIXED (TM_N + NUM_RESERVED + 2)
35
36
37/*
38** Maximum number of elements to sweep in each single step. 30** Maximum number of elements to sweep in each single step.
39** (Large enough to dissipate fixed overheads but small enough 31** (Large enough to dissipate fixed overheads but small enough
40** to allow small steps for the collector.) 32** to allow small steps for the collector.)
@@ -42,6 +34,12 @@
42#define GCSWEEPMAX 20 34#define GCSWEEPMAX 20
43 35
44 36
37/*
38** Cost (in work units) of running one finalizer.
39*/
40#define CWUFIN 10
41
42
45/* mask with all color bits */ 43/* mask with all color bits */
46#define maskcolors (bitmask(BLACKBIT) | WHITEBITS) 44#define maskcolors (bitmask(BLACKBIT) | WHITEBITS)
47 45
@@ -95,7 +93,7 @@
95 93
96 94
97static void reallymarkobject (global_State *g, GCObject *o); 95static void reallymarkobject (global_State *g, GCObject *o);
98static l_obj atomic (lua_State *L); 96static void atomic (lua_State *L);
99static void entersweep (lua_State *L); 97static void entersweep (lua_State *L);
100 98
101 99
@@ -112,6 +110,66 @@ static void entersweep (lua_State *L);
112#define gnodelast(h) gnode(h, cast_sizet(sizenode(h))) 110#define gnodelast(h) gnode(h, cast_sizet(sizenode(h)))
113 111
114 112
113static size_t objsize (GCObject *o) {
114 switch (o->tt) {
115 case LUA_VTABLE: {
116 /* Fow now, table size does not consider 'haslastfree' */
117 Table *t = gco2t(o);
118 size_t sz = sizeof(Table)
119 + luaH_realasize(t) * (sizeof(Value) + 1);
120 if (!isdummy(t))
121 sz += sizenode(t) * sizeof(Node);
122 return sz;
123 }
124 case LUA_VLCL: {
125 LClosure *cl = gco2lcl(o);
126 return sizeLclosure(cl->nupvalues);
127 }
128 case LUA_VCCL: {
129 CClosure *cl = gco2ccl(o);
130 return sizeCclosure(cl->nupvalues);
131 break;
132 }
133 case LUA_VUSERDATA: {
134 Udata *u = gco2u(o);
135 return sizeudata(u->nuvalue, u->len);
136 }
137 case LUA_VPROTO: {
138 Proto *p = gco2p(o);
139 size_t sz = sizeof(Proto)
140 + cast_uint(p->sizep) * sizeof(Proto*)
141 + cast_uint(p->sizek) * sizeof(TValue)
142 + cast_uint(p->sizelocvars) * sizeof(LocVar)
143 + cast_uint(p->sizeupvalues) * sizeof(Upvaldesc);
144 if (!(p->flag & PF_FIXED)) {
145 sz += cast_uint(p->sizecode) * sizeof(Instruction)
146 + cast_uint(p->sizelineinfo) * sizeof(lu_byte)
147 + cast_uint(p->sizeabslineinfo) * sizeof(AbsLineInfo);
148 }
149 return sz;
150 }
151 case LUA_VTHREAD: {
152 lua_State *L1 = gco2th(o);
153 size_t sz = sizeof(lua_State) + LUA_EXTRASPACE
154 + cast_uint(L1->nci) * sizeof(CallInfo);
155 if (L1->stack.p != NULL)
156 sz += cast_uint(stacksize(L1) + EXTRA_STACK) * sizeof(StackValue);
157 return sz;
158 }
159 case LUA_VSHRSTR: {
160 TString *ts = gco2ts(o);
161 return sizestrshr(cast_uint(ts->shrlen));
162 }
163 case LUA_VLNGSTR: {
164 TString *ts = gco2ts(o);
165 return luaS_sizelngstr(ts->u.lnglen, ts->shrlen);
166 }
167 case LUA_VUPVAL: return sizeof(UpVal);
168 default: lua_assert(0); return 0;
169 }
170}
171
172
115static GCObject **getgclist (GCObject *o) { 173static GCObject **getgclist (GCObject *o) {
116 switch (o->tt) { 174 switch (o->tt) {
117 case LUA_VTABLE: return &gco2t(o)->gclist; 175 case LUA_VTABLE: return &gco2t(o)->gclist;
@@ -250,7 +308,6 @@ GCObject *luaC_newobjdt (lua_State *L, lu_byte tt, size_t sz, size_t offset) {
250 global_State *g = G(L); 308 global_State *g = G(L);
251 char *p = cast_charp(luaM_newobject(L, novariant(tt), sz)); 309 char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
252 GCObject *o = cast(GCObject *, p + offset); 310 GCObject *o = cast(GCObject *, p + offset);
253 g->GCdebt--;
254 o->marked = luaC_white(g); 311 o->marked = luaC_white(g);
255 o->tt = tt; 312 o->tt = tt;
256 o->next = g->allgc; 313 o->next = g->allgc;
@@ -290,7 +347,7 @@ GCObject *luaC_newobj (lua_State *L, lu_byte tt, size_t sz) {
290** (only closures can), and a userdata's metatable must be a table. 347** (only closures can), and a userdata's metatable must be a table.
291*/ 348*/
292static void reallymarkobject (global_State *g, GCObject *o) { 349static void reallymarkobject (global_State *g, GCObject *o) {
293 g->GCmarked++; 350 g->GCmarked += cast(l_mem, objsize(o));
294 switch (o->tt) { 351 switch (o->tt) {
295 case LUA_VSHRSTR: 352 case LUA_VSHRSTR:
296 case LUA_VLNGSTR: { 353 case LUA_VLNGSTR: {
@@ -338,14 +395,10 @@ static void markmt (global_State *g) {
338/* 395/*
339** mark all objects in list of being-finalized 396** mark all objects in list of being-finalized
340*/ 397*/
341static l_obj markbeingfnz (global_State *g) { 398static void markbeingfnz (global_State *g) {
342 GCObject *o; 399 GCObject *o;
343 l_obj count = 0; 400 for (o = g->tobefnz; o != NULL; o = o->next)
344 for (o = g->tobefnz; o != NULL; o = o->next) {
345 count++;
346 markobject(g, o); 401 markobject(g, o);
347 }
348 return count;
349} 402}
350 403
351 404
@@ -360,8 +413,7 @@ static l_obj markbeingfnz (global_State *g) {
360** upvalues, as they have nothing to be checked. (If the thread gets an 413** upvalues, as they have nothing to be checked. (If the thread gets an
361** upvalue later, it will be linked in the list again.) 414** upvalue later, it will be linked in the list again.)
362*/ 415*/
363static l_obj remarkupvals (global_State *g) { 416static void remarkupvals (global_State *g) {
364 l_obj work = 0;
365 lua_State *thread; 417 lua_State *thread;
366 lua_State **p = &g->twups; 418 lua_State **p = &g->twups;
367 while ((thread = *p) != NULL) { 419 while ((thread = *p) != NULL) {
@@ -380,9 +432,7 @@ static l_obj remarkupvals (global_State *g) {
380 } 432 }
381 } 433 }
382 } 434 }
383 work++;
384 } 435 }
385 return work;
386} 436}
387 437
388 438
@@ -401,7 +451,7 @@ static void cleargraylists (global_State *g) {
401*/ 451*/
402static void restartcollection (global_State *g) { 452static void restartcollection (global_State *g) {
403 cleargraylists(g); 453 cleargraylists(g);
404 g->GCmarked = NFIXED; 454 g->GCmarked = 0;
405 markobject(g, g->mainthread); 455 markobject(g, g->mainthread);
406 markvalue(g, &g->l_registry); 456 markvalue(g, &g->l_registry);
407 markmt(g); 457 markmt(g);
@@ -546,7 +596,7 @@ static void traversestrongtable (global_State *g, Table *h) {
546} 596}
547 597
548 598
549static void traversetable (global_State *g, Table *h) { 599static l_mem traversetable (global_State *g, Table *h) {
550 const char *weakkey, *weakvalue; 600 const char *weakkey, *weakvalue;
551 const TValue *mode = gfasttm(g, h->metatable, TM_MODE); 601 const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
552 TString *smode; 602 TString *smode;
@@ -565,15 +615,17 @@ static void traversetable (global_State *g, Table *h) {
565 } 615 }
566 else /* not weak */ 616 else /* not weak */
567 traversestrongtable(g, h); 617 traversestrongtable(g, h);
618 return 1 + sizenode(h) + h->alimit;
568} 619}
569 620
570 621
571static void traverseudata (global_State *g, Udata *u) { 622static l_mem traverseudata (global_State *g, Udata *u) {
572 int i; 623 int i;
573 markobjectN(g, u->metatable); /* mark its metatable */ 624 markobjectN(g, u->metatable); /* mark its metatable */
574 for (i = 0; i < u->nuvalue; i++) 625 for (i = 0; i < u->nuvalue; i++)
575 markvalue(g, &u->uv[i].uv); 626 markvalue(g, &u->uv[i].uv);
576 genlink(g, obj2gco(u)); 627 genlink(g, obj2gco(u));
628 return 1 + u->nuvalue;
577} 629}
578 630
579 631
@@ -582,7 +634,7 @@ static void traverseudata (global_State *g, Udata *u) {
582** arrays can be larger than needed; the extra slots are filled with 634** arrays can be larger than needed; the extra slots are filled with
583** NULL, so the use of 'markobjectN') 635** NULL, so the use of 'markobjectN')
584*/ 636*/
585static void traverseproto (global_State *g, Proto *f) { 637static l_mem traverseproto (global_State *g, Proto *f) {
586 int i; 638 int i;
587 markobjectN(g, f->source); 639 markobjectN(g, f->source);
588 for (i = 0; i < f->sizek; i++) /* mark literals */ 640 for (i = 0; i < f->sizek; i++) /* mark literals */
@@ -593,26 +645,29 @@ static void traverseproto (global_State *g, Proto *f) {
593 markobjectN(g, f->p[i]); 645 markobjectN(g, f->p[i]);
594 for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ 646 for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
595 markobjectN(g, f->locvars[i].varname); 647 markobjectN(g, f->locvars[i].varname);
648 return 1 + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars;
596} 649}
597 650
598 651
599static void traverseCclosure (global_State *g, CClosure *cl) { 652static l_mem traverseCclosure (global_State *g, CClosure *cl) {
600 int i; 653 int i;
601 for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ 654 for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */
602 markvalue(g, &cl->upvalue[i]); 655 markvalue(g, &cl->upvalue[i]);
656 return 1 + cl->nupvalues;
603} 657}
604 658
605/* 659/*
606** Traverse a Lua closure, marking its prototype and its upvalues. 660** Traverse a Lua closure, marking its prototype and its upvalues.
607** (Both can be NULL while closure is being created.) 661** (Both can be NULL while closure is being created.)
608*/ 662*/
609static void traverseLclosure (global_State *g, LClosure *cl) { 663static l_mem traverseLclosure (global_State *g, LClosure *cl) {
610 int i; 664 int i;
611 markobjectN(g, cl->p); /* mark its prototype */ 665 markobjectN(g, cl->p); /* mark its prototype */
612 for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ 666 for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */
613 UpVal *uv = cl->upvals[i]; 667 UpVal *uv = cl->upvals[i];
614 markobjectN(g, uv); /* mark upvalue */ 668 markobjectN(g, uv); /* mark upvalue */
615 } 669 }
670 return 1 + cl->nupvalues;
616} 671}
617 672
618 673
@@ -628,13 +683,13 @@ static void traverseLclosure (global_State *g, LClosure *cl) {
628** (which can only happen in generational mode) or if the traverse is in 683** (which can only happen in generational mode) or if the traverse is in
629** the propagate phase (which can only happen in incremental mode). 684** the propagate phase (which can only happen in incremental mode).
630*/ 685*/
631static void traversethread (global_State *g, lua_State *th) { 686static l_mem traversethread (global_State *g, lua_State *th) {
632 UpVal *uv; 687 UpVal *uv;
633 StkId o = th->stack.p; 688 StkId o = th->stack.p;
634 if (isold(th) || g->gcstate == GCSpropagate) 689 if (isold(th) || g->gcstate == GCSpropagate)
635 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ 690 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
636 if (o == NULL) 691 if (o == NULL)
637 return; /* stack not completely built yet */ 692 return 0; /* stack not completely built yet */
638 lua_assert(g->gcstate == GCSatomic || 693 lua_assert(g->gcstate == GCSatomic ||
639 th->openupval == NULL || isintwups(th)); 694 th->openupval == NULL || isintwups(th));
640 for (; o < th->top.p; o++) /* mark live elements in the stack */ 695 for (; o < th->top.p; o++) /* mark live elements in the stack */
@@ -652,35 +707,33 @@ static void traversethread (global_State *g, lua_State *th) {
652 g->twups = th; 707 g->twups = th;
653 } 708 }
654 } 709 }
710 return 1 + (th->top.p - th->stack.p);
655} 711}
656 712
657 713
658/* 714/*
659** traverse one gray object, turning it to black. 715** traverse one gray object, turning it to black. Return an estimate
716** of the number of slots traversed.
660*/ 717*/
661static void propagatemark (global_State *g) { 718static l_mem propagatemark (global_State *g) {
662 GCObject *o = g->gray; 719 GCObject *o = g->gray;
663 nw2black(o); 720 nw2black(o);
664 g->gray = *getgclist(o); /* remove from 'gray' list */ 721 g->gray = *getgclist(o); /* remove from 'gray' list */
665 switch (o->tt) { 722 switch (o->tt) {
666 case LUA_VTABLE: traversetable(g, gco2t(o)); break; 723 case LUA_VTABLE: return traversetable(g, gco2t(o));
667 case LUA_VUSERDATA: traverseudata(g, gco2u(o)); break; 724 case LUA_VUSERDATA: return traverseudata(g, gco2u(o));
668 case LUA_VLCL: traverseLclosure(g, gco2lcl(o)); break; 725 case LUA_VLCL: return traverseLclosure(g, gco2lcl(o));
669 case LUA_VCCL: traverseCclosure(g, gco2ccl(o)); break; 726 case LUA_VCCL: return traverseCclosure(g, gco2ccl(o));
670 case LUA_VPROTO: traverseproto(g, gco2p(o)); break; 727 case LUA_VPROTO: return traverseproto(g, gco2p(o));
671 case LUA_VTHREAD: traversethread(g, gco2th(o)); break; 728 case LUA_VTHREAD: return traversethread(g, gco2th(o));
672 default: lua_assert(0); 729 default: lua_assert(0); return 0;
673 } 730 }
674} 731}
675 732
676 733
677static l_obj propagateall (global_State *g) { 734static void propagateall (global_State *g) {
678 l_obj work = 0; 735 while (g->gray)
679 while (g->gray) {
680 propagatemark(g); 736 propagatemark(g);
681 work++;
682 }
683 return work;
684} 737}
685 738
686 739
@@ -690,9 +743,8 @@ static l_obj propagateall (global_State *g) {
690** inverts the direction of the traversals, trying to speed up 743** inverts the direction of the traversals, trying to speed up
691** convergence on chains in the same table. 744** convergence on chains in the same table.
692*/ 745*/
693static l_obj convergeephemerons (global_State *g) { 746static void convergeephemerons (global_State *g) {
694 int changed; 747 int changed;
695 l_obj work = 0;
696 int dir = 0; 748 int dir = 0;
697 do { 749 do {
698 GCObject *w; 750 GCObject *w;
@@ -707,11 +759,9 @@ static l_obj convergeephemerons (global_State *g) {
707 propagateall(g); /* propagate changes */ 759 propagateall(g); /* propagate changes */
708 changed = 1; /* will have to revisit all ephemeron tables */ 760 changed = 1; /* will have to revisit all ephemeron tables */
709 } 761 }
710 work++;
711 } 762 }
712 dir = !dir; /* invert direction next time */ 763 dir = !dir; /* invert direction next time */
713 } while (changed); /* repeat until no more changes */ 764 } while (changed); /* repeat until no more changes */
714 return work;
715} 765}
716 766
717/* }====================================================== */ 767/* }====================================================== */
@@ -727,8 +777,7 @@ static l_obj convergeephemerons (global_State *g) {
727/* 777/*
728** clear entries with unmarked keys from all weaktables in list 'l' 778** clear entries with unmarked keys from all weaktables in list 'l'
729*/ 779*/
730static l_obj clearbykeys (global_State *g, GCObject *l) { 780static void clearbykeys (global_State *g, GCObject *l) {
731 l_obj work = 0;
732 for (; l; l = gco2t(l)->gclist) { 781 for (; l; l = gco2t(l)->gclist) {
733 Table *h = gco2t(l); 782 Table *h = gco2t(l);
734 Node *limit = gnodelast(h); 783 Node *limit = gnodelast(h);
@@ -739,9 +788,7 @@ static l_obj clearbykeys (global_State *g, GCObject *l) {
739 if (isempty(gval(n))) /* is entry empty? */ 788 if (isempty(gval(n))) /* is entry empty? */
740 clearkey(n); /* clear its key */ 789 clearkey(n); /* clear its key */
741 } 790 }
742 work++;
743 } 791 }
744 return work;
745} 792}
746 793
747 794
@@ -749,8 +796,7 @@ static l_obj clearbykeys (global_State *g, GCObject *l) {
749** clear entries with unmarked values from all weaktables in list 'l' up 796** clear entries with unmarked values from all weaktables in list 'l' up
750** to element 'f' 797** to element 'f'
751*/ 798*/
752static l_obj clearbyvalues (global_State *g, GCObject *l, GCObject *f) { 799static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) {
753 l_obj work = 0;
754 for (; l != f; l = gco2t(l)->gclist) { 800 for (; l != f; l = gco2t(l)->gclist) {
755 Table *h = gco2t(l); 801 Table *h = gco2t(l);
756 Node *n, *limit = gnodelast(h); 802 Node *n, *limit = gnodelast(h);
@@ -767,9 +813,7 @@ static l_obj clearbyvalues (global_State *g, GCObject *l, GCObject *f) {
767 if (isempty(gval(n))) /* is entry empty? */ 813 if (isempty(gval(n))) /* is entry empty? */
768 clearkey(n); /* clear its key */ 814 clearkey(n); /* clear its key */
769 } 815 }
770 work++;
771 } 816 }
772 return work;
773} 817}
774 818
775 819
@@ -781,7 +825,6 @@ static void freeupval (lua_State *L, UpVal *uv) {
781 825
782 826
783static void freeobj (lua_State *L, GCObject *o) { 827static void freeobj (lua_State *L, GCObject *o) {
784 G(L)->GCtotalobjs--;
785 switch (o->tt) { 828 switch (o->tt) {
786 case LUA_VPROTO: 829 case LUA_VPROTO:
787 luaF_freeproto(L, gco2p(o)); 830 luaF_freeproto(L, gco2p(o));
@@ -835,12 +878,11 @@ static void freeobj (lua_State *L, GCObject *o) {
835** for next collection cycle. Return where to continue the traversal or 878** for next collection cycle. Return where to continue the traversal or
836** NULL if list is finished. 879** NULL if list is finished.
837*/ 880*/
838static GCObject **sweeplist (lua_State *L, GCObject **p, l_obj countin) { 881static GCObject **sweeplist (lua_State *L, GCObject **p, l_mem countin) {
839 global_State *g = G(L); 882 global_State *g = G(L);
840 int ow = otherwhite(g); 883 int ow = otherwhite(g);
841 l_obj i;
842 int white = luaC_white(g); /* current white */ 884 int white = luaC_white(g); /* current white */
843 for (i = 0; *p != NULL && i < countin; i++) { 885 while (*p != NULL && countin-- > 0) {
844 GCObject *curr = *p; 886 GCObject *curr = *p;
845 int marked = curr->marked; 887 int marked = curr->marked;
846 if (isdeadm(ow, marked)) { /* is 'curr' dead? */ 888 if (isdeadm(ow, marked)) { /* is 'curr' dead? */
@@ -1052,8 +1094,8 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
1052** approximately (marked * pause / 100). 1094** approximately (marked * pause / 100).
1053*/ 1095*/
1054static void setpause (global_State *g) { 1096static void setpause (global_State *g) {
1055 l_obj threshold = applygcparam(g, PAUSE, g->GCmarked); 1097 l_mem threshold = applygcparam(g, PAUSE, g->GCmarked);
1056 l_obj debt = threshold - gettotalobjs(g); 1098 l_mem debt = threshold - gettotalbytes(g);
1057 if (debt < 0) debt = 0; 1099 if (debt < 0) debt = 0;
1058 luaE_setdebt(g, debt); 1100 luaE_setdebt(g, debt);
1059} 1101}
@@ -1103,7 +1145,7 @@ static void sweep2old (lua_State *L, GCObject **p) {
1103*/ 1145*/
1104static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, 1146static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
1105 GCObject *limit, GCObject **pfirstold1, 1147 GCObject *limit, GCObject **pfirstold1,
1106 l_obj *paddedold) { 1148 l_mem *paddedold) {
1107 static const lu_byte nextage[] = { 1149 static const lu_byte nextage[] = {
1108 G_SURVIVAL, /* from G_NEW */ 1150 G_SURVIVAL, /* from G_NEW */
1109 G_OLD1, /* from G_SURVIVAL */ 1151 G_OLD1, /* from G_SURVIVAL */
@@ -1113,7 +1155,7 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
1113 G_TOUCHED1, /* from G_TOUCHED1 (do not change) */ 1155 G_TOUCHED1, /* from G_TOUCHED1 (do not change) */
1114 G_TOUCHED2 /* from G_TOUCHED2 (do not change) */ 1156 G_TOUCHED2 /* from G_TOUCHED2 (do not change) */
1115 }; 1157 };
1116 l_obj addedold = 0; 1158 l_mem addedold = 0;
1117 int white = luaC_white(g); 1159 int white = luaC_white(g);
1118 GCObject *curr; 1160 GCObject *curr;
1119 while ((curr = *p) != limit) { 1161 while ((curr = *p) != limit) {
@@ -1132,7 +1174,7 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
1132 lua_assert(age != G_OLD1); /* advanced in 'markold' */ 1174 lua_assert(age != G_OLD1); /* advanced in 'markold' */
1133 setage(curr, nextage[age]); 1175 setage(curr, nextage[age]);
1134 if (getage(curr) == G_OLD1) { 1176 if (getage(curr) == G_OLD1) {
1135 addedold++; /* one more object becoming old */ 1177 addedold += cast(l_mem, objsize(curr)); /* bytes becoming old */
1136 if (*pfirstold1 == NULL) 1178 if (*pfirstold1 == NULL)
1137 *pfirstold1 = curr; /* first OLD1 object in the list */ 1179 *pfirstold1 = curr; /* first OLD1 object in the list */
1138 } 1180 }
@@ -1257,9 +1299,9 @@ static void minor2inc (lua_State *L, global_State *g, lu_byte kind) {
1257** than 'minormajor'% of the number of lived objects after the last 1299** than 'minormajor'% of the number of lived objects after the last
1258** major collection. (That percentage is computed in 'limit'.) 1300** major collection. (That percentage is computed in 'limit'.)
1259*/ 1301*/
1260static int checkminormajor (global_State *g, l_obj addedold1) { 1302static int checkminormajor (global_State *g, l_mem addedold1) {
1261 l_obj step = applygcparam(g, MINORMUL, g->GCmajorminor); 1303 l_mem step = applygcparam(g, MINORMUL, g->GCmajorminor);
1262 l_obj limit = applygcparam(g, MINORMAJOR, g->GCmajorminor); 1304 l_mem limit = applygcparam(g, MINORMAJOR, g->GCmajorminor);
1263 return (addedold1 >= (step >> 1) || g->GCmarked >= limit); 1305 return (addedold1 >= (step >> 1) || g->GCmarked >= limit);
1264} 1306}
1265 1307
@@ -1269,8 +1311,8 @@ static int checkminormajor (global_State *g, l_obj addedold1) {
1269** sweep all lists and advance pointers. Finally, finish the collection. 1311** sweep all lists and advance pointers. Finally, finish the collection.
1270*/ 1312*/
1271static void youngcollection (lua_State *L, global_State *g) { 1313static void youngcollection (lua_State *L, global_State *g) {
1272 l_obj addedold1 = 0; 1314 l_mem addedold1 = 0;
1273 l_obj marked = g->GCmarked; /* preserve 'g->GCmarked' */ 1315 l_mem marked = g->GCmarked; /* preserve 'g->GCmarked' */
1274 GCObject **psurvival; /* to point to first non-dead survival object */ 1316 GCObject **psurvival; /* to point to first non-dead survival object */
1275 GCObject *dummy; /* dummy out parameter to 'sweepgen' */ 1317 GCObject *dummy; /* dummy out parameter to 'sweepgen' */
1276 lua_assert(g->gcstate == GCSpropagate); 1318 lua_assert(g->gcstate == GCSpropagate);
@@ -1346,7 +1388,9 @@ static void atomic2gen (lua_State *L, global_State *g) {
1346 1388
1347/* 1389/*
1348** Set debt for the next minor collection, which will happen when 1390** Set debt for the next minor collection, which will happen when
1349** total number of objects grows 'genminormul'%. 1391** total number of bytes grows 'genminormul'% in relation to
1392** the base, GCmajorminor, which is the number of bytes being used
1393** after the last major collection.
1350*/ 1394*/
1351static void setminordebt (global_State *g) { 1395static void setminordebt (global_State *g) {
1352 luaE_setdebt(g, applygcparam(g, MINORMUL, g->GCmajorminor)); 1396 luaE_setdebt(g, applygcparam(g, MINORMUL, g->GCmajorminor));
@@ -1404,18 +1448,18 @@ static void fullgen (lua_State *L, global_State *g) {
1404*/ 1448*/
1405static int checkmajorminor (lua_State *L, global_State *g) { 1449static int checkmajorminor (lua_State *L, global_State *g) {
1406 if (g->gckind == KGC_GENMAJOR) { /* generational mode? */ 1450 if (g->gckind == KGC_GENMAJOR) { /* generational mode? */
1407 l_obj numobjs = gettotalobjs(g); 1451 l_mem numbytes = gettotalbytes(g);
1408 l_obj addedobjs = numobjs - g->GCmajorminor; 1452 l_mem addedobjs = numbytes - g->GCmajorminor;
1409 l_obj limit = applygcparam(g, MAJORMINOR, addedobjs); 1453 l_mem limit = applygcparam(g, MAJORMINOR, addedobjs);
1410 l_obj tobecollected = numobjs - g->GCmarked; 1454 l_mem tobecollected = numbytes - g->GCmarked;
1411 if (tobecollected > limit) { 1455 if (tobecollected > limit) {
1412 atomic2gen(L, g); /* return to generational mode */ 1456 atomic2gen(L, g); /* return to generational mode */
1413 setminordebt(g); 1457 setminordebt(g);
1414 return 0; /* exit incremental collection */ 1458 return 1; /* exit incremental collection */
1415 } 1459 }
1416 } 1460 }
1417 g->GCmajorminor = g->GCmarked; /* prepare for next collection */ 1461 g->GCmajorminor = g->GCmarked; /* prepare for next collection */
1418 return 1; /* stay doing incremental collections */ 1462 return 0; /* stay doing incremental collections */
1419} 1463}
1420 1464
1421/* }====================================================== */ 1465/* }====================================================== */
@@ -1474,8 +1518,7 @@ void luaC_freeallobjects (lua_State *L) {
1474} 1518}
1475 1519
1476 1520
1477static l_obj atomic (lua_State *L) { 1521static void atomic (lua_State *L) {
1478 l_obj work = 0;
1479 global_State *g = G(L); 1522 global_State *g = G(L);
1480 GCObject *origweak, *origall; 1523 GCObject *origweak, *origall;
1481 GCObject *grayagain = g->grayagain; /* save original list */ 1524 GCObject *grayagain = g->grayagain; /* save original list */
@@ -1487,33 +1530,32 @@ static l_obj atomic (lua_State *L) {
1487 /* registry and global metatables may be changed by API */ 1530 /* registry and global metatables may be changed by API */
1488 markvalue(g, &g->l_registry); 1531 markvalue(g, &g->l_registry);
1489 markmt(g); /* mark global metatables */ 1532 markmt(g); /* mark global metatables */
1490 work += propagateall(g); /* empties 'gray' list */ 1533 propagateall(g); /* empties 'gray' list */
1491 /* remark occasional upvalues of (maybe) dead threads */ 1534 /* remark occasional upvalues of (maybe) dead threads */
1492 work += remarkupvals(g); 1535 remarkupvals(g);
1493 work += propagateall(g); /* propagate changes */ 1536 propagateall(g); /* propagate changes */
1494 g->gray = grayagain; 1537 g->gray = grayagain;
1495 work += propagateall(g); /* traverse 'grayagain' list */ 1538 propagateall(g); /* traverse 'grayagain' list */
1496 work += convergeephemerons(g); 1539 convergeephemerons(g);
1497 /* at this point, all strongly accessible objects are marked. */ 1540 /* at this point, all strongly accessible objects are marked. */
1498 /* Clear values from weak tables, before checking finalizers */ 1541 /* Clear values from weak tables, before checking finalizers */
1499 work += clearbyvalues(g, g->weak, NULL); 1542 clearbyvalues(g, g->weak, NULL);
1500 work += clearbyvalues(g, g->allweak, NULL); 1543 clearbyvalues(g, g->allweak, NULL);
1501 origweak = g->weak; origall = g->allweak; 1544 origweak = g->weak; origall = g->allweak;
1502 separatetobefnz(g, 0); /* separate objects to be finalized */ 1545 separatetobefnz(g, 0); /* separate objects to be finalized */
1503 work += markbeingfnz(g); /* mark objects that will be finalized */ 1546 markbeingfnz(g); /* mark objects that will be finalized */
1504 work += propagateall(g); /* remark, to propagate 'resurrection' */ 1547 propagateall(g); /* remark, to propagate 'resurrection' */
1505 work += convergeephemerons(g); 1548 convergeephemerons(g);
1506 /* at this point, all resurrected objects are marked. */ 1549 /* at this point, all resurrected objects are marked. */
1507 /* remove dead objects from weak tables */ 1550 /* remove dead objects from weak tables */
1508 work += clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron */ 1551 clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron */
1509 work += clearbykeys(g, g->allweak); /* clear keys from all 'allweak' */ 1552 clearbykeys(g, g->allweak); /* clear keys from all 'allweak' */
1510 /* clear values from resurrected weak tables */ 1553 /* clear values from resurrected weak tables */
1511 work += clearbyvalues(g, g->weak, origweak); 1554 clearbyvalues(g, g->weak, origweak);
1512 work += clearbyvalues(g, g->allweak, origall); 1555 clearbyvalues(g, g->allweak, origall);
1513 luaS_clearcache(g); 1556 luaS_clearcache(g);
1514 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ 1557 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
1515 lua_assert(g->gray == NULL); 1558 lua_assert(g->gray == NULL);
1516 return work;
1517} 1559}
1518 1560
1519 1561
@@ -1524,7 +1566,7 @@ static l_obj atomic (lua_State *L) {
1524static void sweepstep (lua_State *L, global_State *g, 1566static void sweepstep (lua_State *L, global_State *g,
1525 lu_byte nextstate, GCObject **nextlist, int fast) { 1567 lu_byte nextstate, GCObject **nextlist, int fast) {
1526 if (g->sweepgc) 1568 if (g->sweepgc)
1527 g->sweepgc = sweeplist(L, g->sweepgc, fast ? MAX_LOBJ : GCSWEEPMAX); 1569 g->sweepgc = sweeplist(L, g->sweepgc, fast ? MAX_LMEM : GCSWEEPMAX);
1528 else { /* enter next state */ 1570 else { /* enter next state */
1529 g->gcstate = nextstate; 1571 g->gcstate = nextstate;
1530 g->sweepgc = nextlist; 1572 g->sweepgc = nextlist;
@@ -1544,72 +1586,80 @@ static void sweepstep (lua_State *L, global_State *g,
1544** That avoids traversing twice some objects, such as threads and 1586** That avoids traversing twice some objects, such as threads and
1545** weak tables. 1587** weak tables.
1546*/ 1588*/
1547static l_obj singlestep (lua_State *L, int fast) { 1589
1590#define step2pause -3 /* finished collection; entered pause state */
1591#define atomicstep -2 /* atomic step */
1592#define step2minor -1 /* moved to minor collections */
1593
1594
1595static l_mem singlestep (lua_State *L, int fast) {
1548 global_State *g = G(L); 1596 global_State *g = G(L);
1549 l_obj work; 1597 l_mem stepresult;
1550 lua_assert(!g->gcstopem); /* collector is not reentrant */ 1598 lua_assert(!g->gcstopem); /* collector is not reentrant */
1551 g->gcstopem = 1; /* no emergency collections while collecting */ 1599 g->gcstopem = 1; /* no emergency collections while collecting */
1552 switch (g->gcstate) { 1600 switch (g->gcstate) {
1553 case GCSpause: { 1601 case GCSpause: {
1554 restartcollection(g); 1602 restartcollection(g);
1555 g->gcstate = GCSpropagate; 1603 g->gcstate = GCSpropagate;
1556 work = 1; 1604 stepresult = 1;
1557 break; 1605 break;
1558 } 1606 }
1559 case GCSpropagate: { 1607 case GCSpropagate: {
1560 if (fast || g->gray == NULL) { 1608 if (fast || g->gray == NULL) {
1561 g->gcstate = GCSenteratomic; /* finish propagate phase */ 1609 g->gcstate = GCSenteratomic; /* finish propagate phase */
1562 work = 0; 1610 stepresult = 1;
1563 }
1564 else {
1565 propagatemark(g); /* traverse one gray object */
1566 work = 1;
1567 } 1611 }
1612 else
1613 stepresult = propagatemark(g); /* traverse one gray object */
1568 break; 1614 break;
1569 } 1615 }
1570 case GCSenteratomic: { 1616 case GCSenteratomic: {
1571 work = atomic(L); 1617 atomic(L);
1572 if (checkmajorminor(L, g)) 1618 if (checkmajorminor(L, g))
1619 stepresult = step2minor;
1620 else {
1573 entersweep(L); 1621 entersweep(L);
1622 stepresult = atomicstep;
1623 }
1574 break; 1624 break;
1575 } 1625 }
1576 case GCSswpallgc: { /* sweep "regular" objects */ 1626 case GCSswpallgc: { /* sweep "regular" objects */
1577 sweepstep(L, g, GCSswpfinobj, &g->finobj, fast); 1627 sweepstep(L, g, GCSswpfinobj, &g->finobj, fast);
1578 work = GCSWEEPMAX; 1628 stepresult = GCSWEEPMAX;
1579 break; 1629 break;
1580 } 1630 }
1581 case GCSswpfinobj: { /* sweep objects with finalizers */ 1631 case GCSswpfinobj: { /* sweep objects with finalizers */
1582 sweepstep(L, g, GCSswptobefnz, &g->tobefnz, fast); 1632 sweepstep(L, g, GCSswptobefnz, &g->tobefnz, fast);
1583 work = GCSWEEPMAX; 1633 stepresult = GCSWEEPMAX;
1584 break; 1634 break;
1585 } 1635 }
1586 case GCSswptobefnz: { /* sweep objects to be finalized */ 1636 case GCSswptobefnz: { /* sweep objects to be finalized */
1587 sweepstep(L, g, GCSswpend, NULL, fast); 1637 sweepstep(L, g, GCSswpend, NULL, fast);
1588 work = GCSWEEPMAX; 1638 stepresult = GCSWEEPMAX;
1589 break; 1639 break;
1590 } 1640 }
1591 case GCSswpend: { /* finish sweeps */ 1641 case GCSswpend: { /* finish sweeps */
1592 checkSizes(L, g); 1642 checkSizes(L, g);
1593 g->gcstate = GCScallfin; 1643 g->gcstate = GCScallfin;
1594 work = 0; 1644 stepresult = GCSWEEPMAX;
1595 break; 1645 break;
1596 } 1646 }
1597 case GCScallfin: { /* call finalizers */ 1647 case GCScallfin: { /* call finalizers */
1598 if (g->tobefnz && !g->gcemergency) { 1648 if (g->tobefnz && !g->gcemergency) {
1599 g->gcstopem = 0; /* ok collections during finalizers */ 1649 g->gcstopem = 0; /* ok collections during finalizers */
1600 GCTM(L); /* call one finalizer */ 1650 GCTM(L); /* call one finalizer */
1601 work = 1; 1651 stepresult = CWUFIN;
1602 } 1652 }
1603 else { /* emergency mode or no more finalizers */ 1653 else { /* emergency mode or no more finalizers */
1604 g->gcstate = GCSpause; /* finish collection */ 1654 g->gcstate = GCSpause; /* finish collection */
1605 work = 0; 1655 stepresult = step2pause;
1606 } 1656 }
1607 break; 1657 break;
1608 } 1658 }
1609 default: lua_assert(0); return 0; 1659 default: lua_assert(0); return 0;
1610 } 1660 }
1611 g->gcstopem = 0; 1661 g->gcstopem = 0;
1612 return work; 1662 return stepresult;
1613} 1663}
1614 1664
1615 1665
@@ -1635,25 +1685,26 @@ void luaC_runtilstate (lua_State *L, int state, int fast) {
1635** controls when next step will be performed. 1685** controls when next step will be performed.
1636*/ 1686*/
1637static void incstep (lua_State *L, global_State *g) { 1687static void incstep (lua_State *L, global_State *g) {
1638 l_obj stepsize = applygcparam(g, STEPSIZE, 100); 1688 l_mem stepsize = applygcparam(g, STEPSIZE, 100);
1639 l_obj work2do = applygcparam(g, STEPMUL, stepsize); 1689 l_mem work2do = applygcparam(g, STEPMUL, stepsize);
1640 int fast = 0; 1690 l_mem stres;
1641 if (work2do == 0) { /* special case: do a full collection */ 1691 int fast = (work2do == 0); /* special case: do a full collection */
1642 work2do = MAX_LOBJ; /* do unlimited work */ 1692 do { /* repeat until enough work */
1643 fast = 1; 1693 stres = singlestep(L, fast); /* perform one single step */
1644 } 1694 if (stres == step2minor) /* returned to minor collections? */
1645 do { /* repeat until pause or enough work */
1646 l_obj work = singlestep(L, fast); /* perform one single step */
1647 if (g->gckind == KGC_GENMINOR) /* returned to minor collections? */
1648 return; /* nothing else to be done here */ 1695 return; /* nothing else to be done here */
1649 work2do -= work; 1696 else if (stres == step2pause || (stres == atomicstep && !fast))
1650 } while (work2do > 0 && g->gcstate != GCSpause); 1697 break; /* end of cycle or atomic */
1698 else
1699 work2do -= stres;
1700 } while (fast || work2do > 0);
1651 if (g->gcstate == GCSpause) 1701 if (g->gcstate == GCSpause)
1652 setpause(g); /* pause until next cycle */ 1702 setpause(g); /* pause until next cycle */
1653 else 1703 else
1654 luaE_setdebt(g, stepsize); 1704 luaE_setdebt(g, stepsize);
1655} 1705}
1656 1706
1707
1657/* 1708/*
1658** Performs a basic GC step if collector is running. (If collector is 1709** Performs a basic GC step if collector is running. (If collector is
1659** not running, set a reasonable debt to avoid it being called at 1710** not running, set a reasonable debt to avoid it being called at
@@ -1663,17 +1714,23 @@ void luaC_step (lua_State *L) {
1663 global_State *g = G(L); 1714 global_State *g = G(L);
1664 lua_assert(!g->gcemergency); 1715 lua_assert(!g->gcemergency);
1665 if (!gcrunning(g)) /* not running? */ 1716 if (!gcrunning(g)) /* not running? */
1666 luaE_setdebt(g, 2000); 1717 luaE_setdebt(g, 20000);
1667 else { 1718 else {
1719// printf("mem: %ld kind: %s ", gettotalbytes(g),
1720// g->gckind == KGC_INC ? "inc" : g->gckind == KGC_GENMAJOR ? "genmajor" :
1721// "genminor");
1668 switch (g->gckind) { 1722 switch (g->gckind) {
1669 case KGC_INC: case KGC_GENMAJOR: 1723 case KGC_INC: case KGC_GENMAJOR:
1724// printf("(%d -> ", g->gcstate);
1670 incstep(L, g); 1725 incstep(L, g);
1726// printf("%d) ", g->gcstate);
1671 break; 1727 break;
1672 case KGC_GENMINOR: 1728 case KGC_GENMINOR:
1673 youngcollection(L, g); 1729 youngcollection(L, g);
1674 setminordebt(g); 1730 setminordebt(g);
1675 break; 1731 break;
1676 } 1732 }
1733// printf("-> mem: %ld debt: %ld\n", gettotalbytes(g), g->GCdebt);
1677 } 1734 }
1678} 1735}
1679 1736
@@ -1692,7 +1749,7 @@ static void fullinc (lua_State *L, global_State *g) {
1692 luaC_runtilstate(L, GCSpause, 1); 1749 luaC_runtilstate(L, GCSpause, 1);
1693 luaC_runtilstate(L, GCScallfin, 1); /* run up to finalizers */ 1750 luaC_runtilstate(L, GCScallfin, 1); /* run up to finalizers */
1694 /* 'marked' must be correct after a full GC cycle */ 1751 /* 'marked' must be correct after a full GC cycle */
1695 lua_assert(g->GCmarked == gettotalobjs(g)); 1752 /* lua_assert(g->GCmarked == gettotalobjs(g)); ??? */
1696 luaC_runtilstate(L, GCSpause, 1); /* finish collection */ 1753 luaC_runtilstate(L, GCSpause, 1); /* finish collection */
1697 setpause(g); 1754 setpause(g);
1698} 1755}
diff --git a/lgc.h b/lgc.h
index a30755d0..0b16ac7f 100644
--- a/lgc.h
+++ b/lgc.h
@@ -23,8 +23,9 @@
23** never point to a white one. Moreover, any gray object must be in a 23** never point to a white one. Moreover, any gray object must be in a
24** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it 24** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it
25** can be visited again before finishing the collection cycle. (Open 25** can be visited again before finishing the collection cycle. (Open
26** upvalues are an exception to this rule.) These lists have no meaning 26** upvalues are an exception to this rule, as they are attached to
27** when the invariant is not being enforced (e.g., sweep phase). 27** a corresponding thread.) These lists have no meaning when the
28** invariant is not being enforced (e.g., sweep phase).
28*/ 29*/
29 30
30 31
@@ -48,10 +49,10 @@
48 49
49/* 50/*
50** macro to tell when main invariant (white objects cannot point to black 51** macro to tell when main invariant (white objects cannot point to black
51** ones) must be kept. During a collection, the sweep 52** ones) must be kept. During a collection, the sweep phase may break
52** phase may break the invariant, as objects turned white may point to 53** the invariant, as objects turned white may point to still-black
53** still-black objects. The invariant is restored when sweep ends and 54** objects. The invariant is restored when sweep ends and all objects
54** all objects are white again. 55** are white again.
55*/ 56*/
56 57
57#define keepinvariant(g) ((g)->gcstate <= GCSatomic) 58#define keepinvariant(g) ((g)->gcstate <= GCSatomic)
@@ -163,34 +164,37 @@
163 164
164/* 165/*
165** Minor collections will shift to major ones after LUAI_MINORMAJOR% 166** Minor collections will shift to major ones after LUAI_MINORMAJOR%
166** objects become old. 167** bytes become old.
167*/ 168*/
168#define LUAI_MINORMAJOR 100 169#define LUAI_MINORMAJOR 100
169 170
170/* 171/*
171** Major collections will shift to minor ones after a collection 172** Major collections will shift to minor ones after a collection
172** collects at least LUAI_MAJORMINOR% of the new objects. 173** collects at least LUAI_MAJORMINOR% of the new bytes.
173*/ 174*/
174#define LUAI_MAJORMINOR 50 175#define LUAI_MAJORMINOR 50
175 176
176/* 177/*
177** A young (minor) collection will run after creating LUAI_GENMINORMUL% 178** A young (minor) collection will run after creating LUAI_GENMINORMUL%
178** new objects. 179** new bytes.
179*/ 180*/
180#define LUAI_GENMINORMUL 25 181#define LUAI_GENMINORMUL 25
181 182
182 183
183/* incremental */ 184/* incremental */
184 185
185/* Number of objects must be LUAI_GCPAUSE% before starting new cycle */ 186/* Number of bytes must be LUAI_GCPAUSE% before starting new cycle */
186#define LUAI_GCPAUSE 200 187#define LUAI_GCPAUSE 200
187 188
188/* Step multiplier. (Roughly, the collector handles LUAI_GCMUL% objects 189/*
189 for each new allocated object.) */ 190** Step multiplier: The collector handles LUAI_GCMUL% work units for
190#define LUAI_GCMUL 200 191** each new allocated byte. (Each "work unit" corresponds roughly to
192** sweeping or marking one object.)
193*/
194#define LUAI_GCMUL 20 /* ??? */
191 195
192/* How many objects to allocate before next GC step */ 196/* How many bytes to allocate before next GC step */
193#define LUAI_GCSTEPSIZE 250 197#define LUAI_GCSTEPSIZE (250 * sizeof(void*))
194 198
195 199
196#define setgcparam(g,p,v) (g->gcparams[LUA_GCP##p] = luaO_codeparam(v)) 200#define setgcparam(g,p,v) (g->gcparams[LUA_GCP##p] = luaO_codeparam(v))
diff --git a/llimits.h b/llimits.h
index d7ae065b..f189048c 100644
--- a/llimits.h
+++ b/llimits.h
@@ -16,25 +16,24 @@
16 16
17 17
18/* 18/*
19** 'lu_mem' is an unsigned integer big enough to count the total memory 19** 'l_mem' is a signed integer big enough to count the total memory
20** used by Lua (in bytes). 'l_obj' is a signed integer big enough to 20** used by Lua. (It is signed due to the use of debt in several
21** count the total number of objects used by Lua. (It is signed due 21** computations.) Usually, 'ptrdiff_t' should work, but we use 'long'
22** to the use of debt in several computations.) Usually, 'size_t' and 22** for 16-bit machines.
23** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines.
24*/ 23*/
25#if defined(LUAI_MEM) /* { external definitions? */ 24#if defined(LUAI_MEM) /* { external definitions? */
25typedef LUAI_MEM l_mem;
26typedef LUAI_UMEM lu_mem; 26typedef LUAI_UMEM lu_mem;
27typedef LUAI_MEM l_obj;
28#elif LUAI_IS32INT /* }{ */ 27#elif LUAI_IS32INT /* }{ */
28typedef ptrdiff_t l_mem;
29typedef size_t lu_mem; 29typedef size_t lu_mem;
30typedef ptrdiff_t l_obj;
31#else /* 16-bit ints */ /* }{ */ 30#else /* 16-bit ints */ /* }{ */
31typedef long l_mem;
32typedef unsigned long lu_mem; 32typedef unsigned long lu_mem;
33typedef long l_obj;
34#endif /* } */ 33#endif /* } */
35 34
36#define MAX_LOBJ \ 35#define MAX_LMEM \
37 cast(l_obj, (cast(lu_mem, 1) << (sizeof(l_obj) * CHAR_BIT - 1)) - 1) 36 cast(l_mem, (cast(lu_mem, 1) << (sizeof(l_mem) * 8 - 1)) - 1)
38 37
39 38
40/* chars used as small naturals (so that 'char' is reserved for characters) */ 39/* chars used as small naturals (so that 'char' is reserved for characters) */
diff --git a/lmem.c b/lmem.c
index f18ea172..de8503d9 100644
--- a/lmem.c
+++ b/lmem.c
@@ -151,7 +151,7 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
151 global_State *g = G(L); 151 global_State *g = G(L);
152 lua_assert((osize == 0) == (block == NULL)); 152 lua_assert((osize == 0) == (block == NULL));
153 callfrealloc(g, block, osize, 0); 153 callfrealloc(g, block, osize, 0);
154 g->GCtotalbytes -= osize; 154 g->GCdebt += cast(l_mem, osize);
155} 155}
156 156
157 157
@@ -181,10 +181,10 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
181 if (l_unlikely(newblock == NULL && nsize > 0)) { 181 if (l_unlikely(newblock == NULL && nsize > 0)) {
182 newblock = tryagain(L, block, osize, nsize); 182 newblock = tryagain(L, block, osize, nsize);
183 if (newblock == NULL) /* still no memory? */ 183 if (newblock == NULL) /* still no memory? */
184 return NULL; /* do not update 'GCtotalbytes' */ 184 return NULL; /* do not update 'GCdebt' */
185 } 185 }
186 lua_assert((nsize == 0) == (newblock == NULL)); 186 lua_assert((nsize == 0) == (newblock == NULL));
187 g->GCtotalbytes += nsize - osize; 187 g->GCdebt -= cast(l_mem, nsize) - cast(l_mem, osize);
188 return newblock; 188 return newblock;
189} 189}
190 190
@@ -209,7 +209,7 @@ void *luaM_malloc_ (lua_State *L, size_t size, int tag) {
209 if (newblock == NULL) 209 if (newblock == NULL)
210 luaM_error(L); 210 luaM_error(L);
211 } 211 }
212 g->GCtotalbytes += size; 212 g->GCdebt -= cast(l_mem, size);
213 return newblock; 213 return newblock;
214 } 214 }
215} 215}
diff --git a/lobject.c b/lobject.c
index f7159547..1ca03e76 100644
--- a/lobject.c
+++ b/lobject.c
@@ -85,7 +85,7 @@ lu_byte luaO_codeparam (unsigned int p) {
85** more significant bits, as long as the multiplication does not 85** more significant bits, as long as the multiplication does not
86** overflow, so we check which order is best. 86** overflow, so we check which order is best.
87*/ 87*/
88l_obj luaO_applyparam (lu_byte p, l_obj x) { 88l_mem luaO_applyparam (lu_byte p, l_mem x) {
89 unsigned int m = p & 0xF; /* mantissa */ 89 unsigned int m = p & 0xF; /* mantissa */
90 int e = (p >> 4); /* exponent */ 90 int e = (p >> 4); /* exponent */
91 if (e > 0) { /* normalized? */ 91 if (e > 0) { /* normalized? */
@@ -94,19 +94,19 @@ l_obj luaO_applyparam (lu_byte p, l_obj x) {
94 } 94 }
95 e -= 7; /* correct excess-7 */ 95 e -= 7; /* correct excess-7 */
96 if (e >= 0) { 96 if (e >= 0) {
97 if (x < (MAX_LOBJ / 0x1F) >> e) /* no overflow? */ 97 if (x < (MAX_LMEM / 0x1F) >> e) /* no overflow? */
98 return (x * m) << e; /* order doesn't matter here */ 98 return (x * m) << e; /* order doesn't matter here */
99 else /* real overflow */ 99 else /* real overflow */
100 return MAX_LOBJ; 100 return MAX_LMEM;
101 } 101 }
102 else { /* negative exponent */ 102 else { /* negative exponent */
103 e = -e; 103 e = -e;
104 if (x < MAX_LOBJ / 0x1F) /* multiplication cannot overflow? */ 104 if (x < MAX_LMEM / 0x1F) /* multiplication cannot overflow? */
105 return (x * m) >> e; /* multiplying first gives more precision */ 105 return (x * m) >> e; /* multiplying first gives more precision */
106 else if ((x >> e) < MAX_LOBJ / 0x1F) /* cannot overflow after shift? */ 106 else if ((x >> e) < MAX_LMEM / 0x1F) /* cannot overflow after shift? */
107 return (x >> e) * m; 107 return (x >> e) * m;
108 else /* real overflow */ 108 else /* real overflow */
109 return MAX_LOBJ; 109 return MAX_LMEM;
110 } 110 }
111} 111}
112 112
diff --git a/lobject.h b/lobject.h
index fb66dff7..2411410b 100644
--- a/lobject.h
+++ b/lobject.h
@@ -838,7 +838,7 @@ typedef struct Table {
838LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x); 838LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x);
839LUAI_FUNC lu_byte luaO_ceillog2 (unsigned int x); 839LUAI_FUNC lu_byte luaO_ceillog2 (unsigned int x);
840LUAI_FUNC lu_byte luaO_codeparam (unsigned int p); 840LUAI_FUNC lu_byte luaO_codeparam (unsigned int p);
841LUAI_FUNC l_obj luaO_applyparam (lu_byte p, l_obj x); 841LUAI_FUNC l_mem luaO_applyparam (lu_byte p, l_mem x);
842 842
843LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1, 843LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1,
844 const TValue *p2, TValue *res); 844 const TValue *p2, TValue *res);
diff --git a/lstate.c b/lstate.c
index f4c9081d..8e7c8b86 100644
--- a/lstate.c
+++ b/lstate.c
@@ -77,12 +77,12 @@ typedef struct LG {
77** objects (GCtotalobjs - GCdebt) invariant and avoiding overflows in 77** objects (GCtotalobjs - GCdebt) invariant and avoiding overflows in
78** 'GCtotalobjs'. 78** 'GCtotalobjs'.
79*/ 79*/
80void luaE_setdebt (global_State *g, l_obj debt) { 80void luaE_setdebt (global_State *g, l_mem debt) {
81 l_obj tb = gettotalobjs(g); 81 l_mem tb = gettotalbytes(g);
82 lua_assert(tb > 0); 82 lua_assert(tb > 0);
83 if (debt > MAX_LOBJ - tb) 83 if (debt > MAX_LMEM - tb)
84 debt = MAX_LOBJ - tb; /* will make GCtotalobjs == MAX_LOBJ */ 84 debt = MAX_LMEM - tb; /* will make GCtotalbytes == MAX_LMEM */
85 g->GCtotalobjs = tb + debt; 85 g->GCtotalbytes = tb + debt;
86 g->GCdebt = debt; 86 g->GCdebt = debt;
87} 87}
88 88
@@ -269,8 +269,7 @@ static void close_state (lua_State *L) {
269 } 269 }
270 luaM_freearray(L, G(L)->strt.hash, cast_sizet(G(L)->strt.size)); 270 luaM_freearray(L, G(L)->strt.hash, cast_sizet(G(L)->strt.size));
271 freestack(L); 271 freestack(L);
272 lua_assert(g->GCtotalbytes == sizeof(LG)); 272 lua_assert(gettotalbytes(g) == sizeof(LG));
273 lua_assert(gettotalobjs(g) == 1);
274 (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ 273 (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */
275} 274}
276 275
@@ -379,7 +378,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud, unsigned seed) {
379 g->weak = g->ephemeron = g->allweak = NULL; 378 g->weak = g->ephemeron = g->allweak = NULL;
380 g->twups = NULL; 379 g->twups = NULL;
381 g->GCtotalbytes = sizeof(LG); 380 g->GCtotalbytes = sizeof(LG);
382 g->GCtotalobjs = 1;
383 g->GCmarked = 0; 381 g->GCmarked = 0;
384 g->GCdebt = 0; 382 g->GCdebt = 0;
385 setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */ 383 setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */
diff --git a/lstate.h b/lstate.h
index 6aa02889..2a03576d 100644
--- a/lstate.h
+++ b/lstate.h
@@ -274,11 +274,10 @@ struct CallInfo {
274typedef struct global_State { 274typedef struct global_State {
275 lua_Alloc frealloc; /* function to reallocate memory */ 275 lua_Alloc frealloc; /* function to reallocate memory */
276 void *ud; /* auxiliary data to 'frealloc' */ 276 void *ud; /* auxiliary data to 'frealloc' */
277 lu_mem GCtotalbytes; /* number of bytes currently allocated */ 277 l_mem GCtotalbytes; /* number of bytes currently allocated + debt */
278 l_obj GCtotalobjs; /* total number of objects allocated + GCdebt */ 278 l_mem GCdebt; /* bytes counted but not yet allocated */
279 l_obj GCdebt; /* objects counted but not yet allocated */ 279 l_mem GCmarked; /* number of objects marked in a GC cycle */
280 l_obj GCmarked; /* number of objects marked in a GC cycle */ 280 l_mem GCmajorminor; /* auxiliary counter to control major-minor shifts */
281 l_obj GCmajorminor; /* auxiliary counter to control major-minor shifts */
282 stringtable strt; /* hash table for strings */ 281 stringtable strt; /* hash table for strings */
283 TValue l_registry; 282 TValue l_registry;
284 TValue nilvalue; /* a nil value */ 283 TValue nilvalue; /* a nil value */
@@ -411,11 +410,11 @@ union GCUnion {
411#define obj2gco(v) check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc)) 410#define obj2gco(v) check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc))
412 411
413 412
414/* actual number of total objects allocated */ 413/* actual number of total memory allocated */
415#define gettotalobjs(g) ((g)->GCtotalobjs - (g)->GCdebt) 414#define gettotalbytes(g) ((g)->GCtotalbytes - (g)->GCdebt)
416 415
417 416
418LUAI_FUNC void luaE_setdebt (global_State *g, l_obj debt); 417LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
419LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); 418LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
420LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); 419LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
421LUAI_FUNC void luaE_shrinkCI (lua_State *L); 420LUAI_FUNC void luaE_shrinkCI (lua_State *L);
diff --git a/ltests.c b/ltests.c
index 7d134e2d..91bce2a1 100644
--- a/ltests.c
+++ b/ltests.c
@@ -537,7 +537,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead,
537} 537}
538 538
539 539
540static l_obj checkgraylist (global_State *g, GCObject *o) { 540static l_mem checkgraylist (global_State *g, GCObject *o) {
541 int total = 0; /* count number of elements in the list */ 541 int total = 0; /* count number of elements in the list */
542 cast_void(g); /* better to keep it if we need to print an object */ 542 cast_void(g); /* better to keep it if we need to print an object */
543 while (o) { 543 while (o) {
@@ -566,8 +566,8 @@ static l_obj checkgraylist (global_State *g, GCObject *o) {
566/* 566/*
567** Check objects in gray lists. 567** Check objects in gray lists.
568*/ 568*/
569static l_obj checkgrays (global_State *g) { 569static l_mem checkgrays (global_State *g) {
570 l_obj total = 0; /* count number of elements in all lists */ 570 l_mem total = 0; /* count number of elements in all lists */
571 if (!keepinvariant(g)) return total; 571 if (!keepinvariant(g)) return total;
572 total += checkgraylist(g, g->gray); 572 total += checkgraylist(g, g->gray);
573 total += checkgraylist(g, g->grayagain); 573 total += checkgraylist(g, g->grayagain);
@@ -583,7 +583,7 @@ static l_obj checkgrays (global_State *g) {
583** 'count' and check its TESTBIT. (It must have been previously set by 583** 'count' and check its TESTBIT. (It must have been previously set by
584** 'checkgraylist'.) 584** 'checkgraylist'.)
585*/ 585*/
586static void incifingray (global_State *g, GCObject *o, l_obj *count) { 586static void incifingray (global_State *g, GCObject *o, l_mem *count) {
587 if (!keepinvariant(g)) 587 if (!keepinvariant(g))
588 return; /* gray lists not being kept in these phases */ 588 return; /* gray lists not being kept in these phases */
589 if (o->tt == LUA_VUPVAL) { 589 if (o->tt == LUA_VUPVAL) {
@@ -600,10 +600,10 @@ static void incifingray (global_State *g, GCObject *o, l_obj *count) {
600} 600}
601 601
602 602
603static l_obj checklist (global_State *g, int maybedead, int tof, 603static l_mem checklist (global_State *g, int maybedead, int tof,
604 GCObject *newl, GCObject *survival, GCObject *old, GCObject *reallyold) { 604 GCObject *newl, GCObject *survival, GCObject *old, GCObject *reallyold) {
605 GCObject *o; 605 GCObject *o;
606 l_obj total = 0; /* number of object that should be in gray lists */ 606 l_mem total = 0; /* number of object that should be in gray lists */
607 for (o = newl; o != survival; o = o->next) { 607 for (o = newl; o != survival; o = o->next) {
608 checkobject(g, o, maybedead, G_NEW); 608 checkobject(g, o, maybedead, G_NEW);
609 incifingray(g, o, &total); 609 incifingray(g, o, &total);
@@ -632,8 +632,8 @@ int lua_checkmemory (lua_State *L) {
632 global_State *g = G(L); 632 global_State *g = G(L);
633 GCObject *o; 633 GCObject *o;
634 int maybedead; 634 int maybedead;
635 l_obj totalin; /* total of objects that are in gray lists */ 635 l_mem totalin; /* total of objects that are in gray lists */
636 l_obj totalshould; /* total of objects that should be in gray lists */ 636 l_mem totalshould; /* total of objects that should be in gray lists */
637 if (keepinvariant(g)) { 637 if (keepinvariant(g)) {
638 assert(!iswhite(g->mainthread)); 638 assert(!iswhite(g->mainthread));
639 assert(!iswhite(gcvalue(&g->l_registry))); 639 assert(!iswhite(gcvalue(&g->l_registry)));
@@ -1040,7 +1040,7 @@ static int table_query (lua_State *L) {
1040 1040
1041static int query_GCparams (lua_State *L) { 1041static int query_GCparams (lua_State *L) {
1042 global_State *g = G(L); 1042 global_State *g = G(L);
1043 lua_pushinteger(L, cast(lua_Integer, gettotalobjs(g))); 1043 lua_pushinteger(L, cast(lua_Integer, gettotalbytes(g)));
1044 lua_pushinteger(L, cast(lua_Integer, g->GCdebt)); 1044 lua_pushinteger(L, cast(lua_Integer, g->GCdebt));
1045 lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MINORMUL, 100))); 1045 lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MINORMUL, 100)));
1046 lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MAJORMINOR, 100))); 1046 lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MAJORMINOR, 100)));