diff --git a/src/lapi.c b/src/lapi.c
index 5d5145d..67133cc 100644
--- a/src/lapi.c
+++ b/src/lapi.c
@@ -547,7 +547,9 @@ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) {
   lua_lock(L);
   t = index2adr(L, idx);
   api_checkvalidindex(L, t);
+  fixedstack(L);
   setsvalue(L, &key, luaS_new(L, k));
+  unfixedstack(L);
   luaV_gettable(L, t, &key, L->top);
   api_incr_top(L);
   lua_unlock(L);
@@ -656,14 +658,14 @@ LUA_API void lua_settable (lua_State *L, int idx) {
 
 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);
 }
 
@@ -674,7 +676,9 @@ LUA_API void lua_rawset (lua_State *L, int idx) {
   api_checknelems(L, 2);
   t = index2adr(L, idx);
   api_check(L, ttistable(t));
+  fixedstack(L);
   setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1);
+  unfixedstack(L);
   luaC_barriert(L, hvalue(t), L->top-1);
   L->top -= 2;
   lua_unlock(L);
@@ -687,7 +691,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, int n) {
   api_checknelems(L, 1);
   o = index2adr(L, idx);
   api_check(L, ttistable(o));
+  fixedstack(L);
   setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1);
+  unfixedstack(L);
   luaC_barriert(L, hvalue(o), L->top-1);
   L->top--;
   lua_unlock(L);
@@ -903,11 +909,11 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
   g = G(L);
   switch (what) {
     case LUA_GCSTOP: {
-      g->GCthreshold = MAX_LUMEM;
+      set_block_gc(L);
       break;
     }
     case LUA_GCRESTART: {
-      g->GCthreshold = g->totalbytes;
+      unset_block_gc(L);
       break;
     }
     case LUA_GCCOLLECT: {
@@ -924,6 +930,10 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
       break;
     }
     case LUA_GCSTEP: {
+      if(is_block_gc(L)) {
+        res = 1; /* gc is block so we need to pretend that the collection cycle finished. */
+        break;
+      }
       lu_mem a = (cast(lu_mem, data) << 10);
       if (a <= g->totalbytes)
         g->GCthreshold = g->totalbytes - a;
@@ -948,6 +958,24 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
       g->gcstepmul = data;
       break;
     }
+    case LUA_GCSETMEMLIMIT: {
+      /* GC values are expressed in Kbytes: #bytes/2^10 */
+      lu_mem new_memlimit = (cast(lu_mem, data) << 10);
+      if(new_memlimit > 0 && new_memlimit < g->totalbytes) {
+        /* run a full GC to make totalbytes < the new limit. */
+        luaC_fullgc(L);
+        if(new_memlimit < g->totalbytes)
+          new_memlimit = (g->totalbytes + 1024) & ~(1024-1); /* round up to next multiple of 1024 */
+      }
+      g->memlimit = new_memlimit;
+      /* new memlimit might be > then requested memlimit. */
+      res = cast_int(new_memlimit >> 10);
+      break;
+    }
+    case LUA_GCGETMEMLIMIT: {
+      res = cast_int(g->memlimit >> 10);
+      break;
+    }
     default: res = -1;  /* invalid option */
   }
   lua_unlock(L);
diff --git a/src/lauxlib.c b/src/lauxlib.c
index 10f14e2..b281579 100644
--- a/src/lauxlib.c
+++ b/src/lauxlib.c
@@ -23,6 +23,10 @@
 #include "lua.h"
 
 #include "lauxlib.h"
+#include "lgc.h"
+#include "ldo.h"
+#include "lobject.h"
+#include "lstate.h"
 
 
 #define FREELIST_REF	0	/* free list of references */
@@ -624,15 +628,44 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) {
 /* }====================================================== */
 
 
+static int l_check_memlimit(lua_State *L, size_t needbytes) {
+  global_State *g = G(L);
+  int cycle_count = 0;
+  lu_mem limit = g->memlimit - needbytes;
+  /* don't allow allocation if it requires more memory then the total limit. */
+  if (needbytes > g->memlimit) return 1;
+  /* make sure the GC is not disabled. */
+  if (!is_block_gc(L)) {
+    while (g->totalbytes >= limit) {
+      /* only allow the GC to finished atleast 1 full cycle. */
+      if (g->gcstate == GCSpause && ++cycle_count > 1) break;
+      luaC_step(L);
+    }
+  }
+  return (g->totalbytes >= limit) ? 1 : 0;
+}
+
+
 static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
-  (void)ud;
-  (void)osize;
+  lua_State *L = (lua_State *)ud;
+  void *nptr;
   if (nsize == 0) {
     free(ptr);
     return NULL;
   }
-  else
-    return realloc(ptr, nsize);
+  if(nsize > osize && L != NULL) {
+#if defined(LUA_STRESS_EMERGENCY_GC)
+    luaC_fullgc(L);
+#endif
+    if(G(L)->memlimit > 0 && l_check_memlimit(L, nsize - osize))
+      return NULL;
+  }
+  nptr = realloc(ptr, nsize);
+  if (nptr == NULL && L != NULL) {
+    luaC_fullgc(L); /* emergency full collection. */
+    nptr = realloc(ptr, nsize); /* try allocation again */
+  }
+  return nptr;
 }
 
 
