From 65141832d29824ebfbf26e8af9e6e4b8549518d4 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 7 Aug 2020 14:53:38 -0300 Subject: [PATCH] Open upvalues should be gray when entering gen. mode Open upvalues are never black; so, when entering generational mode, they must be colored gray, not black. --- lgc.c | 21 +++++++++++++-------- lstate.h | 14 ++++++++------ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lgc.c b/lgc.c index cb820f9c..7d62fafb 100644 --- a/lgc.c +++ b/lgc.c @@ -267,21 +267,22 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { ** Mark an object. Userdata, strings, and closed upvalues are visited ** and turned black here. Other objects are marked gray and added ** to appropriate list to be visited (and turned black) later. (Open -** upvalues are already linked in 'headuv' list. They are kept gray -** to avoid barriers, as their values will be revisited by the thread.) +** upvalues are already indirectly linked through the 'twups' list. They +** are kept gray to avoid barriers, as their values will be revisited by +** the thread or by 'remarkupvals'.) */ static void reallymarkobject (global_State *g, GCObject *o) { white2gray(o); switch (o->tt) { case LUA_VSHRSTR: case LUA_VLNGSTR: { - gray2black(o); + gray2black(o); /* nothing to visit */ break; } case LUA_VUPVAL: { UpVal *uv = gco2upv(o); if (!upisopen(uv)) /* open upvalues are kept gray */ - gray2black(o); + gray2black(o); /* closed upvalues are visited here */ markvalue(g, uv->v); /* mark its content */ break; } @@ -296,7 +297,7 @@ static void reallymarkobject (global_State *g, GCObject *o) { } /* FALLTHROUGH */ case LUA_VLCL: case LUA_VCCL: case LUA_VTABLE: case LUA_VTHREAD: case LUA_VPROTO: { - linkobjgclist(o, g->gray); + linkobjgclist(o, g->gray); /* to be visited later */ break; } default: lua_assert(0); break; @@ -355,8 +356,10 @@ static int remarkupvals (global_State *g) { for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { lua_assert(getage(uv) <= getage(thread)); work++; - if (!iswhite(uv)) /* upvalue already visited? */ + if (!iswhite(uv)) { /* upvalue already visited? */ + lua_assert(upisopen(uv) && isgray(uv)); markvalue(g, uv->v); /* mark its value */ + } } } } @@ -1028,8 +1031,8 @@ static void setpause (global_State *g); /* ** Sweep a list of objects to enter generational mode. Deletes dead ** objects and turns the non dead to old. All non-dead threads---which -** are now old---must be in a gray list. Everything else is not in a -** gray list. +** are now old---must be in a gray list. Everything else is not in a +** gray list. Open upvalues are also kept gray. */ static void sweep2old (lua_State *L, GCObject **p) { GCObject *curr; @@ -1047,6 +1050,8 @@ static void sweep2old (lua_State *L, GCObject **p) { linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ black2gray(th); /* OK if already gray */ } + else if (curr->tt == LUA_VUPVAL && upisopen(gco2upv(curr))) + black2gray(curr); /* open upvalues are always gray */ else /* everything else is black */ gray2black(curr); /* OK if already black */ p = &curr->next; /* go to next element */ diff --git a/lstate.h b/lstate.h index 697d73b2..1b6bcdf8 100644 --- a/lstate.h +++ b/lstate.h @@ -63,7 +63,7 @@ ** can become gray have such a field. The field is not the same ** in all objects, but it always has this name.) Any gray object ** must belong to one of these lists, and all objects in these lists -** must be gray (with one exception explained below): +** must be gray (with two exceptions explained below): ** ** 'gray': regular gray objects, still waiting to be visited. ** 'grayagain': objects that must be revisited at the atomic phase. @@ -75,11 +75,13 @@ ** 'ephemeron': ephemeron tables with white->white entries; ** 'allweak': tables with weak keys and/or weak values to be cleared. ** -** The exception to that "gray rule" is the TOUCHED2 objects in -** generational mode. Those objects stay in a gray list (because they -** must be visited again at the end of the cycle), but they are marked -** black (because assignments to them must activate barriers, to move -** them back to TOUCHED1). +** The exceptions to that "gray rule" are: +** - TOUCHED2 objects in generational mode stay in a gray list (because +** they must be visited again at the end of the cycle), but they are +** marked black because assignments to them must activate barriers (to +** move them back to TOUCHED1). +** - Open upvales are kept gray to avoid barriers, but they stay out +** of gray lists. (They don't even have a 'gclist' field.) */