Better tests for gray lists

Test uses an extra bit in 'marked' to mark all elements in gray lists
and then check against elements colored gray.
This commit is contained in:
Roberto Ierusalimschy 2020-08-07 14:45:20 -03:00
parent 7c3cb71fa4
commit f13dc59416
3 changed files with 37 additions and 10 deletions

5
lgc.h
View File

@ -69,13 +69,16 @@
/*
** Layout for bit use in 'marked' field. First three bits are
** used for object "age" in generational mode.
** used for object "age" in generational mode. Last bit is used
** by tests.
*/
#define WHITE0BIT 3 /* object is white (type 0) */
#define WHITE1BIT 4 /* object is white (type 1) */
#define BLACKBIT 5 /* object is black */
#define FINALIZEDBIT 6 /* object has been marked for finalization */
#define TESTBIT 7
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)

View File

@ -522,7 +522,11 @@ static lu_mem checkgraylist (global_State *g, GCObject *o) {
int total = 0; /* count number of elements in the list */
((void)g); /* better to keep it available if we need to print an object */
while (o) {
lua_assert(isgray(o) || getage(o) == G_TOUCHED2);
lua_assert(!!isgray(o) ^ (getage(o) == G_TOUCHED2));
//lua_assert(isgray(o) || getage(o) == G_TOUCHED2);
lua_assert(!testbit(o->marked, TESTBIT));
if (keepinvariant(g))
l_setbit(o->marked, TESTBIT); /* mark that object is in a gray list */
total++;
switch (o->tt) {
case LUA_VTABLE: o = gco2t(o)->gclist; break;
@ -556,9 +560,27 @@ static lu_mem checkgrays (global_State *g) {
}
/* Increment 't' if 'o' should be in a gray list */
#define incifingray(o,t) \
if (isgray(o) || getage(o) == G_TOUCHED2) (t)++
/*
** Check whether 'o' should be in a gray list. If so, increment
** 'count' and check its TESTBIT. (It must have been previously set by
** 'checkgraylist'.)
*/
static void incifingray (global_State *g, GCObject *o, lu_mem *count) {
if (!keepinvariant(g))
return; /* gray lists not being kept in these phases */
if (o->tt == LUA_VUPVAL) {
/* only open upvalues can be gray */
lua_assert(!isgray(o) || upisopen(gco2upv(o)));
return; /* upvalues are never in gray lists */
}
/* these are the ones that must be in gray lists */
if (isgray(o) || getage(o) == G_TOUCHED2) {
(*count)++;
lua_assert(testbit(o->marked, TESTBIT));
resetbit(o->marked, TESTBIT); /* prepare for next cycle */
}
}
static lu_mem checklist (global_State *g, int maybedead, int tof,
GCObject *newl, GCObject *survival, GCObject *old, GCObject *reallyold) {
@ -566,22 +588,22 @@ static lu_mem checklist (global_State *g, int maybedead, int tof,
lu_mem total = 0; /* number of object that should be in gray lists */
for (o = newl; o != survival; o = o->next) {
checkobject(g, o, maybedead, G_NEW);
incifingray(o, total);
incifingray(g, o, &total);
lua_assert(!tof == !tofinalize(o));
}
for (o = survival; o != old; o = o->next) {
checkobject(g, o, 0, G_SURVIVAL);
incifingray(o, total);
incifingray(g, o, &total);
lua_assert(!tof == !tofinalize(o));
}
for (o = old; o != reallyold; o = o->next) {
checkobject(g, o, 0, G_OLD1);
incifingray(o, total);
incifingray(g, o, &total);
lua_assert(!tof == !tofinalize(o));
}
for (o = reallyold; o != NULL; o = o->next) {
checkobject(g, o, 0, G_OLD);
incifingray(o, total);
incifingray(g, o, &total);
lua_assert(!tof == !tofinalize(o));
}
return total;
@ -619,7 +641,7 @@ int lua_checkmemory (lua_State *L) {
/* check 'tobefnz' list */
for (o = g->tobefnz; o != NULL; o = o->next) {
checkobject(g, o, 0, G_NEW);
incifingray(o, totalshould);
incifingray(g, o, &totalshould);
lua_assert(tofinalize(o));
lua_assert(o->tt == LUA_VUSERDATA || o->tt == LUA_VTABLE);
}

View File

@ -88,6 +88,7 @@ for _, sa in ipairs(sizes) do -- 'sa' is size of the array part
arr[1 + sa + sh + 1] = "}"
local prog = table.concat(arr)
local f = assert(load(prog))
collectgarbage("stop")
f() -- call once to ensure stack space
-- make sure table is not resized after being created
if sa == 0 or sh == 0 then
@ -97,6 +98,7 @@ for _, sa in ipairs(sizes) do -- 'sa' is size of the array part
end
local t = f()
T.alloccount();
collectgarbage("restart")
assert(#t == sa)
check(t, sa, mp2(sh))
end