@@ -646,6 +679,7 @@ static int panic (lua_State *L) {
 
 LUALIB_API lua_State *luaL_newstate (void) {
   lua_State *L = lua_newstate(l_alloc, NULL);
+  lua_setallocf(L, l_alloc, L); /* allocator need lua_State. */
   if (L) lua_atpanic(L, &panic);
   return L;
 }
diff --git a/src/lbaselib.c b/src/lbaselib.c
index 2a4c079..7a82778 100644
--- a/src/lbaselib.c
+++ b/src/lbaselib.c
@@ -192,9 +192,10 @@ static int luaB_gcinfo (lua_State *L) {
 
 static int luaB_collectgarbage (lua_State *L) {
   static const char *const opts[] = {"stop", "restart", "collect",
-    "count", "step", "setpause", "setstepmul", NULL};
+    "count", "step", "setpause", "setstepmul","setmemlimit","getmemlimit", NULL};
   static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
-    LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL};
+    LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
+		LUA_GCSETMEMLIMIT,LUA_GCGETMEMLIMIT};
   int o = luaL_checkoption(L, 1, "collect", opts);
   int ex = luaL_optint(L, 2, 0);
   int res = lua_gc(L, optsnum[o], ex);
diff --git a/src/ldo.c b/src/ldo.c
index 8de05f7..336e242 100644
--- a/src/ldo.c
+++ b/src/ldo.c
@@ -51,11 +51,13 @@ struct lua_longjmp {
 void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
   switch (errcode) {
     case LUA_ERRMEM: {
-      setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG));
+      ptrdiff_t oldtopr = savestack(L, oldtop);
+      setsvalue2s(L, restorestack(L, oldtopr), luaS_newliteral(L, MEMERRMSG));
       break;
     }
     case LUA_ERRERR: {
-      setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
+      ptrdiff_t oldtopr = savestack(L, oldtop);
+      setsvalue2s(L, restorestack(L, oldtopr), luaS_newliteral(L, "error in error handling"));
       break;
     }
     case LUA_ERRSYNTAX:
@@ -92,6 +94,8 @@ static void resetstack (lua_State *L, int status) {
 
 
 void luaD_throw (lua_State *L, int errcode) {
+  unfixedstack(L); /* make sure the fixedstack & block_gc flags get reset. */
+  unset_block_gc(L);
   if (L->errorJmp) {
     L->errorJmp->status = errcode;
     LUAI_THROW(L, L->errorJmp);
@@ -208,7 +212,9 @@ void luaD_callhook (lua_State *L, int event, int line) {
 static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
   int i;
   int nfixargs = p->numparams;
+#if defined(LUA_COMPAT_VARARG)
   Table *htab = NULL;
+#endif
   StkId base, fixed;
   for (; actual < nfixargs; ++actual)
     setnilvalue(L->top++);
@@ -218,10 +224,15 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
     lua_assert(p->is_vararg & VARARG_HASARG);
     luaC_checkGC(L);
     htab = luaH_new(L, nvar, 1);  /* create `arg' table */
+    sethvalue2s(L, L->top, htab); /* put table on stack */
+    incr_top(L);
+    fixedstack(L);
     for (i=0; i<nvar; i++)  /* put extra arguments into `arg' table */
-      setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i);
+      setobj2n(L, luaH_setnum(L, htab, i+1), L->top - 1 - nvar + i);
+    unfixedstack(L);
     /* store counter in field `n' */
     setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar));
+    L->top--; /* remove table from stack */
   }
 #endif
   /* move fixed parameters to final position */
@@ -231,11 +242,13 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
     setobjs2s(L, L->top++, fixed+i);
     setnilvalue(fixed+i);
   }
+#if defined(LUA_COMPAT_VARARG)
   /* add `arg' parameter */
   if (htab) {
     sethvalue(L, L->top++, htab);
     lua_assert(iswhite(obj2gco(htab)));
   }
+#endif
   return base;
 }
 
@@ -494,6 +507,7 @@ static void f_parser (lua_State *L, void *ud) {
   struct SParser *p = cast(struct SParser *, ud);
   int c = luaZ_lookahead(p->z);
   luaC_checkGC(L);
+  set_block_gc(L);  /* 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 +516,7 @@ static void f_parser (lua_State *L, void *ud) {
     cl->l.upvals[i] = luaF_newupval(L);
   setclvalue(L, L->top, cl);
   incr_top(L);
+  unset_block_gc(L);
 }
 
 
diff --git a/src/lfunc.c b/src/lfunc.c
index 813e88f..d2ce63d 100644
--- a/src/lfunc.c
+++ b/src/lfunc.c
@@ -66,7 +66,6 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
   }
   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->next = *pp;  /* chain it in the proper position */
   *pp = obj2gco(uv);
@@ -74,6 +73,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
   uv->u.l.next = g->uvhead.u.l.next;
   uv->u.l.next->u.l.prev = uv;
   g->uvhead.u.l.next = uv;
+  luaC_marknew(L, obj2gco(uv));
   lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
   return uv;
 }
diff --git a/src/lgc.c b/src/lgc.c
index d9e0b78..a906288 100644
--- a/src/lgc.c
+++ b/src/lgc.c
@@ -232,8 +232,10 @@ static void traverseclosure (global_State *g, Closure *cl) {
     int i;
     lua_assert(cl->l.nupvalues == cl->l.p->nups);
     markobject(g, cl->l.p);
-    for (i=0; i<cl->l.nupvalues; i++)  /* mark its upvalues */
-      markobject(g, cl->l.upvals[i]);
+    for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */
+      if(cl->l.upvals[i])
+        markobject(g, cl->l.upvals[i]);
+    }
   }
 }
 
@@ -258,6 +260,7 @@ static void traversestack (global_State *g, lua_State *l) {
   CallInfo *ci;
   markvalue(g, gt(l));
   lim = l->top;
+  if(l->stack == NULL) return; /* no stack to traverse */
   for (ci = l->base_ci; ci <= l->ci; ci++) {
     lua_assert(ci->top <= l->stack_last);
     if (lim < ci->top) lim = ci->top;
@@ -266,7 +269,8 @@ static void traversestack (global_State *g, lua_State *l) {
     markvalue(g, o);
   for (; o <= lim; o++)
     setnilvalue(o);
-  checkstacksizes(l, lim);
+  if (!isfixedstack(l)) /* if stack size is fixed, can't resize it. */
+    checkstacksizes(l, lim);
 }
 
 
@@ -419,8 +423,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
     else {  /* must erase `curr' */
       lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
       *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);
     }
   }
@@ -434,6 +436,8 @@ static void checkSizes (lua_State *L) {
   if (g->strt.nuse < cast(lu_int32, g->strt.size/4) &&
       g->strt.size > MINSTRTABSIZE*2)
     luaS_resize(L, g->strt.size/2);  /* table is too big */
+  /* it is not safe to re-size the buffer if it is in use. */
+  if (luaZ_bufflen(&g->buff) > 0) return;
   /* check size of buffer */
   if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) {  /* buffer too big? */
     size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
@@ -552,6 +556,15 @@ static void atomic (lua_State *L) {
   g->estimate = g->totalbytes - udsize;  /* first estimate */
 }
 
+static void sweepstrstep (global_State *g, lua_State *L) {
+  lu_mem old = g->totalbytes;
+  sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
+  if (g->sweepstrgc >= g->strt.size)  /* nothing more to sweep? */
+    g->gcstate = GCSsweep;  /* end sweep-string phase */
+  lua_assert(old >= g->totalbytes);
+  g->estimate -= old - g->totalbytes;
+}
+
 
 static l_mem singlestep (lua_State *L) {
   global_State *g = G(L);
@@ -570,12 +583,7 @@ static l_mem singlestep (lua_State *L) {
       }
     }
     case GCSsweepstring: {
-      lu_mem old = g->totalbytes;
-      sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
-      if (g->sweepstrgc >= g->strt.size)  /* nothing more to sweep? */
-        g->gcstate = GCSsweep;  /* end sweep-string phase */
-      lua_assert(old >= g->totalbytes);
-      g->estimate -= old - g->totalbytes;
+      sweepstrstep(g, L);
       return GCSWEEPCOST;
     }
     case GCSsweep: {
@@ -609,10 +617,14 @@ static l_mem singlestep (lua_State *L) {
 
 void luaC_step (lua_State *L) {
   global_State *g = G(L);
+  if(is_block_gc(L)) return;
+  set_block_gc(L);
   l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul;
   if (lim == 0)
     lim = (MAX_LUMEM-1)/2;  /* no limit */
   g->gcdept += g->totalbytes - g->GCthreshold;
+  if (g->estimate > g->totalbytes)
+    g->estimate = g->totalbytes;
   do {
     lim -= singlestep(L);
     if (g->gcstate == GCSpause)
@@ -630,11 +642,23 @@ void luaC_step (lua_State *L) {
     lua_assert(g->totalbytes >= g->estimate);
     setthreshold(g);
   }
+  unset_block_gc(L);
 }
 
 
+int luaC_sweepstrgc (lua_State *L) {
+  global_State *g = G(L);
+  if (g->gcstate == GCSsweepstring) {
+    sweepstrstep(g, L);
+    return (g->gcstate == GCSsweepstring) ? 1 : 0;
+  }
+  return 0;
+}
+
 void luaC_fullgc (lua_State *L) {
   global_State *g = G(L);
+  if(is_block_gc(L)) return;
+  set_block_gc(L);
   if (g->gcstate <= GCSpropagate) {
     /* reset sweep marks to sweep all elements (returning them to white) */
     g->sweepstrgc = 0;
@@ -656,6 +680,7 @@ void luaC_fullgc (lua_State *L) {
     singlestep(L);
   }
   setthreshold(g);
+  unset_block_gc(L);
 }
 
 
@@ -683,6 +708,14 @@ void luaC_barrierback (lua_State *L, Table *t) {
 }
 
 
+void luaC_marknew (lua_State *L, GCObject *o) {
+  global_State *g = G(L);
+  o->gch.marked = luaC_white(g);
+  if (g->gcstate == GCSpropagate)
+    reallymarkobject(g, o);  /* mark new objects as gray during propagate state. */
+}
+
+
 void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
   global_State *g = G(L);
   o->gch.next = g->rootgc;
diff --git a/src/lgc.h b/src/lgc.h
index 5a8dc60..3a83e2c 100644
--- a/src/lgc.h
+++ b/src/lgc.h
@@ -37,12 +37,30 @@
 #define test2bits(x,b1,b2)	testbits(x, (bit2mask(b1, b2)))
 
 
+/*
+** Possible Garbage Collector flags.
+** Layout for bit use in 'gsflags' field in global_State structure.
+** bit 0 - Protect GC from recursive calls.
+** bit 1 - Don't try to shrink string table if EGC was called during a string table resize.
+*/
+#define GCFlagsNone          0
+#define GCBlockGCBit         0
+#define GCResizingStringsBit 1
+
+
+#define is_block_gc(L)    testbit(G(L)->gcflags, GCBlockGCBit)
+#define set_block_gc(L)   l_setbit(G(L)->gcflags, GCBlockGCBit)
+#define unset_block_gc(L) resetbit(G(L)->gcflags, GCBlockGCBit)
+#define is_resizing_strings_gc(L)    testbit(G(L)->gcflags, GCResizingStringsBit)
+#define set_resizing_strings_gc(L)   l_setbit(G(L)->gcflags, GCResizingStringsBit)
+#define unset_resizing_strings_gc(L) resetbit(G(L)->gcflags, GCResizingStringsBit)
 
 /*
 ** Layout for bit use in `marked' field:
 ** bit 0 - object is white (type 0)
 ** bit 1 - object is white (type 1)
 ** bit 2 - object is black
+** bit 3 - for thread: Don't resize thread's stack
 ** bit 3 - for userdata: has been finalized
 ** bit 3 - for tables: has weak keys
 ** bit 4 - for tables: has weak values
@@ -54,6 +72,7 @@
 #define WHITE0BIT	0
 #define WHITE1BIT	1
 #define BLACKBIT	2
+#define FIXEDSTACKBIT	3
 #define FINALIZEDBIT	3
 #define KEYWEAKBIT	3
 #define VALUEWEAKBIT	4
@@ -76,6 +95,9 @@
 
 #define luaC_white(g)	cast(lu_byte, (g)->currentwhite & WHITEBITS)
 
+#define isfixedstack(x)	testbit((x)->marked, FIXEDSTACKBIT)
+#define fixedstack(x)	l_setbit((x)->marked, FIXEDSTACKBIT)
+#define unfixedstack(x)	resetbit((x)->marked, FIXEDSTACKBIT)
 
 #define luaC_checkGC(L) { \
   condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \
@@ -101,6 +123,8 @@ LUAI_FUNC void luaC_callGCTM (lua_State *L);
 LUAI_FUNC void luaC_freeall (lua_State *L);
 LUAI_FUNC void luaC_step (lua_State *L);
 LUAI_FUNC void luaC_fullgc (lua_State *L);
+LUAI_FUNC int luaC_sweepstrgc (lua_State *L);
+LUAI_FUNC void luaC_marknew (lua_State *L, GCObject *o);
 LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt);
 LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv);
 LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v);
diff --git a/src/lobject.h b/src/lobject.h
index f1e447e..1442ae3 100644
--- a/src/lobject.h
+++ b/src/lobject.h
@@ -117,42 +117,48 @@ typedef struct lua_TValue {
 #define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
 
 #define setnvalue(obj,x) \
-  { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; }
+  { lua_Number i_x = (x); TValue *i_o=(obj); i_o->value.n=i_x; i_o->tt=LUA_TNUMBER; }
 
 #define setpvalue(obj,x) \
-  { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; }
+  { void *i_x = (x); TValue *i_o=(obj); i_o->value.p=i_x; i_o->tt=LUA_TLIGHTUSERDATA; }
 
 #define setbvalue(obj,x) \
-  { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; }
+  { int i_x = (x); TValue *i_o=(obj); i_o->value.b=i_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; \
+  { GCObject *i_x = cast(GCObject *, (x)); \
+    TValue *i_o=(obj); \
+    i_o->value.gc=i_x; i_o->tt=LUA_TSTRING; \
     checkliveness(G(L),i_o); }
 
 #define setuvalue(L,obj,x) \
-  { TValue *i_o=(obj); \
-    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \
+  { GCObject *i_x = cast(GCObject *, (x)); \
+    TValue *i_o=(obj); \
+    i_o->value.gc=i_x; i_o->tt=LUA_TUSERDATA; \
     checkliveness(G(L),i_o); }
 
 #define setthvalue(L,obj,x) \
-  { TValue *i_o=(obj); \
-    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \
+  { GCObject *i_x = cast(GCObject *, (x)); \
+    TValue *i_o=(obj); \
+    i_o->value.gc=i_x; i_o->tt=LUA_TTHREAD; \
     checkliveness(G(L),i_o); }
 
 #define setclvalue(L,obj,x) \
-  { TValue *i_o=(obj); \
-    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \
+  { GCObject *i_x = cast(GCObject *, (x)); \
+    TValue *i_o=(obj); \
+    i_o->value.gc=i_x; i_o->tt=LUA_TFUNCTION; \
     checkliveness(G(L),i_o); }
 
 #define sethvalue(L,obj,x) \
-  { TValue *i_o=(obj); \
-    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \
+  { GCObject *i_x = cast(GCObject *, (x)); \
+    TValue *i_o=(obj); \
+    i_o->value.gc=i_x; i_o->tt=LUA_TTABLE; \
     checkliveness(G(L),i_o); }
 
 #define setptvalue(L,obj,x) \
-  { TValue *i_o=(obj); \
-    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \
+  { GCObject *i_x = cast(GCObject *, (x)); \
+    TValue *i_o=(obj); \
+    i_o->value.gc=i_x; i_o->tt=LUA_TPROTO; \
     checkliveness(G(L),i_o); }
 
 
diff --git a/src/lparser.c b/src/lparser.c
index 1e2a9a8..46e81fe 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -383,14 +383,18 @@ static void close_func (LexState *ls) {
 Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) {
   struct LexState lexstate;
   struct FuncState funcstate;
+  TString *tname = luaS_new(L, name);
+  setsvalue2s(L, L->top, tname);  /* protect name */
+  incr_top(L);
   lexstate.buff = buff;
-  luaX_setinput(L, &lexstate, z, luaS_new(L, name));
+  luaX_setinput(L, &lexstate, z, tname);
   open_func(&lexstate, &funcstate);
   funcstate.f->is_vararg = VARARG_ISVARARG;  /* main func. is always vararg */
   luaX_next(&lexstate);  /* read first token */
   chunk(&lexstate);
   check(&lexstate, TK_EOS);
   close_func(&lexstate);
+  L->top--; /* remove 'name' from stack */
   lua_assert(funcstate.prev == NULL);
   lua_assert(funcstate.f->nups == 0);
   lua_assert(lexstate.fs == NULL);
diff --git a/src/lstate.c b/src/lstate.c
index 4313b83..64dd71f 100644
--- a/src/lstate.c
+++ b/src/lstate.c
@@ -119,6 +119,8 @@ static void close_state (lua_State *L) {
 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);
+  setthvalue(L, L->top, L1); /* put thread on stack */
+  incr_top(L);
   preinit_state(L1, G(L));
   stack_init(L1, L);  /* init stack */
   setobj2n(L, gt(L1), gt(L));  /* share table of globals */
@@ -126,7 +128,8 @@ lua_State *luaE_newthread (lua_State *L) {
   L1->basehookcount = L->basehookcount;
   L1->hook = L->hook;
   resethookcount(L1);
-  lua_assert(iswhite(obj2gco(L1)));
+  lua_assert(!isdead(G(L), obj2gco(L1)));
+  L->top--; /* remove thread from stack */
   return L1;
 }
 
@@ -160,6 +163,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   g->uvhead.u.l.prev = &g->uvhead;
   g->uvhead.u.l.next = &g->uvhead;
   g->GCthreshold = 0;  /* mark it as unfinished state */
+  g->estimate = 0;
   g->strt.size = 0;
   g->strt.nuse = 0;
   g->strt.hash = NULL;
@@ -167,6 +171,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   luaZ_initbuffer(L, &g->buff);
   g->panic = NULL;
   g->gcstate = GCSpause;
+  g->gcflags = GCFlagsNone;
   g->rootgc = obj2gco(L);
   g->sweepstrgc = 0;
   g->sweepgc = &g->rootgc;
@@ -175,6 +180,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   g->weak = NULL;
   g->tmudata = NULL;
   g->totalbytes = sizeof(LG);
+  g->memlimit = 0;
   g->gcpause = LUAI_GCPAUSE;
   g->gcstepmul = LUAI_GCMUL;
   g->gcdept = 0;
diff --git a/src/lstate.h b/src/lstate.h
index 3bc575b..93fc594 100644
--- a/src/lstate.h
+++ b/src/lstate.h
@@ -71,6 +71,7 @@ typedef struct global_State {
   void *ud;         /* auxiliary data to `frealloc' */
   lu_byte currentwhite;
   lu_byte gcstate;  /* state of garbage collector */
+  lu_byte gcflags;  /* flags for the garbage collector */
   int sweepstrgc;  /* position of sweep in `strt' */
   GCObject *rootgc;  /* list of all collectable objects */
   GCObject **sweepgc;  /* position of sweep in `rootgc' */
@@ -81,6 +82,7 @@ typedef struct global_State {
   Mbuffer buff;  /* temporary buffer for string concatentation */
   lu_mem GCthreshold;
   lu_mem totalbytes;  /* number of bytes currently allocated */
+  lu_mem memlimit;  /* maximum number of bytes that can be allocated, 0 = no limit. */
   lu_mem estimate;  /* an estimate of number of bytes actually in use */
   lu_mem gcdept;  /* how much GC is `behind schedule' */
   int gcpause;  /* size of pause between successive GCs */
diff --git a/src/lstring.c b/src/lstring.c
index 4911315..5d681b1 100644
--- a/src/lstring.c
+++ b/src/lstring.c
@@ -20,30 +20,34 @@
 
 
 void luaS_resize (lua_State *L, int newsize) {
-  GCObject **newhash;
   stringtable *tb;
   int i;
-  if (G(L)->gcstate == GCSsweepstring)
-    return;  /* cannot resize during GC traverse */
-  newhash = luaM_newvector(L, newsize, GCObject *);
   tb = &G(L)->strt;
-  for (i=0; i<newsize; i++) newhash[i] = NULL;
+  if (luaC_sweepstrgc(L) || newsize == tb->size || is_resizing_strings_gc(L))
+    return;  /* cannot resize during GC traverse or doesn't need to be resized */
+  set_resizing_strings_gc(L);
+  if (newsize > tb->size) {
+    luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *);
+    for (i=tb->size; i<newsize; i++) tb->hash[i] = NULL;
+  }
   /* rehash */
   for (i=0; i<tb->size; i++) {
     GCObject *p = tb->hash[i];
+    tb->hash[i] = NULL;
     while (p) {  /* for each node in the list */
       GCObject *next = p->gch.next;  /* save next */
       unsigned int h = gco2ts(p)->hash;
       int h1 = lmod(h, newsize);  /* new position */
       lua_assert(cast_int(h%newsize) == lmod(h, newsize));
-      p->gch.next = newhash[h1];  /* chain it */
-      newhash[h1] = p;
+      p->gch.next = tb->hash[h1];  /* chain it */
+      tb->hash[h1] = p;
       p = next;
     }
   }
-  luaM_freearray(L, tb->hash, tb->size, TString *);
+  if (newsize < tb->size)
+    luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *);
   tb->size = newsize;
-  tb->hash = newhash;
+  unset_resizing_strings_gc(L);
 }
 
 
@@ -53,6 +57,9 @@ static TString *newlstr (lua_State *L, const char *str, size_t l,
   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 +68,10 @@ static TString *newlstr (lua_State *L, const char *str, size_t l,
   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;
 }
 
diff --git a/src/ltable.c b/src/ltable.c
index ec84f4f..92eac99 100644
--- a/src/ltable.c
+++ b/src/ltable.c
@@ -269,20 +269,35 @@ static void setarrayvector (lua_State *L, Table *t, int size) {
 }
 
 
-static void setnodevector (lua_State *L, Table *t, int size) {
+static Node *getfreepos (Table *t) {
+  while (t->lastfree-- > t->node) {
+    if (ttisnil(gkey(t->lastfree)))
+      return t->lastfree;
+  }
+  return NULL;  /* could not find a free place */
+}
+
+
+static void resizenodevector (lua_State *L, Table *t, int oldsize, int newsize) {
   int lsize;
-  if (size == 0) {  /* no elements to hash part? */
+  if (newsize == 0) {  /* no elements to hash part? */
     t->node = cast(Node *, dummynode);  /* use common `dummynode' */
     lsize = 0;
   }
   else {
+    Node *node = t->node;
     int i;
-    lsize = ceillog2(size);
+    lsize = ceillog2(newsize);
     if (lsize > MAXBITS)
       luaG_runerror(L, "table overflow");
-    size = twoto(lsize);
-    t->node = luaM_newvector(L, size, Node);
-    for (i=0; i<size; i++) {
+    newsize = twoto(lsize);
+    if (node == dummynode) {
+      oldsize = 0;
+      node = NULL; /* don't try to realloc `dummynode' pointer. */
+    }
+    luaM_reallocvector(L, node, oldsize, newsize, Node);
+    t->node = node;
+    for (i=oldsize; i<newsize; i++) {
       Node *n = gnode(t, i);
       gnext(n) = NULL;
       setnilvalue(gkey(n));
@@ -290,19 +305,138 @@ static void setnodevector (lua_State *L, Table *t, int size) {
     }
   }
   t->lsizenode = cast_byte(lsize);
-  t->lastfree = gnode(t, size);  /* all positions are free */
+  t->lastfree = gnode(t, newsize);  /* reset lastfree to end of table. */
+}
+
+
+static Node *find_prev_node(Node *mp, Node *next) {
+  Node *prev = mp;
+  while (prev != NULL && gnext(prev) != next) prev = gnext(prev);
+  return prev;
+}
+
+
+/*
+** move a node from it's old position to it's new position during a rehash;
+** first, check whether the moving node's main position is free. If not, check whether
+** colliding node is in its main position or not: if it is not, move colliding
+** node to an empty place and put moving node in its main position; otherwise
+** (colliding node is in its main position), moving node goes to an empty position. 
+*/
+static int move_node (lua_State *L, Table *t, Node *node) {
+  Node *mp = mainposition(t, key2tval(node));
+  /* if node is in it's main position, don't need to move node. */
+  if (mp == node) return 1;
+  /* if node is in it's main position's chain, don't need to move node. */
+  if (find_prev_node(mp, node) != NULL) return 1;
+  /* is main position is free? */
+  if (!ttisnil(gval(mp)) || mp == dummynode) {
+    /* no; move main position node if it is out of its main position */
+    Node *othermp;
+    othermp = mainposition(t, key2tval(mp));
+    if (othermp != mp) {  /* is colliding node out of its main position? */
+      /* yes; swap colliding node with the node that is being moved. */
+      Node *prev;
+      Node tmp;
+      tmp = *node;
+      prev = find_prev_node(othermp, mp);  /* find previous */
+      if (prev != NULL) gnext(prev) = node;  /* redo the chain with `n' in place of `mp' */
+      *node = *mp;  /* copy colliding node into free pos. (mp->next also goes) */
+      *mp = tmp;
+      return (prev != NULL) ? 1 : 0; /* is colliding node part of its main position chain? */
+    }
+    else {  /* colliding node is in its own main position */
+      /* add node to main position's chain. */
+      gnext(node) = gnext(mp);  /* chain new position */
+      gnext(mp) = node;
+    }
+  }
+  else { /* main position is free, move node */
+    *mp = *node;
+    gnext(node) = NULL;
+    setnilvalue(gkey(node));
+    setnilvalue(gval(node));
+  }
+  return 1;
+}
+
+
+static int move_number (lua_State *L, Table *t, Node *node) {
+  int key;
+  lua_Number n = nvalue(key2tval(node));
+  lua_number2int(key, n);
+  if (luai_numeq(cast_num(key), nvalue(key2tval(node)))) {/* index is int? */
+    /* (1 <= key && key <= t->sizearray) */
+    if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) {
+      setobjt2t(L, &t->array[key-1], gval(node));
+      setnilvalue(gkey(node));
+      setnilvalue(gval(node));
+      return 1;
+    }
+  }
+  return 0;
+}
+
+
+static void resize_hashpart (lua_State *L, Table *t, int nhsize) {
+  int i;
+  int lsize=0;
+  int oldhsize = (t->node != dummynode) ? twoto(t->lsizenode) : 0;
+  if (nhsize > 0) { /* round new hashpart size up to next power of two. */
+    lsize=ceillog2(nhsize);
+    if (lsize > MAXBITS)
+      luaG_runerror(L, "table overflow");
+  }
+  nhsize = twoto(lsize);
+  /* grow hash part to new size. */
+  if (oldhsize < nhsize)
+    resizenodevector(L, t, oldhsize, nhsize);
+  else { /* hash part might be shrinking */
+    if (nhsize > 0) {
+      t->lsizenode = cast_byte(lsize);
+      t->lastfree = gnode(t, nhsize);  /* reset lastfree back to end of table. */
+    }
+    else { /* new hashpart size is zero. */
+      resizenodevector(L, t, oldhsize, nhsize);
+      return;
+    }
+  }
+  /* break old chains, try moving int keys to array part and compact keys into new hashpart */
+  for (i = 0; i < oldhsize; i++) {
+    Node *old = gnode(t, i);
+    gnext(old) = NULL;
+    if (ttisnil(gval(old))) { /* clear nodes with nil values. */
+      setnilvalue(gkey(old));
+      continue;
+    }
+    if (ttisnumber(key2tval(old))) { /* try moving the int keys into array part. */
+      if(move_number(L, t, old))
+        continue;
+    }
+    if (i >= nhsize) { /* move all valid keys to indices < nhsize. */
+      Node *n = getfreepos(t);  /* get a free place */
+      lua_assert(n != dummynode && n != NULL);
+      *n = *old;
+    }
+  }
+  /* shrink hash part */
+  if (oldhsize > nhsize)
+    resizenodevector(L, t, oldhsize, nhsize);
+  /* move nodes to their new mainposition and re-create node chains */
+  for (i = 0; i < nhsize; i++) {
+    Node *curr = gnode(t, i);
+    if (!ttisnil(gval(curr)))
+      while (move_node(L, t, curr) == 0);
+  }
 }
 
 
 static void resize (lua_State *L, Table *t, int nasize, int nhsize) {
   int i;
   int oldasize = t->sizearray;
-  int oldhsize = t->lsizenode;
-  Node *nold = t->node;  /* save old hash ... */
   if (nasize > oldasize)  /* array part must grow? */
     setarrayvector(L, t, nasize);
-  /* create new hash part with appropriate size */
-  setnodevector(L, t, nhsize);  
+  resize_hashpart(L, t, nhsize);
   if (nasize < oldasize) {  /* array part must shrink? */
     t->sizearray = nasize;
     /* re-insert elements from vanishing slice */
@@ -313,14 +447,6 @@ static void resize (lua_State *L, Table *t, int nasize, int nhsize) {
     /* shrink array */
     luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
   }
-  /* re-insert elements from hash part */
-  for (i = twoto(oldhsize) - 1; i >= 0; i--) {
-    Node *old = nold+i;
-    if (!ttisnil(gval(old)))
-      setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old));
-  }
-  if (nold != dummynode)
-    luaM_freearray(L, nold, twoto(oldhsize), Node);  /* free old array */
 }
 
 
@@ -358,6 +484,8 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) {
 Table *luaH_new (lua_State *L, int narray, int nhash) {
   Table *t = luaM_new(L, Table);
   luaC_link(L, obj2gco(t), LUA_TTABLE);
+  sethvalue2s(L, L->top, t); /* put table on stack */
+  incr_top(L);
   t->metatable = NULL;
   t->flags = cast_byte(~0);
   /* temporary values (kept only if some malloc fails) */
@@ -366,7 +494,8 @@ Table *luaH_new (lua_State *L, int narray, int nhash) {
   t->lsizenode = 0;
   t->node = cast(Node *, dummynode);
   setarrayvector(L, t, narray);
-  setnodevector(L, t, nhash);
+  resizenodevector(L, t, 0, nhash);
+  L->top--; /* remove table from stack */
   return t;
 }
 
@@ -379,15 +508,6 @@ void luaH_free (lua_State *L, Table *t) {
 }
 
 
-static Node *getfreepos (Table *t) {
-  while (t->lastfree-- > t->node) {
-    if (ttisnil(gkey(t->lastfree)))
-      return t->lastfree;
-  }
-  return NULL;  /* could not find a free place */
-}
-
-
 
 /*
 ** inserts a new key into a hash table; first, check whether key's main 
diff --git a/src/lua.c b/src/lua.c
index 3a46609..670b1de 100644
--- a/src/lua.c
+++ b/src/lua.c
@@ -45,6 +45,7 @@ static void print_usage (void) {
   "Available options are:\n"
   "  -e stat  execute string " LUA_QL("stat") "\n"
   "  -l name  require library " LUA_QL("name") "\n"
+  "  -m limit set memory limit. (units are in Kbytes)\n"
   "  -i       enter interactive mode after executing " LUA_QL("script") "\n"
   "  -v       show version information\n"
   "  --       stop handling options\n"
@@ -278,6 +279,7 @@ static int collectargs (char **argv, int *pi, int *pv, int *pe) {
         break;
       case 'e':
         *pe = 1;  /* go through */
+      case 'm':   /* go through */
       case 'l':
         if (argv[i][2] == '\0') {
           i++;
@@ -305,6 +307,15 @@ static int runargs (lua_State *L, char **argv, int n) {
           return 1;
         break;
       }
+      case 'm': {
+        const char *limit = argv[i] + 2;
+        int memlimit=0;
+        if (*limit == '\0') limit = argv[++i];
+        lua_assert(limit != NULL);
+        memlimit = atoi(limit);
+        lua_gc(L, LUA_GCSETMEMLIMIT, memlimit);
+        break;
+      }
       case 'l': {
         const char *filename = argv[i] + 2;
         if (*filename == '\0') filename = argv[++i];
diff --git a/src/lua.h b/src/lua.h
index e4bdfd3..c8707ba 100644
--- a/src/lua.h
+++ b/src/lua.h
@@ -226,6 +226,8 @@ LUA_API int  (lua_status) (lua_State *L);
 #define LUA_GCSTEP		5
 #define LUA_GCSETPAUSE		6
 #define LUA_GCSETSTEPMUL	7
+#define LUA_GCSETMEMLIMIT	8
+#define LUA_GCGETMEMLIMIT	9
 
 LUA_API int (lua_gc) (lua_State *L, int what, int data);
 
diff --git a/src/luaconf.h b/src/luaconf.h
index e2cb261..f132ec1 100644
--- a/src/luaconf.h
+++ b/src/luaconf.h
@@ -368,6 +368,16 @@
 
 
 /*
+@@ LUA_STRESS_EMERGENCY_GC enables stress testing code for the Emergency GC.
+** CHANGE it to defined if you want to test for Emergency GC related bugs.
+** Note that this will make the Lua vm very slow, since it will force a
+** full GC on every new allocation.
+*/
+#undef LUA_STRESS_EMERGENCY_GC
+
+
+
+/*
 @@ luai_apicheck is the assert macro used by the Lua-C API.
 ** CHANGE luai_apicheck if you want Lua to perform some checks in the
 ** parameters it gets from API calls. This may slow down the interpreter
diff --git a/src/lvm.c b/src/lvm.c
index ee3256a..99da5d8 100644
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -49,9 +49,10 @@ int luaV_tostring (lua_State *L, StkId obj) {
     return 0;
   else {
     char s[LUAI_MAXNUMBER2STR];
+    ptrdiff_t objr = savestack(L, obj);
     lua_Number n = nvalue(obj);
     lua_number2str(s, n);
-    setsvalue2s(L, obj, luaS_new(L, s));
+    setsvalue2s(L, restorestack(L, objr), luaS_new(L, s));
     return 1;
   }
 }
@@ -133,6 +134,10 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
 
 void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
   int loop;
+  TValue temp;
+  setnilvalue(L->top);
+  L->top++;
+  fixedstack(L);
   for (loop = 0; loop < MAXTAGLOOP; loop++) {
     const TValue *tm;
     if (ttistable(t)) {  /* `t' is a table? */
@@ -140,6 +145,8 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
       TValue *oldval = luaH_set(L, h, key); /* do a primitive set */
       if (!ttisnil(oldval) ||  /* result is no nil? */
           (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */
+        L->top--;
+        unfixedstack(L);
         setobj2t(L, oldval, val);
         luaC_barriert(L, h, val);
         return;
@@ -149,10 +156,15 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
     else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
       luaG_typeerror(L, t, "index");
     if (ttisfunction(tm)) {
+      L->top--;
+      unfixedstack(L);
       callTM(L, tm, t, key, val);
       return;
     }
-    t = tm;  /* else repeat with `tm' */ 
+    /* else repeat with `tm' */
+    setobj(L, &temp, tm);  /* avoid pointing inside table (may rehash) */
+    t = &temp;
+    setobj2s(L, L->top-1, t);  /* need to protect value from EGC. */
   }
   luaG_runerror(L, "loop in settable");
 }
@@ -276,12 +288,17 @@ int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) {
 
 
 void luaV_concat (lua_State *L, int total, int last) {
+  lu_mem max_sizet = MAX_SIZET;
+  if (G(L)->memlimit < max_sizet) max_sizet = G(L)->memlimit;
   do {
     StkId top = L->base + last + 1;
     int n = 2;  /* number of elements handled in this pass (at least 2) */
     if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) {
-      if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
+      if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) {
+        /* restore 'top' pointer, since stack might have been reallocted */
+        top = L->base + last + 1;
         luaG_concaterror(L, top-2, top-1);
+      }
     } else if (tsvalue(top-1)->len == 0)  /* second op is empty? */
       (void)tostring(L, top - 2);  /* result is first op (as string) */
     else {
@@ -289,12 +306,14 @@ void luaV_concat (lua_State *L, int total, int last) {
       size_t tl = tsvalue(top-1)->len;
       char *buffer;
       int i;
+      fixedstack(L);
       /* collect total length */
       for (n = 1; n < total && tostring(L, top-n-1); n++) {
         size_t l = tsvalue(top-n-1)->len;
-        if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
+        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 */
@@ -303,6 +322,8 @@ void luaV_concat (lua_State *L, int total, int last) {
         tl += l;
       }
       setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
+      luaZ_resetbuffer(&G(L)->buff);
+      unfixedstack(L);
     }
     total -= n-1;  /* got `n' strings to create 1 new */
     last -= n-1;
@@ -328,8 +349,13 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb,
       default: lua_assert(0); break;
     }
   }
-  else if (!call_binTM(L, rb, rc, ra, op))
-    luaG_aritherror(L, rb, rc);
+  else {
+    ptrdiff_t br = savestack(L, rb);
+    ptrdiff_t cr = savestack(L, rc);
+    if (!call_binTM(L, rb, rc, ra, op)) {
+      luaG_aritherror(L, restorestack(L, br), restorestack(L, cr));
+    }
+  }
 }
 
 
@@ -457,7 +483,9 @@ void luaV_execute (lua_State *L, int nexeccalls) {
       case OP_NEWTABLE: {
         int b = GETARG_B(i);
         int c = GETARG_C(i);
-        sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
+        Table *h;
+        Protect(h = luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
+        sethvalue(L, RA(i), h);
         Protect(luaC_checkGC(L));
         continue;
       }
@@ -519,9 +547,10 @@ void luaV_execute (lua_State *L, int nexeccalls) {
             break;
           }
           default: {  /* try metamethod */
+            ptrdiff_t br = savestack(L, rb);
             Protect(
               if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN))
-                luaG_typeerror(L, rb, "get length of");
+                luaG_typeerror(L, restorestack(L, br), "get length of");
             )
           }
         }
@@ -695,6 +724,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
         int c = GETARG_C(i);
         int last;
         Table *h;
+        fixedstack(L);
         if (n == 0) {
           n = cast_int(L->top - ra) - 1;
           L->top = L->ci->top;
@@ -710,6 +740,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
           setobj2t(L, luaH_setnum(L, h, last--), val);
           luaC_barriert(L, h, val);
         }
+        unfixedstack(L);
         continue;
       }
       case OP_CLOSE: {
@@ -722,7 +753,9 @@ void luaV_execute (lua_State *L, int nexeccalls) {
         int nup, j;
         p = cl->p->p[GETARG_Bx(i)];
         nup = p->nups;
+        fixedstack(L);
         ncl = luaF_newLclosure(L, nup, cl->env);
+        setclvalue(L, ra, ncl);
         ncl->l.p = p;
         for (j=0; j<nup; j++, pc++) {
           if (GET_OPCODE(*pc) == OP_GETUPVAL)
@@ -732,7 +765,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
             ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc));
           }
         }
-        setclvalue(L, ra, ncl);
+        unfixedstack(L);
         Protect(luaC_checkGC(L));
         continue;
       }
diff --git a/src/lzio.h b/src/lzio.h
index 51d695d..d6073d7 100644
--- a/src/lzio.h
+++ b/src/lzio.h
@@ -27,7 +27,7 @@ typedef struct Mbuffer {
   size_t buffsize;
 } Mbuffer;
 
-#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0)
+#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->n = 0, (buff)->buffsize = 0)
 
 #define luaZ_buffer(buff)	((buff)->buffer)
 #define luaZ_sizebuffer(buff)	((buff)->buffsize)
