diff --git a/lapi.c b/lapi.c index 3ea3d0aa..aa2ee735 100644 --- a/lapi.c +++ b/lapi.c @@ -1186,27 +1186,37 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { break; } case LUA_GCGEN: { +#if defined(LUA_COMPAT_GCPARAMS) int minormul = va_arg(argp, int); int minormajor = va_arg(argp, int); - int majorminor = va_arg(argp, int); + if (minormul > 0) setgcparam(g, MINORMUL, minormul); + if (minormajor > 0) setgcparam(g, MINORMAJOR, minormajor); +#endif res = (g->gckind == KGC_INC) ? LUA_GCINC : LUA_GCGEN; - setgcparam(g, gcpgenminormul, minormul); - setgcparam(g, gcpminormajor, minormajor); - setgcparam(g, gcpmajorminor, majorminor); luaC_changemode(L, KGC_GENMINOR); break; } case LUA_GCINC: { +#if defined(LUA_COMPAT_GCPARAMS) int pause = va_arg(argp, int); int stepmul = va_arg(argp, int); int stepsize = va_arg(argp, int); + if (pause > 0) setgcparam(g, PAUSE, pause); + if (stepmul > 0) setgcparam(g, STEPMUL, stepmul); + if (stepsize > 0) setgcparam(g, STEPSIZE, 1u << stepsize); +#endif res = (g->gckind == KGC_INC) ? LUA_GCINC : LUA_GCGEN; - setgcparam(g, gcppause, pause); - setgcparam(g, gcpstepmul, stepmul); - setgcparam(g, gcpstepsize, stepsize); luaC_changemode(L, KGC_INC); break; } + case LUA_GCSETPARAM: { + int param = va_arg(argp, int); + int value = va_arg(argp, int); + api_check(L, 0 <= param && param < LUA_GCPN, "invalid parameter"); + res = luaO_applyparam(g->gcparams[param], 100); + g->gcparams[param] = luaO_codeparam(value); + break; + } default: res = -1; /* invalid option */ } va_end(argp); diff --git a/lbaselib.c b/lbaselib.c index 9ad84dcf..03df57f8 100644 --- a/lbaselib.c +++ b/lbaselib.c @@ -198,9 +198,11 @@ static int pushmode (lua_State *L, int oldmode) { static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", - "count", "step", "isrunning", "generational", "incremental", NULL}; - static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, - LUA_GCCOUNT, LUA_GCSTEP, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC}; + "count", "step", "isrunning", "generational", "incremental", + "setparam", NULL}; + static const char optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC, + LUA_GCSETPARAM}; int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; switch (o) { case LUA_GCCOUNT: { @@ -224,17 +226,39 @@ static int luaB_collectgarbage (lua_State *L) { return 1; } case LUA_GCGEN: { +#if defined(LUA_COMPAT_GCPARAMS) int minormul = (int)luaL_optinteger(L, 2, -1); int majorminor = (int)luaL_optinteger(L, 3, -1); - int minormajor = (int)luaL_optinteger(L, 4, -1); - return pushmode(L, lua_gc(L, o, minormul, majorminor, minormajor)); +#else + int minormul = 0; + int majorminor = 0; +#endif + return pushmode(L, lua_gc(L, o, minormul, majorminor)); } case LUA_GCINC: { +#if defined(LUA_COMPAT_GCPARAMS) int pause = (int)luaL_optinteger(L, 2, -1); int stepmul = (int)luaL_optinteger(L, 3, -1); int stepsize = (int)luaL_optinteger(L, 4, -1); +#else + int pause = 0; + int stepmul = 0; + int stepsize = 0; +#endif return pushmode(L, lua_gc(L, o, pause, stepmul, stepsize)); } + case LUA_GCSETPARAM: { + static const char *const params[] = { + "minormul", "majorminor", "minormajor", + "pause", "stepmul", "stepsize", NULL}; + static const char pnum[] = { + LUA_GCPMINORMUL, LUA_GCPMAJORMINOR, LUA_GCPMINORMAJOR, + LUA_GCPPAUSE, LUA_GCPSTEPMUL, LUA_GCPSTEPSIZE}; + int p = pnum[luaL_checkoption(L, 2, NULL, params)]; + lua_Integer value = luaL_checkinteger(L, 3); + lua_pushinteger(L, lua_gc(L, o, p, value)); + return 1; + } default: { int res = lua_gc(L, o); checkvalres(res); diff --git a/lgc.c b/lgc.c index 149dddf6..bc4ddb0b 100644 --- a/lgc.c +++ b/lgc.c @@ -1049,7 +1049,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { ** approximately (marked * pause / 100). */ static void setpause (global_State *g) { - l_obj threshold = luaO_applyparam(g->gcppause, g->marked); + l_obj threshold = applygcparam(g, PAUSE, g->marked); l_obj debt = threshold - gettotalobjs(g); if (debt < 0) debt = 0; luaE_setdebt(g, debt); @@ -1239,7 +1239,7 @@ static void minor2inc (lua_State *L, global_State *g, int kind) { g->finobjrold = g->finobjold1 = g->finobjsur = NULL; entersweep(L); /* continue as an incremental cycle */ /* set a debt equal to the step size */ - luaE_setdebt(g, luaO_applyparam(g->gcpstepsize, 100)); + luaE_setdebt(g, applygcparam(g, STEPSIZE, 100)); } @@ -1255,8 +1255,8 @@ static void minor2inc (lua_State *L, global_State *g, int kind) { ** major collection. (That percentage is computed in 'limit'.) */ static int checkminormajor (lua_State *L, global_State *g, l_obj addedold1) { - l_obj step = luaO_applyparam(g->gcpgenminormul, g->GCmajorminor); - l_obj limit = luaO_applyparam(g->gcpminormajor, g->GCmajorminor); + l_obj step = applygcparam(g, MINORMUL, g->GCmajorminor); + l_obj limit = applygcparam(g, MINORMAJOR, g->GCmajorminor); //printf("-> major? %ld %ld %ld %ld (%ld)\n", g->marked, limit, step, addedold1, gettotalobjs(g)); if (addedold1 >= (step >> 1) || g->marked >= limit) { minor2inc(L, g, KGC_GENMAJOR); /* go to major mode */ @@ -1347,7 +1347,7 @@ static void atomic2gen (lua_State *L, global_State *g) { ** total number of objects grows 'genminormul'%. */ static void setminordebt (global_State *g) { - luaE_setdebt(g, luaO_applyparam(g->gcpgenminormul, g->GCmajorminor)); + luaE_setdebt(g, applygcparam(g, MINORMUL, g->GCmajorminor)); } @@ -1404,7 +1404,7 @@ static int checkmajorminor (lua_State *L, global_State *g) { if (g->gckind == KGC_GENMAJOR) { l_obj numobjs = gettotalobjs(g); l_obj addedobjs = numobjs - g->GCmajorminor; - l_obj limit = luaO_applyparam(g->gcpmajorminor, addedobjs); + l_obj limit = applygcparam(g, MAJORMINOR, addedobjs); l_obj tobecollected = numobjs - g->marked; //printf("-> minor? %ld %ld %ld\n", tobecollected, limit, numobjs); if (tobecollected > limit) { @@ -1634,8 +1634,8 @@ void luaC_runtilstate (lua_State *L, int state, int fast) { ** controls when next step will be performed. */ static void incstep (lua_State *L, global_State *g) { - l_obj stepsize = luaO_applyparam(g->gcpstepsize, 100); - l_obj work2do = luaO_applyparam(g->gcpstepmul, stepsize); + l_obj stepsize = applygcparam(g, STEPSIZE, 100); + l_obj work2do = applygcparam(g, STEPMUL, stepsize); int fast = 0; if (work2do == 0) { /* special case: do a full collection */ work2do = MAX_LOBJ; /* do unlimited work */ diff --git a/lgc.h b/lgc.h index 6a03f787..9aff11f5 100644 --- a/lgc.h +++ b/lgc.h @@ -193,7 +193,8 @@ #define LUAI_GCSTEPSIZE 250 -#define setgcparam(g,p,v) if ((v) >= 0) {g->p = luaO_codeparam(v);} +#define setgcparam(g,p,v) (g->gcparams[LUA_GCP##p] = luaO_codeparam(v)) +#define applygcparam(g,p,x) luaO_applyparam(g->gcparams[LUA_GCP##p], x) /* ** Control when GC is running: diff --git a/lstate.c b/lstate.c index 19505845..de02c91a 100644 --- a/lstate.c +++ b/lstate.c @@ -365,12 +365,12 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud, unsigned int seed) { g->marked = 0; g->GCdebt = 0; setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */ - setgcparam(g, gcppause, LUAI_GCPAUSE); - setgcparam(g, gcpstepmul, LUAI_GCMUL); - setgcparam(g, gcpstepsize, LUAI_GCSTEPSIZE); - setgcparam(g, gcpgenminormul, LUAI_GENMINORMUL); - setgcparam(g, gcpminormajor, LUAI_MINORMAJOR); - setgcparam(g, gcpmajorminor, LUAI_MAJORMINOR); + setgcparam(g, PAUSE, LUAI_GCPAUSE); + setgcparam(g, STEPMUL, LUAI_GCMUL); + setgcparam(g, STEPSIZE, LUAI_GCSTEPSIZE); + setgcparam(g, MINORMUL, LUAI_GENMINORMUL); + setgcparam(g, MINORMAJOR, LUAI_MINORMAJOR); + setgcparam(g, MAJORMINOR, LUAI_MAJORMINOR); for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { /* memory allocation error: free partial state */ diff --git a/lstate.h b/lstate.h index 5e2020e7..7f567453 100644 --- a/lstate.h +++ b/lstate.h @@ -264,12 +264,7 @@ typedef struct global_State { TValue l_registry; TValue nilvalue; /* a nil value */ unsigned int seed; /* randomized seed for hashes */ - lu_byte gcpgenminormul; /* control minor generational collections */ - lu_byte gcpmajorminor; /* control shift major->minor */ - lu_byte gcpminormajor; /* control shift minor->major */ - lu_byte gcppause; /* size of pause between successive GCs */ - lu_byte gcpstepmul; /* GC "speed" */ - lu_byte gcpstepsize; /* GC granularity */ + lu_byte gcparams[LUA_GCPN]; lu_byte currentwhite; lu_byte gcstate; /* state of garbage collector */ lu_byte gckind; /* kind of GC running */ diff --git a/ltests.c b/ltests.c index 93af528e..cf9a8eaf 100644 --- a/ltests.c +++ b/ltests.c @@ -1037,12 +1037,12 @@ static int query_GCparams (lua_State *L) { global_State *g = G(L); lua_pushinteger(L, gettotalobjs(g)); lua_pushinteger(L, g->GCdebt); - lua_pushinteger(L, luaO_applyparam(g->gcpgenminormul, 100)); - lua_pushinteger(L, luaO_applyparam(g->gcpmajorminor, 100)); - lua_pushinteger(L, luaO_applyparam(g->gcpminormajor, 100)); - lua_pushinteger(L, luaO_applyparam(g->gcppause, 100)); - lua_pushinteger(L, luaO_applyparam(g->gcpstepmul, 100)); - lua_pushinteger(L, luaO_applyparam(g->gcpstepsize, 100)); + lua_pushinteger(L, applygcparam(g, MINORMUL, 100)); + lua_pushinteger(L, applygcparam(g, MAJORMINOR, 100)); + lua_pushinteger(L, applygcparam(g, MINORMAJOR, 100)); + lua_pushinteger(L, applygcparam(g, PAUSE, 100)); + lua_pushinteger(L, applygcparam(g, STEPMUL, 100)); + lua_pushinteger(L, applygcparam(g, STEPSIZE, 100)); return 8; } diff --git a/ltests.h b/ltests.h index da773d6e..70afa7a3 100644 --- a/ltests.h +++ b/ltests.h @@ -15,6 +15,8 @@ #define LUA_COMPAT_MATHLIB #define LUA_COMPAT_LT_LE +#define LUA_COMPAT_GCPARAMS + #define LUA_DEBUG diff --git a/lua.c b/lua.c index d26dd8ac..1e884b07 100644 --- a/lua.c +++ b/lua.c @@ -646,7 +646,7 @@ static int pmain (lua_State *L) { luai_openlibs(L); /* open standard libraries */ createargtable(L, argv, argc, script); /* create table 'arg' */ lua_gc(L, LUA_GCRESTART); /* start GC... */ - lua_gc(L, LUA_GCGEN, -1, -1, -1); /* ...in generational mode */ + lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */ if (!(args & has_E)) { /* no option '-E'? */ if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */ return 0; /* error running LUA_INIT */ diff --git a/lua.h b/lua.h index 32768561..5e2e08d9 100644 --- a/lua.h +++ b/lua.h @@ -325,7 +325,7 @@ LUA_API void (lua_warning) (lua_State *L, const char *msg, int tocont); /* -** garbage-collection function and options +** garbage-collection options */ #define LUA_GCSTOP 0 @@ -337,6 +337,25 @@ LUA_API void (lua_warning) (lua_State *L, const char *msg, int tocont); #define LUA_GCISRUNNING 6 #define LUA_GCGEN 7 #define LUA_GCINC 8 +#define LUA_GCSETPARAM 9 + + +/* +** garbage-collection parameters +*/ +/* parameters for generational mode */ +#define LUA_GCPMINORMUL 0 /* control minor collections */ +#define LUA_GCPMAJORMINOR 1 /* control shift major->minor */ +#define LUA_GCPMINORMAJOR 2 /* control shift minor->major */ + +/* parameters for incremental mode */ +#define LUA_GCPPAUSE 3 /* size of pause between successive GCs */ +#define LUA_GCPSTEPMUL 4 /* GC "speed" */ +#define LUA_GCPSTEPSIZE 5 /* GC granularity */ + +/* number of parameters */ +#define LUA_GCPN 6 + LUA_API int (lua_gc) (lua_State *L, int what, ...); diff --git a/manual/manual.of b/manual/manual.of index e6a3cd9e..92d408e5 100644 --- a/manual/manual.of +++ b/manual/manual.of @@ -681,12 +681,10 @@ effectively producing a non-incremental, stop-the-world collector. The garbage-collector step size controls the size of each incremental step, specifically how many objects the interpreter creates -before performing a step. -This parameter is logarithmic: -A value of @M{n} means the interpreter will create @M{2@sp{n}} -objects between steps. -The default value is 8, -which means steps of approximately @N{256 objects}. +before performing a step: +A value of @M{n} means the interpreter will create +approximately @M{n} objects between steps. +The default value is 250. } @@ -728,11 +726,13 @@ The default value is 100. The major-minor multiplier controls the shift back to minor collections. For a multiplier @M{x}, the collector will shift back to minor collections -after a major collection collects at least @M{x%} of the allocated objects. +after a major collection collects at least @M{x%} +of the objects allocated during the last cycle. + In particular, for a multiplier of 0, the collector will immediately shift back to minor collections after doing one cycle of major collections. -The default value is 20. +The default value is 80. } @@ -3336,19 +3336,32 @@ Returns a boolean that tells whether the collector is running (i.e., not stopped). } -@item{@defid{LUA_GCINC} (int pause, int stepmul, int stepsize)| -Changes the collector to incremental mode -with the given parameters @see{incmode}. +@item{@defid{LUA_GCINC}| +Changes the collector to incremental mode. Returns the previous mode (@id{LUA_GCGEN} or @id{LUA_GCINC}). } -@item{@defid{LUA_GCGEN} (int minormul, int minormajor, int majorminor)| -Changes the collector to generational mode -with the given parameters @see{genmode}. +@item{@defid{LUA_GCGEN}| +Changes the collector to generational mode. Returns the previous mode (@id{LUA_GCGEN} or @id{LUA_GCINC}). } +@item{@defid{LUA_GCSETPARAM} (int param, int value)| +Changes the values of a parameter of the collector and returns +the previous value of that parameter. +The argument @id{param} must have one of the following values: +@description{ +@item{@defid{LUA_GCPMINORMUL}| The minor multiplier. } +@item{@defid{LUA_GCPMAJORMINOR}| The major-minor multiplier. } +@item{@defid{LUA_GCPMINORMAJOR}| The minor-major multiplier. } +@item{@defid{LUA_GCPPAUSE}| The garbage-collector pause. } +@item{@defid{LUA_GCPSTEPMUL}| The step multiplier. } +@item{@defid{LUA_GCPSTEPSIZE}| The step size. } } +} + +} + For more details about these options, see @Lid{collectgarbage}. @@ -6347,20 +6360,35 @@ Returns a boolean that tells whether the collector is running } @item{@St{incremental}| -Change the collector mode to incremental. -This option can be followed by three numbers: -the garbage-collector pause, -the step multiplier, -and the step size @see{incmode}. -A -1 or absent value means to not change that value. +Changes the collector mode to incremental and returns the previous mode. } @item{@St{generational}| -Change the collector mode to generational. -This option can be followed by three numbers: -the garbage-collector minor multiplier, -the minor-major multiplier, and the major-minor multiplier @see{genmode}. -A -1 or absent value means to not change that value. +Changes the collector mode to generational and returns the previous mode. +} + +@item{@St{setparam}| +Changes the values of a parameter of the collector and returns +the previous value of that parameter. +This option must be followed by two extra arguments: +The name of the parameter being changed (a string) +and the new value for that parameter (an integer). +The argument @id{param} must have one of the following values: +@description{ +@item{@St{minormul}| The minor multiplier. } +@item{@St{majorminor}| The major-minor multiplier. } +@item{@St{minormajor}| The minor-major multiplier. } +@item{@St{pause}| The garbage-collector pause. } +@item{@St{stepmul}| The step multiplier. } +@item{@St{stepsize}| The step size. } +} +To be able to divide by 100 +(as most parameters are given as percentages) +without using floating-point arithmetic, +Lua stores these parameters encoded. +This encoding approximates the real value; +so, the value returned as the previous value may not be +equal to the last value set. } } @@ -9249,9 +9277,10 @@ declare a local variable with the same name in the loop body. @itemize{ @item{ -There were several changes in the parameters -for the options @St{incremental} and @St{generational} -of the function @Lid{collectgarbage}. +Parameters for the garbage collection are not set +with the options @St{incremental} and @St{generational}; +instead, there is a new option @St{setparam} to that end. +Moreover, there were some changes in the parameters themselves. } } @@ -9277,9 +9306,10 @@ to signal the end of the dump. } @item{ -There were several changes in the parameters -for the options @Lid{LUA_GCINC} and @Lid{LUA_GCGEN} -of the function @Lid{lua_gc}. +Parameters for the garbage collection are not set +with the options @Lid{LUA_GCINC} and @Lid{LUA_GCGEN}; +instead, there is a new option @Lid{LUA_GCSETPARAM} to that end. +Moreover, there were some changes in the parameters themselves. } } diff --git a/testes/gc.lua b/testes/gc.lua index d7e0c4ff..61b5da9c 100644 --- a/testes/gc.lua +++ b/testes/gc.lua @@ -27,17 +27,20 @@ end -- test weird parameters to 'collectgarbage' do + collectgarbage("incremental") + local opause = collectgarbage("setparam", "pause", 100) + local ostepmul = collectgarbage("setparam", "stepmul", 100) local t = {0, 2, 10, 90, 500, 5000, 30000, 0x7ffffffe} for i = 1, #t do - local p = t[i] + collectgarbage("setparam", "pause", t[i]) for j = 1, #t do - local m = t[j] - collectgarbage("incremental", p, m) + collectgarbage("setparam", "stepmul", t[j]) collectgarbage("step") end end -- restore original parameters - collectgarbage("incremental", 200, 300) + collectgarbage("setparam", "pause", opause) + collectgarbage("setparam", "stepmul", ostepmul) collectgarbage() end diff --git a/testes/gengc.lua b/testes/gengc.lua index d708d7fc..cae07285 100644 --- a/testes/gengc.lua +++ b/testes/gengc.lua @@ -163,14 +163,15 @@ assert(collectgarbage'isrunning') do print"testing stop-the-world collection" - collectgarbage("incremental", nil, 0) + local step = collectgarbage("setparam", "stepsize", 0); + collectgarbage("incremental") -- each step does a complete cycle assert(collectgarbage("step")) assert(collectgarbage("step")) -- back to default value - collectgarbage("incremental", nil, 200) + collectgarbage("setparam", "stepsize", step); end collectgarbage(oldmode)