Index: src/lua/lauxlib.c
===================================================================
--- src/lua/lauxlib.c	(revision 281)
+++ src/lua/lauxlib.c	(working copy)
@@ -25,6 +25,10 @@
 #include "lrotable.h"
 
 #include "lauxlib.h"
+#include "lgc.h"
+#include "ldo.h"
+#include "lobject.h"
+#include "lstate.h"
 
 
 #define FREELIST_REF	0	/* free list of references */
@@ -674,15 +678,39 @@
 /* }====================================================== */
 
 
+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;
+  /* 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(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;
 }
 
 
@@ -696,6 +724,7 @@
 
 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;
 }
Index: src/lua/ldo.c
===================================================================
--- src/lua/ldo.c	(revision 281)
+++ src/lua/ldo.c	(working copy)
@@ -208,7 +208,9 @@
 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 +220,13 @@
     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);
     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);
     /* 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 +236,13 @@
     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;
 }
 
@@ -498,6 +505,7 @@
   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)));
@@ -506,6 +514,7 @@
     cl->l.upvals[i] = luaF_newupval(L);
   setclvalue(L, L->top, cl);
   incr_top(L);
+  unset_block_gc(L);
 }
 
 
Index: src/lua/lstate.c
===================================================================
--- src/lua/lstate.c	(revision 281)
+++ src/lua/lstate.c	(working copy)
@@ -119,6 +119,8 @@
 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 @@
   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 @@
   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 @@
   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 @@
   g->weak = NULL;
   g->tmudata = NULL;
   g->totalbytes = sizeof(LG);
+  g->memlimit = 0;
   g->gcpause = LUAI_GCPAUSE;
   g->gcstepmul = LUAI_GCMUL;
   g->gcdept = 0;
Index: src/lua/lvm.c
===================================================================
--- src/lua/lvm.c	(revision 281)
+++ src/lua/lvm.c	(working copy)
@@ -319,6 +319,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 */
@@ -327,6 +328,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;
@@ -481,7 +483,9 @@
       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;
       }
@@ -748,6 +752,7 @@
         p = cl->p->p[GETARG_Bx(i)];
         nup = p->nups;
         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)
@@ -757,7 +762,6 @@
             ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc));
           }
         }
-        setclvalue(L, ra, ncl);
         Protect(luaC_checkGC(L));
         continue;
       }
Index: src/lua/lstate.h
===================================================================
--- src/lua/lstate.h	(revision 281)
+++ src/lua/lstate.h	(working copy)
@@ -71,6 +71,7 @@
   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 @@
   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 */
Index: src/lua/ltable.c
===================================================================
--- src/lua/ltable.c	(revision 281)
+++ src/lua/ltable.c	(working copy)
@@ -277,20 +277,35 @@
 }
 
 
-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));
@@ -298,19 +313,138 @@
     }
   }
   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 */
@@ -321,14 +455,6 @@
     /* 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 */
 }
 
 
@@ -366,6 +492,8 @@
 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) */
@@ -374,7 +502,8 @@
   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;
 }
 
@@ -387,16 +516,7 @@
 }
 
 
-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 
 ** position is free. If not, check whether colliding node is in its main 
Index: src/lua/lgc.c
===================================================================
--- src/lua/lgc.c	(revision 281)
+++ src/lua/lgc.c	(working copy)
@@ -232,8 +232,10 @@
     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 @@
   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;
@@ -419,8 +422,6 @@
     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);
     }
   }
@@ -437,7 +438,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);
   }
 }
 
@@ -609,10 +613,14 @@
 
 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 +638,14 @@
     lua_assert(g->totalbytes >= g->estimate);
     setthreshold(g);
   }
+  unset_block_gc(L);
 }
 
 
 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 +667,7 @@
     singlestep(L);
   }
   setthreshold(g);
+  unset_block_gc(L);
 }
 
 
@@ -683,6 +695,14 @@
 }
 
 
+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;
Index: src/lua/lfunc.c
===================================================================
--- src/lua/lfunc.c	(revision 281)
+++ src/lua/lfunc.c	(working copy)
@@ -66,7 +66,6 @@
   }
   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 @@
   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;
 }
Index: src/lua/lgc.h
===================================================================
--- src/lua/lgc.h	(revision 281)
+++ src/lua/lgc.h	(working copy)
@@ -37,7 +37,23 @@
 #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.
+*/
+#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)
@@ -101,6 +117,7 @@
 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 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);
Index: src/lua/lbaselib.c
===================================================================
--- src/lua/lbaselib.c	(revision 281)
+++ src/lua/lbaselib.c	(working copy)
@@ -193,9 +193,10 @@
 
 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);
Index: src/lua/lua.c
===================================================================
--- src/lua/lua.c	(revision 281)
+++ src/lua/lua.c	(working copy)
@@ -45,6 +45,7 @@
   "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 @@
         break;
       case 'e':
         *pe = 1;  /* go through */
+      case 'm':   /* go through */
       case 'l':
         if (argv[i][2] == '\0') {
           i++;
@@ -305,6 +307,15 @@
           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];
Index: src/lua/lstring.c
===================================================================
--- src/lua/lstring.c	(revision 281)
+++ src/lua/lstring.c	(working copy)
@@ -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 (G(L)->gcstate == GCSsweepstring || 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 @@
   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 @@
   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;
 }
 
Index: src/lua/lapi.c
===================================================================
--- src/lua/lapi.c	(revision 281)
+++ src/lua/lapi.c	(working copy)
@@ -687,14 +687,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);
 }
 
@@ -940,11 +940,11 @@
   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: {
@@ -961,6 +961,10 @@
       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;
@@ -985,6 +989,24 @@
       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);
Index: src/lua/lua.h
===================================================================
--- src/lua/lua.h	(revision 281)
+++ src/lua/lua.h	(working copy)
@@ -228,6 +228,8 @@
 #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);
 
