--- 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,14 @@ 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) */
+	setlvmtop(L, L->top + idx + 1); /* `subtract' index (index is negative) */
   }
   lua_unlock(L);
 }
@@ -183,7 +186,7 @@ LUA_API void lua_remove (lua_State *L, i
   p = index2adr(L, idx);
   api_checkvalidindex(L, p);
   while (++p < L->top) setobjs2s(L, p-1, p);
-  L->top--;
+  setlvmtop(L, L->top - 1);
   lua_unlock(L);
 }
 
@@ -196,6 +199,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);
 }
 
@@ -220,7 +224,7 @@ LUA_API void lua_replace (lua_State *L, 
     if (idx < LUA_GLOBALSINDEX)  /* function upvalue? */
       luaC_barrier(L, curr_func(L), L->top - 1);
   }
-  L->top--;
+  setlvmtop(L, L->top - 1);
   lua_unlock(L);
 }
 
@@ -259,14 +263,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 +323,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 +337,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 +373,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 +469,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 +552,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 +606,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 +695,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);
@@ -709,21 +715,21 @@ LUA_API void lua_settable (lua_State *L,
   t = index2adr(L, idx);
   api_checkvalidindex(L, t);
   luaV_settable(L, t, L->top - 2, L->top - 1);
-  L->top -= 2;  /* pop index and value */
+  setlvmtop(L, L->top - 2);  /* pop index and value */
   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);
   api_checkvalidindex(L, t);
   setsvalue(L, &key, luaS_new(L, k));
   luaV_settable(L, t, &key, L->top - 1);
-  L->top--;  /* pop value */
+  setlvmtop(L, L->top - 1);  /* pop value */
   lua_unlock(L);
 }
 
@@ -736,7 +742,7 @@ LUA_API void lua_rawset (lua_State *L, i
   api_check(L, ttistable(t));
   setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1);
   luaC_barriert(L, hvalue(t), L->top-1);
-  L->top -= 2;
+  setlvmtop(L, L->top - 2);
   lua_unlock(L);
 }
 
@@ -749,7 +755,7 @@ LUA_API void lua_rawseti (lua_State *L, 
   api_check(L, ttistable(o));
   setobj2t(L, luaH_setint(L, hvalue(o), n), L->top-1);
   luaC_barriert(L, hvalue(o), L->top-1);
-  L->top--;
+  setlvmtop(L, L->top - 1);
   lua_unlock(L);
 }
 
@@ -785,7 +791,7 @@ LUA_API int lua_setmetatable (lua_State 
       break;
     }
   }
-  L->top--;
+  setlvmtop(L, L->top - 1);
   lua_unlock(L);
   return 1;
 }
@@ -814,7 +820,7 @@ LUA_API int lua_setfenv (lua_State *L, i
       break;
   }
   if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1));
-  L->top--;
+  setlvmtop(L, L->top - 1);
   lua_unlock(L);
   return res;
 }
@@ -1040,20 +1046,21 @@ LUA_API int lua_next (lua_State *L, int 
   if (more) {
     api_incr_top(L);
   }
-  else  /* no more elements */
-    L->top -= 1;  /* remove key */
+  else {  /* no more elements */
+    setlvmtop(L, L->top - 1);  /* remove key */
+  }
   lua_unlock(L);
   return more;
 }
 
 
 LUA_API void lua_concat (lua_State *L, int n) {
   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);
+    setlvmtop(L, L->top - (n-1));
   }
   else if (n == 0) {  /* push empty string */
     setsvalue2s(L, L->top, luaS_newlstr(L, "", 0));
@@ -1139,6 +1147,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 +1169,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
@@ -142,6 +142,7 @@ LUA_API const char *lua_setlocal (lua_St
   if (name)
       setobjs2s(L, ci->base + (n - 1), L->top - 1);
   L->top--;  /* pop value */
+  setnilvalue(L, L->top);
   lua_unlock(L);
   return name;
 }
@@ -176,7 +177,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 +249,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 +587,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,7 @@ 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);
+    setnilvalue(L, fixed+i);
   }
   /* add `arg' parameter */
   if (htab) {
@@ -294,7 +294,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,8 +354,8 @@ 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++);
-  L->top = res;
+    setnilvalue(L, res++);
+  setlvmtop(L, res);
   return (wanted - LUA_MULTRET);  /* 0 iff wanted == LUA_MULTRET */
 }
 
@@ -463,8 +463,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;
 }
 
@@ -67,8 +67,14 @@ UpVal *luaF_findupval (lua_State *L, Stk
   uv = luaM_new(L, UpVal);  /* not found: create a new one */
   uv->tt = LUA_TUPVAL;
   uv->marked = luaC_white(g);
-  uv->v = level;  /* current value lives in the stack */
+  uv->v = luaV_ref(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,12 @@ static GCObject **sweeplist (lua_State *
     }
     else {  /* must erase `curr' */
       lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
+      if (curr->gch.next)
+        curr->gch.next->gch.prev = curr->gch.prev;
       *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 +551,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 +693,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 +386,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 +423,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 +666,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 +676,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 +688,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));
@@ -895,7 +900,7 @@ void luaV_execute (lua_State *L, int nex
         if (--nexeccalls == 0)  /* was previous function running `here'? */
           return;  /* no: return */
         else {  /* yes: continue its execution */
-          if (b) L->top = L->ci->top;
+          if (b) setlvmtop(L, L->ci->top);
           lua_assert(isLua(L->ci));
           lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL);
           goto reentry;
@@ -986,6 +991,7 @@ void luaV_execute (lua_State *L, int nex
         for (; n > 0; n--) {
           TValue *val = ra+n;
           setobj2t(L, luaH_setint(L, h, last--), val);
+          setnilvalue(L, val);
           luaC_barriert(L, h, val);
         }
         continue;
@@ -1030,7 +1036,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 */
 }
--- a/src/lstate.h
+++ b/src/lstate.h
@@ -144,6 +144,13 @@ union GCObject {
   struct lua_State th;  /* thread */
 };
 
+#define setlvmtop(L, val) do { \
+	int __i; \
+	for (__i = L->top - val; __i-- > 0;) \
+		setnilvalue(L, val + __i); \
+	L->top = val; \
+} while (0)
+
 
 /* macros to convert a GCObject into a specific value */
 #define rawgco2ts(o)	check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts))