use of a common `dummynode' for all empty tables

This commit is contained in:
Roberto Ierusalimschy 2002-04-23 12:04:39 -03:00
parent f1a1bb23fe
commit 383e8b9e77
4 changed files with 46 additions and 35 deletions

15
lgc.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lgc.c,v 1.133 2002/03/26 18:55:50 roberto Exp roberto $ ** $Id: lgc.c,v 1.134 2002/04/05 18:54:31 roberto Exp roberto $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -211,14 +211,13 @@ static void traversetable (GCState *st, Table *h) {
int weakkey = 0; int weakkey = 0;
int weakvalue = 0; int weakvalue = 0;
marktable(st, h->metatable); marktable(st, h->metatable);
lua_assert(h->lsizenode || h->node == G(st->L)->dummynode);
mode = fasttm(st->L, h->metatable, TM_WEAKMODE); mode = fasttm(st->L, h->metatable, TM_WEAKMODE);
if (mode) { /* weak table? must be cleared after GC... */ if (mode && ttype(mode) == LUA_TSTRING) { /* weak table? */
h->mark = st->toclear; /* put in the appropriate list */ h->mark = st->toclear; /* must be cleared after GC, ... */
st->toclear = h; st->toclear = h; /* ...put in the appropriate list */
if (ttype(mode) == LUA_TSTRING) { weakkey = (strchr(svalue(mode), 'k') != NULL);
weakkey = (strchr(svalue(mode), 'k') != NULL); weakvalue = (strchr(svalue(mode), 'v') != NULL);
weakvalue = (strchr(svalue(mode), 'v') != NULL);
}
} }
if (!weakvalue) { if (!weakvalue) {
i = sizearray(h); i = sizearray(h);

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lstate.c,v 1.89 2002/04/16 17:08:28 roberto Exp roberto $ ** $Id: lstate.c,v 1.90 2002/04/22 14:40:23 roberto Exp roberto $
** Global State ** Global State
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -69,6 +69,9 @@ static void f_luaopen (lua_State *L, void *ud) {
G(L)->rootupval = NULL; G(L)->rootupval = NULL;
G(L)->rootudata = NULL; G(L)->rootudata = NULL;
G(L)->tmudata = NULL; G(L)->tmudata = NULL;
setnilvalue(key(G(L)->dummynode));
setnilvalue(val(G(L)->dummynode));
G(L)->dummynode->next = NULL;
G(L)->nblocks = sizeof(lua_State) + sizeof(global_State); G(L)->nblocks = sizeof(lua_State) + sizeof(global_State);
stack_init(L, L); /* init stack */ stack_init(L, L); /* init stack */
/* create default meta table with a dummy table, and then close the loop */ /* create default meta table with a dummy table, and then close the loop */

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lstate.h,v 1.82 2002/04/10 12:11:07 roberto Exp roberto $ ** $Id: lstate.h,v 1.83 2002/04/16 17:08:28 roberto Exp roberto $
** Global State ** Global State
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -113,6 +113,7 @@ typedef struct global_State {
lu_mem GCthreshold; lu_mem GCthreshold;
lu_mem nblocks; /* number of `bytes' currently allocated */ lu_mem nblocks; /* number of `bytes' currently allocated */
lua_CFunction panic; /* to be called in unprotected errors */ lua_CFunction panic; /* to be called in unprotected errors */
Node dummynode[1]; /* common node array for all empty tables */
TString *tmname[TM_N]; /* array with tag-method names */ TString *tmname[TM_N]; /* array with tag-method names */
} global_State; } global_State;

View File

