From 330e51bed3159aa83dcc9cc559c22e7d84d37604 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 10 May 2000 13:33:20 -0300 Subject: [PATCH] string hash uses one single hash table --- lgc.c | 55 +++++++++++++++------------ lobject.h | 4 +- lparser.c | 6 +-- lstate.h | 10 ++--- lstring.c | 111 +++++++++++++++++------------------------------------- lstring.h | 12 +++--- ltests.c | 23 ++++++----- 7 files changed, 90 insertions(+), 131 deletions(-) diff --git a/lgc.c b/lgc.c index 32dd6471..0a2cc596 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 1.47 2000/04/14 18:12:35 roberto Exp roberto $ +** $Id: lgc.c,v 1.48 2000/05/08 19:32:53 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -166,36 +166,41 @@ static void collecttable (lua_State *L) { ** with limit=1, that means all unmarked elements; ** with limit=MAX_INT, that means all elements. */ -static void collectstring (lua_State *L, int limit) { - TObject o; /* to call userdata `gc' tag method */ +static void collectstringtab (lua_State *L, int limit, stringtable *tb) { int i; + TObject o; /* to call userdata `gc' tag method */ ttype(&o) = TAG_USERDATA; - for (i=0; istring_root[i]; - int j; - for (j=0; jsize; j++) { /* for each list */ - TString **p = &tb->hash[j]; - TString *next; - while ((next = *p) != NULL) { - if (next->marked >= limit) { - if (next->marked < FIXMARK) /* does not change FIXMARKs */ - next->marked = 0; - p = &next->nexthash; - } - else { /* collect */ - if (next->constindex == -1) { /* is userdata? */ - tsvalue(&o) = next; - luaD_gcTM(L, &o); - } - *p = next->nexthash; - luaS_free(L, next); - tb->nuse--; + for (i=0; isize; i++) { /* for each list */ + TString **p = &tb->hash[i]; + TString *next; + while ((next = *p) != NULL) { + if (next->marked >= limit) { + if (next->marked < FIXMARK) /* does not change FIXMARKs */ + next->marked = 0; + p = &next->nexthash; + } + else { /* collect */ + if (tb == &L->strt) /* is string? */ + L->nblocks -= gcsizestring(L, next->u.s.len); + else { + tsvalue(&o) = next; + luaD_gcTM(L, &o); + L->nblocks -= gcsizeudata; } + *p = next->nexthash; + tb->nuse--; + luaM_free(L, next); } } - if ((tb->nuse+1)*6 < tb->size) - luaS_resize(L, tb, tb->size/2); /* table is too big */ } + if (tb->nuse < (tb->size/4) && tb->size > 10) + luaS_resize(L, tb, tb->size/2); /* table is too big */ +} + + +static void collectstring (lua_State *L, int limit) { + collectstringtab(L, limit, &L->strt); + collectstringtab(L, limit, &L->udt); } diff --git a/lobject.h b/lobject.h index a02cc047..cb9670ed 100644 --- a/lobject.h +++ b/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 1.62 2000/05/08 19:32:53 roberto Exp roberto $ +** $Id: lobject.h,v 1.63 2000/05/08 19:37:10 roberto Exp roberto $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -93,6 +93,7 @@ typedef struct TString { struct { /* for strings */ unsigned long hash; long len; + int constindex; /* hint to reuse constants */ } s; struct { /* for userdata */ int tag; @@ -100,7 +101,6 @@ typedef struct TString { } d; } u; struct TString *nexthash; /* chain for hash table */ - int constindex; /* hint to reuse constants (= -1 if this is a userdata) */ unsigned char marked; char str[1]; /* variable length string!! must be the last field! */ } TString; diff --git a/lparser.c b/lparser.c index 0c6878a1..42cee394 100644 --- a/lparser.c +++ b/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 1.83 2000/04/27 17:39:56 roberto Exp roberto $ +** $Id: lparser.c,v 1.84 2000/05/08 18:46:34 roberto Exp roberto $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ @@ -139,13 +139,13 @@ static void check_END (LexState *ls, int who, int where) { static int string_constant (FuncState *fs, TString *s) { Proto *f = fs->f; - int c = s->constindex; + int c = s->u.s.constindex; if (c >= f->nkstr || f->kstr[c] != s) { luaM_growvector(fs->L, f->kstr, f->nkstr, 1, TString *, constantEM, MAXARG_U); c = f->nkstr++; f->kstr[c] = s; - s->constindex = c; /* hint for next time */ + s->u.s.constindex = c; /* hint for next time */ } return c; } diff --git a/lstate.h b/lstate.h index 6e943b30..6c0cee86 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 1.31 2000/03/30 17:19:48 roberto Exp roberto $ +** $Id: lstate.h,v 1.32 2000/05/08 19:32:53 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -42,7 +42,7 @@ struct C_Lua_Stack { typedef struct stringtable { int size; - int nuse; /* number of elements */ + long nuse; /* number of elements */ TString **hash; } stringtable; @@ -66,7 +66,8 @@ struct lua_State { Proto *rootproto; /* list of all prototypes */ Closure *rootcl; /* list of all closures */ Hash *roottable; /* list of all tables */ - stringtable *string_root; /* array of hash tables for strings and udata */ + stringtable strt; /* hash table for strings */ + stringtable udt; /* hash table for udata */ Hash *gt; /* table for globals */ struct IM *IMtable; /* table for tag methods */ int last_tag; /* last used tag in IMtable */ @@ -82,8 +83,5 @@ struct lua_State { }; - - - #endif diff --git a/lstring.c b/lstring.c index 3c9d0d8f..507e945a 100644 --- a/lstring.c +++ b/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 1.34 2000/03/10 18:37:44 roberto Exp roberto $ +** $Id: lstring.c,v 1.35 2000/05/08 19:32:53 roberto Exp roberto $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -17,30 +17,20 @@ -#define gcsizestring(L, l) numblocks(L, 0, sizeof(TString)+l) -#define gcsizeudata gcsizestring(L, 0) - - - void luaS_init (lua_State *L) { - int i; - L->string_root = luaM_newvector(L, NUM_HASHS, stringtable); - for (i=0; istring_root[i].size = 1; - L->string_root[i].nuse = 0; - L->string_root[i].hash = luaM_newvector(L, 1, TString *);; - L->string_root[i].hash[0] = NULL; - } + L->strt.size = L->udt.size = 1; + L->strt.nuse = L->udt.nuse = 0; + L->strt.hash = luaM_newvector(L, 1, TString *); + L->udt.hash = luaM_newvector(L, 1, TString *); + L->strt.hash[0] = L->udt.hash[0] = NULL; } void luaS_freeall (lua_State *L) { - int i; - for (i=0; istring_root[i].nuse==0, "non-empty string table"); - luaM_free(L, L->string_root[i].hash); - } - luaM_free(L, L->string_root); + LUA_ASSERT(L, L->strt.nuse==0, "non-empty string table"); + luaM_free(L, L->strt.hash); + LUA_ASSERT(L, L->udt.nuse==0, "non-empty udata table"); + luaM_free(L, L->udt.hash); } @@ -62,8 +52,7 @@ void luaS_resize (lua_State *L, stringtable *tb, int newsize) { TString *p = tb->hash[i]; while (p) { /* for each node in the list */ TString *next = p->nexthash; /* save next */ - unsigned long h = (p->constindex == -1) ? IntPoint(p->u.d.value) : - p->u.s.hash; + unsigned long h = (tb == &L->strt) ? p->u.s.hash : IntPoint(p->u.d.value); int h1 = h&(newsize-1); /* new position */ LUA_ASSERT(L, h%newsize == (h&(newsize-1)), "a&(x-1) == a%x, for x power of 2"); @@ -78,79 +67,55 @@ void luaS_resize (lua_State *L, stringtable *tb, int newsize) { } -static TString *newone (lua_State *L, long l) { - TString *ts = (TString *)luaM_malloc(L, sizeof(TString)+l*sizeof(char)); - ts->marked = 0; - ts->nexthash = NULL; - return ts; -} - - -static TString *newone_s (lua_State *L, const char *str, - long l, unsigned long h) { - TString *ts = newone(L, l); - memcpy(ts->str, str, l); - ts->str[l] = 0; /* ending 0 */ - ts->u.s.len = l; - ts->u.s.hash = h; - ts->constindex = 0; - L->nblocks += gcsizestring(L, l); - return ts; -} - - -static TString *newone_u (lua_State *L, void *buff, int tag) { - TString *ts = newone(L, 0); - ts->u.d.value = buff; - ts->u.d.tag = (tag == LUA_ANYTAG) ? 0 : tag; - ts->constindex = -1; /* tag -> this is a userdata */ - L->nblocks += gcsizeudata; - return ts; -} - - static void newentry (lua_State *L, stringtable *tb, TString *ts, int h) { ts->nexthash = tb->hash[h]; /* chain new entry */ tb->hash[h] = ts; tb->nuse++; - if (tb->nuse > tb->size) /* too crowded? */ + if (tb->nuse > tb->size && tb->size < MAX_INT/2) /* too crowded? */ luaS_resize(L, tb, tb->size*2); } + TString *luaS_newlstr (lua_State *L, const char *str, long l) { unsigned long h = hash_s(str, l); - stringtable *tb = &L->string_root[(l==0) ? 0 : - ((unsigned int)(str[0]+str[l-1]))&(NUM_HASHSTR-1)]; - int h1 = h&(tb->size-1); + int h1 = h&(L->strt.size-1); TString *ts; - for (ts = tb->hash[h1]; ts; ts = ts->nexthash) { + for (ts = L->strt.hash[h1]; ts; ts = ts->nexthash) { if (ts->u.s.len == l && (memcmp(str, ts->str, l) == 0)) return ts; } /* not found */ - ts = newone_s(L, str, l, h); /* create new entry */ - newentry(L, tb, ts, h1); /* insert it on table */ + ts = (TString *)luaM_malloc(L, sizeof(TString)+l*sizeof(char)); + ts->marked = 0; + ts->nexthash = NULL; + ts->u.s.len = l; + ts->u.s.hash = h; + ts->u.s.constindex = 0; + memcpy(ts->str, str, l); + ts->str[l] = 0; /* ending 0 */ + L->nblocks += gcsizestring(L, l); + newentry(L, &L->strt, ts, h1); /* insert it on table */ return ts; } -/* -** uses '%' for one hashing with userdata because addresses are too regular, -** so two '&' operations would be highly correlated -*/ TString *luaS_createudata (lua_State *L, void *udata, int tag) { unsigned long h = IntPoint(udata); - stringtable *tb = &L->string_root[(h%NUM_HASHUDATA)+NUM_HASHSTR]; - int h1 = h&(tb->size-1); + int h1 = h&(L->udt.size-1); TString *ts; - for (ts = tb->hash[h1]; ts; ts = ts->nexthash) { + for (ts = L->udt.hash[h1]; ts; ts = ts->nexthash) { if (udata == ts->u.d.value && (tag == ts->u.d.tag || tag == LUA_ANYTAG)) return ts; } /* not found */ - ts = newone_u(L, udata, tag); - newentry(L, tb, ts, h1); + ts = luaM_new(L, TString); + ts->marked = 0; + ts->nexthash = NULL; + ts->u.d.value = udata; + ts->u.d.tag = (tag == LUA_ANYTAG) ? 0 : tag; + L->nblocks += gcsizeudata; + newentry(L, &L->udt, ts, h1); /* insert it on table */ return ts; } @@ -159,16 +124,10 @@ TString *luaS_new (lua_State *L, const char *str) { return luaS_newlstr(L, str, strlen(str)); } + TString *luaS_newfixed (lua_State *L, const char *str) { TString *ts = luaS_new(L, str); if (ts->marked == 0) ts->marked = FIXMARK; /* avoid GC */ return ts; } - -void luaS_free (lua_State *L, TString *t) { - L->nblocks -= (t->constindex == -1) ? gcsizeudata : - gcsizestring(L, t->u.s.len); - luaM_free(L, t); -} - diff --git a/lstring.h b/lstring.h index 8e307292..5d6ff49f 100644 --- a/lstring.h +++ b/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.18 2000/03/10 18:37:44 roberto Exp roberto $ +** $Id: lstring.h,v 1.19 2000/05/08 19:32:53 roberto Exp roberto $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -12,11 +12,6 @@ #include "lstate.h" -#define NUM_HASHSTR 32 -#define NUM_HASHUDATA 31 -#define NUM_HASHS (NUM_HASHSTR+NUM_HASHUDATA) - - /* ** any TString with mark>=FIXMARK is never collected. ** Marks>=RESERVEDMARK are used to identify reserved words. @@ -25,11 +20,14 @@ #define RESERVEDMARK 3 +#define gcsizestring(L, l) numblocks(L, 0, sizeof(TString)+l) +#define gcsizeudata gcsizestring(L, 0) + + void luaS_init (lua_State *L); void luaS_resize (lua_State *L, stringtable *tb, int newsize); TString *luaS_createudata (lua_State *L, void *udata, int tag); void luaS_freeall (lua_State *L); -void luaS_free (lua_State *L, TString *ts); TString *luaS_newlstr (lua_State *L, const char *str, long l); TString *luaS_new (lua_State *L, const char *str); TString *luaS_newfixed (lua_State *L, const char *str); diff --git a/ltests.c b/ltests.c index 03baa6e6..4646c5c9 100644 --- a/ltests.c +++ b/ltests.c @@ -1,5 +1,5 @@ /* -** $Id: ltests.c,v 1.16 2000/04/14 17:46:15 roberto Exp roberto $ +** $Id: ltests.c,v 1.17 2000/05/08 19:32:53 roberto Exp roberto $ ** Internal Module for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -14,6 +14,7 @@ #include "lapi.h" #include "lauxlib.h" +#include "ldo.h" #include "lmem.h" #include "lopcodes.h" #include "lstate.h" @@ -193,24 +194,22 @@ static void table_query (lua_State *L) { static void string_query (lua_State *L) { - int h = luaL_check_int(L, 1) - 1; + stringtable *tb = (*luaL_check_string(L, 1) == 's') ? &L->strt : &L->udt; int s = luaL_opt_int(L, 2, 0) - 1; if (s==-1) { - if (h < NUM_HASHS) { - lua_pushnumber(L, L->string_root[h].nuse); - lua_pushnumber(L, L->string_root[h].size); - } + lua_pushnumber(L, tb->nuse); + lua_pushnumber(L, tb->size); } - else { - TString *ts = L->string_root[h].hash[s]; - for (ts = L->string_root[h].hash[s]; ts; ts = ts->nexthash) { - if (ts->constindex == -1) lua_pushstring(L, ""); - else lua_pushstring(L, ts->str); + else if (s < tb->size) { + TString *ts; + for (ts = tb->hash[s]; ts; ts = ts->nexthash) { + ttype(L->top) = TAG_STRING; + tsvalue(L->top) = ts; + incr_top; } } } - /* ** {====================================================== ** function to test the API with C. It interprets a kind of "assembler"