diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-05-26 16:14:29 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-05-26 16:14:29 -0300 |
commit | 72d82a296c1430a1d2bb3fac8ed8cbfb97868707 (patch) | |
tree | 4ea80148c5f1bfd38f0e7ca1cb8ef82e00e7e19c | |
parent | 4804bbd9bbfb89deb8a6c7dc2bc65601a701222b (diff) | |
download | lua-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.c | 44 | ||||
-rw-r--r-- | lbaselib.c | 39 | ||||
-rw-r--r-- | lgc.c | 278 | ||||
-rw-r--r-- | lgc.h | 20 | ||||
-rw-r--r-- | lstate.c | 12 | ||||
-rw-r--r-- | lstate.h | 9 | ||||
-rw-r--r-- | lua.h | 4 |
7 files changed, 208 insertions, 198 deletions
@@ -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 | 1049 | LUA_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 | |||
1055 | LUA_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 | } |
@@ -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 | } |
@@ -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 | ||
88 | static void reallymarkobject (global_State *g, GCObject *o); | 94 | static void reallymarkobject (global_State *g, GCObject *o); |
89 | static l_mem atomic (lua_State *L); | 95 | static 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 | */ |
317 | static void markbeingfnz (global_State *g) { | 316 | static 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 | */ |
330 | static void remarkupvals (global_State *g) { | 333 | static 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 | ||
551 | static lu_mem traverseCclosure (global_State *g, CClosure *cl) { | 552 | static 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 | */ |
562 | static lu_mem traverseLclosure (global_State *g, LClosure *cl) { | 563 | static 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 | ||
573 | static lu_mem traversethread (global_State *g, lua_State *th) { | 574 | static 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 | */ |
602 | static void propagatemark (global_State *g) { | 602 | static 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 | ||
645 | static void propagateall (global_State *g) { | 638 | static 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) | ||
774 | static 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 | */ |
784 | static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { | 776 | static 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) { | |||
807 | static GCObject **sweeptolive (lua_State *L, GCObject **p) { | 803 | static 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 | */ |
897 | static int runafewfinalizers (lua_State *L) { | 893 | static 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 | */ |
1307 | static void setpause (global_State *g) { | 1297 | static 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 | ||
1334 | static 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 | */ | ||
1330 | static 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 | */ | ||
1343 | void luaC_freeallobjects (lua_State *L) { | 1343 | void 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 | ||
1356 | static l_mem atomic (lua_State *L) { | 1356 | static 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 | ||
1406 | static lu_mem sweepstep (lua_State *L, global_State *g, | 1399 | static 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 |
1491 | static 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 | */ |
1505 | static void incstep (lua_State *L, global_State *g) { | 1486 | static 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 | */ |
1523 | void luaC_step (lua_State *L) { | 1506 | void 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 | */ | ||
1556 | void luaC_fullgc (lua_State *L, int isemergency) { | 1542 | void 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); |
@@ -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 |
@@ -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 */ |
@@ -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 */ |
@@ -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 | ||
314 | LUA_API int (lua_gc) (lua_State *L, int what, int data); | 314 | LUA_API int (lua_gc) (lua_State *L, int what, ...); |
315 | 315 | ||
316 | 316 | ||
317 | /* | 317 | /* |