mirror of https://github.com/rusefi/lua.git
barrier for prototype's cache (with new gray list 'protogray' to keep
prototypes to have their caches visited again) + constant 'MAXMISS'
This commit is contained in:
parent
8634b2a011
commit
2376eb6347
9
lfunc.h
9
lfunc.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
** $Id: lfunc.h,v 2.15 2015/01/13 15:49:11 roberto Exp roberto $
|
** $Id: lfunc.h,v 2.16 2017/04/11 18:41:09 roberto Exp roberto $
|
||||||
** Auxiliary functions to manipulate prototypes and closures
|
** Auxiliary functions to manipulate prototypes and closures
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -32,6 +32,13 @@
|
||||||
#define upisopen(up) ((up)->v != &(up)->u.value)
|
#define upisopen(up) ((up)->v != &(up)->u.value)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** maximum number of misses before giving up the cache of closures
|
||||||
|
** in prototypes
|
||||||
|
*/
|
||||||
|
#define MAXMISS 10
|
||||||
|
|
||||||
|
|
||||||
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
|
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
|
||||||
LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems);
|
LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems);
|
||||||
LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems);
|
LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems);
|
||||||
|
|
75
lgc.c
75
lgc.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
** $Id: lgc.c,v 2.226 2017/04/24 17:52:18 roberto Exp roberto $
|
** $Id: lgc.c,v 2.227 2017/04/30 20:43:26 roberto Exp roberto $
|
||||||
** Garbage Collector
|
** Garbage Collector
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -179,6 +179,26 @@ void luaC_barrierback_ (lua_State *L, Table *t) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Barrier for prototype's cache of closures. For an 'old1'
|
||||||
|
** object, making it gray stops it from being visited by 'markold',
|
||||||
|
** so it is linked in the 'grayagain' list to ensure it will be
|
||||||
|
** visited. Otherwise, it goes to 'protogray', as only its 'cache' field
|
||||||
|
** needs to be revisited. (A prototype to be in this barrier must be
|
||||||
|
** already finished, so its other fields cannot change and do not need
|
||||||
|
** to be revisited.)
|
||||||
|
*/
|
||||||
|
LUAI_FUNC void luaC_protobarrier_ (lua_State *L, Proto *p) {
|
||||||
|
global_State *g = G(L);
|
||||||
|
lua_assert(g->gckind != KGC_GEN || isold(p));
|
||||||
|
if (getage(p) == G_OLD1) /* still need to be visited? */
|
||||||
|
linkgclist(p, g->grayagain); /* link it in 'grayagain' */
|
||||||
|
else
|
||||||
|
linkgclist(p, g->protogray); /* link it in 'protogray' */
|
||||||
|
black2gray(p); /* make prototype gray (to avoid other barriers) */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaC_fix (lua_State *L, GCObject *o) {
|
void luaC_fix (lua_State *L, GCObject *o) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */
|
lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */
|
||||||
|
@ -332,7 +352,7 @@ static void remarkupvals (global_State *g) {
|
||||||
*/
|
*/
|
||||||
static void restartcollection (global_State *g) {
|
static void restartcollection (global_State *g) {
|
||||||
g->gray = g->grayagain = NULL;
|
g->gray = g->grayagain = NULL;
|
||||||
g->weak = g->allweak = g->ephemeron = NULL;
|
g->weak = g->allweak = g->ephemeron = g->protogray = NULL;
|
||||||
markobject(g, g->mainthread);
|
markobject(g, g->mainthread);
|
||||||
markvalue(g, &g->l_registry);
|
markvalue(g, &g->l_registry);
|
||||||
markmt(g);
|
markmt(g);
|
||||||
|
@ -476,6 +496,32 @@ static lu_mem traversetable (global_State *g, Table *h) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Check the cache of a prototype, to keep invariants. If the
|
||||||
|
** cache is white, clear it. (A cache should not prevent the
|
||||||
|
** collection of its reference.) Otherwise, if in generational
|
||||||
|
** mode, check the generational invariant. If the cache is old,
|
||||||
|
** everything is ok. If the prototype is 'old0', everything
|
||||||
|
** is ok too. (It will naturally be visited again.) If the
|
||||||
|
** prototype is older than 'old0', then its cache (whith is new)
|
||||||
|
** must be visited again in the next collection, so the prototype
|
||||||
|
** goes to the 'protogray' list. (If the prototype has a cache,
|
||||||
|
** it is already immutable and does not need other barriers;
|
||||||
|
** then, it can become gray without problems for its other fields.)
|
||||||
|
*/
|
||||||
|
static void checkprotocache (global_State *g, Proto *p) {
|
||||||
|
if (p->cache) {
|
||||||
|
if (iswhite(p->cache))
|
||||||
|
p->cache = NULL; /* allow cache to be collected */
|
||||||
|
else if (g->gckind == KGC_GEN && !isold(p->cache) && getage(p) >= G_OLD1) {
|
||||||
|
linkgclist(p, g->protogray); /* link it in 'protogray' */
|
||||||
|
black2gray(p); /* make prototype gray */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p->cachemiss = 0; /* restart counting */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Traverse a prototype. (While a prototype is being build, its
|
** Traverse a prototype. (While a prototype is being build, its
|
||||||
** arrays can be larger than needed; the extra slots are filled with
|
** arrays can be larger than needed; the extra slots are filled with
|
||||||
|
@ -483,9 +529,7 @@ static lu_mem traversetable (global_State *g, Table *h) {
|
||||||
*/
|
*/
|
||||||
static int traverseproto (global_State *g, Proto *f) {
|
static int traverseproto (global_State *g, Proto *f) {
|
||||||
int i;
|
int i;
|
||||||
if (f->cache && iswhite(f->cache))
|
checkprotocache(g, f);
|
||||||
f->cache = NULL; /* allow cache to be collected */
|
|
||||||
f->cachemiss = 0; /* restart counting */
|
|
||||||
markobjectN(g, f->source);
|
markobjectN(g, f->source);
|
||||||
for (i = 0; i < f->sizek; i++) /* mark literals */
|
for (i = 0; i < f->sizek; i++) /* mark literals */
|
||||||
markvalue(g, &f->k[i]);
|
markvalue(g, &f->k[i]);
|
||||||
|
@ -629,6 +673,19 @@ static void convergeephemerons (global_State *g) {
|
||||||
** =======================================================
|
** =======================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static void clearprotolist (global_State *g) {
|
||||||
|
GCObject *p = g->protogray;
|
||||||
|
g->protogray = NULL;
|
||||||
|
while (p != NULL) {
|
||||||
|
Proto *pp = gco2p(p);
|
||||||
|
GCObject *next = pp->gclist;
|
||||||
|
lua_assert(isgray(pp) && (pp->cache != NULL || pp->cachemiss >= MAXMISS));
|
||||||
|
gray2black(pp);
|
||||||
|
checkprotocache(g, pp);
|
||||||
|
p = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** clear entries with unmarked keys from all weaktables in list 'l'
|
** clear entries with unmarked keys from all weaktables in list 'l'
|
||||||
|
@ -1073,14 +1130,15 @@ static void correctgraylists (global_State *g) {
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Mark 'old1' objects when starting a new young collection. (Threads
|
** Mark 'old1' objects when starting a new young collection.
|
||||||
** and open upvalues are always gray, and do not need to be marked.
|
** Gray objects are already in some gray list, and so will be visited
|
||||||
** All other old objects are black.)
|
** in the atomic step.
|
||||||
*/
|
*/
|
||||||
static void markold (global_State *g, GCObject *from, GCObject *to) {
|
static void markold (global_State *g, GCObject *from, GCObject *to) {
|
||||||
GCObject *p;
|
GCObject *p;
|
||||||
for (p = from; p != to; p = p->next) {
|
for (p = from; p != to; p = p->next) {
|
||||||
if (getage(p) == G_OLD1) {
|
if (getage(p) == G_OLD1) {
|
||||||
|
lua_assert(!iswhite(p));
|
||||||
if (isblack(p)) {
|
if (isblack(p)) {
|
||||||
black2gray(p); /* should be '2white', but gray works too */
|
black2gray(p); /* should be '2white', but gray works too */
|
||||||
reallymarkobject(g, p);
|
reallymarkobject(g, p);
|
||||||
|
@ -1337,6 +1395,7 @@ static l_mem atomic (lua_State *L) {
|
||||||
clearvalues(g, g->weak, origweak);
|
clearvalues(g, g->weak, origweak);
|
||||||
clearvalues(g, g->allweak, origall);
|
clearvalues(g, g->allweak, origall);
|
||||||
luaS_clearcache(g);
|
luaS_clearcache(g);
|
||||||
|
clearprotolist(g);
|
||||||
g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
|
g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
|
||||||
lua_assert(g->gray == NULL);
|
lua_assert(g->gray == NULL);
|
||||||
work += g->GCmemtrav; /* complete counting */
|
work += g->GCmemtrav; /* complete counting */
|
||||||
|
|
6
lgc.h
6
lgc.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
** $Id: lgc.h,v 2.95 2017/04/10 13:33:04 roberto Exp roberto $
|
** $Id: lgc.h,v 2.96 2017/04/11 18:41:09 roberto Exp roberto $
|
||||||
** Garbage Collector
|
** Garbage Collector
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -151,6 +151,9 @@
|
||||||
(isblack(p) && iswhite(o)) ? \
|
(isblack(p) && iswhite(o)) ? \
|
||||||
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
|
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
|
||||||
|
|
||||||
|
#define luaC_protobarrier(L,p,o) \
|
||||||
|
(isblack(p) ? luaC_protobarrier_(L,p) : cast_void(0))
|
||||||
|
|
||||||
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
|
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
|
||||||
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
|
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
|
||||||
LUAI_FUNC void luaC_step (lua_State *L);
|
LUAI_FUNC void luaC_step (lua_State *L);
|
||||||
|
@ -159,6 +162,7 @@ LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
|
||||||
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
|
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
|
||||||
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
|
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
|
||||||
LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o);
|
LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o);
|
||||||
|
LUAI_FUNC void luaC_protobarrier_ (lua_State *L, Proto *p);
|
||||||
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
|
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
|
||||||
LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);
|
LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);
|
||||||
|
|
||||||
|
|
4
lstate.c
4
lstate.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
** $Id: lstate.c,v 2.137 2017/04/12 18:56:25 roberto Exp roberto $
|
** $Id: lstate.c,v 2.138 2017/04/24 16:59:26 roberto Exp roberto $
|
||||||
** Global State
|
** Global State
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -324,7 +324,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
||||||
g->finobjsur = g->finobjold = g->finobjrold = NULL;
|
g->finobjsur = g->finobjold = g->finobjrold = NULL;
|
||||||
g->sweepgc = NULL;
|
g->sweepgc = NULL;
|
||||||
g->gray = g->grayagain = NULL;
|
g->gray = g->grayagain = NULL;
|
||||||
g->weak = g->ephemeron = g->allweak = NULL;
|
g->weak = g->ephemeron = g->allweak = g->protogray = NULL;
|
||||||
g->twups = NULL;
|
g->twups = NULL;
|
||||||
g->totalbytes = sizeof(LG);
|
g->totalbytes = sizeof(LG);
|
||||||
g->GCdebt = 0;
|
g->GCdebt = 0;
|
||||||
|
|
6
lstate.h
6
lstate.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
** $Id: lstate.h,v 2.138 2017/04/19 17:02:50 roberto Exp roberto $
|
** $Id: lstate.h,v 2.139 2017/04/24 16:59:26 roberto Exp roberto $
|
||||||
** Global State
|
** Global State
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -43,7 +43,8 @@
|
||||||
** 'weak': tables with weak values to be cleared;
|
** 'weak': tables with weak values to be cleared;
|
||||||
** 'ephemeron': ephemeron tables with white->white entries;
|
** 'ephemeron': ephemeron tables with white->white entries;
|
||||||
** 'allweak': tables with weak keys and/or weak values to be cleared.
|
** 'allweak': tables with weak keys and/or weak values to be cleared.
|
||||||
** The last three lists are used only during the atomic phase.
|
** There is also a list 'protogray' for prototypes that need to have
|
||||||
|
** their caches cleared.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -159,6 +160,7 @@ typedef struct global_State {
|
||||||
GCObject *weak; /* list of tables with weak values */
|
GCObject *weak; /* list of tables with weak values */
|
||||||
GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
|
GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
|
||||||
GCObject *allweak; /* list of all-weak tables */
|
GCObject *allweak; /* list of all-weak tables */
|
||||||
|
GCObject *protogray; /* list of prototypes with "new" caches */
|
||||||
GCObject *tobefnz; /* list of userdata to be GC */
|
GCObject *tobefnz; /* list of userdata to be GC */
|
||||||
GCObject *fixedgc; /* list of objects not to be collected */
|
GCObject *fixedgc; /* list of objects not to be collected */
|
||||||
/* fields for generational collector */
|
/* fields for generational collector */
|
||||||
|
|
5
ltests.c
5
ltests.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
** $Id: ltests.c,v 2.215 2017/04/24 16:59:26 roberto Exp roberto $
|
** $Id: ltests.c,v 2.216 2017/04/24 18:06:12 roberto Exp roberto $
|
||||||
** Internal Module for Debugging of the Lua Implementation
|
** Internal Module for Debugging of the Lua Implementation
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -409,6 +409,8 @@ static void checkobject (global_State *g, GCObject *o, int maybedead,
|
||||||
getage(o) == G_TOUCHED1 ||
|
getage(o) == G_TOUCHED1 ||
|
||||||
getage(o) == G_OLD0 ||
|
getage(o) == G_OLD0 ||
|
||||||
o->tt == LUA_TTHREAD ||
|
o->tt == LUA_TTHREAD ||
|
||||||
|
(o->tt == LUA_TPROTO &&
|
||||||
|
(gco2p(o)->cache != NULL || gco2p(o)->cachemiss >= MAXMISS)) ||
|
||||||
(o->tt == LUA_TUPVAL && upisopen(gco2upv(o))));
|
(o->tt == LUA_TUPVAL && upisopen(gco2upv(o))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -446,6 +448,7 @@ static void markgrays (global_State *g) {
|
||||||
checkgraylist(g, g->weak);
|
checkgraylist(g, g->weak);
|
||||||
checkgraylist(g, g->ephemeron);
|
checkgraylist(g, g->ephemeron);
|
||||||
checkgraylist(g, g->allweak);
|
checkgraylist(g, g->allweak);
|
||||||
|
checkgraylist(g, g->protogray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
10
lvm.c
10
lvm.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
** $Id: lvm.c,v 2.274 2017/04/28 20:57:45 roberto Exp roberto $
|
** $Id: lvm.c,v 2.275 2017/04/30 20:43:26 roberto Exp roberto $
|
||||||
** Lua virtual machine
|
** Lua virtual machine
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -626,9 +626,7 @@ static LClosure *getcached (Proto *p, UpVal **encup, StkId base) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** create a new Lua closure, push it in the stack, and initialize
|
** create a new Lua closure, push it in the stack, and initialize
|
||||||
** its upvalues. Note that the closure is not cached if prototype is
|
** its upvalues. ???
|
||||||
** already black (which means that 'cache' was already cleared by the
|
|
||||||
** GC).
|
|
||||||
*/
|
*/
|
||||||
static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
|
static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
|
||||||
StkId ra) {
|
StkId ra) {
|
||||||
|
@ -645,11 +643,11 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
|
||||||
ncl->upvals[i] = encup[uv[i].idx];
|
ncl->upvals[i] = encup[uv[i].idx];
|
||||||
/* new closure is white, so we do not need a barrier here */
|
/* new closure is white, so we do not need a barrier here */
|
||||||
}
|
}
|
||||||
if (p->cachemiss >= 10) /* too many missings? */
|
if (p->cachemiss >= MAXMISS) /* too many missings? */
|
||||||
p->cache = NULL; /* give up cache */
|
p->cache = NULL; /* give up cache */
|
||||||
else {
|
else {
|
||||||
if (!isblack(p)) /* cache will not break GC invariant? */
|
|
||||||
p->cache = ncl; /* save it on cache for reuse */
|
p->cache = ncl; /* save it on cache for reuse */
|
||||||
|
luaC_protobarrier(L, p, ncl);
|
||||||
p->cachemiss++;
|
p->cachemiss++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue