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 | /* |
