diff --git a/lgc.c b/lgc.c index fb02f015..c11a5280 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id$ +** $Id: lgc.c $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -212,7 +212,7 @@ void luaC_barrierback_ (lua_State *L, GCObject *o) { lua_assert(g->gckind != KGC_GEN || (isold(o) && getage(o) != G_TOUCHED1)); if (getage(o) != G_TOUCHED2) /* not already in gray list? */ linkobjgclist(o, g->grayagain); /* link it in 'grayagain' */ - black2gray(o); /* make table gray (again) */ + black2gray(o); /* make object gray (again) */ setage(o, G_TOUCHED1); /* touched in current cycle */ } @@ -515,6 +515,19 @@ static lu_mem traversetable (global_State *g, Table *h) { } +static int traverseudata (global_State *g, Udata *u) { + int i; + markobjectN(g, u->metatable); /* mark its metatable */ + for (i = 0; i < u->nuvalue; i++) + markvalue(g, &u->uv[i].uv); + if (g->gckind == KGC_GEN) { + linkgclist(u, g->grayagain); /* keep it in some gray list */ + black2gray(u); + } + return 1 + u->nuvalue; +} + + /* ** Check the cache of a prototype, to keep invariants. If the ** cache is white, clear it. (A cache should not prevent the @@ -613,15 +626,6 @@ static int traversethread (global_State *g, lua_State *th) { } -static int traverseudata (global_State *g, Udata *u) { - int i; - markobjectN(g, u->metatable); /* mark its metatable */ - for (i = 0; i < u->nuvalue; i++) - markvalue(g, &u->uv[i].uv); - return 1 + u->nuvalue; -} - - /* ** traverse one gray object, turning it to black (except for threads, ** which are always gray). diff --git a/testes/all.lua b/testes/all.lua index cfe21603..37796254 100755 --- a/testes/all.lua +++ b/testes/all.lua @@ -1,5 +1,5 @@ #!../lua --- $Id: all.lua,v 1.100 2018/03/09 14:23:48 roberto Exp $ +-- $Id: all.lua $ -- See Copyright Notice at the end of this file @@ -162,7 +162,7 @@ olddofile('strings.lua') olddofile('literals.lua') dofile('tpack.lua') assert(dofile('attrib.lua') == 27) - +dofile('gengc.lua') assert(dofile('locals.lua') == 5) dofile('constructs.lua') dofile('code.lua', true) diff --git a/testes/gc.lua b/testes/gc.lua index 9647cd54..05072efd 100644 --- a/testes/gc.lua +++ b/testes/gc.lua @@ -1,7 +1,7 @@ --- $Id: gc.lua,v 1.82 2018/03/12 14:19:36 roberto Exp $ +-- $Id: gc.lua $ -- See Copyright Notice in file all.lua -print('testing garbage collection') +print('testing incremental garbage collection') local debug = require"debug" diff --git a/testes/gengc.lua b/testes/gengc.lua new file mode 100644 index 00000000..36aed806 --- /dev/null +++ b/testes/gengc.lua @@ -0,0 +1,83 @@ +-- $Id: gengc.lua $ +-- See Copyright Notice in file all.lua + +print('testing generational garbage collection') + +local debug = require"debug" + +assert(collectgarbage("isrunning")) + +collectgarbage() + +local oldmode = collectgarbage("generational") + + +-- ensure that table barrier evolves correctly +do + local U = {} + -- full collection makes 'U' old + collectgarbage() + assert(not T or T.gcage(U) == "old") + + -- U refers to a new table, so it becomes 'touched1' + U[1] = {x = {234}} + assert(not T or (T.gcage(U) == "touched1" and T.gcage(U[1]) == "new")) + + -- both U and the table survive one more collection + collectgarbage("step", 0) + assert(not T or (T.gcage(U) == "touched2" and T.gcage(U[1]) == "survival")) + + -- both U and the table survive yet another collection + -- now everything is old + collectgarbage("step", 0) + assert(not T or (T.gcage(U) == "old" and T.gcage(U[1]) == "old1")) + + -- data was not corrupted + assert(U[1].x[1] == 234) +end + + +if T == nil then + (Message or print)('\n >>> testC not active: \z + skipping some generational tests <<<\n') + print 'OK' + return +end + + +-- ensure that userdata barrier evolves correctly +do + local U = T.newuserdata(0, 1) + -- full collection makes 'U' old + collectgarbage() + assert(T.gcage(U) == "old") + + -- U refers to a new table, so it becomes 'touched1' + debug.setuservalue(U, {x = {234}}) + assert(T.gcage(U) == "touched1" and + T.gcage(debug.getuservalue(U)) == "new") + + -- both U and the table survive one more collection + collectgarbage("step", 0) + assert(T.gcage(U) == "touched2" and + T.gcage(debug.getuservalue(U)) == "survival") + + -- both U and the table survive yet another collection + -- now everything is old + collectgarbage("step", 0) + assert(T.gcage(U) == "old" and + T.gcage(debug.getuservalue(U)) == "old1") + + -- data was not corrupted + assert(debug.getuservalue(U).x[1] == 234) +end + + + +-- just to make sure +assert(collectgarbage'isrunning') + +collectgarbage(oldmode) + +print('OK') +