lua: add reference counting for strings - this will need A LOT of testing, but it...
authorFelix Fietkau <nbd@openwrt.org>
Sat, 24 Oct 2009 22:19:13 +0000 (22:19 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sat, 24 Oct 2009 22:19:13 +0000 (22:19 +0000)
SVN-Revision: 18136

package/lua/patches/040-memory-limits.patch [deleted file]
package/lua/patches/300-opcode_performance.patch
package/lua/patches/600-refcounting.patch [new file with mode: 0644]

diff --git a/package/lua/patches/040-memory-limits.patch b/package/lua/patches/040-memory-limits.patch
deleted file mode 100644 (file)
index bc6526b..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
---- a/src/lapi.c
-+++ b/src/lapi.c
-@@ -716,14 +716,14 @@
- LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
-   StkId t;
--  TValue key;
-   lua_lock(L);
-   api_checknelems(L, 1);
-   t = index2adr(L, idx);
-   api_checkvalidindex(L, t);
--  setsvalue(L, &key, luaS_new(L, k));
--  luaV_settable(L, t, &key, L->top - 1);
--  L->top--;  /* pop value */
-+  setsvalue2s(L, L->top, luaS_new(L, k));
-+  api_incr_top(L);
-+  luaV_settable(L, t, L->top - 1, L->top - 2);
-+  L->top -= 2;  /* pop key and value */
-   lua_unlock(L);
- }
-@@ -971,7 +971,12 @@
-       break;
-     }
-     case LUA_GCCOLLECT: {
--      luaC_fullgc(L);
-+      lu_mem old_thres = g->GCthreshold;
-+      if(g->GCthreshold != MAX_LUMEM) {
-+        g->GCthreshold = MAX_LUMEM;
-+        luaC_fullgc(L);
-+        g->GCthreshold = old_thres;
-+      }
-       break;
-     }
-     case LUA_GCCOUNT: {
---- a/src/ldo.c
-+++ b/src/ldo.c
-@@ -494,6 +494,7 @@
-   struct SParser *p = cast(struct SParser *, ud);
-   int c = luaZ_lookahead(p->z);
-   luaC_checkGC(L);
-+      lua_gc(L, LUA_GCSTOP, 0);  /* stop collector during parsing */
-   tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z,
-                                                              &p->buff, p->name);
-   cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L)));
-@@ -502,6 +503,7 @@
-     cl->l.upvals[i] = luaF_newupval(L);
-   setclvalue(L, L->top, cl);
-   incr_top(L);
-+      lua_gc(L, LUA_GCRESTART, 0);
- }
---- a/src/lgc.c
-+++ b/src/lgc.c
-@@ -437,7 +437,10 @@
-   /* check size of buffer */
-   if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) {  /* buffer too big? */
-     size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
--    luaZ_resizebuffer(L, &g->buff, newsize);
-+    /* make sure newsize is larger then the buffer's in use size. */
-+    newsize = (luaZ_bufflen(&g->buff) > newsize) ? luaZ_bufflen(&g->buff) : newsize;
-+    if(newsize < luaZ_sizebuffer(&g->buff))
-+      luaZ_resizebuffer(L, &g->buff, newsize);
-   }
- }
---- a/src/lstate.c
-+++ b/src/lstate.c
-@@ -118,7 +118,6 @@
- lua_State *luaE_newthread (lua_State *L) {
-   lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State)));
--  luaC_link(L, obj2gco(L1), LUA_TTHREAD);
-   preinit_state(L1, G(L));
-   stack_init(L1, L);  /* init stack */
-   setobj2n(L, gt(L1), gt(L));  /* share table of globals */
-@@ -126,6 +125,7 @@
-   L1->basehookcount = L->basehookcount;
-   L1->hook = L->hook;
-   resethookcount(L1);
-+  luaC_link(L, obj2gco(L1), LUA_TTHREAD);
-   lua_assert(iswhite(obj2gco(L1)));
-   return L1;
- }
---- a/src/lstring.c
-+++ b/src/lstring.c
-@@ -53,6 +53,9 @@
-   stringtable *tb;
-   if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char))
-     luaM_toobig(L);
-+  tb = &G(L)->strt;
-+  if ((tb->nuse + 1) > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
-+    luaS_resize(L, tb->size*2);  /* too crowded */
-   ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString)));
-   ts->tsv.len = l;
-   ts->tsv.hash = h;
-@@ -61,13 +64,10 @@
-   ts->tsv.reserved = 0;
-   memcpy(ts+1, str, l*sizeof(char));
-   ((char *)(ts+1))[l] = '\0';  /* ending 0 */
--  tb = &G(L)->strt;
-   h = lmod(h, tb->size);
-   ts->tsv.next = tb->hash[h];  /* chain new entry */
-   tb->hash[h] = obj2gco(ts);
-   tb->nuse++;
--  if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
--    luaS_resize(L, tb->size*2);  /* too crowded */
-   return ts;
- }
---- a/src/ltable.c
-+++ b/src/ltable.c
-@@ -371,7 +371,6 @@
- Table *luaH_new (lua_State *L, int narray, int nhash) {
-   Table *t = luaM_new(L, Table);
--  luaC_link(L, obj2gco(t), LUA_TTABLE);
-   t->metatable = NULL;
-   t->flags = cast_byte(~0);
-   /* temporary values (kept only if some malloc fails) */
-@@ -381,6 +380,7 @@
-   t->node = cast(Node *, dummynode);
-   setarrayvector(L, t, narray);
-   setnodevector(L, t, nhash);
-+  luaC_link(L, obj2gco(t), LUA_TTABLE);
-   return t;
- }
---- a/src/lvm.c
-+++ b/src/lvm.c
-@@ -375,6 +375,7 @@
-         if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
-         tl += l;
-       }
-+      G(L)->buff.n = tl;
-       buffer = luaZ_openspace(L, &G(L)->buff, tl);
-       tl = 0;
-       for (i=n; i>0; i--) {  /* concat all strings */
-@@ -383,6 +384,7 @@
-         tl += l;
-       }
-       setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
-+      luaZ_resetbuffer(&G(L)->buff);
-     }
-     total -= n-1;  /* got `n' strings to create 1 new */
-     last -= n-1;
---- a/src/lua.c
-+++ b/src/lua.c
-@@ -19,6 +19,94 @@
- #include "llimits.h"
-+typedef struct {
-+      char            *name;
-+      lua_State       *L;
-+      size_t          memused;
-+      size_t          peak_memused;
-+      size_t          gc_memused;
-+      size_t          max_memused;
-+      int             collecting;
-+} script_info_t;
-+
-+
-+static void *script_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
-+{
-+      script_info_t *info=(script_info_t *)ud;
-+      size_t old_size = info->memused;
-+
-+      info->memused -= osize;
-+      if (nsize == 0) {
-+              free(ptr);
-+              return NULL;
-+      }
-+      info->memused += nsize;
-+      if(info->max_memused > 0 && nsize > osize &&
-+        (info->memused >= info->max_memused || info->memused >= info->gc_memused)) {
-+#ifdef LOW_MEM_DEBUG
-+              printf("LOW MEM: 1 osize=%zd, nsize=%zd, used=%zu, peak=%zu, need=%zd\n", osize, nsize,
-+                      info->memused, info->peak_memused, (info->memused - info->max_memused));
-+#endif
-+              info->memused = old_size;
-+              /* don't allow a recursive garbage collection call. */
-+              if(info->collecting != 0) {
-+                      return NULL;
-+              }
-+              info->collecting = 1;
-+              /* try to free memory by collecting garbage. */
-+              lua_gc(info->L, LUA_GCCOLLECT, 0);
-+              info->collecting = 0;
-+#ifdef LOW_MEM_DEBUG
-+              printf("LOW MEM: 2 used=%zu, peak=%zu\n", info->memused, info->peak_memused);
-+#endif
-+              /* check memory usage again. */
-+              old_size = info->memused;
-+              info->memused -= osize;
-+              info->memused += nsize;
-+              if(info->memused >= info->max_memused) {
-+                      info->memused = old_size;
-+#ifdef LOW_MEM_DEBUG
-+                      printf("OUT OF MEMORY: memused=%zd, osize=%zd, nsize=%zd\n", info->memused, osize, nsize);
-+#endif
-+                      return NULL;
-+              }
-+      }
-+      if(info->memused > info->peak_memused) info->peak_memused = info->memused;
-+      return realloc(ptr, nsize);
-+}
-+
-+static int set_memory_limit(lua_State *L)
-+{
-+      int hardlimit = luaL_checknumber(L, 1);
-+      int softlimit = luaL_optnumber(L, 2, 0);
-+
-+      script_info_t *info;
-+      lua_getallocf(L, (void *)(&info));
-+
-+      if( hardlimit >= 0 )
-+      {
-+              if( softlimit <= 0 )
-+                      softlimit = (int)((float)hardlimit * 0.75);
-+
-+              info->max_memused = hardlimit;
-+              info->gc_memused  = softlimit;
-+      }
-+
-+      lua_pushnumber(L, hardlimit);
-+      lua_pushnumber(L, softlimit);
-+      return 2;
-+}
-+
-+static int get_memory_limit(lua_State *L)
-+{
-+      script_info_t *info;
-+      lua_getallocf(L, (void *)(&info));
-+      lua_pushnumber(L, info->max_memused);
-+      lua_pushnumber(L, info->gc_memused);
-+      return 2;
-+}
-+
-+
- static lua_State *globalL = NULL;
- static const char *progname = LUA_PROGNAME;
-@@ -377,11 +465,28 @@
- int main (int argc, char **argv) {
-   int status;
-   struct Smain s;
--  lua_State *L = lua_open();  /* create state */
-+  script_info_t *info;
-+
-+  info = (script_info_t *)calloc(1, sizeof(script_info_t));
-+  info->max_memused = 0;
-+  info->collecting = 0;
-+  info->name = argv[0];
-+  info->memused = 0;
-+  info->peak_memused = 0;
-+
-+  lua_State *L = lua_newstate(script_alloc, info);
-+
-   if (L == NULL) {
-     l_message(argv[0], "cannot create state: not enough memory");
-     return EXIT_FAILURE;
-   }
-+
-+  info->L = L;
-+
-+  luaL_openlibs(L);
-+  lua_register(L, "set_memory_limit", set_memory_limit);
-+  lua_register(L, "get_memory_limit", get_memory_limit);
-+
-   /* Checking 'sizeof(lua_Integer)' cannot be made in preprocessor on all compilers.
-   */
- #ifdef LNUM_INT16
-@@ -396,6 +501,14 @@
-   status = lua_cpcall(L, &pmain, &s);
-   report(L, status);
-   lua_close(L);
-+
-+#ifdef LOW_MEM_DEBUG
-+  printf("%s: memused=%zd, peak_memused=%zd\n", info->name,
-+      info->memused, info->peak_memused);
-+#endif
-+
-+  free(info);
-+
-   return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
- }
index fb1f9a1..e870a25 100644 (file)
@@ -10,7 +10,7 @@
  
  /*
   * If 'obj' is a string, it is tried to be interpreted as a number.
-@@ -564,12 +567,63 @@
+@@ -562,12 +565,63 @@ static inline int arith_mode( const TVal
      ARITH_OP1_END
  #endif
  
@@ -74,7 +74,7 @@
   reentry:  /* entry point */
    lua_assert(isLua(L->ci));
    pc = L->savedpc;
