From 1e81da51bab87148981486a84b846399050f4ef2 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 17 Oct 2001 19:12:57 -0200 Subject: [PATCH] new API for registry and C upvalues + new implementation for references --- lapi.c | 120 +++++++++++++++++++++++++---------------------------- lbaselib.c | 25 ++++------- ldblib.c | 16 +++---- ldo.c | 13 +++--- lgc.c | 5 +-- lstate.c | 7 +--- lstate.h | 5 +-- ltests.c | 21 +++++----- lua.c | 4 +- lua.h | 18 ++++++-- 10 files changed, 111 insertions(+), 123 deletions(-) diff --git a/lapi.c b/lapi.c index 7c7f68b8..a25707d5 100644 --- a/lapi.c +++ b/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 1.152 2001/09/07 17:39:10 roberto Exp $ +** $Id: lapi.c,v 1.154 2001/10/11 21:40:56 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -40,15 +40,28 @@ const l_char lua_ident[] = +static TObject *negindex (lua_State *L, int index) { + if (index > LUA_REGISTRYINDEX) { + api_check(L, index != 0 && -index <= L->top - L->ci->base); + return L->top+index; + } else if (index == LUA_REGISTRYINDEX) /* pseudo-indices */ + return &G(L)->registry; + else { + TObject *func = (L->ci->base - 1); + index = LUA_REGISTRYINDEX - index; + api_check(L, iscfunction(func) && index <= clvalue(func)->c.nupvalues); + return &clvalue(func)->c.upvalue[index-1]; + } +} + + TObject *luaA_index (lua_State *L, int index) { if (index > 0) { api_check(L, index <= L->top - L->ci->base); return L->ci->base+index-1; } - else { - api_check(L, index != 0 && -index <= L->top - L->ci->base); - return L->top+index; - } + else + return negindex(L, index); } @@ -59,10 +72,8 @@ static TObject *luaA_indexAcceptable (lua_State *L, int index) { if (o >= L->top) return NULL; else return o; } - else { - api_check(L, index != 0 && -index <= L->top - L->ci->base); - return L->top+index; - } + else + return negindex(L, index); } @@ -378,24 +389,6 @@ LUA_API void lua_getglobals (lua_State *L) { } -LUA_API int lua_getref (lua_State *L, int ref) { - int status; - lua_lock(L); - if (ref == LUA_REFNIL) { - setnilvalue(L->top); - status = 1; - } - else { - setobj(L->top, luaH_getnum(G(L)->weakregistry, ref)); - status = (ttype(L->top) != LUA_TNIL); - } - if (status) - api_incr_top(L); - lua_unlock(L); - return status; -} - - LUA_API void lua_newtable (lua_State *L) { lua_lock(L); sethvalue(L->top, luaH_new(L, 0)); @@ -404,22 +397,6 @@ LUA_API void lua_newtable (lua_State *L) { } -LUA_API void lua_getregistry (lua_State *L) { - lua_lock(L); - sethvalue(L->top, G(L)->registry); - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API void lua_getweakregistry (lua_State *L) { - lua_lock(L); - sethvalue(L->top, G(L)->weakregistry); - api_incr_top(L); - lua_unlock(L); -} - - /* ** set functions (stack -> Lua) @@ -483,26 +460,25 @@ LUA_API void lua_setglobals (lua_State *L) { LUA_API int lua_ref (lua_State *L, int lock) { int ref; + if (lock == 0) lua_error(L, l_s("unlocked references are obsolete")); if (lua_isnil(L, -1)) { lua_pop(L, 1); - ref = LUA_REFNIL; + return LUA_REFNIL; } - else { - lua_getweakregistry(L); - ref = lua_getn(L, -1) + 1; - lua_pushvalue(L, -2); - lua_rawseti(L, -2, ref); - if (lock) { - lua_getregistry(L); - lua_pushvalue(L, -3); - lua_rawseti(L, -2, ref); - lua_pop(L, 1); /* remove registry */ - } + lua_rawgeti(L, LUA_REGISTRYINDEX, 0); /* get first free element */ + ref = lua_tonumber(L, -1); + lua_pop(L, 1); /* remove it from stack */ + if (ref != 0) { /* some free element? */ + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); /* remove it from list */ + lua_rawseti(L, LUA_REGISTRYINDEX, 0); + } + else { /* no free elements */ + ref = lua_getn(L, LUA_REGISTRYINDEX) + 1; /* use next `n' */ lua_pushliteral(L, l_s("n")); lua_pushnumber(L, ref); - lua_settable(L, -3); - lua_pop(L, 2); + lua_settable(L, LUA_REGISTRYINDEX); /* n = n+1 */ } + lua_rawseti(L, LUA_REGISTRYINDEX, ref); return ref; } @@ -661,13 +637,10 @@ LUA_API void lua_error (lua_State *L, const l_char *s) { LUA_API void lua_unref (lua_State *L, int ref) { if (ref >= 0) { - lua_getregistry(L); - lua_pushnil(L); - lua_rawseti(L, -2, ref); - lua_getweakregistry(L); - lua_pushnil(L); - lua_rawseti(L, -2, ref); - lua_pop(L, 2); /* remove both registries */ + lua_rawgeti(L, LUA_REGISTRYINDEX, 0); + lua_pushnumber(L, ref); + lua_rawseti(L, LUA_REGISTRYINDEX, 0); + lua_rawseti(L, LUA_REGISTRYINDEX, ref); } } @@ -787,3 +760,22 @@ LUA_API void lua_setweakmode (lua_State *L, int mode) { lua_unlock(L); } + + +LUA_API void lua_pushupvalues (lua_State *L) { + TObject *func; + int n, i; + lua_lock(L); + func = (L->ci->base - 1); + api_check(L, iscfunction(func)); + n = clvalue(func)->c.nupvalues; + if (LUA_MINSTACK+n > lua_stackspace(L)) + luaD_error(L, l_s("stack overflow")); + for (i=0; itop, &clvalue(func)->c.upvalue[i]); + L->top++; + } + lua_unlock(L); +} + + diff --git a/lbaselib.c b/lbaselib.c index 62695c04..cbb0cf36 100644 --- a/lbaselib.c +++ b/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.41 2001/08/31 19:46:07 roberto Exp $ +** $Id: lbaselib.c,v 1.43 2001/10/11 21:41:21 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -363,18 +363,8 @@ static int luaB_require (lua_State *L) { lua_pushvalue(L, -1); /* duplicate to leave a copy on stack */ lua_setglobal(L, LUA_PATH); } - lua_getregistry(L); - lua_pushliteral(L, LUA_PATH); - lua_gettable(L, 3); /* get book-keeping table */ - if (lua_isnil(L, 4)) { /* no book-keeping table? */ - lua_pop(L, 1); /* pop the `nil' */ - lua_newtable(L); /* create book-keeping table */ - lua_pushliteral(L, LUA_PATH); - lua_pushvalue(L, -2); /* duplicate table to leave a copy on stack */ - lua_settable(L, 3); /* store book-keeping table in registry */ - } - lua_pushvalue(L, 1); - lua_gettable(L, 4); /* check package's name in book-keeping table */ + lua_pushvalue(L, 1); /* check package's name in book-keeping table */ + lua_gettable(L, lua_upvalueindex(1)); if (!lua_isnil(L, -1)) /* is it there? */ return 0; /* package is already loaded */ else { /* must load it */ @@ -385,7 +375,7 @@ static int luaB_require (lua_State *L) { lua_pushvalue(L, 1); /* package name */ lua_concat(L, 2); /* concat directory with package name */ res = lua_dofile(L, lua_tostring(L, -1)); /* try to load it */ - lua_settop(L, 4); /* pop string and eventual results from dofile */ + lua_settop(L, 2); /* pop string and eventual results from dofile */ if (res == 0) break; /* ok; file done */ else if (res != LUA_ERRFILE) lua_error(L, NULL); /* error running package; propagate it */ @@ -397,7 +387,7 @@ static int luaB_require (lua_State *L) { } lua_pushvalue(L, 1); lua_pushnumber(L, 1); - lua_settable(L, 4); /* mark it as loaded */ + lua_settable(L, lua_upvalueindex(1)); /* mark it as loaded */ return 0; } @@ -713,7 +703,6 @@ static const luaL_reg base_funcs[] = { {l_s("rawgettable"), luaB_rawget}, /* for compatibility 3.2 */ {l_s("rawsettable"), luaB_rawset}, /* for compatibility 3.2 */ {l_s("rawtype"), luaB_rawtype}, - {l_s("require"), luaB_require}, {l_s("setglobal"), luaB_setglobal}, {l_s("settag"), luaB_settype}, /* for compatibility 4.0 */ {l_s("settype"), luaB_settype}, @@ -737,6 +726,10 @@ LUALIB_API int lua_baselibopen (lua_State *L) { luaL_openl(L, base_funcs); lua_pushliteral(L, l_s(LUA_VERSION)); lua_setglobal(L, l_s("_VERSION")); + /* `require' needs an empty table as upvalue */ + lua_newtable(L); + lua_pushcclosure(L, luaB_require, 1); + lua_setglobal(L, l_s("require")); return 0; } diff --git a/ldblib.c b/ldblib.c index f91bb551..3c95fdb8 100644 --- a/ldblib.c +++ b/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.37 2001/06/06 18:00:19 roberto Exp $ +** $Id: ldblib.c,v 1.38 2001/08/31 19:46:07 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -116,16 +116,14 @@ static int setlocal (lua_State *L) { static void hookf (lua_State *L, const l_char *key) { - lua_getregistry(L); lua_pushstring(L, key); - lua_gettable(L, -2); + lua_gettable(L, LUA_REGISTRYINDEX); if (lua_isfunction(L, -1)) { - lua_pushvalue(L, -3); /* original argument (below table and function) */ + lua_pushvalue(L, -2); /* original argument (below function) */ lua_rawcall(L, 1, 0); } else lua_pop(L, 1); /* pop result from gettable */ - lua_pop(L, 1); /* pop table */ } @@ -150,13 +148,11 @@ static void sethook (lua_State *L, const l_char *key, lua_Hook hook, (*sethookf)(L, hook); else luaL_argerror(L, 1, l_s("function expected")); - lua_getregistry(L); lua_pushstring(L, key); - lua_pushvalue(L, -1); /* dup key */ - lua_gettable(L, -3); /* get old value */ - lua_pushvalue(L, -2); /* key (again) */ + lua_gettable(L, LUA_REGISTRYINDEX); /* get old value */ + lua_pushstring(L, key); lua_pushvalue(L, 1); - lua_settable(L, -5); /* set new value */ + lua_settable(L, LUA_REGISTRYINDEX); /* set new value */ } diff --git a/ldo.c b/ldo.c index 60e5dc2e..087863cb 100644 --- a/ldo.c +++ b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.141 2001/09/25 17:05:49 roberto Exp $ +** $Id: ldo.c,v 1.142 2001/10/02 16:45:03 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -44,7 +44,8 @@ void luaD_init (lua_State *L, int stacksize) { stacksize += EXTRA_STACK; L->stack = luaM_newvector(L, stacksize, TObject); L->stacksize = stacksize; - L->basefunc.base = L->top = L->stack; + setnilvalue(L->stack); /* the `initial' function */ + L->top = L->basefunc.base = L->stack + 1; restore_stack_limit(L); } @@ -119,12 +120,12 @@ static void luaD_callHook (lua_State *L, lua_Hook callhook, static StkId callCclosure (lua_State *L, const struct CClosure *cl) { - int nup = cl->nupvalues; /* number of upvalues */ int n; - luaD_checkstack(L, nup+LUA_MINSTACK); /* ensure minimum stack size */ - for (n=0; ntop++, &cl->upvalue[n]); + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ lua_unlock(L); +#if LUA_COMPATUPVALUES + lua_pushupvalues(L); +#endif n = (*cl->f)(L); /* do the actual call */ lua_lock(L); return L->top - n; /* return index of first result */ diff --git a/lgc.c b/lgc.c index cb08df35..35251ce3 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 1.111 2001/09/07 17:39:10 roberto Exp $ +** $Id: lgc.c,v 1.112 2001/10/02 16:45:03 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -171,8 +171,7 @@ static void markall (lua_State *L) { marktagmethods(G(L), &st); /* mark tag methods */ markstacks(L, &st); /* mark all stacks */ marktable(&st, G(L)->type2tag); - marktable(&st, G(L)->registry); - marktable(&st, G(L)->weakregistry); + markobject(&st, &G(L)->registry); while (st.tmark) { /* mark tables */ Hash *h = st.tmark; /* get first table from list */ st.tmark = h->mark; /* remove it from list */ diff --git a/lstate.c b/lstate.c index 4b404b0b..640bfcde 100644 --- a/lstate.c +++ b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 1.66 2001/07/17 17:54:46 roberto Exp $ +** $Id: lstate.c,v 1.68 2001/09/07 17:39:10 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -66,10 +66,7 @@ static void f_luaopen (lua_State *L, void *ud) { luaD_init(L, so->stacksize); /* init stack */ L->gt = luaH_new(L, 10); /* table of globals */ G(L)->type2tag = luaH_new(L, 10); - G(L)->registry = luaH_new(L, 0); - G(L)->weakregistry = luaH_new(L, 0); - /* make weakregistry weak */ - G(L)->weakregistry->weakmode = LUA_WEAK_KEY | LUA_WEAK_VALUE; + sethvalue(&G(L)->registry, luaH_new(L, 0)); luaS_resize(L, MINPOWER2); luaX_init(L); luaT_init(L); diff --git a/lstate.h b/lstate.h index ebeeab52..aa29c3bd 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 1.59 2001/09/07 17:39:10 roberto Exp $ +** $Id: lstate.h,v 1.60 2001/10/02 16:43:29 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -58,8 +58,7 @@ typedef struct global_State { size_t Mbuffsize; /* size of Mbuffer */ stringtable strt; /* hash table for strings */ Hash *type2tag; /* hash table from type names to tags */ - Hash *registry; /* (strong) registry table */ - Hash *weakregistry; /* weakregistry table */ + TObject registry; /* registry table */ struct TM *TMtable; /* table for tag methods */ int sizeTM; /* size of TMtable */ int ntag; /* number of tags in TMtable */ diff --git a/ltests.c b/ltests.c index 03d65657..afcc460a 100644 --- a/ltests.c +++ b/ltests.c @@ -1,5 +1,5 @@ /* -** $Id: ltests.c,v 1.91 2001/09/07 17:39:10 roberto Exp $ +** $Id: ltests.c,v 1.92 2001/10/02 16:45:03 roberto Exp $ ** Internal Module for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -317,21 +317,16 @@ static int tref (lua_State *L) { int level = lua_gettop(L); luaL_checkany(L, 1); lua_pushvalue(L, 1); - lua_pushnumber(L, lua_ref(L, luaL_opt_int(L, 2, 1))); + lua_pushnumber(L, lua_ref(L, 1)); assert(lua_gettop(L) == level+1); /* +1 for result */ return 1; } static int getref (lua_State *L) { int level = lua_gettop(L); - if (lua_getref(L, luaL_check_int(L, 1))) { - assert(lua_gettop(L) == level+1); - return 1; - } - else { - assert(lua_gettop(L) == level); - return 0; - } + lua_getref(L, luaL_check_int(L, 1)); + assert(lua_gettop(L) == level+1); + return 1; } static int unref (lua_State *L) { @@ -570,6 +565,12 @@ static int testC (lua_State *L) { else if EQ(l_s("pushvalue")) { lua_pushvalue(L, getnum); } + else if EQ(l_s("pushcclosure")) { + lua_pushcclosure(L, testC, getnum); + } + else if EQ(l_s("pushupvalues")) { + lua_pushupvalues(L); + } else if EQ(l_s("remove")) { lua_remove(L, getnum); } diff --git a/lua.c b/lua.c index b1c4cb7b..d390a7aa 100644 --- a/lua.c +++ b/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.69 2001/08/30 20:54:02 roberto Exp $ +** $Id: lua.c,v 1.70 2001/09/25 17:06:34 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -141,7 +141,7 @@ static void getargs (l_char *argv[]) { static int l_getargs (lua_State *l) { - l_char **argv = (l_char **)lua_touserdata(l, -1); + l_char **argv = (l_char **)lua_touserdata(l, lua_upvalueindex(1)); getargs(argv); return 1; } diff --git a/lua.h b/lua.h index 3ec57716..1325f5f4 100644 --- a/lua.h +++ b/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.103 2001/08/31 19:46:07 roberto Exp $ +** $Id: lua.h,v 1.104 2001/10/11 21:41:21 roberto Exp $ ** Lua - An Extensible Extension Language ** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil ** e-mail: info@lua.org @@ -35,6 +35,13 @@ #define LUA_MULTRET (-1) +/* pseudo-index for registry */ +#define LUA_REGISTRYINDEX (-10000) + +/* pseudo-indices for upvalues */ +#define lua_upvalueindex(i) (LUA_REGISTRYINDEX-(i)) + + /* error codes for `lua_do*' and the like */ #define LUA_ERRRUN 1 #define LUA_ERRFILE 2 @@ -160,9 +167,7 @@ LUA_API void lua_rawget (lua_State *L, int index); LUA_API void lua_rawgeti (lua_State *L, int index, int n); LUA_API void lua_getglobals (lua_State *L); LUA_API void lua_gettagmethod (lua_State *L, int tag, const lua_char *event); -LUA_API int lua_getref (lua_State *L, int ref); LUA_API void lua_newtable (lua_State *L); -LUA_API void lua_getregistry (lua_State *L); LUA_API void lua_getweakregistry (lua_State *L); @@ -246,14 +251,19 @@ LUA_API int lua_getweakmode (lua_State *L, int index); #define lua_pushliteral(L, s) lua_pushlstring(L, s, \ (sizeof(s)/sizeof(lua_char))-1) +#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX); + +#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, ref) /* -** compatibility macros +** compatibility macros and functions */ #define lua_newtag(L) lua_newtype(L, NULL, LUA_TNONE) #define lua_typename lua_tag2name +LUA_API void lua_pushupvalues (lua_State *L); + #endif