From beee01b170c5fea9ed4527b28b9221d2df1baaba Mon Sep 17 00:00:00 2001
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Tue, 17 Apr 2001 14:35:54 -0300
Subject: re-implementation of refs through weak tables

---
 lapi.c   | 76 +++++++++++++++++++++++++++++++++++++++-------------------------
 lgc.c    | 35 +++---------------------------
 lstate.c | 25 ++++-----------------
 lstate.h | 22 +++----------------
 ltests.c | 15 ++++++++++---
 lua.h    | 25 +++++++++++----------
 6 files changed, 81 insertions(+), 117 deletions(-)

diff --git a/lapi.c b/lapi.c
index 243087fe..c715301d 100644
--- a/lapi.c
+++ b/lapi.c
@@ -1,5 +1,5 @@
 /*
-** $Id: lapi.c,v 1.138 2001/04/11 14:42:41 roberto Exp roberto $
+** $Id: lapi.c,v 1.139 2001/04/11 18:39:37 roberto Exp roberto $
 ** Lua API
 ** See Copyright Notice in lua.h
 */
@@ -417,21 +417,18 @@ LUA_API void lua_getglobals (lua_State *L) {
 
 
 LUA_API int lua_getref (lua_State *L, int ref) {
-  int status = 1;
+  int status;
   lua_lock(L);
   if (ref == LUA_REFNIL) {
     setnilvalue(L->top);
-    api_incr_top(L);
+    status = 1;
   }
   else {
-    api_check(L, 0 <= ref && ref < G(L)->nref);
-    if (G(L)->refArray[ref].st != LOCK && G(L)->refArray[ref].st != HOLD)
-      status = 0;
-    else {
-      setobj(L->top, &G(L)->refArray[ref].o);
-      api_incr_top(L);
-    }
+    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;
 }
@@ -445,6 +442,22 @@ 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)
@@ -508,25 +521,26 @@ LUA_API void lua_setglobals (lua_State *L) {
 
 LUA_API int lua_ref (lua_State *L,  int lock) {
   int ref;
-  lua_lock(L);
-  api_checknelems(L, 1);
-  if (ttype(L->top-1) == LUA_TNIL)
+  if (lua_isnil(L, -1)) {
+    lua_pop(L, 1);
     ref = LUA_REFNIL;
+  }
   else {
-    if (G(L)->refFree != NONEXT) {  /* is there a free place? */
-      ref = G(L)->refFree;
-      G(L)->refFree = G(L)->refArray[ref].st;
-    }
-    else {  /* no more free places */
-      luaM_growvector(L, G(L)->refArray, G(L)->nref, G(L)->sizeref, struct Ref,
-                      MAX_INT, l_s("reference table overflow"));
-      ref = G(L)->nref++;
+    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 */
     }
-    setobj(&G(L)->refArray[ref].o, L->top-1);
-    G(L)->refArray[ref].st = lock ? LOCK : HOLD;
+    lua_pushliteral(L, "n");
+    lua_pushnumber(L, ref);
+    lua_settable(L, -3);
+    lua_pop(L, 2);
   }
-  L->top--;
-  lua_unlock(L);
   return ref;
 }
 
@@ -671,13 +685,15 @@ LUA_API void lua_error (lua_State *L, const l_char *s) {
 
 
 LUA_API void lua_unref (lua_State *L, int ref) {
-  lua_lock(L);
   if (ref >= 0) {
-    api_check(L, ref < G(L)->nref && G(L)->refArray[ref].st < 0);
-    G(L)->refArray[ref].st = G(L)->refFree;
-    G(L)->refFree = ref;
+    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_unlock(L);
 }
 
 
diff --git a/lgc.c b/lgc.c
index a7f96f8c..0237b88c 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 1.95 2001/03/26 14:31:49 roberto Exp roberto $
+** $Id: lgc.c,v 1.96 2001/04/11 14:42:41 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -111,15 +111,6 @@ static void markstacks (lua_State *L, GCState *st) {
 }
 
 
-static void marklock (global_State *G, GCState *st) {
-  int i;
-  for (i=0; i<G->nref; i++) {
-    if (G->refArray[i].st == LOCK)
-      markobject(st, &G->refArray[i].o);
-  }
-}
-
-
 static void marktagmethods (global_State *G, GCState *st) {
   int t;
   for (t=0; t<G->ntag; t++) {
@@ -176,8 +167,9 @@ static void markall (lua_State *L) {
   st.tmark = NULL;
   marktagmethods(G(L), &st);  /* mark tag methods */
   markstacks(L, &st); /* mark all stacks */
-  marklock(G(L), &st); /* mark locked objects */
   marktable(&st, G(L)->type2tag);
+  marktable(&st, G(L)->registry);
+  marktable(&st, G(L)->weakregistry);
   for (;;) {  /* mark tables and closures */
     if (st.cmark) {
       Closure *f = st.cmark;  /* get first closure from list */
@@ -208,26 +200,6 @@ static int hasmark (const TObject *o) {
 }
 
 
-/* macro for internal debugging; check if a link of free refs is valid */
-#define VALIDLINK(L, st,n)      (NONEXT <= (st) && (st) < (n))
-
-static void invalidaterefs (global_State *G) {
-  int n = G->nref;
-  int i;
-  for (i=0; i<n; i++) {
-    struct Ref *r = &G->refArray[i];
-    if (r->st == HOLD && !hasmark(&r->o))
-      r->st = COLLECTED;
-    lua_assert((r->st == LOCK && hasmark(&r->o)) ||
-               (r->st == HOLD && hasmark(&r->o)) ||
-                r->st == COLLECTED ||
-                r->st == NONEXT ||
-               (r->st < n && VALIDLINK(L, G->refArray[r->st].st, n)));
-  }
-  lua_assert(VALIDLINK(L, G->refFree, n));
-}
-
-
 static void invalidatetable (Hash *h) {
   int i;
   for (i=0; i<h->size; i++) {
@@ -408,7 +380,6 @@ void luaC_collect (lua_State *L, int all) {
 
 void luaC_collectgarbage (lua_State *L) {
   markall(L);
-  invalidaterefs(G(L));  /* check unlocked references */
   invalidatetables(G(L));
   luaC_collect(L, 0);
   checkMbuffer(L);
diff --git a/lstate.c b/lstate.c
index 1006dbec..63e15283 100644
--- a/lstate.c
+++ b/lstate.c
@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 1.60 2001/03/09 18:05:05 roberto Exp roberto $
+** $Id: lstate.c,v 1.61 2001/03/26 14:31:49 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -29,20 +29,6 @@ struct Sopen {
 static void close_state (lua_State *L, lua_State *OL);
 
 
-/*
-** initialize ref array and registry
-*/
-#define INIT_REFSIZE	4
-
-static void ref_init (lua_State *L) {
-  G(L)->refArray = luaM_newvector(L, INIT_REFSIZE, struct Ref);
-  G(L)->sizeref = INIT_REFSIZE;
-  sethvalue(&G(L)->refArray[0].o, luaH_new(L, 0));
-  G(L)->refArray[0].st = LOCK;
-  G(L)->nref = 1;
-}
-
-
 /*
 ** open parts that may cause memory-allocation errors
 */
@@ -74,18 +60,16 @@ static void f_luaopen (lua_State *L, void *ud) {
     G(L)->TMtable = NULL;
     G(L)->sizeTM = 0;
     G(L)->ntag = 0;
-    G(L)->refArray = NULL;
-    G(L)->nref = 0;
-    G(L)->sizeref = 0;
-    G(L)->refFree = NONEXT;
     G(L)->nblocks = sizeof(lua_State) + sizeof(global_State);
     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);
+    G(L)->weakregistry->weakmode = LUA_WEAK_VALUE;  /* make weakregistry weak */
     luaS_init(L);
     luaX_init(L);
     luaT_init(L);
-    ref_init(L);
     G(L)->GCthreshold = 4*G(L)->nblocks;
   }
 }
@@ -133,7 +117,6 @@ static void close_state (lua_State *L, lua_State *OL) {
     lua_assert(G(L)->roottable == NULL);
     luaS_freeall(L);
     luaM_freearray(L, G(L)->TMtable, G(L)->sizeTM, struct TM);
-    luaM_freearray(L, G(L)->refArray, G(L)->sizeref, struct Ref);
     luaM_freearray(L, G(L)->Mbuffer, G(L)->Mbuffsize, l_char);
     luaM_freelem(NULL, L->G, global_State);
   }
diff --git a/lstate.h b/lstate.h
index 69fd02ad..7c0e808d 100644
--- a/lstate.h
+++ b/lstate.h
@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.h,v 1.54 2001/03/02 17:27:50 roberto Exp roberto $
+** $Id: lstate.h,v 1.55 2001/03/07 18:09:25 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -32,20 +32,6 @@
 #endif
 
 
-/*
-** marks for Reference array
-*/
-#define NONEXT          -1      /* to end the free list */
-#define HOLD            -2
-#define COLLECTED       -3
-#define LOCK            -4
-
-
-struct Ref {
-  TObject o;
-  int st;  /* can be LOCK, HOLD, COLLECTED, or next (for free list) */
-};
-
 
 struct lua_longjmp;  /* defined in ldo.c */
 struct TM;  /* defined in ltm.h */
@@ -70,13 +56,11 @@ typedef struct global_State {
   stringtable strt;  /* hash table for strings */
   stringtable udt;   /* hash table for udata */
   Hash *type2tag;  /* hash table from type names to tags */
+  Hash *registry;  /* (strong) registry table */
+  Hash *weakregistry;  /* weakregistry table */
   struct TM *TMtable;  /* table for tag methods */
   int sizeTM;  /* size of TMtable */
   int ntag;  /* number of tags in TMtable */
-  struct Ref *refArray;  /* locked objects */
-  int nref;  /* first unused element in refArray */
-  int sizeref;  /* size of refArray */
-  int refFree;  /* list of free positions in refArray */
   lu_mem GCthreshold;
   lu_mem nblocks;  /* number of `bytes' currently allocated */
 } global_State;
diff --git a/ltests.c b/ltests.c
index d012df8b..d761d065 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1,5 +1,5 @@
 /*
-** $Id: ltests.c,v 1.77 2001/03/26 14:31:49 roberto Exp roberto $
+** $Id: ltests.c,v 1.78 2001/04/11 14:42:41 roberto Exp roberto $
 ** Internal Module for Debugging of the Lua Implementation
 ** See Copyright Notice in lua.h
 */
@@ -383,21 +383,30 @@ static int string_query (lua_State *L) {
 
 
 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)));
+  assert(lua_gettop(L) == level+1);  /* +1 for result */
   return 1;
 }
 
 static int getref (lua_State *L) {
-  if (lua_getref(L, luaL_check_int(L, 1)))
+  int level = lua_gettop(L);
+  if (lua_getref(L, luaL_check_int(L, 1))) {
+    assert(lua_gettop(L) == level+1);
     return 1;
-  else
+  }
+  else {
+    assert(lua_gettop(L) == level);
     return 0;
+  }
 }
 
 static int unref (lua_State *L) {
+  int level = lua_gettop(L);
   lua_unref(L, luaL_check_int(L, 1));
+  assert(lua_gettop(L) == level);
   return 0;
 }
 
diff --git a/lua.h b/lua.h
index 313a32be..4bfbc336 100644
--- a/lua.h
+++ b/lua.h
@@ -1,8 +1,8 @@
 /*
-** $Id: lua.h,v 1.94 2001/04/11 14:42:41 roberto Exp roberto $
+** $Id: lua.h,v 1.95 2001/04/11 18:39:37 roberto Exp roberto $
 ** Lua - An Extensible Extension Language
 ** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil
-** e-mail: lua@tecgraf.puc-rio.br
+** e-mail: info@lua.org
 ** www: http://www.lua.org
 ** See Copyright Notice at the end of this file
 */
@@ -29,24 +29,20 @@
 /* pre-defined references */
 #define LUA_NOREF	(-2)
 #define LUA_REFNIL	(-1)
-#define LUA_REFREGISTRY	0
-
-/* pre-defined tags */
-#define LUA_NOTAG	(-2)
 
 
-/* option for multiple returns in lua_call */
+/* option for multiple returns in `lua_call' */
 #define LUA_MULTRET	(-1)
 
 
-/* error codes for lua_do* */
+/* error codes for `lua_do*' and the like */
 #define LUA_ERRRUN	1
 #define LUA_ERRFILE	2
 #define LUA_ERRSYNTAX	3
 #define LUA_ERRMEM	4
 #define LUA_ERRERR	5
 
-/* weak modes */
+/* weak-table modes */
 #define LUA_WEAK_KEY	1
 #define LUA_WEAK_VALUE	2
 
@@ -67,6 +63,11 @@ typedef int (*lua_CFunction) (lua_State *L);
 #define LUA_TTABLE	4
 #define LUA_TFUNCTION	5
 
+/*
+** an invalid `tag'
+*/
+#define LUA_NOTAG	(-2)
+
 
 
 /*
@@ -77,7 +78,7 @@ typedef int (*lua_CFunction) (lua_State *L);
 #endif
 
 
-/* minimum stack available for a C function */
+/* minimum Lua stack available to a C function */
 #define LUA_MINSTACK	20
 
 
@@ -163,6 +164,8 @@ 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);
 
 
 /*
@@ -241,8 +244,6 @@ LUA_API int  lua_getweakmode (lua_State *L, int index);
 #define lua_isnil(L,n)		(lua_type(L,n) == LUA_TNIL)
 #define lua_isnull(L,n)		(lua_type(L,n) == LUA_TNONE)
 
-#define lua_getregistry(L)	lua_getref(L, LUA_REFREGISTRY)
-
 #define lua_pushliteral(L, s)	lua_pushlstring(L, s, \
                                                 (sizeof(s)/sizeof(lua_char))-1)
 
-- 
cgit v1.2.3-55-g6feb