--- a/src/lapi.c
+++ b/src/lapi.c
@@ -716,14 +716,14 @@
 
 LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
   StkId t;
-  TValue key;
   lua_lock(L);
   api_checknelems(L, 1);
   t = index2adr(L, idx);
   api_checkvalidindex(L, t);
-  setsvalue(L, &key, luaS_new(L, k));
-  luaV_settable(L, t, &key, L->top - 1);
-  L->top--;  /* pop value */
+  setsvalue2s(L, L->top, luaS_new(L, k));
+  api_incr_top(L);
+  luaV_settable(L, t, L->top - 1, L->top - 2);
+  L->top -= 2;  /* pop key and value */
   lua_unlock(L);
 }
 
@@ -971,7 +971,12 @@
       break;
     }
     case LUA_GCCOLLECT: {
-      luaC_fullgc(L);
+      lu_mem old_thres = g->GCthreshold;
+      if(g->GCthreshold != MAX_LUMEM) {
+        g->GCthreshold = MAX_LUMEM;
+        luaC_fullgc(L);
+        g->GCthreshold = old_thres;
+      }
       break;
     }
     case LUA_GCCOUNT: {
--- a/src/ldo.c
+++ b/src/ldo.c
@@ -494,6 +494,7 @@
   struct SParser *p = cast(struct SParser *, ud);
   int c = luaZ_lookahead(p->z);
   luaC_checkGC(L);
+	lua_gc(L, LUA_GCSTOP, 0);  /* stop collector during parsing */
   tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z,
                                                              &p->buff, p->name);
   cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L)));
@@ -502,6 +503,7 @@
     cl->l.upvals[i] = luaF_newupval(L);
   setclvalue(L, L->top, cl);
   incr_top(L);
+	lua_gc(L, LUA_GCRESTART, 0);
 }
 
 
--- a/src/lgc.c
+++ b/src/lgc.c
@@ -437,7 +437,10 @@
   /* check size of buffer */
   if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) {  /* buffer too big? */
     size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
-    luaZ_resizebuffer(L, &g->buff, newsize);
+    /* make sure newsize is larger then the buffer's in use size. */
+    newsize = (luaZ_bufflen(&g->buff) > newsize) ? luaZ_bufflen(&g->buff) : newsize;
+    if(newsize < luaZ_sizebuffer(&g->buff))
+      luaZ_resizebuffer(L, &g->buff, newsize);
   }
 }
 
--- a/src/lstate.c
+++ b/src/lstate.c
@@ -118,7 +118,6 @@
 
 lua_State *luaE_newthread (lua_State *L) {
   lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State)));
-  luaC_link(L, obj2gco(L1), LUA_TTHREAD);
   preinit_state(L1, G(L));
   stack_init(L1, L);  /* init stack */
   setobj2n(L, gt(L1), gt(L));  /* share table of globals */
@@ -126,6 +125,7 @@
   L1->basehookcount = L->basehookcount;
   L1->hook = L->hook;
   resethookcount(L1);
+  luaC_link(L, obj2gco(L1), LUA_TTHREAD);
   lua_assert(iswhite(obj2gco(L1)));
   return L1;
 }
--- a/src/lstring.c
+++ b/src/lstring.c
@@ -53,6 +53,9 @@
   stringtable *tb;
   if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char))
     luaM_toobig(L);
+  tb = &G(L)->strt;
+  if ((tb->nuse + 1) > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
+    luaS_resize(L, tb->size*2);  /* too crowded */
   ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString)));
   ts->tsv.len = l;
   ts->tsv.hash = h;
@@ -61,13 +64,10 @@
   ts->tsv.reserved = 0;
   memcpy(ts+1, str, l*sizeof(char));
   ((char *)(ts+1))[l] = '\0';  /* ending 0 */
-  tb = &G(L)->strt;
   h = lmod(h, tb->size);
   ts->tsv.next = tb->hash[h];  /* chain new entry */
   tb->hash[h] = obj2gco(ts);
   tb->nuse++;
-  if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
-    luaS_resize(L, tb->size*2);  /* too crowded */
   return ts;
 }
 
--- a/src/ltable.c
+++ b/src/ltable.c
@@ -371,7 +371,6 @@
 
 Table *luaH_new (lua_State *L, int narray, int nhash) {
   Table *t = luaM_new(L, Table);
-  luaC_link(L, obj2gco(t), LUA_TTABLE);
   t->metatable = NULL;
   t->flags = cast_byte(~0);
   /* temporary values (kept only if some malloc fails) */
@@ -381,6 +380,7 @@
   t->node = cast(Node *, dummynode);
   setarrayvector(L, t, narray);
   setnodevector(L, t, nhash);
+  luaC_link(L, obj2gco(t), LUA_TTABLE);
   return t;
 }
 
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -375,6 +375,7 @@
         if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
         tl += l;
       }
