mirror of
https://github.com/lua/lua
synced 2025-01-06 01:22:06 +03:00
double-linked list of all upvalues elliminated and changed to a
traversal of all non-marked threads
This commit is contained in:
parent
677d90165f
commit
623e388bb4
34
lfunc.c
34
lfunc.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lfunc.c,v 2.30 2012/10/03 12:36:46 roberto Exp roberto $
|
||||
** $Id: lfunc.c,v 2.31 2013/08/05 16:58:28 roberto Exp roberto $
|
||||
** Auxiliary functions to manipulate prototypes and closures
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -38,7 +38,7 @@ Closure *luaF_newLclosure (lua_State *L, int n) {
|
||||
|
||||
UpVal *luaF_newupval (lua_State *L) {
|
||||
UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv;
|
||||
uv->v = &uv->u.value;
|
||||
uv->v = &uv->value;
|
||||
setnilvalue(uv->v);
|
||||
return uv;
|
||||
}
|
||||
@ -51,7 +51,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
|
||||
UpVal *uv;
|
||||
while (*pp != NULL && (p = gco2uv(*pp))->v >= level) {
|
||||
GCObject *o = obj2gco(p);
|
||||
lua_assert(p->v != &p->u.value);
|
||||
lua_assert(p->v != &p->value);
|
||||
if (p->v == level) { /* found a corresponding upvalue? */
|
||||
if (isdead(g, o)) /* is it dead? */
|
||||
changewhite(o); /* resurrect it */
|
||||
@ -62,42 +62,22 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
|
||||
/* not found: create a new one */
|
||||
uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv;
|
||||
uv->v = level; /* current value lives in the stack */
|
||||
uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */
|
||||
uv->u.l.next = g->uvhead.u.l.next;
|
||||
uv->u.l.next->u.l.prev = uv;
|
||||
g->uvhead.u.l.next = uv;
|
||||
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
|
||||
return uv;
|
||||
}
|
||||
|
||||
|
||||
static void unlinkupval (UpVal *uv) {
|
||||
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
|
||||
uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */
|
||||
uv->u.l.prev->u.l.next = uv->u.l.next;
|
||||
}
|
||||
|
||||
|
||||
void luaF_freeupval (lua_State *L, UpVal *uv) {
|
||||
if (uv->v != &uv->u.value) /* is it open? */
|
||||
unlinkupval(uv); /* remove from open list */
|
||||
luaM_free(L, uv); /* free upvalue */
|
||||
}
|
||||
|
||||
|
||||
void luaF_close (lua_State *L, StkId level) {
|
||||
UpVal *uv;
|
||||
global_State *g = G(L);
|
||||
while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) {
|
||||
GCObject *o = obj2gco(uv);
|
||||
lua_assert(!isblack(o) && uv->v != &uv->u.value);
|
||||
lua_assert(!isblack(o) && uv->v != &uv->value);
|
||||
L->openupval = uv->next; /* remove from `open' list */
|
||||
if (isdead(g, o))
|
||||
luaF_freeupval(L, uv); /* free upvalue */
|
||||
luaM_free(L, uv); /* free upvalue */
|
||||
else {
|
||||
unlinkupval(uv); /* remove upvalue from 'uvhead' list */
|
||||
setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */
|
||||
uv->v = &uv->u.value; /* now current value lives here */
|
||||
setobj(L, &uv->value, uv->v); /* move value to upvalue slot */
|
||||
uv->v = &uv->value; /* now current value lives here */
|
||||
gch(o)->next = g->allgc; /* link upvalue into 'allgc' list */
|
||||
g->allgc = o;
|
||||
luaC_checkupvalcolor(g, uv);
|
||||
|
3
lfunc.h
3
lfunc.h
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lfunc.h,v 2.7 2012/01/20 22:05:50 roberto Exp roberto $
|
||||
** $Id: lfunc.h,v 2.8 2012/05/08 13:53:33 roberto Exp roberto $
|
||||
** Auxiliary functions to manipulate prototypes and closures
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -25,7 +25,6 @@ LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
|
||||
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
|
||||
LUAI_FUNC void luaF_close (lua_State *L, StkId level);
|
||||
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
|
||||
LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv);
|
||||
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
|
||||
int pc);
|
||||
|
||||
|
25
lgc.c
25
lgc.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lgc.c,v 2.141 2013/04/26 18:26:49 roberto Exp roberto $
|
||||
** $Id: lgc.c,v 2.142 2013/08/05 16:58:28 roberto Exp roberto $
|
||||
** Garbage Collector
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -258,7 +258,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
|
||||
case LUA_TUPVAL: {
|
||||
UpVal *uv = gco2uv(o);
|
||||
markvalue(g, uv->v);
|
||||
if (uv->v != &uv->u.value) /* open? */
|
||||
if (uv->v != &uv->value) /* open? */
|
||||
return; /* open upvalues remain gray */
|
||||
size = sizeof(UpVal);
|
||||
break;
|
||||
@ -317,14 +317,21 @@ static void markbeingfnz (global_State *g) {
|
||||
|
||||
|
||||
/*
|
||||
** mark all values stored in marked open upvalues. (See comment in
|
||||
** 'lstate.h'.)
|
||||
** Mark all values stored in marked open upvalues from non-marked threads.
|
||||
** (Values from marked threads were already marked when traversing the
|
||||
** thread.)
|
||||
*/
|
||||
static void remarkupvals (global_State *g) {
|
||||
UpVal *uv;
|
||||
for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
|
||||
if (isgray(obj2gco(uv)))
|
||||
markvalue(g, uv->v);
|
||||
GCObject *thread = hvalue(&g->l_registry)->next;
|
||||
for (; thread != NULL; thread = gch(thread)->next) {
|
||||
lua_assert(!isblack(thread)); /* threads are never black */
|
||||
if (!isgray(thread)) { /* dead thread? */
|
||||
GCObject *uv = gco2th(thread)->openupval;
|
||||
for (; uv != NULL; uv = gch(uv)->next) {
|
||||
if (isgray(uv)) /* marked? */
|
||||
markvalue(g, gco2uv(uv)->v); /* remark upvalue's value */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -669,7 +676,7 @@ static void freeobj (lua_State *L, GCObject *o) {
|
||||
luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues));
|
||||
break;
|
||||
}
|
||||
case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
|
||||
case LUA_TUPVAL: luaM_free(L, gco2uv(o)); break;
|
||||
case LUA_TTABLE: luaH_free(L, gco2t(o)); break;
|
||||
case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break;
|
||||
case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;
|
||||
|
10
lobject.h
10
lobject.h
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lobject.h,v 2.77 2013/05/06 17:17:09 roberto Exp roberto $
|
||||
** $Id: lobject.h,v 2.78 2013/05/14 15:59:04 roberto Exp roberto $
|
||||
** Type definitions for Lua objects
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -395,13 +395,7 @@ typedef struct Proto {
|
||||
typedef struct UpVal {
|
||||
CommonHeader;
|
||||
TValue *v; /* points to stack or to its own value */
|
||||
union {
|
||||
TValue value; /* the value (when closed) */
|
||||
struct { /* double linked list (when open) */
|
||||
struct UpVal *prev;
|
||||
struct UpVal *next;
|
||||
} l;
|
||||
} u;
|
||||
TValue value; /* the value (when closed) */
|
||||
} UpVal;
|
||||
|
||||
|
||||
|
8
lstate.c
8
lstate.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lstate.c,v 2.99 2012/10/02 17:40:53 roberto Exp roberto $
|
||||
** $Id: lstate.c,v 2.100 2013/08/05 16:58:28 roberto Exp roberto $
|
||||
** Global State
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -230,7 +230,9 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
|
||||
lua_State *L1;
|
||||
lua_lock(L);
|
||||
luaC_checkGC(L);
|
||||
L1 = &luaC_newobj(L, LUA_TTHREAD, sizeof(LX), NULL, offsetof(LX, l))->th;
|
||||
/* create new thread, linked after 'l_registry' */
|
||||
L1 = &luaC_newobj(L, LUA_TTHREAD, sizeof(LX),
|
||||
&hvalue(&G(L)->l_registry)->next, offsetof(LX, l))->th;
|
||||
setthvalue(L, L->top, L1);
|
||||
api_incr_top(L);
|
||||
preinit_state(L1, G(L));
|
||||
@ -273,8 +275,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
||||
g->ud = ud;
|
||||
g->mainthread = L;
|
||||
g->seed = makeseed(L);
|
||||
g->uvhead.u.l.prev = &g->uvhead;
|
||||
g->uvhead.u.l.next = &g->uvhead;
|
||||
g->gcrunning = 0; /* no GC while building state */
|
||||
g->GCestimate = 0;
|
||||
g->strt.size = 0;
|
||||
|
20
lstate.h
20
lstate.h
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lstate.h,v 2.82 2012/07/02 13:37:04 roberto Exp roberto $
|
||||
** $Id: lstate.h,v 2.83 2013/08/05 16:58:28 roberto Exp roberto $
|
||||
** Global State
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -20,17 +20,18 @@
|
||||
** be kept somehow accessible until being freed.
|
||||
**
|
||||
** Lua keeps most objects linked in list g->allgc. The link uses field
|
||||
** 'next' of the CommonHeader.
|
||||
** 'next' of the CommonHeader. Threads (except the main one) ar kept
|
||||
** at the end of the 'allgc' list, after the 'l_registry' (which is
|
||||
** the first object to be added to the list).
|
||||
**
|
||||
** Strings are kept in several lists headed by the array g->strt.hash.
|
||||
** Short strings are kept in several lists headed by the array g->strt.hash.
|
||||
**
|
||||
** Open upvalues are not subject to independent garbage collection. They
|
||||
** are collected together with their respective threads. Lua keeps a
|
||||
** double-linked list with all open upvalues (g->uvhead) so that it can
|
||||
** mark objects referred by them. (They are always gray, so they must
|
||||
** be remarked in the atomic step. Usually their contents would be marked
|
||||
** when traversing the respective threads, but the thread may already be
|
||||
** dead, while the upvalue is still accessible through closures.)
|
||||
** are collected together with their respective threads. (They are
|
||||
** always gray, so they must be remarked in the atomic step. Usually
|
||||
** their contents would be marked when traversing the respective
|
||||
** threads, but the thread may already be dead, while the upvalue is
|
||||
** still accessible through closures.)
|
||||
**
|
||||
** Objects with finalizers are kept in the list g->finobj.
|
||||
**
|
||||
@ -133,7 +134,6 @@ typedef struct global_State {
|
||||
GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
|
||||
GCObject *allweak; /* list of all-weak tables */
|
||||
GCObject *tobefnz; /* list of userdata to be GC */
|
||||
UpVal uvhead; /* head of double-linked list of all open upvalues */
|
||||
Mbuffer buff; /* temporary buffer for string concatenation */
|
||||
int gcpause; /* size of pause between successive GCs */
|
||||
int gcstepmul; /* GC `granularity' */
|
||||
|
19
ltests.c
19
ltests.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ltests.c,v 2.139 2013/06/20 21:59:13 roberto Exp roberto $
|
||||
** $Id: ltests.c,v 2.140 2013/08/05 16:58:28 roberto Exp roberto $
|
||||
** Internal Module for Debugging of the Lua Implementation
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -310,7 +310,7 @@ static void checkstack (global_State *g, lua_State *L1) {
|
||||
lua_assert(!isdead(g, obj2gco(L1)));
|
||||
for (uvo = L1->openupval; uvo != NULL; uvo = gch(uvo)->next) {
|
||||
UpVal *uv = gco2uv(uvo);
|
||||
lua_assert(uv->v != &uv->u.value); /* must be open */
|
||||
lua_assert(uv->v != &uv->value); /* must be open */
|
||||
lua_assert(!isblack(uvo)); /* open upvalues cannot be black */
|
||||
}
|
||||
for (ci = L1->ci; ci != NULL; ci = ci->previous) {
|
||||
@ -334,7 +334,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead) {
|
||||
switch (gch(o)->tt) {
|
||||
case LUA_TUPVAL: {
|
||||
UpVal *uv = gco2uv(o);
|
||||
lua_assert(uv->v == &uv->u.value); /* must be closed */
|
||||
lua_assert(uv->v == &uv->value); /* must be closed */
|
||||
lua_assert(!isgray(o)); /* closed upvalues are never gray */
|
||||
checkvalref(g, o, uv->v);
|
||||
break;
|
||||
@ -419,8 +419,8 @@ static void checkgray (global_State *g, GCObject *o) {
|
||||
int lua_checkmemory (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
GCObject *o;
|
||||
UpVal *uv;
|
||||
int maybedead;
|
||||
int isthread;
|
||||
if (keepinvariant(g)) {
|
||||
lua_assert(!iswhite(obj2gco(g->mainthread)));
|
||||
lua_assert(!iswhite(gcvalue(&g->l_registry)));
|
||||
@ -433,9 +433,12 @@ int lua_checkmemory (lua_State *L) {
|
||||
checkgray(g, g->allgc);
|
||||
lua_assert(g->sweepgc == NULL || issweepphase(g));
|
||||
maybedead = 0;
|
||||
isthread = 0; /* not traversing threads (yet) */
|
||||
for (o = g->allgc; o != NULL; o = gch(o)->next) {
|
||||
if (g->sweepgc && o == *g->sweepgc)
|
||||
maybedead = 1; /* part of the list not yet swept */
|
||||
if (gch(o)->tt == LUA_TTHREAD) isthread = 1; /* now travesing threads... */
|
||||
else lua_assert(!isthread); /* ... and only threads */
|
||||
checkobject(g, o, maybedead);
|
||||
lua_assert(!testbit(o->gch.marked, SEPARATED));
|
||||
}
|
||||
@ -455,14 +458,6 @@ int lua_checkmemory (lua_State *L) {
|
||||
lua_assert(gch(o)->tt == LUA_TUSERDATA ||
|
||||
gch(o)->tt == LUA_TTABLE);
|
||||
}
|
||||
/* check 'uvhead' list */
|
||||
for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
|
||||
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
|
||||
lua_assert(uv->v != &uv->u.value); /* must be open */
|
||||
lua_assert(!isblack(obj2gco(uv))); /* open upvalues are never black */
|
||||
if (!isdead(g, obj2gco(uv)))
|
||||
checkvalref(g, obj2gco(uv), uv->v);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user