@ -1,5 +1,5 @@
/* /*
** $Id: ltable.c,v 1.103 2002/04/05 18:54:31 roberto Exp roberto $ ** $Id: ltable.c,v 1.104 2002/04/22 14:40:23 roberto Exp roberto $
** Lua tables (hash) ** Lua tables (hash)
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -52,13 +52,13 @@
#define hashnum(t,n) \ #define hashnum(t,n) \
(node(t, lmod(cast(lu_hash, cast(ls_hash, n)), sizenode(t)))) (node(t, lmod(cast(lu_hash, cast(ls_hash, n)), sizenode(t))))
#define hashstr(t,str) (node(t, lmod((str)->tsv.hash, sizenode(t)))) #define hashstr(t,str) (node(t, lmod((str)->tsv.hash, sizenode(t))))
#define hashboolean(t,p) (node(t, p)) /* `p' in [0,1] < minimum table size */ #define hashboolean(t,p) (node(t, lmod(p, sizenode(t))))
/* /*
** for pointers, avoid modulus by power of 2, as they tend to have many ** for pointers, avoid modulus by power of 2, as they tend to have many
** 2 factors. ** 2 factors.
*/ */
#define hashpointer(t,p) (node(t, (IntPoint(p) % (sizenode(t)-1)))) #define hashpointer(t,p) (node(t, (IntPoint(p) % ((sizenode(t)-1)|1))))
/* /*
@ -200,12 +200,6 @@ static void numuse (const Table *t, int *narray, int *nhash) {
} }
/*
** (log2 of) minimum size for hash part of a table
*/
#define MINHASHSIZE 1
static void setarrayvector (lua_State *L, Table *t, int size) { static void setarrayvector (lua_State *L, Table *t, int size) {
int i; int i;
luaM_reallocvector(L, t->array, t->sizearray, size, TObject); luaM_reallocvector(L, t->array, t->sizearray, size, TObject);
@ -217,16 +211,22 @@ static void setarrayvector (lua_State *L, Table *t, int size) {
static void setnodevector (lua_State *L, Table *t, int lsize) { static void setnodevector (lua_State *L, Table *t, int lsize) {
int i; int i;
int size; int size = twoto(lsize);
if (lsize < MINHASHSIZE) lsize = MINHASHSIZE; if (lsize > MAXBITS)
else if (lsize > MAXBITS)
luaD_runerror(L, "table overflow"); luaD_runerror(L, "table overflow");
size = twoto(lsize); if (lsize == 0) { /* no elements to hash part? */
t->node = luaM_newvector(L, size, Node); t->node = G(L)->dummynode; /* use common `dummynode' */
for (i=0; i<size; i++) { lua_assert(ttype(key(t->node)) == LUA_TNIL); /* assert invariants: */
t->node[i].next = NULL; lua_assert(ttype(val(t->node)) == LUA_TNIL);
setnilvalue(key(node(t, i))); lua_assert(t->node->next == NULL); /* (`dummynode' must be empty) */
setnilvalue(val(node(t, i))); }
else {
t->node = luaM_newvector(L, size, Node);
for (i=0; i<size; i++) {
t->node[i].next = NULL;
setnilvalue(key(node(t, i)));
setnilvalue(val(node(t, i)));
}
} }
t->lsizenode = cast(lu_byte, lsize); t->lsizenode = cast(lu_byte, lsize);
t->firstfree = node(t, size-1); /* first free position to be used */ t->firstfree = node(t, size-1); /* first free position to be used */
@ -235,14 +235,22 @@ static void setnodevector (lua_State *L, Table *t, int lsize) {
static void resize (lua_State *L, Table *t, int nasize, int nhsize) { static void resize (lua_State *L, Table *t, int nasize, int nhsize) {
int i; int i;
int oldasize, oldhsize; int oldasize = t->sizearray;
int oldhsize = t->lsizenode;
Node *nold; Node *nold;
oldasize = t->sizearray; Node temp[1];
if (oldhsize)
nold = t->node; /* save old hash ... */
else { /* old hash is `dummynode' */
lua_assert(t->node == G(L)->dummynode);
temp[0] = t->node[0]; /* copy it to `temp' (in case of errors) */
nold = temp;
setnilvalue(key(G(L)->dummynode)); /* restate invariant */
setnilvalue(val(G(L)->dummynode));
}
if (nasize > oldasize) /* should grow array part? */ if (nasize > oldasize) /* should grow array part? */
setarrayvector(L, t, nasize); setarrayvector(L, t, nasize);
/* create new hash part with appropriate size */ /* create new hash part with appropriate size */
nold = t->node; /* save old hash ... */
oldhsize = t->lsizenode; /* ... and (log of) old size */
setnodevector(L, t, nhsize); setnodevector(L, t, nhsize);
/* re-insert elements */ /* re-insert elements */
if (nasize < oldasize) { /* array part must shrink? */ if (nasize < oldasize) { /* array part must shrink? */
@ -262,7 +270,8 @@ static void resize (lua_State *L, Table *t, int nasize, int nhsize) {
if (ttype(val(old)) != LUA_TNIL) if (ttype(val(old)) != LUA_TNIL)
luaH_set(L, t, key(old), val(old)); luaH_set(L, t, key(old), val(old));
} }
luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ if (oldhsize)
luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */
} }
@ -299,8 +308,7 @@ Table *luaH_new (lua_State *L, int narray, int lnhash) {
void luaH_free (lua_State *L, Table *t) { void luaH_free (lua_State *L, Table *t) {
lua_assert(t->lsizenode > 0 || t->node == NULL); if (t->lsizenode)
if (t->lsizenode > 0)
luaM_freearray(L, t->node, sizenode(t), Node); luaM_freearray(L, t->node, sizenode(t), Node);
luaM_freearray(L, t->array, t->sizearray, TObject); luaM_freearray(L, t->array, t->sizearray, TObject);
luaM_freelem(L, t); luaM_freelem(L, t);