-@@ -594,33 +648,33 @@
+@@ -592,33 +646,33 @@ void luaV_execute (lua_State *L, int nex
      lua_assert(base == L->base && L->base == L->ci->base);
      lua_assert(base <= L->top && L->top <= L->stack + L->stacksize);
      lua_assert(L->top == L->ci->top || luaG_checkopenop(i));
          TValue g;
          TValue *rb = KBx(i);
          sethvalue(L, &g, cl->env);
-@@ -628,88 +682,88 @@
+@@ -626,88 +680,88 @@ void luaV_execute (lua_State *L, int nex
          Protect(luaV_gettable(L, &g, rb, ra));
          continue;
        }
          const TValue *rb = RB(i);
          switch (ttype(rb)) {
            case LUA_TTABLE: {
-@@ -729,18 +783,18 @@
+@@ -727,18 +781,18 @@ void luaV_execute (lua_State *L, int nex
          }
          continue;
        }
          TValue *rb = RKB(i);
          TValue *rc = RKC(i);
          Protect(
-@@ -750,7 +804,7 @@
+@@ -748,7 +802,7 @@ void luaV_execute (lua_State *L, int nex
          pc++;
          continue;
        }
          Protect(
            if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i))
              dojump(L, pc, GETARG_sBx(*pc));
-@@ -758,7 +812,7 @@
+@@ -756,7 +810,7 @@ void luaV_execute (lua_State *L, int nex
          pc++;
          continue;
        }
          Protect(
            if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i))
              dojump(L, pc, GETARG_sBx(*pc));
-@@ -766,13 +820,13 @@
+@@ -764,13 +818,13 @@ void luaV_execute (lua_State *L, int nex
          pc++;
          continue;
        }
          TValue *rb = RB(i);
          if (l_isfalse(rb) != GETARG_C(i)) {
            setobjs2s(L, ra, rb);
-@@ -781,7 +835,7 @@
+@@ -779,7 +833,7 @@ void luaV_execute (lua_State *L, int nex
          pc++;
          continue;
        }
          int b = GETARG_B(i);
          int nresults = GETARG_C(i) - 1;
          if (b != 0) L->top = ra+b;  /* else previous instruction set top */
-@@ -802,7 +856,7 @@
+@@ -800,7 +854,7 @@ void luaV_execute (lua_State *L, int nex
            }
          }
        }
          int b = GETARG_B(i);
          if (b != 0) L->top = ra+b;  /* else previous instruction set top */
          L->savedpc = pc;
-@@ -834,7 +888,7 @@
+@@ -832,7 +886,7 @@ void luaV_execute (lua_State *L, int nex
            }
          }
        }
          int b = GETARG_B(i);
          if (b != 0) L->top = ra+b-1;
          if (L->openupval) luaF_close(L, base);
-@@ -849,7 +903,7 @@
+@@ -847,7 +901,7 @@ void luaV_execute (lua_State *L, int nex
            goto reentry;
          }
        }
          /* If start,step and limit are all integers, we don't need to check
           * against overflow in the looping.
           */
-@@ -877,7 +931,7 @@
+@@ -875,7 +929,7 @@ void luaV_execute (lua_State *L, int nex
          }
          continue;
        }
          const TValue *init = ra;
          const TValue *plimit = ra+1;
          const TValue *pstep = ra+2;
