summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-05-26 16:14:29 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-05-26 16:14:29 -0300
commit72d82a296c1430a1d2bb3fac8ed8cbfb97868707 (patch)
tree4ea80148c5f1bfd38f0e7ca1cb8ef82e00e7e19c
parent4804bbd9bbfb89deb8a6c7dc2bc65601a701222b (diff)
downloadlua-72d82a296c1430a1d2bb3fac8ed8cbfb97868707.tar.gz
lua-72d82a296c1430a1d2bb3fac8ed8cbfb97868707.tar.bz2
lua-72d82a296c1430a1d2bb3fac8ed8cbfb97868707.zip
revamping the incremental collector
Some simplifications (not counting bytes, couting only slots visited; no more 'gcfinnum'); more GC parameters; using vararg in 'lua_gc' to set parameters in different GC modes
-rw-r--r--lapi.c44
-rw-r--r--lbaselib.c39
-rw-r--r--lgc.c278
-rw-r--r--lgc.h20
-rw-r--r--lstate.c12
-rw-r--r--lstate.h9
-rw-r--r--lua.h4
7 files changed, 208 insertions, 198 deletions
diff --git a/lapi.c b/lapi.c
index e7d59b45..0c109e1e 100644
--- a/lapi.c
+++ b/lapi.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lapi.c,v 2.266 2017/05/11 18:57:46 roberto Exp roberto $ 2** $Id: lapi.c,v 2.267 2017/05/18 12:34:58 roberto Exp roberto $
3** Lua API 3** Lua API
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -1046,17 +1046,12 @@ LUA_API int lua_status (lua_State *L) {
1046/* 1046/*
1047** Garbage-collection function 1047** Garbage-collection function
1048*/ 1048*/
1049 1049LUA_API int lua_gc (lua_State *L, int what, ...) {
1050#if !defined(LUA_GENMAJORMUL) 1050 va_list argp;
1051#define LUA_GENMAJORMUL 100
1052#define LUA_GENMINORMUL 5
1053#endif
1054
1055LUA_API int lua_gc (lua_State *L, int what, int data) {
1056 int res = 0; 1051 int res = 0;
1057 global_State *g; 1052 global_State *g = G(L);
1058 lua_lock(L); 1053 lua_lock(L);
1059 g = G(L); 1054 va_start(argp, what);
1060 switch (what) { 1055 switch (what) {
1061 case LUA_GCSTOP: { 1056 case LUA_GCSTOP: {
1062 g->gcrunning = 0; 1057 g->gcrunning = 0;
@@ -1081,11 +1076,12 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
1081 break; 1076 break;
1082 } 1077 }
1083 case LUA_GCSTEP: { 1078 case LUA_GCSTEP: {
1079 int data = va_arg(argp, int);
1084 l_mem debt = 1; /* =1 to signal that it did an actual step */ 1080 l_mem debt = 1; /* =1 to signal that it did an actual step */
1085 lu_byte oldrunning = g->gcrunning; 1081 lu_byte oldrunning = g->gcrunning;
1086 g->gcrunning = 1; /* allow GC to run */ 1082 g->gcrunning = 1; /* allow GC to run */
1087 if (data == 0) { 1083 if (data == 0) {
1088 luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */ 1084 luaE_setdebt(g, 0); /* do a basic step */
1089 luaC_step(L); 1085 luaC_step(L);
1090 } 1086 }
1091 else { /* add 'data' to total debt */ 1087 else { /* add 'data' to total debt */
@@ -1099,14 +1095,15 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
1099 break; 1095 break;
1100 } 1096 }
1101 case LUA_GCSETPAUSE: { 1097 case LUA_GCSETPAUSE: {
1102 res = g->gcpause; 1098 int data = va_arg(argp, int);
1103 g->gcpause = data; 1099 res = g->gcpause + 100;
1100 g->gcpause = (data >= 100) ? data - 100 : 0;
1104 break; 1101 break;
1105 } 1102 }
1106 case LUA_GCSETSTEPMUL: { 1103 case LUA_GCSETSTEPMUL: {
1107 res = g->gcstepmul; 1104 int data = va_arg(argp, int);
1108 if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */ 1105 res = g->gcstepmul * 10;
1109 g->gcstepmul = data; 1106 g->gcstepmul = data / 10;
1110 break; 1107 break;
1111 } 1108 }
1112 case LUA_GCISRUNNING: { 1109 case LUA_GCISRUNNING: {
@@ -1114,19 +1111,26 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
1114 break; 1111 break;
1115 } 1112 }
1116 case LUA_GCGEN: { 1113 case LUA_GCGEN: {
1117 lu_byte aux = data & 0xff; 1114 int minormul = va_arg(argp, int);
1118 g->genminormul = (aux == 0) ? LUA_GENMINORMUL : aux; 1115 int majormul = va_arg(argp, int);
1119 aux = (data >> 8) & 0xff; 1116 g->genminormul = (minormul == 0) ? LUAI_GENMINORMUL : minormul;
1120 g->genmajormul = (aux == 0) ? LUA_GENMAJORMUL : aux; 1117 g->genmajormul = (majormul == 0) ? LUAI_GENMAJORMUL : majormul;
1121 luaC_changemode(L, KGC_GEN); 1118 luaC_changemode(L, KGC_GEN);
1122 break; 1119 break;
1123 } 1120 }
1124 case LUA_GCINC: { 1121 case LUA_GCINC: {
1122 int pause = va_arg(argp, int);
1123 int stepmul = va_arg(argp, int);
1124 int stepsize = va_arg(argp, int);
1125 g->gcpause = (pause == 0) ? LUAI_GCPAUSE : pause;
1126 g->gcstepmul = (stepmul == 0) ? LUAI_GCMUL : stepmul;
1127 g->gcstepsize = (stepsize == 0) ? LUAI_GCSTEPSIZE : stepsize;
1125 luaC_changemode(L, KGC_INC); 1128 luaC_changemode(L, KGC_INC);
1126 break; 1129 break;
1127 } 1130 }
1128 default: res = -1; /* invalid option */ 1131 default: res = -1; /* invalid option */
1129 } 1132 }
1133 va_end(argp);
1130 lua_unlock(L); 1134 lua_unlock(L);
1131 return res; 1135 return res;
1132} 1136}
diff --git a/lbaselib.c b/lbaselib.c
index 04fdd5c2..55b56f35 100644
--- a/lbaselib.c
+++ b/lbaselib.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lbaselib.c,v 1.314 2016/09/05 19:06:34 roberto Exp roberto $ 2** $Id: lbaselib.c,v 1.315 2017/02/23 21:07:34 roberto Exp roberto $
3** Basic library 3** Basic library
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -178,19 +178,46 @@ static int luaB_collectgarbage (lua_State *L) {
178 LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, 178 LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
179 LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC}; 179 LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC};
180 int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; 180 int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
181 int ex = (int)luaL_optinteger(L, 2, 0);
182 int res = lua_gc(L, o, ex);
183 switch (o) { 181 switch (o) {
184 case LUA_GCCOUNT: { 182 case LUA_GCCOUNT: {
185 int b = lua_gc(L, LUA_GCCOUNTB, 0); 183 int k = lua_gc(L, o);
186 lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024)); 184 int b = lua_gc(L, LUA_GCCOUNTB);
185 lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024));
187 return 1; 186 return 1;
188 } 187 }
189 case LUA_GCSTEP: case LUA_GCISRUNNING: { 188 case LUA_GCSTEP: {
189 int step = (int)luaL_optinteger(L, 2, 0);
190 int res = lua_gc(L, o, step);
190 lua_pushboolean(L, res); 191 lua_pushboolean(L, res);
191 return 1; 192 return 1;
192 } 193 }
194 case LUA_GCSETPAUSE:
195 case LUA_GCSETSTEPMUL: {
196 int p = (int)luaL_optinteger(L, 2, 0);
197 int previous = lua_gc(L, o, p);
198 lua_pushinteger(L, previous);
199 return 1;
200 }
201 case LUA_GCISRUNNING: {
202 int res = lua_gc(L, o);
203 lua_pushboolean(L, res);
204 return 1;
205 }
206 case LUA_GCGEN: {
207 int minormul = (int)luaL_optinteger(L, 2, 0);
208 int majormul = (int)luaL_optinteger(L, 3, 0);
209 lua_gc(L, o, minormul, majormul);
210 return 0;
211 }
212 case LUA_GCINC: {
213 int pause = (int)luaL_optinteger(L, 2, 0);
214 int stepmul = (int)luaL_optinteger(L, 3, 0);
215 int stepsize = (int)luaL_optinteger(L, 4, 0);
216 lua_gc(L, o, pause, stepmul, stepsize);
217 return 0;
218 }
193 default: { 219 default: {
220 int res = lua_gc(L, o);
194 lua_pushinteger(L, res); 221 lua_pushinteger(L, res);
195 return 1; 222 return 1;
196 } 223 }
diff --git a/lgc.c b/lgc.c
index a0253405..4600c435 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 2.227 2017/04/30 20:43:26 roberto Exp roberto $ 2** $Id: lgc.c,v 2.228 2017/05/04 13:32:01 roberto Exp roberto $
3** Garbage Collector 3** Garbage Collector
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -27,23 +27,29 @@
27 27
28 28
29/* 29/*
30** cost of sweeping one element (the size of a small object divided 30** Maximum number of elements to sweep in each single step.
31** by some adjust for the sweep speed) 31** (Large enough to dissipate fixed overheads but small enough
32** to allow small steps for the collector.)
32*/ 33*/
33#define GCSWEEPCOST ((sizeof(TString) + 4) / 4) 34#define GCSWEEPMAX 100
35
36/*
37** Maximum number of finalizers to call in each single step.
38*/
39#define GCFINMAX 10
34 40
35/* maximum number of elements to sweep in each single step */
36#define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4))
37 41
38/* cost of calling one finalizer */ 42/*
39#define GCFINALIZECOST GCSWEEPCOST 43** Cost of calling one finalizer.
44*/
45#define GCFINALIZECOST 50
40 46
41 47
42/* 48/*
43** macro to adjust 'stepmul': 'stepmul' is actually used like 49** The equivalent, in bytes, of one unit of "work" (visiting a slot,
44** 'stepmul / STEPMULADJ' (value chosen by tests) 50** sweeping an object, etc.) * 10 (for scaling)
45*/ 51*/
46#define STEPMULADJ 200 52#define WORK2MEM (sizeof(TValue) * 10)
47 53
48 54
49/* 55/*
@@ -86,7 +92,7 @@
86#define markobjectN(g,t) { if (t) markobject(g,t); } 92#define markobjectN(g,t) { if (t) markobject(g,t); }
87 93
88static void reallymarkobject (global_State *g, GCObject *o); 94static void reallymarkobject (global_State *g, GCObject *o);
89static l_mem atomic (lua_State *L); 95static lu_mem atomic (lua_State *L);
90 96
91 97
92/* 98/*
@@ -246,21 +252,15 @@ static void reallymarkobject (global_State *g, GCObject *o) {
246 reentry: 252 reentry:
247 white2gray(o); 253 white2gray(o);
248 switch (o->tt) { 254 switch (o->tt) {
249 case LUA_TSHRSTR: { 255 case LUA_TSHRSTR:
250 gray2black(o);
251 g->GCmemtrav += sizelstring(gco2ts(o)->shrlen);
252 break;
253 }
254 case LUA_TLNGSTR: { 256 case LUA_TLNGSTR: {
255 gray2black(o); 257 gray2black(o);
256 g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen);
257 break; 258 break;
258 } 259 }
259 case LUA_TUSERDATA: { 260 case LUA_TUSERDATA: {
260 TValue uvalue; 261 TValue uvalue;
261 markobjectN(g, gco2u(o)->metatable); /* mark its metatable */ 262 markobjectN(g, gco2u(o)->metatable); /* mark its metatable */
262 gray2black(o); 263 gray2black(o);
263 g->GCmemtrav += sizeudata(gco2u(o));
264 getuservalue(g->mainthread, gco2u(o), &uvalue); 264 getuservalue(g->mainthread, gco2u(o), &uvalue);
265 if (valiswhite(&uvalue)) { /* markvalue(g, &uvalue); */ 265 if (valiswhite(&uvalue)) { /* markvalue(g, &uvalue); */
266 o = gcvalue(&uvalue); 266 o = gcvalue(&uvalue);
@@ -270,7 +270,6 @@ static void reallymarkobject (global_State *g, GCObject *o) {
270 } 270 }
271 case LUA_TUPVAL: { 271 case LUA_TUPVAL: {
272 UpVal *uv = gco2upv(o); 272 UpVal *uv = gco2upv(o);
273 g->GCmemtrav += sizeof(UpVal);
274 if (!upisopen(uv)) /* open upvalues are kept gray */ 273 if (!upisopen(uv)) /* open upvalues are kept gray */
275 gray2black(o); 274 gray2black(o);
276 markvalue(g, uv->v); /* mark its content */ 275 markvalue(g, uv->v); /* mark its content */
@@ -314,10 +313,14 @@ static void markmt (global_State *g) {
314/* 313/*
315** mark all objects in list of being-finalized 314** mark all objects in list of being-finalized
316*/ 315*/
317static void markbeingfnz (global_State *g) { 316static lu_mem markbeingfnz (global_State *g) {
318 GCObject *o; 317 GCObject *o;
319 for (o = g->tobefnz; o != NULL; o = o->next) 318 lu_mem count = 0;
319 for (o = g->tobefnz; o != NULL; o = o->next) {
320 count++;
320 markobject(g, o); 321 markobject(g, o);
322 }
323 return count;
321} 324}
322 325
323 326
@@ -327,10 +330,12 @@ static void markbeingfnz (global_State *g) {
327** thread.) Remove from the list threads that no longer have upvalues and 330** thread.) Remove from the list threads that no longer have upvalues and
328** not-marked threads. 331** not-marked threads.
329*/ 332*/
330static void remarkupvals (global_State *g) { 333static int remarkupvals (global_State *g) {
331 lua_State *thread; 334 lua_State *thread;
332 lua_State **p = &g->twups; 335 lua_State **p = &g->twups;
336 int work = 0;
333 while ((thread = *p) != NULL) { 337 while ((thread = *p) != NULL) {
338 work++;
334 lua_assert(!isblack(thread)); /* threads are never black */ 339 lua_assert(!isblack(thread)); /* threads are never black */
335 if (isgray(thread) && thread->openupval != NULL) 340 if (isgray(thread) && thread->openupval != NULL)
336 p = &thread->twups; /* keep marked thread with upvalues in the list */ 341 p = &thread->twups; /* keep marked thread with upvalues in the list */
@@ -339,11 +344,13 @@ static void remarkupvals (global_State *g) {
339 *p = thread->twups; /* remove thread from the list */ 344 *p = thread->twups; /* remove thread from the list */
340 thread->twups = thread; /* mark that it is out of list */ 345 thread->twups = thread; /* mark that it is out of list */
341 for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { 346 for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) {
347 work++;
342 if (!iswhite(uv)) /* upvalue already visited? */ 348 if (!iswhite(uv)) /* upvalue already visited? */
343 markvalue(g, uv->v); /* mark its value */ 349 markvalue(g, uv->v); /* mark its value */
344 } 350 }
345 } 351 }
346 } 352 }
353 return work;
347} 354}
348 355
349 356
@@ -491,8 +498,7 @@ static lu_mem traversetable (global_State *g, Table *h) {
491 } 498 }
492 else /* not weak */ 499 else /* not weak */
493 traversestrongtable(g, h); 500 traversestrongtable(g, h);
494 return sizeof(Table) + sizeof(TValue) * h->sizearray + 501 return 1 + h->sizearray + 2 * allocsizenode(h);
495 sizeof(Node) * cast(size_t, allocsizenode(h));
496} 502}
497 503
498 504
@@ -539,38 +545,33 @@ static int traverseproto (global_State *g, Proto *f) {
539 markobjectN(g, f->p[i]); 545 markobjectN(g, f->p[i]);
540 for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ 546 for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
541 markobjectN(g, f->locvars[i].varname); 547 markobjectN(g, f->locvars[i].varname);
542 return sizeof(Proto) + sizeof(Instruction) * f->sizecode + 548 return 1 + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars;
543 sizeof(Proto *) * f->sizep +
544 sizeof(TValue) * f->sizek +
545 sizeof(int) * f->sizelineinfo +
546 sizeof(LocVar) * f->sizelocvars +
547 sizeof(Upvaldesc) * f->sizeupvalues;
548} 549}
549 550
550 551
551static lu_mem traverseCclosure (global_State *g, CClosure *cl) { 552static int traverseCclosure (global_State *g, CClosure *cl) {
552 int i; 553 int i;
553 for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ 554 for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */
554 markvalue(g, &cl->upvalue[i]); 555 markvalue(g, &cl->upvalue[i]);
555 return sizeCclosure(cl->nupvalues); 556 return 1 + cl->nupvalues;
556} 557}
557 558
558/* 559/*
559** Traverse a Lua closure, marking its prototype and its upvalues. 560** Traverse a Lua closure, marking its prototype and its upvalues.
560** (Both can be NULL while closure is being created.) 561** (Both can be NULL while closure is being created.)
561*/ 562*/
562static lu_mem traverseLclosure (global_State *g, LClosure *cl) { 563static int traverseLclosure (global_State *g, LClosure *cl) {
563 int i; 564 int i;
564 markobjectN(g, cl->p); /* mark its prototype */ 565 markobjectN(g, cl->p); /* mark its prototype */
565 for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ 566 for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */
566 UpVal *uv = cl->upvals[i]; 567 UpVal *uv = cl->upvals[i];
567 markobjectN(g, uv); /* mark upvalue */ 568 markobjectN(g, uv); /* mark upvalue */
568 } 569 }
569 return sizeLclosure(cl->nupvalues); 570 return 1 + cl->nupvalues;
570} 571}
571 572
572 573
573static lu_mem traversethread (global_State *g, lua_State *th) { 574static int traversethread (global_State *g, lua_State *th) {
574 StkId o = th->stack; 575 StkId o = th->stack;
575 if (o == NULL) 576 if (o == NULL)
576 return 1; /* stack not completely built yet */ 577 return 1; /* stack not completely built yet */
@@ -590,8 +591,7 @@ static lu_mem traversethread (global_State *g, lua_State *th) {
590 } 591 }
591 else if (!g->gcemergency) 592 else if (!g->gcemergency)
592 luaD_shrinkstack(th); /* do not change stack in emergency cycle */ 593 luaD_shrinkstack(th); /* do not change stack in emergency cycle */
593 return (sizeof(lua_State) + sizeof(TValue) * th->stacksize + 594 return 1 + th->stacksize;
594 sizeof(CallInfo) * th->nci);
595} 595}
596 596
597 597
@@ -599,51 +599,47 @@ static lu_mem traversethread (global_State *g, lua_State *th) {
599** traverse one gray object, turning it to black (except for threads, 599** traverse one gray object, turning it to black (except for threads,
600** which are always gray). 600** which are always gray).
601*/ 601*/
602static void propagatemark (global_State *g) { 602static lu_mem propagatemark (global_State *g) {
603 lu_mem size;
604 GCObject *o = g->gray; 603 GCObject *o = g->gray;
605 gray2black(o); 604 gray2black(o);
606 switch (o->tt) { 605 switch (o->tt) {
607 case LUA_TTABLE: { 606 case LUA_TTABLE: {
608 Table *h = gco2t(o); 607 Table *h = gco2t(o);
609 g->gray = h->gclist; /* remove from 'gray' list */ 608 g->gray = h->gclist; /* remove from 'gray' list */
610 size = traversetable(g, h); 609 return traversetable(g, h);
611 break;
612 } 610 }
613 case LUA_TLCL: { 611 case LUA_TLCL: {
614 LClosure *cl = gco2lcl(o); 612 LClosure *cl = gco2lcl(o);
615 g->gray = cl->gclist; /* remove from 'gray' list */ 613 g->gray = cl->gclist; /* remove from 'gray' list */
616 size = traverseLclosure(g, cl); 614 return traverseLclosure(g, cl);
617 break;
618 } 615 }
619 case LUA_TCCL: { 616 case LUA_TCCL: {
620 CClosure *cl = gco2ccl(o); 617 CClosure *cl = gco2ccl(o);
621 g->gray = cl->gclist; /* remove from 'gray' list */ 618 g->gray = cl->gclist; /* remove from 'gray' list */
622 size = traverseCclosure(g, cl); 619 return traverseCclosure(g, cl);
623 break;
624 } 620 }
625 case LUA_TTHREAD: { 621 case LUA_TTHREAD: {
626 lua_State *th = gco2th(o); 622 lua_State *th = gco2th(o);
627 g->gray = th->gclist; /* remove from 'gray' list */ 623 g->gray = th->gclist; /* remove from 'gray' list */
628 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ 624 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
629 black2gray(o); 625 black2gray(o);
630 size = traversethread(g, th); 626 return traversethread(g, th);
631 break;
632 } 627 }
633 case LUA_TPROTO: { 628 case LUA_TPROTO: {
634 Proto *p = gco2p(o); 629 Proto *p = gco2p(o);
635 g->gray = p->gclist; /* remove from 'gray' list */ 630 g->gray = p->gclist; /* remove from 'gray' list */
636 size = traverseproto(g, p); 631 return traverseproto(g, p);
637 break;
638 } 632 }
639 default: lua_assert(0); return; 633 default: lua_assert(0); return 0;
640 } 634 }
641 g->GCmemtrav += size;
642} 635}
643 636
644 637
645static void propagateall (global_State *g) { 638static lu_mem propagateall (global_State *g) {
646 while (g->gray) propagatemark(g); 639 lu_mem tot = 0;
640 while (g->gray)
641 tot += propagatemark(g);
642 return tot;
647} 643}
648 644
649 645
@@ -719,7 +715,7 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) {
719 setnilvalue(o); /* remove value */ 715 setnilvalue(o); /* remove value */
720 } 716 }
721 for (n = gnode(h, 0); n < limit; n++) { 717 for (n = gnode(h, 0); n < limit; n++) {
722 if (!ttisnil(gval(n)) && iscleared(g, gval(n))) { 718 if (iscleared(g, gval(n))) {
723 setnilvalue(gval(n)); /* remove value ... */ 719 setnilvalue(gval(n)); /* remove value ... */
724 removeentry(n); /* and remove entry from table */ 720 removeentry(n); /* and remove entry from table */
725 } 721 }
@@ -770,22 +766,20 @@ static void freeobj (lua_State *L, GCObject *o) {
770} 766}
771 767
772 768
773#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM)
774static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count);
775
776
777/* 769/*
778** sweep at most 'count' elements from a list of GCObjects erasing dead 770** sweep at most 'countin' elements from a list of GCObjects erasing dead
779** objects, where a dead object is one marked with the old (non current) 771** objects, where a dead object is one marked with the old (non current)
780** white; change all non-dead objects back to white, preparing for next 772** white; change all non-dead objects back to white, preparing for next
781** collection cycle. Return where to continue the traversal or NULL if 773** collection cycle. Return where to continue the traversal or NULL if
782** list is finished. 774** list is finished. ('*countout' gets the number of elements traversed.)
783*/ 775*/
784static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { 776static GCObject **sweeplist (lua_State *L, GCObject **p, int countin,
777 int *countout) {
785 global_State *g = G(L); 778 global_State *g = G(L);
786 int ow = otherwhite(g); 779 int ow = otherwhite(g);
780 int i;
787 int white = luaC_white(g); /* current white */ 781 int white = luaC_white(g); /* current white */
788 while (*p != NULL && count-- > 0) { 782 for (i = 0; *p != NULL && i < countin; i++) {
789 GCObject *curr = *p; 783 GCObject *curr = *p;
790 int marked = curr->marked; 784 int marked = curr->marked;
791 if (isdeadm(ow, marked)) { /* is 'curr' dead? */ 785 if (isdeadm(ow, marked)) { /* is 'curr' dead? */
@@ -797,6 +791,8 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
797 p = &curr->next; /* go to next element */ 791 p = &curr->next; /* go to next element */
798 } 792 }
799 } 793 }
794 if (countout)
795 *countout = i; /* number of elements traversed */
800 return (*p == NULL) ? NULL : p; 796 return (*p == NULL) ? NULL : p;
801} 797}
802 798
@@ -807,7 +803,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
807static GCObject **sweeptolive (lua_State *L, GCObject **p) { 803static GCObject **sweeptolive (lua_State *L, GCObject **p) {
808 GCObject **old = p; 804 GCObject **old = p;
809 do { 805 do {
810 p = sweeplist(L, p, 1); 806 p = sweeplist(L, p, 1, NULL);
811 } while (p == old); 807 } while (p == old);
812 return p; 808 return p;
813} 809}
@@ -892,16 +888,13 @@ static void GCTM (lua_State *L, int propagateerrors) {
892 888
893 889
894/* 890/*
895** call a few (up to 'g->gcfinnum') finalizers 891** Call a few finalizers
896*/ 892*/
897static int runafewfinalizers (lua_State *L) { 893static int runafewfinalizers (lua_State *L, int n) {
898 global_State *g = G(L); 894 global_State *g = G(L);
899 unsigned int i; 895 int i;
900 lua_assert(!g->tobefnz || g->gcfinnum > 0); 896 for (i = 0; i < n && g->tobefnz; i++)
901 for (i = 0; g->tobefnz && i < g->gcfinnum; i++)
902 GCTM(L, 1); /* call one finalizer */ 897 GCTM(L, 1); /* call one finalizer */
903 g->gcfinnum = (!g->tobefnz) ? 0 /* nothing more to finalize? */
904 : g->gcfinnum * 2; /* else call a few more next time */
905 return i; 898 return i;
906} 899}
907 900
@@ -1285,9 +1278,6 @@ static void genstep (lua_State *L, global_State *g) {
1285//lua_checkmemory(L); 1278//lua_checkmemory(L);
1286} 1279}
1287 1280
1288
1289
1290
1291/* }====================================================== */ 1281/* }====================================================== */
1292 1282
1293 1283
@@ -1299,26 +1289,28 @@ static void genstep (lua_State *L, global_State *g) {
1299 1289
1300 1290
1301/* 1291/*
1302** Set a reasonable "time" to wait before starting a new GC cycle; cycle 1292** Set the "time" to wait before starting a new GC cycle; cycle will
1303** will start when memory use hits threshold. (Division by 'estimate' 1293** start when memory use hits the threshold of ('estimate' * gcpause /
1304** should be OK: it cannot be zero (because Lua cannot even start with 1294** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
1305** less than PAUSEADJ bytes). 1295** because Lua cannot even start with less than PAUSEADJ bytes).
1306*/ 1296*/
1307static void setpause (global_State *g) { 1297static void setpause (global_State *g) {
1308 l_mem threshold, debt; 1298 l_mem threshold, debt;
1299 int pause = g->gcpause + 100;
1309 l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ 1300 l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
1310 lua_assert(estimate > 0); 1301 lua_assert(estimate > 0);
1311 threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */ 1302 threshold = (pause < MAX_LMEM / estimate) /* overflow? */
1312 ? estimate * g->gcpause /* no overflow */ 1303 ? estimate * pause /* no overflow */
1313 : MAX_LMEM; /* overflow; truncate to maximum */ 1304 : MAX_LMEM; /* overflow; truncate to maximum */
1314 debt = gettotalbytes(g) - threshold; 1305 debt = gettotalbytes(g) - threshold;
1306 if (debt > 0) debt = 0;
1315 luaE_setdebt(g, debt); 1307 luaE_setdebt(g, debt);
1316} 1308}
1317 1309
1318 1310
1319/* 1311/*
1320** Enter first sweep phase. 1312** Enter first sweep phase.
1321** The call to 'sweeplist' tries to make pointer point to an object 1313** The call to 'sweeptolive' makes the pointer point to an object
1322** inside the list (instead of to the header), so that the real sweep do 1314** inside the list (instead of to the header), so that the real sweep do
1323** not need to skip objects created between "now" and the start of the 1315** not need to skip objects created between "now" and the start of the
1324** real sweep. 1316** real sweep.
@@ -1327,11 +1319,15 @@ static void entersweep (lua_State *L) {
1327 global_State *g = G(L); 1319 global_State *g = G(L);
1328 g->gcstate = GCSswpallgc; 1320 g->gcstate = GCSswpallgc;
1329 lua_assert(g->sweepgc == NULL); 1321 lua_assert(g->sweepgc == NULL);
1330 g->sweepgc = sweeplist(L, &g->allgc, 1); 1322 g->sweepgc = sweeptolive(L, &g->allgc);
1331} 1323}
1332 1324
1333 1325
1334static void deletealllist (lua_State *L, GCObject *p, GCObject *limit) { 1326/*
1327** Delete all objects in list 'p' until (but not including) object
1328** 'limit'.
1329*/
1330static void deletelist (lua_State *L, GCObject *p, GCObject *limit) {
1335 while (p != limit) { 1331 while (p != limit) {
1336 GCObject *next = p->next; 1332 GCObject *next = p->next;
1337 freeobj(L, p); 1333 freeobj(L, p);
@@ -1340,52 +1336,50 @@ static void deletealllist (lua_State *L, GCObject *p, GCObject *limit) {
1340} 1336}
1341 1337
1342 1338
1339/*
1340** Call all finalizers of the objects in the given Lua state, and
1341** then free all objects, except for the main thread.
1342*/
1343void luaC_freeallobjects (lua_State *L) { 1343void luaC_freeallobjects (lua_State *L) {
1344 global_State *g = G(L); 1344 global_State *g = G(L);
1345 luaC_changemode(L, KGC_INC); 1345 luaC_changemode(L, KGC_INC);
1346 separatetobefnz(g, 1); /* separate all objects with finalizers */ 1346 separatetobefnz(g, 1); /* separate all objects with finalizers */
1347 lua_assert(g->finobj == NULL); 1347 lua_assert(g->finobj == NULL);
1348 callallpendingfinalizers(L); 1348 callallpendingfinalizers(L);
1349 deletealllist(L, g->allgc, obj2gco(g->mainthread)); 1349 deletelist(L, g->allgc, obj2gco(g->mainthread));
1350 deletealllist(L, g->finobj, NULL); 1350 deletelist(L, g->finobj, NULL);
1351 deletealllist(L, g->fixedgc, NULL); /* collect fixed objects */ 1351 deletelist(L, g->fixedgc, NULL); /* collect fixed objects */
1352 lua_assert(g->strt.nuse == 0); 1352 lua_assert(g->strt.nuse == 0);
1353} 1353}
1354 1354
1355 1355
1356static l_mem atomic (lua_State *L) { 1356static lu_mem atomic (lua_State *L) {
1357 global_State *g = G(L); 1357 global_State *g = G(L);
1358 l_mem work; 1358 lu_mem work = 0;
1359 GCObject *origweak, *origall; 1359 GCObject *origweak, *origall;
1360 GCObject *grayagain = g->grayagain; /* save original list */ 1360 GCObject *grayagain = g->grayagain; /* save original list */
1361 g->grayagain = NULL; 1361 g->grayagain = NULL;
1362 lua_assert(g->ephemeron == NULL && g->weak == NULL); 1362 lua_assert(g->ephemeron == NULL && g->weak == NULL);
1363 lua_assert(!iswhite(g->mainthread)); 1363 lua_assert(!iswhite(g->mainthread));
1364 g->gcstate = GCSatomic; 1364 g->gcstate = GCSatomic;
1365 g->GCmemtrav = 0; /* start counting work */
1366 markobject(g, L); /* mark running thread */ 1365 markobject(g, L); /* mark running thread */
1367 /* registry and global metatables may be changed by API */ 1366 /* registry and global metatables may be changed by API */
1368 markvalue(g, &g->l_registry); 1367 markvalue(g, &g->l_registry);
1369 markmt(g); /* mark global metatables */ 1368 markmt(g); /* mark global metatables */
1370 /* remark occasional upvalues of (maybe) dead threads */ 1369 /* remark occasional upvalues of (maybe) dead threads */
1371 remarkupvals(g); 1370 work += remarkupvals(g);
1372 propagateall(g); /* propagate changes */ 1371 work += propagateall(g); /* propagate changes */
1373 work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */
1374 g->gray = grayagain; 1372 g->gray = grayagain;
1375 propagateall(g); /* traverse 'grayagain' list */ 1373 work += propagateall(g); /* traverse 'grayagain' list */
1376 g->GCmemtrav = 0; /* restart counting */
1377 convergeephemerons(g); 1374 convergeephemerons(g);
1378 /* at this point, all strongly accessible objects are marked. */ 1375 /* at this point, all strongly accessible objects are marked. */
1379 /* Clear values from weak tables, before checking finalizers */ 1376 /* Clear values from weak tables, before checking finalizers */
1380 clearvalues(g, g->weak, NULL); 1377 clearvalues(g, g->weak, NULL);
1381 clearvalues(g, g->allweak, NULL); 1378 clearvalues(g, g->allweak, NULL);
1382 origweak = g->weak; origall = g->allweak; 1379 origweak = g->weak; origall = g->allweak;
1383 work += g->GCmemtrav; /* stop counting (objects being finalized) */
1384 separatetobefnz(g, 0); /* separate objects to be finalized */ 1380 separatetobefnz(g, 0); /* separate objects to be finalized */
1385 g->gcfinnum = 1; /* there may be objects to be finalized */ 1381 work += markbeingfnz(g); /* mark objects that will be finalized */
1386 markbeingfnz(g); /* mark objects that will be finalized */ 1382 work += propagateall(g); /* remark, to propagate 'resurrection' */
1387 propagateall(g); /* remark, to propagate 'resurrection' */
1388 g->GCmemtrav = 0; /* restart counting */
1389 convergeephemerons(g); 1383 convergeephemerons(g);
1390 /* at this point, all resurrected objects are marked. */ 1384 /* at this point, all resurrected objects are marked. */
1391 /* remove dead objects from weak tables */ 1385 /* remove dead objects from weak tables */
@@ -1398,24 +1392,24 @@ static l_mem atomic (lua_State *L) {
1398 clearprotolist(g); 1392 clearprotolist(g);
1399 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ 1393 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
1400 lua_assert(g->gray == NULL); 1394 lua_assert(g->gray == NULL);
1401 work += g->GCmemtrav; /* complete counting */ 1395 return work; /* estimate of slots marked by 'atomic' */
1402 return work; /* estimate of memory marked by 'atomic' */
1403} 1396}
1404 1397
1405 1398
1406static lu_mem sweepstep (lua_State *L, global_State *g, 1399static int sweepstep (lua_State *L, global_State *g,
1407 int nextstate, GCObject **nextlist) { 1400 int nextstate, GCObject **nextlist) {
1408 if (g->sweepgc) { 1401 if (g->sweepgc) {
1409 l_mem olddebt = g->GCdebt; 1402 l_mem olddebt = g->GCdebt;
1410 g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); 1403 int count;
1404 g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX, &count);
1411 g->GCestimate += g->GCdebt - olddebt; /* update estimate */ 1405 g->GCestimate += g->GCdebt - olddebt; /* update estimate */
1412 if (g->sweepgc) /* is there still something to sweep? */ 1406 return count;
1413 return (GCSWEEPMAX * GCSWEEPCOST); 1407 }
1408 else { /* enter next state */
1409 g->gcstate = nextstate;
1410 g->sweepgc = nextlist;
1411 return 0; /* no work done */
1414 } 1412 }
1415 /* else enter next state */
1416 g->gcstate = nextstate;
1417 g->sweepgc = nextlist;
1418 return 0;
1419} 1413}
1420 1414
1421 1415
@@ -1423,23 +1417,21 @@ static lu_mem singlestep (lua_State *L) {
1423 global_State *g = G(L); 1417 global_State *g = G(L);
1424 switch (g->gcstate) { 1418 switch (g->gcstate) {
1425 case GCSpause: { 1419 case GCSpause: {
1426 g->GCmemtrav = g->strt.size * sizeof(GCObject*);
1427 restartcollection(g); 1420 restartcollection(g);
1428 g->gcstate = GCSpropagate; 1421 g->gcstate = GCSpropagate;
1429 return g->GCmemtrav; 1422 return 1;
1430 } 1423 }
1431 case GCSpropagate: { 1424 case GCSpropagate: {
1432 g->GCmemtrav = 0; 1425 if (g->gray == NULL) { /* no more gray objects? */
1433 if (g->gray == NULL) /* no more gray objects? */
1434 g->gcstate = GCSenteratomic; /* finish propagate phase */ 1426 g->gcstate = GCSenteratomic; /* finish propagate phase */
1427 return 0;
1428 }
1435 else 1429 else
1436 propagatemark(g); /* traverse one gray object */ 1430 return propagatemark(g); /* traverse one gray object */
1437 return g->GCmemtrav; /* memory traversed in this step */
1438 } 1431 }
1439 case GCSenteratomic: { 1432 case GCSenteratomic: {
1440 lu_mem work; 1433 lu_mem work = propagateall(g); /* make sure gray list is empty */
1441 propagateall(g); /* make sure gray list is empty */ 1434 work += atomic(L); /* work is what was traversed by 'atomic' */
1442 work = atomic(L); /* work is what was traversed by 'atomic' */
1443 entersweep(L); 1435 entersweep(L);
1444 g->GCestimate = gettotalbytes(g); /* first estimate */; 1436 g->GCestimate = gettotalbytes(g); /* first estimate */;
1445 return work; 1437 return work;
@@ -1460,8 +1452,8 @@ static lu_mem singlestep (lua_State *L) {
1460 } 1452 }
1461 case GCScallfin: { /* call remaining finalizers */ 1453 case GCScallfin: { /* call remaining finalizers */
1462 if (g->tobefnz && !g->gcemergency) { 1454 if (g->tobefnz && !g->gcemergency) {
1463 int n = runafewfinalizers(L); 1455 int n = runafewfinalizers(L, GCFINMAX);
1464 return (n * GCFINALIZECOST); 1456 return n * GCFINALIZECOST;
1465 } 1457 }
1466 else { /* emergency mode or no more finalizers */ 1458 else { /* emergency mode or no more finalizers */
1467 g->gcstate = GCSpause; /* finish collection */ 1459 g->gcstate = GCSpause; /* finish collection */
@@ -1485,45 +1477,36 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
1485 1477
1486 1478
1487/* 1479/*
1488** get GC debt and convert it from Kb to 'work units' (avoid zero debt 1480** Performs a basic incremental step. The debt and step size are
1489** and overflows) 1481** converted from bytes to "units of work"; then the function loops
1490*/ 1482** running single steps until adding that many units of work or
1491static l_mem getdebt (global_State *g) { 1483** finishing a cycle (pause state). Finally, it sets the debt that
1492 l_mem debt = g->GCdebt; 1484** controls when next step will be performed.
1493 int stepmul = g->gcstepmul;
1494 if (debt <= 0) return 0; /* minimal debt */
1495 else {
1496 debt = (debt / STEPMULADJ) + 1;
1497 debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
1498 return debt;
1499 }
1500}
1501
1502/*
1503** performs a basic incremental step
1504*/ 1485*/
1505static void incstep (lua_State *L, global_State *g) { 1486static void incstep (lua_State *L, global_State *g) {
1506 l_mem debt = getdebt(g); /* GC deficit (to be paid now) */ 1487 int stepmul = (g->gcstepmul | 1); /* avoid division by 0 */
1488 l_mem debt = (g->GCdebt / WORK2MEM) * stepmul;
1489 l_mem stepsize = cast(l_mem, 1) << g->gcstepsize;
1490 stepsize = -((stepsize / WORK2MEM) * stepmul);
1507 do { /* repeat until pause or enough "credit" (negative debt) */ 1491 do { /* repeat until pause or enough "credit" (negative debt) */
1508 lu_mem work = singlestep(L); /* perform one single step */ 1492 lu_mem work = singlestep(L); /* perform one single step */
1509 debt -= work; 1493 debt -= work;
1510 } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); 1494 } while (debt > stepsize && g->gcstate != GCSpause);
1511 if (g->gcstate == GCSpause) 1495 if (g->gcstate == GCSpause)
1512 setpause(g); /* pause until next cycle */ 1496 setpause(g); /* pause until next cycle */
1513 else { 1497 else {
1514 debt = (debt / g->gcstepmul) * STEPMULADJ; /* convert 'work units' to Kb */ 1498 debt = (debt / stepmul) * WORK2MEM; /* convert 'work units' to bytes */
1515 luaE_setdebt(g, debt); 1499 luaE_setdebt(g, debt);
1516 runafewfinalizers(L);
1517 } 1500 }
1518} 1501}
1519 1502
1520/* 1503/*
1521** performs a basic GC step when collector is running 1504** performs a basic GC step if collector is running
1522*/ 1505*/
1523void luaC_step (lua_State *L) { 1506void luaC_step (lua_State *L) {
1524 global_State *g = G(L); 1507 global_State *g = G(L);
1525 if (!g->gcrunning) /* not running? */ 1508 if (!g->gcrunning) /* not running? */
1526 luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */ 1509 luaE_setdebt(g, -MAX_LMEM); /* avoid being called without need */
1527 else if (g->gckind == KGC_INC) 1510 else if (g->gckind == KGC_INC)
1528 incstep(L, g); 1511 incstep(L, g);
1529 else 1512 else
@@ -1532,9 +1515,7 @@ void luaC_step (lua_State *L) {
1532 1515
1533 1516
1534/* 1517/*
1535** Performs a full GC cycle; if 'isemergency', set a flag to avoid 1518** Perform a full collection in incremental mode.
1536** some operations which could change the interpreter state in some
1537** unexpected ways (running finalizers and shrinking some structures).
1538** Before running the collection, check 'keepinvariant'; if it is true, 1519** Before running the collection, check 'keepinvariant'; if it is true,
1539** there may be some objects marked as black, so the collector has 1520** there may be some objects marked as black, so the collector has
1540** to sweep all objects to turn them back to white (as white has not 1521** to sweep all objects to turn them back to white (as white has not
@@ -1553,6 +1534,11 @@ static void fullinc (lua_State *L, global_State *g) {
1553} 1534}
1554 1535
1555 1536
1537/*
1538** Performs a full GC cycle; if 'isemergency', set a flag to avoid
1539** some operations which could change the interpreter state in some
1540** unexpected ways (running finalizers and shrinking some structures).
1541*/
1556void luaC_fullgc (lua_State *L, int isemergency) { 1542void luaC_fullgc (lua_State *L, int isemergency) {
1557 global_State *g = G(L); 1543 global_State *g = G(L);
1558 lua_assert(!g->gcemergency); 1544 lua_assert(!g->gcemergency);
diff --git a/lgc.h b/lgc.h
index 6ee0b012..36f361ec 100644
--- a/lgc.h
+++ b/lgc.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.h,v 2.96 2017/04/11 18:41:09 roberto Exp roberto $ 2** $Id: lgc.h,v 2.97 2017/05/04 13:32:01 roberto Exp roberto $
3** Garbage Collector 3** Garbage Collector
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -25,14 +25,6 @@
25*/ 25*/
26 26
27 27
28
29/* how much to allocate before next GC step */
30#if !defined(GCSTEPSIZE)
31/* ~100 small strings */
32#define GCSTEPSIZE (cast_int(100 * sizeof(TString)))
33#endif
34
35
36/* 28/*
37** Possible states of the Garbage Collector 29** Possible states of the Garbage Collector
38*/ 30*/
@@ -125,6 +117,16 @@
125 check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t))) 117 check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t)))
126 118
127 119
120/* Default Values for GC parameters */
121#define LUAI_GENMAJORMUL 100
122#define LUAI_GENMINORMUL 5
123
124#define LUAI_GCPAUSE 100 /* 100% */
125#define LUAI_GCMUL 10
126/* how much to allocate before next GC step (log2) */
127#define LUAI_GCSTEPSIZE 13 /* 8 KB */
128
129
128/* 130/*
129** Does one step of collection when debt becomes positive. 'pre'/'pos' 131** Does one step of collection when debt becomes positive. 'pre'/'pos'
130** allows some adjustments to be done only when needed. macro 132** allows some adjustments to be done only when needed. macro
diff --git a/lstate.c b/lstate.c
index 3bce076d..5f1c6e48 100644
--- a/lstate.c
+++ b/lstate.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.c,v 2.138 2017/04/24 16:59:26 roberto Exp roberto $ 2** $Id: lstate.c,v 2.139 2017/05/04 13:32:01 roberto Exp roberto $
3** Global State 3** Global State
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -28,14 +28,6 @@
28#include "ltm.h" 28#include "ltm.h"
29 29
30 30
31#if !defined(LUAI_GCPAUSE)
32#define LUAI_GCPAUSE 200 /* 200% */
33#endif
34
35#if !defined(LUAI_GCMUL)
36#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */
37#endif
38
39 31
40/* 32/*
41** a macro to help the creation of a unique random seed when a state is 33** a macro to help the creation of a unique random seed when a state is
@@ -328,9 +320,9 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
328 g->twups = NULL; 320 g->twups = NULL;
329 g->totalbytes = sizeof(LG); 321 g->totalbytes = sizeof(LG);
330 g->GCdebt = 0; 322 g->GCdebt = 0;
331 g->gcfinnum = 0;
332 g->gcpause = LUAI_GCPAUSE; 323 g->gcpause = LUAI_GCPAUSE;
333 g->gcstepmul = LUAI_GCMUL; 324 g->gcstepmul = LUAI_GCMUL;
325 g->gcstepsize = LUAI_GCSTEPSIZE;
334 for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; 326 for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;
335 if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { 327 if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
336 /* memory allocation error: free partial state */ 328 /* memory allocation error: free partial state */
diff --git a/lstate.h b/lstate.h
index d2dabc4d..9a3e778a 100644
--- a/lstate.h
+++ b/lstate.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.h,v 2.140 2017/05/04 13:32:01 roberto Exp roberto $ 2** $Id: lstate.h,v 2.141 2017/05/13 13:54:47 roberto Exp roberto $
3** Global State 3** Global State
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -139,7 +139,6 @@ typedef struct global_State {
139 void *ud; /* auxiliary data to 'frealloc' */ 139 void *ud; /* auxiliary data to 'frealloc' */
140 l_mem totalbytes; /* number of bytes currently allocated - GCdebt */ 140 l_mem totalbytes; /* number of bytes currently allocated - GCdebt */
141 l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ 141 l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
142 lu_mem GCmemtrav; /* memory traversed by the GC */
143 lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ 142 lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
144 stringtable strt; /* hash table for strings */ 143 stringtable strt; /* hash table for strings */
145 TValue l_registry; 144 TValue l_registry;
@@ -151,6 +150,9 @@ typedef struct global_State {
151 lu_byte genmajormul; /* control for major generational collections */ 150 lu_byte genmajormul; /* control for major generational collections */
152 lu_byte gcrunning; /* true if GC is running */ 151 lu_byte gcrunning; /* true if GC is running */
153 lu_byte gcemergency; /* true if this is an emergency collection */ 152 lu_byte gcemergency; /* true if this is an emergency collection */
153 lu_byte gcpause; /* size of pause between successive GCs */
154 lu_byte gcstepmul; /* GC "speed" */
155 lu_byte gcstepsize; /* (log2 of) GC granularity */
154 GCObject *allgc; /* list of all collectable objects */ 156 GCObject *allgc; /* list of all collectable objects */
155 GCObject **sweepgc; /* current position of sweep in list */ 157 GCObject **sweepgc; /* current position of sweep in list */
156 GCObject *finobj; /* list of collectable objects with finalizers */ 158 GCObject *finobj; /* list of collectable objects with finalizers */
@@ -170,9 +172,6 @@ typedef struct global_State {
170 GCObject *finobjold; /* list of old objects with finalizers */ 172 GCObject *finobjold; /* list of old objects with finalizers */
171 GCObject *finobjrold; /* list of really old objects with finalizers */ 173 GCObject *finobjrold; /* list of really old objects with finalizers */
172 struct lua_State *twups; /* list of threads with open upvalues */ 174 struct lua_State *twups; /* list of threads with open upvalues */
173 unsigned int gcfinnum; /* number of finalizers to call in each GC step */
174 int gcpause; /* size of pause between successive GCs */
175 int gcstepmul; /* GC 'granularity' */
176 lua_CFunction panic; /* to be called in unprotected errors */ 175 lua_CFunction panic; /* to be called in unprotected errors */
177 struct lua_State *mainthread; 176 struct lua_State *mainthread;
178 const lua_Number *version; /* pointer to version number */ 177 const lua_Number *version; /* pointer to version number */
diff --git a/lua.h b/lua.h
index 735a2599..1499c04e 100644
--- a/lua.h
+++ b/lua.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lua.h,v 1.333 2017/02/23 21:07:34 roberto Exp roberto $ 2** $Id: lua.h,v 1.334 2017/05/18 12:34:58 roberto Exp roberto $
3** Lua - A Scripting Language 3** Lua - A Scripting Language
4** Lua.org, PUC-Rio, Brazil (http://www.lua.org) 4** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
5** See Copyright Notice at the end of this file 5** See Copyright Notice at the end of this file
@@ -311,7 +311,7 @@ LUA_API int (lua_isyieldable) (lua_State *L);
311#define LUA_GCGEN 10 311#define LUA_GCGEN 10
312#define LUA_GCINC 11 312#define LUA_GCINC 11
313 313
314LUA_API int (lua_gc) (lua_State *L, int what, int data); 314LUA_API int (lua_gc) (lua_State *L, int what, ...);
315 315
316 316
317/* 317/*