+      G(L)->buff.n = tl;
       buffer = luaZ_openspace(L, &G(L)->buff, tl);
       tl = 0;
       for (i=n; i>0; i--) {  /* concat all strings */
@@ -383,6 +384,7 @@
         tl += l;
       }
       setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
+      luaZ_resetbuffer(&G(L)->buff);
     }
     total -= n-1;  /* got `n' strings to create 1 new */
     last -= n-1;
--- a/src/lua.c
+++ b/src/lua.c
@@ -19,6 +19,94 @@
 #include "llimits.h"
 
 
+typedef struct {
+	char		*name;
+	lua_State	*L;
+	size_t		memused;
+	size_t		peak_memused;
+	size_t		gc_memused;
+	size_t		max_memused;
+	int		collecting;
+} script_info_t;
+
+
+static void *script_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
+{
+	script_info_t *info=(script_info_t *)ud;
+	size_t old_size = info->memused;
+
+	info->memused -= osize;
+	if (nsize == 0) {
+		free(ptr);
+		return NULL;
+	}
+	info->memused += nsize;
+	if(info->max_memused > 0 && nsize > osize &&
+	  (info->memused >= info->max_memused || info->memused >= info->gc_memused)) {
+#ifdef LOW_MEM_DEBUG
+		printf("LOW MEM: 1 osize=%zd, nsize=%zd, used=%zu, peak=%zu, need=%zd\n", osize, nsize,
+			info->memused, info->peak_memused, (info->memused - info->max_memused));
+#endif
+		info->memused = old_size;
+		/* don't allow a recursive garbage collection call. */
+		if(info->collecting != 0) {
+			return NULL;
+		}
+		info->collecting = 1;
+		/* try to free memory by collecting garbage. */
+		lua_gc(info->L, LUA_GCCOLLECT, 0);
+		info->collecting = 0;
+#ifdef LOW_MEM_DEBUG
+		printf("LOW MEM: 2 used=%zu, peak=%zu\n", info->memused, info->peak_memused);
+#endif
+		/* check memory usage again. */
+		old_size = info->memused;
+		info->memused -= osize;
+		info->memused += nsize;
+		if(info->memused >= info->max_memused) {
+			info->memused = old_size;
+#ifdef LOW_MEM_DEBUG
+			printf("OUT OF MEMORY: memused=%zd, osize=%zd, nsize=%zd\n", info->memused, osize, nsize);
+#endif
+			return NULL;
+		}
+	}
+	if(info->memused > info->peak_memused) info->peak_memused = info->memused;
+	return realloc(ptr, nsize);
+}
+
+static int set_memory_limit(lua_State *L)
+{
+	int hardlimit = luaL_checknumber(L, 1);
+	int softlimit = luaL_optnumber(L, 2, 0);
+
+	script_info_t *info;
+	lua_getallocf(L, (void *)(&info));
+
+	if( hardlimit >= 0 )
+	{
+		if( softlimit <= 0 )
+			softlimit = (int)((float)hardlimit * 0.75);
+
+		info->max_memused = hardlimit;
+		info->gc_memused  = softlimit;
+	}
+
+	lua_pushnumber(L, hardlimit);
+	lua_pushnumber(L, softlimit);
+	return 2;
+}
+
+static int get_memory_limit(lua_State *L)
+{
+	script_info_t *info;
+	lua_getallocf(L, (void *)(&info));
+	lua_pushnumber(L, info->max_memused);
+	lua_pushnumber(L, info->gc_memused);
+	return 2;
+}
+
+
 static lua_State *globalL = NULL;
 
 static const char *progname = LUA_PROGNAME;
@@ -377,11 +465,28 @@
 int main (int argc, char **argv) {
   int status;
   struct Smain s;
-  lua_State *L = lua_open();  /* create state */
+  script_info_t *info;
+
+  info = (script_info_t *)calloc(1, sizeof(script_info_t));
+  info->max_memused = 0;
+  info->collecting = 0;
+  info->name = argv[0];
+  info->memused = 0;
+  info->peak_memused = 0;
+
+  lua_State *L = lua_newstate(script_alloc, info);
+
   if (L == NULL) {
     l_message(argv[0], "cannot create state: not enough memory");
     return EXIT_FAILURE;
   }
+
+  info->L = L;
+
+  luaL_openlibs(L);
+  lua_register(L, "set_memory_limit", set_memory_limit);
+  lua_register(L, "get_memory_limit", get_memory_limit);
+
   /* Checking 'sizeof(lua_Integer)' cannot be made in preprocessor on all compilers.
   */
 #ifdef LNUM_INT16
@@ -396,6 +501,14 @@
   status = lua_cpcall(L, &pmain, &s);
   report(L, status);
   lua_close(L);
+
+#ifdef LOW_MEM_DEBUG
+  printf("%s: memused=%zd, peak_memused=%zd\n", info->name,
+	info->memused, info->peak_memused);
+#endif
+
+  free(info);
+
   return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
 }