-@@ -900,7 +954,7 @@
+@@ -898,7 +952,7 @@ void luaV_execute (lua_State *L, int nex
          dojump(L, pc, GETARG_sBx(i));
          continue;
        }
          StkId cb = ra + 3;  /* call base */
          setobjs2s(L, cb+2, ra+2);
          setobjs2s(L, cb+1, ra+1);
-@@ -916,7 +970,7 @@
+@@ -914,7 +968,7 @@ void luaV_execute (lua_State *L, int nex
          pc++;
          continue;
        }
          int n = GETARG_B(i);
          int c = GETARG_C(i);
          int last;
-@@ -938,11 +992,11 @@
+@@ -936,11 +990,11 @@ void luaV_execute (lua_State *L, int nex
          }
          continue;
        }
          Proto *p;
          Closure *ncl;
          int nup, j;
-@@ -962,7 +1016,7 @@
+@@ -960,7 +1014,7 @@ void luaV_execute (lua_State *L, int nex
          Protect(luaC_checkGC(L));
          continue;
        }
diff --git a/package/lua/patches/600-refcounting.patch b/package/lua/patches/600-refcounting.patch
new file mode 100644 (file)
index 0000000..10fd533
--- /dev/null
@@ -0,0 +1,1096 @@
+--- a/src/lapi.c
++++ b/src/lapi.c
+@@ -27,8 +27,8 @@
+ #include "ltable.h"
+ #include "ltm.h"
+ #include "lundump.h"
+-#include "lvm.h"
+ #include "lnum.h"
++#include "lvm.h"
+ const char lua_ident[] =
+@@ -117,6 +117,7 @@ LUA_API void lua_xmove (lua_State *from,
+   from->top -= n;
+   for (i = 0; i < n; i++) {
+     setobj2s(to, to->top++, from->top + i);
++    setnilvalue(from, from->top + i);
+   }
+   lua_unlock(to);
+ }
+@@ -166,12 +167,16 @@ LUA_API void lua_settop (lua_State *L, i
+   if (idx >= 0) {
+     api_check(L, idx <= L->stack_last - L->base);
+     while (L->top < L->base + idx)
+-      setnilvalue(L->top++);
++      setnilvalue(L, L->top++);
+     L->top = L->base + idx;
++    setnilvalue(L, L->top);
+   }
+   else {
++    int i;
+     api_check(L, -(idx+1) <= (L->top - L->base));
+     L->top += idx+1;  /* `subtract' index (index is negative) */
++    for (i = 0; i < -(idx+1); i++)
++      setnilvalue(L, L->top + i);
+   }
+   lua_unlock(L);
+ }
+@@ -184,6 +189,7 @@ LUA_API void lua_remove (lua_State *L, i
+   api_checkvalidindex(L, p);
+   while (++p < L->top) setobjs2s(L, p-1, p);
+   L->top--;
++  setnilvalue(L, L->top);
+   lua_unlock(L);
+ }
+@@ -196,6 +202,7 @@ LUA_API void lua_insert (lua_State *L, i
+   api_checkvalidindex(L, p);
+   for (q = L->top; q>p; q--) setobjs2s(L, q, q-1);
+   setobjs2s(L, p, L->top);
++  setnilvalue(L, L->top);
+   lua_unlock(L);
+ }
+@@ -221,6 +228,7 @@ LUA_API void lua_replace (lua_State *L, 
+       luaC_barrier(L, curr_func(L), L->top - 1);
+   }
+   L->top--;
++  setnilvalue(L, L->top);
+   lua_unlock(L);
+ }
+@@ -259,14 +267,14 @@ LUA_API int lua_iscfunction (lua_State *
+ LUA_API int lua_isnumber (lua_State *L, int idx) {
+-  TValue n;
++  TValue n = tvinit();
+   const TValue *o = index2adr(L, idx);
+   return tonumber(o, &n);
+ }
+ LUA_API int lua_isinteger (lua_State *L, int idx) {
+-  TValue tmp;
++  TValue tmp = tvinit();
+   lua_Integer dum;
+   const TValue *o = index2adr(L, idx);
+   return tonumber(o,&tmp) && (ttisint(o) || tt_integer_valued(o,&dum));
+@@ -319,7 +327,7 @@ LUA_API int lua_lessthan (lua_State *L, 
+ LUA_API lua_Number lua_tonumber (lua_State *L, int idx) {
+-  TValue n;
++  TValue n = tvinit();
+   const TValue *o = index2adr(L, idx);
+   if (tonumber(o, &n)) {
+ #ifdef LNUM_COMPLEX
+@@ -333,7 +341,7 @@ LUA_API lua_Number lua_tonumber (lua_Sta
+ LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) {
+-  TValue n;
++  TValue n = tvinit();
+     /* Lua 5.1 documented behaviour is to return nonzero for non-integer:
+      * "If the number is not an integer, it is truncated in some non-specified way." 
+      * I would suggest to change this, to return 0 for anything that would
+@@ -369,7 +377,7 @@ LUA_API lua_Integer lua_tointeger (lua_S
+ #ifdef LNUM_COMPLEX
+ LUA_API lua_Complex lua_tocomplex (lua_State *L, int idx) {
+-  TValue tmp;
++  TValue tmp = tvinit();
+   const TValue *o = index2adr(L, idx);
+   if (tonumber(o, &tmp))
+     return nvalue_complex(o);
+@@ -465,7 +473,7 @@ LUA_API const void *lua_topointer (lua_S
+ LUA_API void lua_pushnil (lua_State *L) {
+   lua_lock(L);
+-  setnilvalue(L->top);
++  setnilvalue(L, L->top);
+   api_incr_top(L);
+   lua_unlock(L);
+ }
+@@ -548,8 +556,10 @@ LUA_API void lua_pushcclosure (lua_State
+   cl = luaF_newCclosure(L, n, getcurrenv(L));
+   cl->c.f = fn;
+   L->top -= n;
+-  while (n--)
++  while (n--) {
+     setobj2n(L, &cl->c.upvalue[n], L->top+n);
++    setnilvalue(L, L->top + n);
++  }
+   setclvalue(L, L->top, cl);
+   lua_assert(iswhite(obj2gco(cl)));
+   api_incr_top(L);
+@@ -600,7 +610,7 @@ LUA_API void lua_gettable (lua_State *L,
+ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) {
+   StkId t;
+-  TValue key;
++  TValue key = tvinit();
+   lua_lock(L);
+   t = index2adr(L, idx);
+   api_checkvalidindex(L, t);
+@@ -689,7 +699,7 @@ LUA_API void lua_getfenv (lua_State *L, 
+       setobj2s(L, L->top,  gt(thvalue(o)));
+       break;
+     default:
+-      setnilvalue(L->top);
++      setnilvalue(L, L->top);
+       break;
+   }
+   api_incr_top(L);
+@@ -710,13 +720,15 @@ LUA_API void lua_settable (lua_State *L,
+   api_checkvalidindex(L, t);
+   luaV_settable(L, t, L->top - 2, L->top - 1);
+   L->top -= 2;  /* pop index and value */
++  setnilvalue(L, L->top);
++  setnilvalue(L, L->top + 1);
+   lua_unlock(L);
+ }
+ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
+   StkId t;
+-  TValue key;
++  TValue key = tvinit();
+   lua_lock(L);
+   api_checknelems(L, 1);
+   t = index2adr(L, idx);
+@@ -724,6 +736,7 @@ LUA_API void lua_setfield (lua_State *L,
+   setsvalue(L, &key, luaS_new(L, k));
+   luaV_settable(L, t, &key, L->top - 1);
+   L->top--;  /* pop value */
++  setnilvalue(L, L->top);
+   lua_unlock(L);
+ }
+@@ -737,6 +750,8 @@ LUA_API void lua_rawset (lua_State *L, i
+   setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1);
+   luaC_barriert(L, hvalue(t), L->top-1);
+   L->top -= 2;
++  setnilvalue(L, L->top);
++  setnilvalue(L, L->top + 1);
+   lua_unlock(L);
+ }
+@@ -750,6 +765,7 @@ LUA_API void lua_rawseti (lua_State *L, 
+   setobj2t(L, luaH_setint(L, hvalue(o), n), L->top-1);
+   luaC_barriert(L, hvalue(o), L->top-1);
+   L->top--;
++  setnilvalue(L, L->top);
+   lua_unlock(L);
+ }
+@@ -786,6 +802,7 @@ LUA_API int lua_setmetatable (lua_State 
+     }
+   }
+   L->top--;
++  setnilvalue(L, L->top);
+   lua_unlock(L);
+   return 1;
+ }
+@@ -815,6 +832,7 @@ LUA_API int lua_setfenv (lua_State *L, i
+   }
+   if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1));
+   L->top--;
++  setnilvalue(L, L->top);
+   lua_unlock(L);
+   return res;
+ }
+@@ -1040,20 +1058,25 @@ LUA_API int lua_next (lua_State *L, int 
+   if (more) {
+     api_incr_top(L);
+   }
+-  else  /* no more elements */
++  else {  /* no more elements */
+     L->top -= 1;  /* remove key */
++    setnilvalue(L, L->top);
++  }
+   lua_unlock(L);
+   return more;
+ }
+ LUA_API void lua_concat (lua_State *L, int n) {
++  int i;
+   lua_lock(L);
+   api_checknelems(L, n);
+   if (n >= 2) {
+     luaC_checkGC(L);
+     luaV_concat(L, n, cast_int(L->top - L->base) - 1);
+     L->top -= (n-1);
++    for (i = 0; i < n - 1; i++)
++      setnilvalue(L, L->top + i);
+   }
+   else if (n == 0) {  /* push empty string */
+     setsvalue2s(L, L->top, luaS_newlstr(L, "", 0));
+@@ -1139,6 +1162,7 @@ LUA_API const char *lua_setupvalue (lua_
+   if (name) {
+     L->top--;
+     setobj(L, val, L->top);
++    setnilvalue(L, L->top);
+     luaC_barrier(L, clvalue(fi), L->top);
+   }
+   lua_unlock(L);
+@@ -1160,7 +1184,7 @@ LUA_API const char *lua_setupvalue (lua_
+ int lua_pushvalue_as_number (lua_State *L, int idx)
+ {
+   const TValue *o = index2adr(L, idx);
+-  TValue tmp;
++  TValue tmp = tvinit();
+   lua_Integer i;
+   if (ttisnumber(o)) {
+     if ( (!ttisint(o)) && tt_integer_valued(o,&i)) {
+--- a/src/lcode.c
++++ b/src/lcode.c
+@@ -23,6 +23,7 @@
+ #include "lparser.h"
+ #include "ltable.h"
+ #include "lnum.h"
++#include "lvm.h"
+ #define hasjumps(e)   ((e)->t != (e)->f)
+@@ -248,7 +249,7 @@ static int addk (FuncState *fs, TValue *
+     setivalue(idx, fs->nk);
+     luaM_growvector(L, f->k, fs->nk, f->sizek, TValue,
+                     MAXARG_Bx, "constant table overflow");
+-    while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
++    while (oldsize < f->sizek) setnilvalue(L, &f->k[oldsize++]);
+     setobj(L, &f->k[fs->nk], v);
+     luaC_barrier(L, f, v);
+     return fs->nk++;
+@@ -257,21 +258,24 @@ static int addk (FuncState *fs, TValue *
+ int luaK_stringK (FuncState *fs, TString *s) {
+-  TValue o;
++  TValue o = tvinit();
+   setsvalue(fs->L, &o, s);
++  luaV_unref(fs->L, &o);
+   return addk(fs, &o, &o);
+ }
+ int luaK_numberK (FuncState *fs, lua_Number r) {
+-  TValue o;
++  lua_State *L = fs->L;
++  TValue o = tvinit();
+   setnvalue(&o, r);
+   return addk(fs, &o, &o);
+ }
+ int luaK_integerK (FuncState *fs, lua_Integer r) {
+-  TValue o;
++  lua_State *L = fs->L;
++  TValue o = tvinit();
+   setivalue(&o, r);
+   return addk(fs, &o, &o);
+ }
+@@ -279,22 +283,24 @@ int luaK_integerK (FuncState *fs, lua_In
+ #ifdef LNUM_COMPLEX
+ static int luaK_imagK (FuncState *fs, lua_Number r) {
+-  TValue o;
++  lua_State *L = fs->L;
++  TValue o = tvinit();
+   setnvalue_complex(&o, r*I);
+   return addk(fs, &o, &o);
+ }
+ #endif
+ static int boolK (FuncState *fs, int b) {
+-  TValue o;
++  lua_State *L = fs->L;
++  TValue o = tvinit();
+   setbvalue(&o, b);
+   return addk(fs, &o, &o);
+ }
+ static int nilK (FuncState *fs) {
+-  TValue k, v;
+-  setnilvalue(&v);
++  TValue k = tvinit(), v = tvinit();
++  setnilvalue(fs->L, &v);
+   /* cannot use nil as key; instead use table itself to represent nil */
+   sethvalue(fs->L, &k, fs->h);
+   return addk(fs, &k, &v);
+--- a/src/ldebug.c
++++ b/src/ldebug.c
+@@ -176,7 +176,7 @@ static void info_tailcall (lua_Debug *ar
+ static void collectvalidlines (lua_State *L, Closure *f) {
+   if (f == NULL || f->c.isC) {
+-    setnilvalue(L->top);
++    setnilvalue(L, L->top);
+   }
+   else {
+     Table *t = luaH_new(L, 0, 0);
+@@ -248,7 +248,7 @@ LUA_API int lua_getinfo (lua_State *L, c
+   }
+   status = auxgetinfo(L, what, ar, f, ci);
+   if (strchr(what, 'f')) {
+-    if (f == NULL) setnilvalue(L->top);
++    if (f == NULL) setnilvalue(L, L->top);
+     else setclvalue(L, L->top, f);
+     incr_top(L);
+   }
+@@ -586,7 +586,7 @@ void luaG_concaterror (lua_State *L, Stk
+ void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) {
+-  TValue temp;
++  TValue temp = tvinit();
+   if (luaV_tonumber(p1, &temp) == NULL)
+     p2 = p1;  /* first operand is wrong */
+   luaG_typeerror(L, p2, "perform arithmetic on");
+--- a/src/ldo.c
++++ b/src/ldo.c
+@@ -211,7 +211,7 @@ static StkId adjust_varargs (lua_State *
+   Table *htab = NULL;
+   StkId base, fixed;
+   for (; actual < nfixargs; ++actual)
+-    setnilvalue(L->top++);
++    setnilvalue(L, L->top++);
+ #if defined(LUA_COMPAT_VARARG)
+   if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */
+     int nvar = actual - nfixargs;  /* number of extra arguments */
+@@ -229,7 +229,6 @@ static StkId adjust_varargs (lua_State *
+   base = L->top;  /* final position of first argument */
+   for (i=0; i<nfixargs; i++) {
+     setobjs2s(L, L->top++, fixed+i);
+-    setnilvalue(fixed+i);
+   }
+   /* add `arg' parameter */
+   if (htab) {
+@@ -294,7 +293,7 @@ int luaD_precall (lua_State *L, StkId fu
+     ci->tailcalls = 0;
+     ci->nresults = nresults;
+     for (st = L->top; st < ci->top; st++)
+-      setnilvalue(st);
++      setnilvalue(L, st);
+     L->top = ci->top;
+     if (L->hookmask & LUA_MASKCALL) {
+       L->savedpc++;  /* hooks assume 'pc' is already incremented */
+@@ -354,7 +353,9 @@ int luaD_poscall (lua_State *L, StkId fi
+   for (i = wanted; i != 0 && firstResult < L->top; i--)
+     setobjs2s(L, res++, firstResult++);
+   while (i-- > 0)
+-    setnilvalue(res++);
++    setnilvalue(L, res++);
++  for (i = (res - L->top); i-- > 0;)
++    setnilvalue(L, L->top + i);
+   L->top = res;
+   return (wanted - LUA_MULTRET);  /* 0 iff wanted == LUA_MULTRET */
+ }
+@@ -463,8 +464,12 @@ int luaD_pcall (lua_State *L, Pfunc func
+   status = luaD_rawrunprotected(L, func, u);
+   if (status != 0) {  /* an error occurred? */
+     StkId oldtop = restorestack(L, old_top);
++      StkId curtop = L->top;
++    int i;
+     luaF_close(L, oldtop);  /* close eventual pending closures */
+     luaD_seterrorobj(L, status, oldtop);
++    for (i = (curtop - L->top); i-- > 0;)
++      setnilvalue(L, L->top + i);
+     L->nCcalls = oldnCcalls;
+     L->ci = restoreci(L, old_ci);
+     L->base = L->ci->base;
+--- a/src/lfunc.c
++++ b/src/lfunc.c
+@@ -17,7 +17,7 @@
+ #include "lmem.h"
+ #include "lobject.h"
+ #include "lstate.h"
+-
++#include "lvm.h"
+ Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) {
+@@ -45,7 +45,7 @@ UpVal *luaF_newupval (lua_State *L) {
+   UpVal *uv = luaM_new(L, UpVal);
+   luaC_link(L, obj2gco(uv), LUA_TUPVAL);
+   uv->v = &uv->u.value;
+-  setnilvalue(uv->v);
++  setnilvalue(L, uv->v);
+   return uv;
+ }
+@@ -69,6 +69,12 @@ UpVal *luaF_findupval (lua_State *L, Stk
+   uv->marked = luaC_white(g);
+   uv->v = level;  /* current value lives in the stack */
+   uv->next = *pp;  /* chain it in the proper position */
++  if (uv->next) {
++      uv->prev = uv->next->gch.prev;
++    uv->next->gch.prev = (GCObject *)uv;
++  } else {
++    uv->prev = NULL;
++  }
+   *pp = obj2gco(uv);
+   uv->u.l.prev = &g->uvhead;  /* double link it in `uvhead' list */
+   uv->u.l.next = g->uvhead.u.l.next;
+--- a/src/lgc.c
++++ b/src/lgc.c
+@@ -21,6 +21,7 @@
+ #include "lstring.h"
+ #include "ltable.h"
+ #include "ltm.h"
++#include "lvm.h"
+ #define GCSTEPSIZE    1024u
+@@ -265,7 +266,7 @@ static void traversestack (global_State 
+   for (o = l->stack; o < l->top; o++)
+     markvalue(g, o);
+   for (; o <= lim; o++)
+-    setnilvalue(o);
++    setnilvalue(l, o);
+   checkstacksizes(l, lim);
+ }
+@@ -348,7 +349,7 @@ static int iscleared (const TValue *o, i
+ /*
+ ** clear collected entries from weaktables
+ */
+-static void cleartable (GCObject *l) {
++static void cleartable (lua_State *L, GCObject *l) {
+   while (l) {
+     Table *h = gco2h(l);
+     int i = h->sizearray;
+@@ -358,7 +359,7 @@ static void cleartable (GCObject *l) {
+       while (i--) {
+         TValue *o = &h->array[i];
+         if (iscleared(o, 0))  /* value was collected? */
+-          setnilvalue(o);  /* remove value */
++          setnilvalue(L, o);  /* remove value */
+       }
+     }
+     i = sizenode(h);
+@@ -366,7 +367,7 @@ static void cleartable (GCObject *l) {
+       Node *n = gnode(h, i);
+       if (!ttisnil(gval(n)) &&  /* non-empty entry? */
+           (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) {
+-        setnilvalue(gval(n));  /* remove value ... */
++        setnilvalue(L, gval(n));  /* remove value ... */
+         removeentry(n);  /* remove entry from table */
+       }
+     }
+@@ -375,7 +376,7 @@ static void cleartable (GCObject *l) {
+ }
+-static void freeobj (lua_State *L, GCObject *o) {
++void luaC_freeobj (lua_State *L, GCObject *o) {
+   switch (o->gch.tt) {
+     case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
+     case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break;
+@@ -418,10 +419,14 @@ static GCObject **sweeplist (lua_State *
+     }
+     else {  /* must erase `curr' */
+       lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
++      if (curr->gch.prev)
++        curr->gch.prev->gch.next = curr->gch.next;
++      if (curr->gch.next)
++        curr->gch.next->gch.prev = (GCObject*)p;
+       *p = curr->gch.next;
+       if (curr == g->rootgc)  /* is the first element of the list? */
+         g->rootgc = curr->gch.next;  /* adjust first */
+-      freeobj(L, curr);
++      luaC_freeobj(L, curr);
+     }
+   }
+   return p;
+@@ -543,7 +548,7 @@ static void atomic (lua_State *L) {
+   udsize = luaC_separateudata(L, 0);  /* separate userdata to be finalized */
+   marktmu(g);  /* mark `preserved' userdata */
+   udsize += propagateall(g);  /* remark, to propagate `preserveness' */
+-  cleartable(g->weak);  /* remove collected objects from weak tables */
++  cleartable(L, g->weak);  /* remove collected objects from weak tables */
+   /* flip current white */
+   g->currentwhite = cast_byte(otherwhite(g));
+   g->sweepstrgc = 0;
+@@ -685,8 +690,11 @@ void luaC_barrierback (lua_State *L, Tab
+ void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
+   global_State *g = G(L);
++  o->gch.prev = (GCObject*)&g->rootgc;
+   o->gch.next = g->rootgc;
+   g->rootgc = o;
++  if (o->gch.next)
++    o->gch.next->gch.prev = o;
+   o->gch.marked = luaC_white(g);
+   o->gch.tt = tt;
+ }
+--- a/src/lgc.h
++++ b/src/lgc.h
+@@ -105,6 +105,6 @@ LUAI_FUNC void luaC_link (lua_State *L, 
+ LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv);
+ LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v);
+ LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t);
+-
++LUAI_FUNC void luaC_freeobj (lua_State *L, GCObject *o);
+ #endif
+--- a/src/lmem.c
++++ b/src/lmem.c
+@@ -6,6 +6,7 @@
+ #include <stddef.h>
++#include <string.h>
+ #define lmem_c
+ #define LUA_CORE
+@@ -80,6 +81,8 @@ void *luaM_realloc_ (lua_State *L, void 
+   if (block == NULL && nsize > 0)
+     luaD_throw(L, LUA_ERRMEM);
+   lua_assert((nsize == 0) == (block == NULL));
++  if (nsize > osize)
++    memset((char *)block + osize, 0, nsize - osize);
+   g->totalbytes = (g->totalbytes - osize) + nsize;
+   return block;
+ }
+--- a/src/lobject.h
++++ b/src/lobject.h
+@@ -44,7 +44,7 @@ typedef union GCObject GCObject;
+ ** Common Header for all collectable objects (in macro form, to be
+ ** included in other objects)
+ */
+-#define CommonHeader  GCObject *next; lu_byte tt; lu_byte marked
++#define CommonHeader  GCObject *next; GCObject *prev; lu_byte tt; lu_byte marked
+ /*
+@@ -83,6 +83,7 @@ typedef struct lua_TValue {
+   TValuefields;
+ } TValue;
++#define tvinit() { .value.b = 0, .tt = 0 }
+ /* Macros to test type */
+ #define ttisnil(o)    (ttype(o) == LUA_TNIL)
+@@ -145,15 +146,15 @@ typedef struct lua_TValue {
+ /* Macros to set values */
+-#define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
++#define setnilvalue(L, obj) (luaV_unref(L, (obj))->tt=LUA_TNIL)
+ /* Must not have side effects, 'x' may be expression.
+ */
+ #define setivalue(obj,x) \
+-    { TValue *i_o=(obj); i_o->value.i=(x); i_o->tt=LUA_TINT; }
++    { TValue *i_o=luaV_unref(L, (obj)); i_o->value.i=(x); i_o->tt=LUA_TINT; }
+ # define setnvalue(obj,x) \
+-    { TValue *i_o=(obj); i_o->value.n= (x); i_o->tt=LUA_TNUMBER; }
++    { TValue *i_o=luaV_unref(L, (obj)); i_o->value.n= (x); i_o->tt=LUA_TNUMBER; }
+ /* Note: Complex always has "inline", both are C99.
+ */
+@@ -170,45 +171,45 @@ typedef struct lua_TValue {
+ #define setpvalue(obj,x) \
+-  { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; }
++  { TValue *i_o=luaV_unref(L, (obj)); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; }
+ #define setbvalue(obj,x) \
+-  { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; }
++  { TValue *i_o=luaV_unref(L, (obj)); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; }
+ #define setsvalue(L,obj,x) \
+-  { TValue *i_o=(obj); \
+-    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \
++  { TValue *i_o=(obj); TString *val=(x); luaS_ref(val); luaV_unref(L, obj); \
++    i_o->value.gc=cast(GCObject *, (val)); i_o->tt=LUA_TSTRING; \
+     checkliveness(G(L),i_o); }
+ #define setuvalue(L,obj,x) \
+-  { TValue *i_o=(obj); \
++  { TValue *i_o=luaV_unref(L, (obj)); \
+     i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \
+     checkliveness(G(L),i_o); }
+ #define setthvalue(L,obj,x) \
+-  { TValue *i_o=(obj); \
++  { TValue *i_o=luaV_unref(L, (obj)); \
+     i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \
+     checkliveness(G(L),i_o); }
+ #define setclvalue(L,obj,x) \
+-  { TValue *i_o=(obj); \
++  { TValue *i_o=luaV_unref(L, (obj)); \
+     i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \
+     checkliveness(G(L),i_o); }
+ #define sethvalue(L,obj,x) \
+-  { TValue *i_o=(obj); \
++  { TValue *i_o=luaV_unref(L, (obj)); \
+     i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \
+     checkliveness(G(L),i_o); }
+ #define setptvalue(L,obj,x) \
+-  { TValue *i_o=(obj); \
++  { TValue *i_o=luaV_unref(L, (obj)); \
+     i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \
+     checkliveness(G(L),i_o); }
+ #define setobj(L,obj1,obj2) \
+-  { const TValue *o2=(obj2); TValue *o1=(obj1); \
++  do { const TValue *o2=luaV_ref((TValue *)(obj2)); TValue *o1=luaV_unref(L, (obj1)); \
+     o1->value = o2->value; o1->tt=o2->tt; \
+-    checkliveness(G(L),o1); }
++    checkliveness(G(L),o1); } while(0)
+ /*
+@@ -253,6 +254,7 @@ typedef union TString {
+     lu_byte reserved;
+     unsigned int hash;
+     size_t len;
++    int refcount;
+   } tsv;
+ } TString;
+@@ -409,6 +411,7 @@ typedef struct Table {
+ #define twoto(x)      (1<<(x))
+ #define sizenode(t)   (twoto((t)->lsizenode))
++#include "lstring.h"
+ #define luaO_nilobject                (&luaO_nilobject_)
+--- a/src/lparser.c
++++ b/src/lparser.c
+@@ -24,6 +24,7 @@
+ #include "lstate.h"
+ #include "lstring.h"
+ #include "ltable.h"
++#include "lvm.h"
+@@ -146,7 +147,7 @@ static int registerlocalvar (LexState *l
+   luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
+                   LocVar, SHRT_MAX, "too many local variables");
+   while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
+-  f->locvars[fs->nlocvars].varname = varname;
++  f->locvars[fs->nlocvars].varname = luaS_ref(varname);
+   luaC_objbarrier(ls->L, f, varname);
+   return fs->nlocvars++;
+ }
+@@ -194,7 +195,7 @@ static int indexupvalue (FuncState *fs, 
+   luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues,
+                   TString *, MAX_INT, "");
+   while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL;
+-  f->upvalues[f->nups] = name;
++  f->upvalues[f->nups] = luaS_ref(name);
+   luaC_objbarrier(fs->L, f, name);
+   lua_assert(v->k == VLOCAL || v->k == VUPVAL);
+   fs->upvalues[f->nups].k = cast_byte(v->k);
+@@ -341,7 +342,7 @@ static void open_func (LexState *ls, Fun
+   fs->nlocvars = 0;
+   fs->nactvar = 0;
+   fs->bl = NULL;
+-  f->source = ls->source;
++  f->source = luaS_ref(ls->source);
+   f->maxstacksize = 2;  /* registers 0/1 are always valid */
+   fs->h = luaH_new(L, 0, 0);
+   /* anchor table of constants and prototype (to avoid being collected) */
+--- a/src/lstate.c
++++ b/src/lstate.c
+@@ -22,6 +22,7 @@
+ #include "lstring.h"
+ #include "ltable.h"
+ #include "ltm.h"
++#include "lvm.h"
+ #define state_size(x) (sizeof(x) + LUAI_EXTRASPACE)
+@@ -52,7 +53,7 @@ static void stack_init (lua_State *L1, l
+   L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1;
+   /* initialize first ci */
+   L1->ci->func = L1->top;
+-  setnilvalue(L1->top++);  /* `function' entry for this `ci' */
++  setnilvalue(L1, L1->top++);  /* `function' entry for this `ci' */
+   L1->base = L1->ci->base = L1->top;
+   L1->ci->top = L1->top + LUA_MINSTACK;
+ }
+@@ -98,7 +99,7 @@ static void preinit_state (lua_State *L,
+   L->base_ci = L->ci = NULL;
+   L->savedpc = NULL;
+   L->errfunc = 0;
+-  setnilvalue(gt(L));
++  setnilvalue(L, gt(L));
+ }
+@@ -163,7 +164,7 @@ LUA_API lua_State *lua_newstate (lua_All
+   g->strt.size = 0;
+   g->strt.nuse = 0;
+   g->strt.hash = NULL;
+-  setnilvalue(registry(L));
++  setnilvalue(L, registry(L));
+   luaZ_initbuffer(L, &g->buff);
+   g->panic = NULL;
+   g->gcstate = GCSpause;
+--- a/src/lstring.c
++++ b/src/lstring.c
+@@ -37,6 +37,9 @@ void luaS_resize (lua_State *L, int news
+       int h1 = lmod(h, newsize);  /* new position */
+       lua_assert(cast_int(h%newsize) == lmod(h, newsize));
+       p->gch.next = newhash[h1];  /* chain it */
++      if (p->gch.next)
++        p->gch.next->gch.prev = p;
++      p->gch.prev = NULL;
+       newhash[h1] = p;
+       p = next;
+     }
+@@ -59,11 +62,15 @@ static TString *newlstr (lua_State *L, c
+   ts->tsv.marked = luaC_white(G(L));
+   ts->tsv.tt = LUA_TSTRING;
+   ts->tsv.reserved = 0;
++  ts->tsv.refcount = 0;
+   memcpy(ts+1, str, l*sizeof(char));
+   ((char *)(ts+1))[l] = '\0';  /* ending 0 */
+   tb = &G(L)->strt;
+   h = lmod(h, tb->size);
+   ts->tsv.next = tb->hash[h];  /* chain new entry */
++  if (ts->tsv.next)
++    ts->tsv.next->gch.prev = (GCObject *)ts;
++  ts->tsv.prev = NULL;
+   tb->hash[h] = obj2gco(ts);
+   tb->nuse++;
+   if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
+@@ -109,3 +116,29 @@ Udata *luaS_newudata (lua_State *L, size
+   return u;
+ }
++void luaS_unref(lua_State *L, TString *ts) {
++  if (!L || !ts)
++    return;
++  if (testbit(ts->tsv.marked, FIXEDBIT))
++    return;
++  ts->tsv.refcount--;
++  if (ts->tsv.refcount < 0) {
++    fprintf(stderr, "REFCOUNT BUG, COUNT=%d, str=%s, len=%d\n", ts->tsv.refcount, (char *) (ts + 1), (int) ts->tsv.len);
++  } else if (ts->tsv.refcount)
++    return;
++
++  if (ts->tsv.prev) {
++    ts->tsv.prev->gch.next = ts->tsv.next;
++  } else {
++    unsigned int idx = lmod(ts->tsv.hash, G(L)->strt.size);
++    lua_assert(G(L)->strt.hash[index] == (GCObject*)ts);
++    G(L)->strt.hash[idx] = ts->tsv.next;
++  }
++
++  if (ts->tsv.next)
++    ts->tsv.next->gch.prev = ts->tsv.prev;
++
++  luaC_freeobj(L, (GCObject *) ts);
++}
++
++
+--- a/src/lstring.h
++++ b/src/lstring.h
+@@ -7,7 +7,7 @@
+ #ifndef lstring_h
+ #define lstring_h
+-
++#include <stdio.h>
+ #include "lgc.h"
+ #include "lobject.h"
+ #include "lstate.h"
+@@ -23,6 +23,12 @@
+ #define luaS_fix(s)   l_setbit((s)->tsv.marked, FIXEDBIT)
++static inline TString *luaS_ref(TString *ts) {
++  ts->tsv.refcount++;
++  return ts;
++}
++
++LUA_API void luaS_unref(lua_State *L, TString *ts);
+ LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
+ LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e);
+ LUA_API TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
+--- a/src/ltable.c
++++ b/src/ltable.c
+@@ -34,6 +34,7 @@
+ #include "lstate.h"
+ #include "ltable.h"
+ #include "lnum.h"
++#include "lvm.h"
+ /*
+@@ -278,7 +279,7 @@ static void setarrayvector (lua_State *L
+   int i;
+   luaM_reallocvector(L, t->array, t->sizearray, size, TValue);
+   for (i=t->sizearray; i<size; i++)
+-     setnilvalue(&t->array[i]);
++     setnilvalue(L, &t->array[i]);
+   t->sizearray = size;
+ }
+@@ -299,8 +300,8 @@ static void setnodevector (lua_State *L,
+     for (i=0; i<size; i++) {
+       Node *n = gnode(t, i);
+       gnext(n) = NULL;
+-      setnilvalue(gkey(n));
+-      setnilvalue(gval(n));
++      setnilvalue(L, gkey(n));
++      setnilvalue(L, gval(n));
+     }
+   }
+   t->lsizenode = cast_byte(lsize);
+@@ -427,9 +428,11 @@ static TValue *newkey (lua_State *L, Tab
+         othern = gnext(othern);  /* find previous */
+       }
+       gnext(othern) = n;  /* redo the chain with `n' in place of `mp' */
++      luaV_ref((TValue *) gkey(mp));
++      luaV_ref(gval(mp));
+       *n = *mp;  /* copy colliding node into free pos. (mp->next also goes) */
+       gnext(mp) = NULL;  /* now `mp' is free */
+-      setnilvalue(gval(mp));
++      setnilvalue(L, gval(mp));
+     }
+     else {  /* colliding node is in its own main position */
+       /* new node will go into free position */
+@@ -438,6 +441,7 @@ static TValue *newkey (lua_State *L, Tab
+       mp = n;
+     }
+   }
++  luaV_ref((TValue *) key);
+   gkey(mp)->value = key->value; gkey(mp)->tt = key->tt;
+   luaC_barriert(L, t, key);
+   lua_assert(ttisnil(gval(mp)));
+@@ -530,7 +534,7 @@ TValue *luaH_setint (lua_State *L, Table
+   if (p != luaO_nilobject)
+     return cast(TValue *, p);
+   else {
+-    TValue k;
++    TValue k = tvinit();
+     setivalue(&k, key);
+     return newkey(L, t, &k);
+   }
+@@ -542,7 +546,7 @@ TValue *luaH_setstr (lua_State *L, Table
+   if (p != luaO_nilobject)
+     return cast(TValue *, p);
+   else {
+-    TValue k;
++    TValue k = tvinit();
+     setsvalue(L, &k, key);
+     return newkey(L, t, &k);
+   }
+--- a/src/luac.c
++++ b/src/luac.c
+@@ -20,8 +20,9 @@
+ #include "lmem.h"
+ #include "lobject.h"
+ #include "lopcodes.h"
+-#include "lstring.h"
+ #include "lundump.h"
++#include "lvm.h"
++#include "lstring.h"
+ #define PROGNAME      "luac"          /* default program name */
+ #define       OUTPUT          PROGNAME ".out" /* default output file */
+--- a/src/lundump.c
++++ b/src/lundump.c
+@@ -19,6 +19,7 @@
+ #include "lstring.h"
+ #include "lundump.h"
+ #include "lzio.h"
++#include "lvm.h"
+ typedef struct {
+  lua_State* L;
+@@ -133,7 +134,7 @@ static TString* LoadString(LoadState* S)
+  {
+   char* s=luaZ_openspace(S->L,S->b,size);
+   LoadBlock(S,s,size);
+-  return luaS_newlstr(S->L,s,size-1);         /* remove trailing '\0' */
++  return luaS_ref(luaS_newlstr(S->L,s,size-1));               /* remove trailing '\0' */
+  }
+ }
+@@ -149,11 +150,12 @@ static Proto* LoadFunction(LoadState* S,
+ static void LoadConstants(LoadState* S, Proto* f)
+ {
++ lua_State *L = S->L;
+  int i,n;
+  n=LoadInt(S);
+  f->k=luaM_newvector(S->L,n,TValue);
+  f->sizek=n;
+- for (i=0; i<n; i++) setnilvalue(&f->k[i]);
++ for (i=0; i<n; i++) setnilvalue(L, &f->k[i]);
+  for (i=0; i<n; i++)
+  {
+   TValue* o=&f->k[i];
+@@ -161,7 +163,7 @@ static void LoadConstants(LoadState* S, 
+   switch (t)
+   {
+    case LUA_TNIL:
+-      setnilvalue(o);
++      setnilvalue(L, o);
+       break;
+    case LUA_TBOOLEAN:
+       setbvalue(o,LoadChar(S)!=0);
+@@ -229,6 +231,7 @@ static Proto* LoadFunction(LoadState* S,
+  LoadDebug(S,f);
+  IF (!luaG_checkcode(f), "bad code");
+  S->L->top--;
++ setnilvalue(S->L, S->L->top);
+  S->L->nCcalls--;
+  return f;
+ }
+--- a/src/lvm.c
++++ b/src/lvm.c
+@@ -39,6 +39,7 @@
+  * If 'obj' is a string, it is tried to be interpreted as a number.
+  */
+ const TValue *luaV_tonumber ( const TValue *obj, TValue *n) {
++  lua_State *L = NULL; /* FIXME */
+   lua_Number d;
+   lua_Integer i;
+   
+@@ -384,6 +385,7 @@ void luaV_concat (lua_State *L, int tota
+         size_t l = tsvalue(top-i)->len;
+         memcpy(buffer+tl, svalue(top-i), l);
+         tl += l;
++              setnilvalue(L, top - i);
+       }
+       setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
+     }
+@@ -420,7 +422,7 @@ void luaV_concat (lua_State *L, int tota
+  */
+ static void Arith (lua_State *L, StkId ra, const TValue *rb,
+                    const TValue *rc, TMS op) {
+-  TValue tempb, tempc;
++  TValue tempb = tvinit(), tempc = tvinit();
+   const TValue *b, *c;
+   lua_Number nb,nc;
+@@ -663,7 +665,7 @@ void luaV_execute (lua_State *L, int nex
+       OPCODE_TARGET(LOADNIL) {
+         TValue *rb = RB(i);
+         do {
+-          setnilvalue(rb--);
++          setnilvalue(L, rb--);
+         } while (rb >= ra);
+         continue;
+       }
+@@ -673,7 +675,7 @@ void luaV_execute (lua_State *L, int nex
+         continue;
+       }
+       OPCODE_TARGET(GETGLOBAL) {
+-        TValue g;
++        TValue g = tvinit();
+         TValue *rb = KBx(i);
+         sethvalue(L, &g, cl->env);
+         lua_assert(ttisstring(rb));
+@@ -685,7 +687,7 @@ void luaV_execute (lua_State *L, int nex
+         continue;
+       }
+       OPCODE_TARGET(SETGLOBAL) {
+-        TValue g;
++        TValue g = tvinit();
+         sethvalue(L, &g, cl->env);
+         lua_assert(ttisstring(KBx(i)));
+         Protect(luaV_settable(L, &g, KBx(i), ra));
+@@ -693,7 +695,7 @@ void luaV_execute (lua_State *L, int nex
+       }
+       OPCODE_TARGET(SETUPVAL) {
+         UpVal *uv = cl->upvals[GETARG_B(i)];
+-        setobj(L, uv->v, ra);
++        setobj(L, uv->v, luaV_ref(ra));
+         luaC_barrier(L, uv, ra);
+         continue;
+       }
+@@ -1030,7 +1032,7 @@ void luaV_execute (lua_State *L, int nex
+             setobjs2s(L, ra + j, ci->base - n + j);
+           }
+           else {
+-            setnilvalue(ra + j);
++            setnilvalue(L, ra + j);
+           }
+         }
+         continue;
+--- a/src/lvm.h
++++ b/src/lvm.h
+@@ -11,6 +11,7 @@
+ #include "ldo.h"
+ #include "lobject.h"
+ #include "ltm.h"
++#include "lstring.h"
+ #define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o)))
+@@ -19,6 +20,19 @@
+ #define equalobj(L,o1,o2) (ttype_ext_same(o1,o2) && luaV_equalval(L, o1, o2))
++static inline TValue *luaV_ref(TValue *tv)
++{
++  if (ttisstring(tv))
++    luaS_ref(rawtsvalue(tv));
++  return tv;
++}
++
++static inline TValue *luaV_unref(lua_State *L, TValue *tv)
++{
++  if (ttisstring(tv))
++    luaS_unref(L, rawtsvalue(tv));
++  return tv;
++}
+ LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
+ LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2);
+--- a/src/llex.c
++++ b/src/llex.c
+@@ -23,6 +23,7 @@
+ #include "ltable.h"
+ #include "lzio.h"
+ #include "lnum.h"
++#include "lvm.h"
+@@ -69,7 +70,7 @@ static void save (LexState *ls, int c) {
+ void luaX_init (lua_State *L) {
+   int i;
+   for (i=0; i<NUM_RESERVED; i++) {
+-    TString *ts = luaS_new(L, luaX_tokens[i]);
++    TString *ts = luaS_ref(luaS_new(L, luaX_tokens[i]));
+     luaS_fix(ts);  /* reserved words are never collected */
+     lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN);
+     ts->tsv.reserved = cast_byte(i+1);  /* reserved word */
+@@ -125,7 +126,7 @@ void luaX_syntaxerror (LexState *ls, con
+ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
+   lua_State *L = ls->L;
+-  TString *ts = luaS_newlstr(L, str, l);
++  TString *ts = luaS_ref(luaS_newlstr(L, str, l));
+   TValue *o = luaH_setstr(L, ls->fs->h, ts);  /* entry for `str' */
+   if (ttisnil(o))
+     setbvalue(o, 1);  /* make sure `str' will not be collected */
+@@ -152,7 +153,7 @@ void luaX_setinput (lua_State *L, LexSta
+   ls->fs = NULL;
+   ls->linenumber = 1;
+   ls->lastline = 1;
+-  ls->source = source;
++  ls->source = luaS_ref(source);
+   luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER);  /* initialize buffer */
+   next(ls);  /* read first char */
+ }