optimizations for space in LClosures and time cleanning weak tables
This commit is contained in:
22
lfunc.c
22
lfunc.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lfunc.c,v 1.47 2001/09/07 17:39:10 roberto Exp $
|
** $Id: lfunc.c,v 1.48 2001/10/02 16:45:03 roberto Exp $
|
||||||
** 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
|
||||||
*/
|
*/
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
cast(int, sizeof(TObject)*((n)-1)))
|
cast(int, sizeof(TObject)*((n)-1)))
|
||||||
|
|
||||||
#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \
|
#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \
|
||||||
cast(int, sizeof(LClosureEntry)*((n)-1)))
|
cast(int, sizeof(TObject *)*((n)-1)))
|
||||||
|
|
||||||
|
|
||||||
Closure *luaF_newCclosure (lua_State *L, int nelems) {
|
Closure *luaF_newCclosure (lua_State *L, int nelems) {
|
||||||
@@ -50,8 +50,8 @@ static StkId uppoint (LClosure *cl) {
|
|||||||
StkId lp = NULL;
|
StkId lp = NULL;
|
||||||
int i;
|
int i;
|
||||||
for (i=0; i<cl->nupvalues; i++) {
|
for (i=0; i<cl->nupvalues; i++) {
|
||||||
if (cl->upvals[i].heap == NULL && (lp == NULL || cl->upvals[i].val > lp))
|
if (!isclosed(cl->upvals[i]) && (lp == NULL || cl->upvals[i] > lp))
|
||||||
lp = cl->upvals[i].val;
|
lp = cl->upvals[i];
|
||||||
}
|
}
|
||||||
return lp;
|
return lp;
|
||||||
}
|
}
|
||||||
@@ -77,17 +77,15 @@ static int closeCl (lua_State *L, LClosure *cl, StkId level) {
|
|||||||
int i;
|
int i;
|
||||||
for (i=0; i<cl->nupvalues; i++) {
|
for (i=0; i<cl->nupvalues; i++) {
|
||||||
StkId var;
|
StkId var;
|
||||||
if (cl->upvals[i].heap == NULL && (var=cl->upvals[i].val) >= level) {
|
if (!isclosed(cl->upvals[i]) && (var=cl->upvals[i]) >= level) {
|
||||||
if (ttype(var) != LUA_TUPVAL) {
|
if (ttype(var) != LUA_TUPVAL) {
|
||||||
UpVal *v = luaM_new(L, UpVal);
|
TObject *v = luaM_newvector(L, 2, TObject);
|
||||||
v->val = *var;
|
v[1] = *var;
|
||||||
v->marked = 0;
|
setupvalue(v, G(L)->rootupval, LUA_HEAPUPVAL);
|
||||||
v->next = G(L)->rootupval;
|
|
||||||
G(L)->rootupval = v;
|
G(L)->rootupval = v;
|
||||||
setupvalue(var, v);
|
setupvalue(var, &v[1], LUA_TUPVAL);
|
||||||
}
|
}
|
||||||
cl->upvals[i].heap = vvalue(var);
|
cl->upvals[i] = vvalue(var);
|
||||||
cl->upvals[i].val = &vvalue(var)->val;
|
|
||||||
got = 1;
|
got = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
100
lgc.c
100
lgc.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lgc.c,v 1.114 2001/10/25 19:14:14 roberto Exp roberto $
|
** $Id: lgc.c,v 1.115 2001/10/31 19:58:11 roberto Exp $
|
||||||
** Garbage Collector
|
** Garbage Collector
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
typedef struct GCState {
|
typedef struct GCState {
|
||||||
Table *tmark; /* list of marked tables to be visited */
|
Table *tmark; /* list of marked tables to be visited */
|
||||||
|
Table *toclear; /* list of visited weak tables (to be cleared after GC) */
|
||||||
} GCState;
|
} GCState;
|
||||||
|
|
||||||
|
|
||||||
@@ -65,10 +66,10 @@ static void markclosure (GCState *st, Closure *cl) {
|
|||||||
lua_assert(cl->l.nupvalues == cl->l.p->nupvalues);
|
lua_assert(cl->l.nupvalues == cl->l.p->nupvalues);
|
||||||
protomark(cl->l.p);
|
protomark(cl->l.p);
|
||||||
for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */
|
for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */
|
||||||
UpVal *u = cl->l.upvals[i].heap;
|
TObject *u = cl->l.upvals[i];
|
||||||
if (u && !u->marked) {
|
if (isclosed(u)) {
|
||||||
u->marked = 1;
|
ttype(u-1) = LUA_TNIL; /* temporary value (to mark as visited) */
|
||||||
markobject(st, &u->val);
|
markobject(st, u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,6 +149,10 @@ static void removekey (Node *n) {
|
|||||||
static void traversetable (GCState *st, Table *h) {
|
static void traversetable (GCState *st, Table *h) {
|
||||||
int i;
|
int i;
|
||||||
int mode = h->weakmode;
|
int mode = h->weakmode;
|
||||||
|
if (mode) { /* weak table? must be cleared after GC... */
|
||||||
|
h->mark = st->toclear; /* put in the appropriate list */
|
||||||
|
st->toclear = h;
|
||||||
|
}
|
||||||
if (!(mode & LUA_WEAK_VALUE)) {
|
if (!(mode & LUA_WEAK_VALUE)) {
|
||||||
i = sizearray(h);
|
i = sizearray(h);
|
||||||
while (i--)
|
while (i--)
|
||||||
@@ -167,17 +172,15 @@ static void traversetable (GCState *st, Table *h) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void markall (lua_State *L) {
|
static void markall (lua_State *L, GCState *st) {
|
||||||
GCState st;
|
marktagmethods(G(L), st); /* mark tag methods */
|
||||||
st.tmark = NULL;
|
markstacks(L, st); /* mark all stacks */
|
||||||
marktagmethods(G(L), &st); /* mark tag methods */
|
marktable(st, G(L)->type2tag);
|
||||||
markstacks(L, &st); /* mark all stacks */
|
markobject(st, &G(L)->registry);
|
||||||
marktable(&st, G(L)->type2tag);
|
while (st->tmark) { /* mark tables */
|
||||||
markobject(&st, &G(L)->registry);
|
Table *h = st->tmark; /* get first table from list */
|
||||||
while (st.tmark) { /* mark tables */
|
st->tmark = h->mark; /* remove it from list */
|
||||||
Table *h = st.tmark; /* get first table from list */
|
traversetable(st, h);
|
||||||
st.tmark = h->mark; /* remove it from list */
|
|
||||||
traversetable(&st, h);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,30 +201,27 @@ static int hasmark (const TObject *o) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void cleardeadnodes (Table *h) {
|
/*
|
||||||
int i;
|
** clear (set to nil) keys and values from weaktables that were collected
|
||||||
i = sizearray(h);
|
*/
|
||||||
while (i--) {
|
static void cleartables (Table *h) {
|
||||||
TObject *o = &h->array[i];
|
for (; h; h = h->mark) {
|
||||||
if (!hasmark(o))
|
int i;
|
||||||
setnilvalue(o); /* remove value */
|
lua_assert(h->weakmode);
|
||||||
}
|
i = sizearray(h);
|
||||||
i = sizenode(h);
|
while (i--) {
|
||||||
while (i--) {
|
TObject *o = &h->array[i];
|
||||||
Node *n = node(h, i);
|
if (!hasmark(o))
|
||||||
if (!hasmark(val(n)) || !hasmark(key(n))) {
|
setnilvalue(o); /* remove value */
|
||||||
setnilvalue(val(n)); /* remove value ... */
|
}
|
||||||
removekey(n); /* ... and key */
|
i = sizenode(h);
|
||||||
|
while (i--) {
|
||||||
|
Node *n = node(h, i);
|
||||||
|
if (!hasmark(val(n)) || !hasmark(key(n))) {
|
||||||
|
setnilvalue(val(n)); /* remove value ... */
|
||||||
|
removekey(n); /* ... and key */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void cleartables (global_State *G) {
|
|
||||||
Table *h;
|
|
||||||
for (h = G->roottable; h; h = h->next) {
|
|
||||||
if (h->weakmode && ismarked(h))
|
|
||||||
cleardeadnodes(h);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,16 +284,17 @@ static void collecttable (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
static void collectupval (lua_State *L) {
|
static void collectupval (lua_State *L) {
|
||||||
UpVal **v = &G(L)->rootupval;
|
TObject **v = &G(L)->rootupval;
|
||||||
UpVal *curr;
|
TObject *curr;
|
||||||
while ((curr = *v) != NULL) {
|
while ((curr = *v) != NULL) {
|
||||||
if (curr->marked) {
|
if (ttype(curr) == LUA_TNIL) { /* was marked? */
|
||||||
curr->marked = 0;
|
ttype(curr) = LUA_HEAPUPVAL; /* unmark */
|
||||||
v = &curr->next;
|
v = &vvalue(curr); /* next */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*v = curr->next;
|
lua_assert(ttype(curr) == LUA_HEAPUPVAL);
|
||||||
luaM_freelem(L, curr);
|
*v = vvalue(curr); /* next */
|
||||||
|
luaM_freearray(L, curr, 2, TObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -411,8 +412,11 @@ void luaC_collect (lua_State *L, int all) {
|
|||||||
|
|
||||||
|
|
||||||
void luaC_collectgarbage (lua_State *L) {
|
void luaC_collectgarbage (lua_State *L) {
|
||||||
markall(L);
|
GCState st;
|
||||||
cleartables(G(L));
|
st.tmark = NULL;
|
||||||
|
st.toclear = NULL;
|
||||||
|
markall(L, &st);
|
||||||
|
cleartables(st.toclear);
|
||||||
luaC_collect(L, 0);
|
luaC_collect(L, 0);
|
||||||
checkMbuffer(L);
|
checkMbuffer(L);
|
||||||
G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */
|
G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */
|
||||||
|
|||||||
38
lobject.h
38
lobject.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lobject.h,v 1.114 2001/10/02 16:45:03 roberto Exp $
|
** $Id: lobject.h,v 1.115 2001/10/25 19:14:14 roberto Exp $
|
||||||
** Type definitions for Lua objects
|
** Type definitions for Lua objects
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -31,8 +31,13 @@
|
|||||||
#define NUM_TAGS 6
|
#define NUM_TAGS 6
|
||||||
|
|
||||||
|
|
||||||
/* extra tag: used locally when moving an upvalue from the stack to the heap */
|
/*
|
||||||
|
** extra tags:
|
||||||
|
** first is used locally when moving an upvalue from the stack to the heap;
|
||||||
|
** second prefixes upvalues in the heap
|
||||||
|
*/
|
||||||
#define LUA_TUPVAL 6
|
#define LUA_TUPVAL 6
|
||||||
|
#define LUA_HEAPUPVAL 7
|
||||||
|
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
@@ -40,7 +45,7 @@ typedef union {
|
|||||||
union Udata *u;
|
union Udata *u;
|
||||||
union Closure *cl;
|
union Closure *cl;
|
||||||
struct Table *h;
|
struct Table *h;
|
||||||
struct UpVal *v;
|
struct lua_TObject *v;
|
||||||
lua_Number n; /* LUA_TNUMBER */
|
lua_Number n; /* LUA_TNUMBER */
|
||||||
} Value;
|
} Value;
|
||||||
|
|
||||||
@@ -81,8 +86,8 @@ typedef struct lua_TObject {
|
|||||||
|
|
||||||
#define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
|
#define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
|
||||||
|
|
||||||
#define setupvalue(obj,x) \
|
#define setupvalue(obj,x,t) \
|
||||||
{ TObject *_o=(obj); _o->tt=LUA_TUPVAL; _o->value.v=(x); }
|
{ TObject *_o=(obj); _o->tt=(t); _o->value.v=(x); }
|
||||||
|
|
||||||
#define setobj(obj1,obj2) \
|
#define setobj(obj1,obj2) \
|
||||||
{ TObject *o1=(obj1); const TObject *o2=(obj2); \
|
{ TObject *o1=(obj1); const TObject *o2=(obj2); \
|
||||||
@@ -165,13 +170,15 @@ typedef struct LocVar {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Upvalues in the heap
|
** Upvalues in the heap. There is a small trick here: to allow a closure to
|
||||||
|
** diferentiate between upvalues in the heap and in the stack, upvalues in
|
||||||
|
** the heap always have another TObject before them (like those in the stack),
|
||||||
|
** but those `prefix' objects have a tag that cannot happen in the stack.
|
||||||
|
** Moreover, we use these extra `prexif' object to store GC-related
|
||||||
|
** information.
|
||||||
*/
|
*/
|
||||||
typedef struct UpVal {
|
|
||||||
TObject val;
|
#define isclosed(u) (ttype((u)-1) == LUA_HEAPUPVAL)
|
||||||
struct UpVal *next;
|
|
||||||
int marked;
|
|
||||||
} UpVal;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -188,20 +195,16 @@ typedef struct CClosure {
|
|||||||
} CClosure;
|
} CClosure;
|
||||||
|
|
||||||
|
|
||||||
typedef struct LClosureEntry {
|
|
||||||
TObject *val;
|
|
||||||
UpVal *heap; /* NULL when upvalue is still in the stack */
|
|
||||||
} LClosureEntry;
|
|
||||||
|
|
||||||
typedef struct LClosure {
|
typedef struct LClosure {
|
||||||
lu_byte isC;
|
lu_byte isC;
|
||||||
lu_byte nupvalues;
|
lu_byte nupvalues;
|
||||||
lu_byte marked;
|
lu_byte marked;
|
||||||
union Closure *next; /* first four fields must be equal to CClosure!! */
|
union Closure *next; /* first four fields must be equal to CClosure!! */
|
||||||
struct Proto *p;
|
struct Proto *p;
|
||||||
LClosureEntry upvals[1];
|
TObject *upvals[1];
|
||||||
} LClosure;
|
} LClosure;
|
||||||
|
|
||||||
|
|
||||||
typedef union Closure {
|
typedef union Closure {
|
||||||
CClosure c;
|
CClosure c;
|
||||||
LClosure l;
|
LClosure l;
|
||||||
@@ -212,7 +215,6 @@ typedef union Closure {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Tables
|
** Tables
|
||||||
*/
|
*/
|
||||||
|
|||||||
13
lvm.c
13
lvm.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lvm.c,v 1.196 2001/10/25 19:14:14 roberto Exp roberto $
|
** $Id: lvm.c,v 1.197 2001/10/31 19:58:11 roberto Exp $
|
||||||
** Lua virtual machine
|
** Lua virtual machine
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -391,8 +391,8 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) {
|
|||||||
}
|
}
|
||||||
case OP_GETUPVAL: {
|
case OP_GETUPVAL: {
|
||||||
int b = GETARG_B(i);
|
int b = GETARG_B(i);
|
||||||
lua_assert(cl->upvals[b].heap || cl->upvals[b].val < base);
|
lua_assert(isclosed(cl->upvals[b]) || cl->upvals[b] < base);
|
||||||
setobj(ra, cl->upvals[b].val);
|
setobj(ra, cl->upvals[b]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_GETGLOBAL: {
|
case OP_GETGLOBAL: {
|
||||||
@@ -411,8 +411,8 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) {
|
|||||||
}
|
}
|
||||||
case OP_SETUPVAL: {
|
case OP_SETUPVAL: {
|
||||||
int b = GETARG_B(i);
|
int b = GETARG_B(i);
|
||||||
lua_assert(cl->upvals[b].heap || cl->upvals[b].val < base);
|
lua_assert(isclosed(cl->upvals[b]) || cl->upvals[b] < base);
|
||||||
setobj(cl->upvals[b].val, ra);
|
setobj(cl->upvals[b], ra);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_SETTABLE: {
|
case OP_SETTABLE: {
|
||||||
@@ -649,8 +649,7 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) {
|
|||||||
ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)];
|
ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)];
|
||||||
else {
|
else {
|
||||||
lua_assert(GET_OPCODE(*pc) == OP_MOVE);
|
lua_assert(GET_OPCODE(*pc) == OP_MOVE);
|
||||||
ncl->l.upvals[j].heap = NULL;
|
ncl->l.upvals[j] = base + GETARG_B(*pc);
|
||||||
ncl->l.upvals[j].val = base + GETARG_B(*pc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
luaF_LConlist(L, ncl);
|
luaF_LConlist(L, ncl);
|
||||||
|
|||||||
Reference in New Issue
Block a user