diff --git a/lapi.c b/lapi.c
index 4f4e3021..c493609a 100644
--- a/lapi.c
+++ b/lapi.c
@@ -53,16 +53,6 @@ const char lua_ident[] =
 #define isupvalue(i)		((i) < LUA_REGISTRYINDEX)
 
 
-/* Advance the garbage collector when creating large objects */
-static void advancegc (lua_State *L, size_t delta) {
-  delta >>= 5;  /* one object for each 32 bytes (empirical) */
-  if (delta > 0) {
-    global_State *g = G(L);
-    luaE_setdebt(g, g->GCdebt - cast(l_obj, delta));
-  }
-}
-
-
 /*
 ** Convert an acceptable index to a pointer to its respective value.
 ** Non-valid indices return the special nil value 'G(L)->nilvalue'.
@@ -540,7 +530,6 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
   ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
   setsvalue2s(L, L->top.p, ts);
   api_incr_top(L);
-  advancegc(L, len);
   luaC_checkGC(L);
   lua_unlock(L);
   return getstr(ts);
@@ -557,7 +546,6 @@ LUA_API const char *lua_pushextlstring (lua_State *L,
   setsvalue2s(L, L->top.p, ts);
   api_incr_top(L);
   if (falloc != NULL)  /* non-static string? */
-    advancegc(L, len);  /* count its memory */
   luaC_checkGC(L);
   lua_unlock(L);
   return getstr(ts);
@@ -1190,16 +1178,16 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
     }
     case LUA_GCCOUNT: {
       /* GC values are expressed in Kbytes: #bytes/2^10 */
-      res = cast_int(g->GCtotalbytes >> 10);
+      res = cast_int(gettotalbytes(g) >> 10);
       break;
     }
     case LUA_GCCOUNTB: {
-      res = cast_int(g->GCtotalbytes & 0x3ff);
+      res = cast_int(gettotalbytes(g) & 0x3ff);
       break;
     }
     case LUA_GCSTEP: {
       lu_byte oldstp = g->gcstp;
-      l_obj n = cast(l_obj, va_arg(argp, size_t));
+      l_mem n = cast(l_mem, va_arg(argp, size_t));
       int work = 0;  /* true if GC did some work */
       g->gcstp = 0;  /* allow GC to run (other bits must be zero here) */
       if (n <= 0)
@@ -1356,7 +1344,6 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
   u = luaS_newudata(L, size, cast(unsigned short, nuvalue));
   setuvalue(L, s2v(L->top.p), u);
   api_incr_top(L);
-  advancegc(L, size);
   luaC_checkGC(L);
   lua_unlock(L);
   return getudatamem(u);
diff --git a/lauxlib.c b/lauxlib.c
index b70b7ae6..defd4d57 100644
--- a/lauxlib.c
+++ b/lauxlib.c
@@ -618,6 +618,7 @@ LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
     box->bsize = 0;  box->box = NULL;
     lua_pushextlstring(L, s, len, allocf, ud);
     lua_closeslot(L, -2);  /* close the box */
+    lua_gc(L, LUA_GCSTEP, len);
   }
   lua_remove(L, -2);  /* remove box or placeholder from the stack */
 }
diff --git a/lgc.c b/lgc.c
index 92034635..a38d11b2 100644
--- a/lgc.c
+++ b/lgc.c
@@ -18,7 +18,6 @@
 #include "ldo.h"
 #include "lfunc.h"
 #include "lgc.h"
-#include "llex.h"
 #include "lmem.h"
 #include "lobject.h"
 #include "lstate.h"
@@ -27,13 +26,6 @@
 #include "ltm.h"
 
 
-/*
-** Number of fixed (luaC_fix) objects in a Lua state: metafield names,
-** plus reserved words, plus "_ENV", plus the memory-error message.
-*/
-#define NFIXED		(TM_N + NUM_RESERVED + 2)
-
-
 /*
 ** Maximum number of elements to sweep in each single step.
 ** (Large enough to dissipate fixed overheads but small enough
@@ -42,6 +34,12 @@
 #define GCSWEEPMAX	20
 
 
+/*
+** Cost (in work units) of running one finalizer.
+*/
+#define CWUFIN	10
+
+
 /* mask with all color bits */
 #define maskcolors	(bitmask(BLACKBIT) | WHITEBITS)
 
@@ -95,7 +93,7 @@
 
 
 static void reallymarkobject (global_State *g, GCObject *o);
-static l_obj atomic (lua_State *L);
+static void atomic (lua_State *L);
 static void entersweep (lua_State *L);
 
 
@@ -112,6 +110,66 @@ static void entersweep (lua_State *L);
 #define gnodelast(h)	gnode(h, cast_sizet(sizenode(h)))
 
 
+static size_t objsize (GCObject *o) {
+  switch (o->tt) {
+    case LUA_VTABLE: {
+      /* Fow now, table size does not consider 'haslastfree' */
+      Table *t = gco2t(o);
+      size_t sz = sizeof(Table)
+                + luaH_realasize(t) * (sizeof(Value) + 1);
+      if (!isdummy(t))
+        sz += sizenode(t) * sizeof(Node);
+      return sz;
+    }
+    case LUA_VLCL: {
+      LClosure *cl = gco2lcl(o);
+      return sizeLclosure(cl->nupvalues);
+    }
+    case LUA_VCCL: {
+      CClosure *cl = gco2ccl(o);
+      return sizeCclosure(cl->nupvalues);
+      break;
+    }
+    case LUA_VUSERDATA: {
+      Udata *u = gco2u(o);
+      return sizeudata(u->nuvalue, u->len);
+    }
+    case LUA_VPROTO: {
+      Proto *p = gco2p(o);
+      size_t sz = sizeof(Proto)
+                + cast_uint(p->sizep) * sizeof(Proto*)
+                + cast_uint(p->sizek) * sizeof(TValue)
+                + cast_uint(p->sizelocvars) * sizeof(LocVar)
+                + cast_uint(p->sizeupvalues) * sizeof(Upvaldesc);
+      if (!(p->flag & PF_FIXED)) {
+        sz +=  cast_uint(p->sizecode) * sizeof(Instruction)
+            +  cast_uint(p->sizelineinfo) * sizeof(lu_byte)
+            + cast_uint(p->sizeabslineinfo) * sizeof(AbsLineInfo);
+      }
+      return sz;
+    }
+    case LUA_VTHREAD: {
+      lua_State *L1 = gco2th(o);
+      size_t sz = sizeof(lua_State) + LUA_EXTRASPACE
+                + cast_uint(L1->nci) * sizeof(CallInfo);
+      if (L1->stack.p != NULL)
+        sz += cast_uint(stacksize(L1) + EXTRA_STACK) * sizeof(StackValue);
+      return sz;
+    }
+    case LUA_VSHRSTR: {
+      TString *ts = gco2ts(o);
+      return sizestrshr(cast_uint(ts->shrlen));
+    }
+    case LUA_VLNGSTR: {
+      TString *ts = gco2ts(o);
+      return luaS_sizelngstr(ts->u.lnglen, ts->shrlen);
+    }
+    case LUA_VUPVAL: return sizeof(UpVal);
+    default: lua_assert(0); return 0;
+  }
+}
+
+
 static GCObject **getgclist (GCObject *o) {
   switch (o->tt) {
     case LUA_VTABLE: return &gco2t(o)->gclist;
@@ -250,7 +308,6 @@ GCObject *luaC_newobjdt (lua_State *L, lu_byte tt, size_t sz, size_t offset) {
   global_State *g = G(L);
   char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
   GCObject *o = cast(GCObject *, p + offset);
-  g->GCdebt--;
   o->marked = luaC_white(g);
   o->tt = tt;
   o->next = g->allgc;
@@ -290,7 +347,7 @@ GCObject *luaC_newobj (lua_State *L, lu_byte tt, size_t sz) {
 ** (only closures can), and a userdata's metatable must be a table.
 */
 static void reallymarkobject (global_State *g, GCObject *o) {
-  g->GCmarked++;
+  g->GCmarked += cast(l_mem, objsize(o));
   switch (o->tt) {
     case LUA_VSHRSTR:
     case LUA_VLNGSTR: {
@@ -338,14 +395,10 @@ static void markmt (global_State *g) {
 /*
 ** mark all objects in list of being-finalized
 */
-static l_obj markbeingfnz (global_State *g) {
+static void markbeingfnz (global_State *g) {
   GCObject *o;
-  l_obj count = 0;
-  for (o = g->tobefnz; o != NULL; o = o->next) {
-    count++;
+  for (o = g->tobefnz; o != NULL; o = o->next)
     markobject(g, o);
-  }
-  return count;
 }
 
 
@@ -360,8 +413,7 @@ static l_obj markbeingfnz (global_State *g) {
 ** upvalues, as they have nothing to be checked. (If the thread gets an
 ** upvalue later, it will be linked in the list again.)
 */
-static l_obj remarkupvals (global_State *g) {
-  l_obj work = 0;
+static void remarkupvals (global_State *g) {
   lua_State *thread;
   lua_State **p = &g->twups;
   while ((thread = *p) != NULL) {
@@ -380,9 +432,7 @@ static l_obj remarkupvals (global_State *g) {
         }
       }
     }
-    work++;
   }
-  return work;
 }
 
 
@@ -401,7 +451,7 @@ static void cleargraylists (global_State *g) {
 */
 static void restartcollection (global_State *g) {
   cleargraylists(g);
-  g->GCmarked = NFIXED;
+  g->GCmarked = 0;
   markobject(g, g->mainthread);
   markvalue(g, &g->l_registry);
   markmt(g);
@@ -546,7 +596,7 @@ static void traversestrongtable (global_State *g, Table *h) {
 }
 
 
-static void traversetable (global_State *g, Table *h) {
+static l_mem traversetable (global_State *g, Table *h) {
   const char *weakkey, *weakvalue;
   const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
   TString *smode;
@@ -565,15 +615,17 @@ static void traversetable (global_State *g, Table *h) {
   }
   else  /* not weak */
     traversestrongtable(g, h);
+  return 1 + sizenode(h) + h->alimit;
 }
 
 
-static void traverseudata (global_State *g, Udata *u) {
+static l_mem traverseudata (global_State *g, Udata *u) {
   int i;
   markobjectN(g, u->metatable);  /* mark its metatable */
   for (i = 0; i < u->nuvalue; i++)
     markvalue(g, &u->uv[i].uv);
   genlink(g, obj2gco(u));
+  return 1 + u->nuvalue;
 }
 
 
@@ -582,7 +634,7 @@ static void traverseudata (global_State *g, Udata *u) {
 ** arrays can be larger than needed; the extra slots are filled with
 ** NULL, so the use of 'markobjectN')
 */
-static void traverseproto (global_State *g, Proto *f) {
+static l_mem traverseproto (global_State *g, Proto *f) {
   int i;
   markobjectN(g, f->source);
   for (i = 0; i < f->sizek; i++)  /* mark literals */
@@ -593,26 +645,29 @@ static void traverseproto (global_State *g, Proto *f) {
     markobjectN(g, f->p[i]);
   for (i = 0; i < f->sizelocvars; i++)  /* mark local-variable names */
     markobjectN(g, f->locvars[i].varname);
+  return 1 + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars;
 }
 
 
-static void traverseCclosure (global_State *g, CClosure *cl) {
+static l_mem traverseCclosure (global_State *g, CClosure *cl) {
   int i;
   for (i = 0; i < cl->nupvalues; i++)  /* mark its upvalues */
     markvalue(g, &cl->upvalue[i]);
+  return 1 + cl->nupvalues;
 }
 
 /*
 ** Traverse a Lua closure, marking its prototype and its upvalues.
 ** (Both can be NULL while closure is being created.)
 */
-static void traverseLclosure (global_State *g, LClosure *cl) {
+static l_mem traverseLclosure (global_State *g, LClosure *cl) {
   int i;
   markobjectN(g, cl->p);  /* mark its prototype */
   for (i = 0; i < cl->nupvalues; i++) {  /* visit its upvalues */
     UpVal *uv = cl->upvals[i];
     markobjectN(g, uv);  /* mark upvalue */
   }
+  return 1 + cl->nupvalues;
 }
 
 
@@ -628,13 +683,13 @@ static void traverseLclosure (global_State *g, LClosure *cl) {
 ** (which can only happen in generational mode) or if the traverse is in
 ** the propagate phase (which can only happen in incremental mode).
 */
-static void traversethread (global_State *g, lua_State *th) {
+static l_mem traversethread (global_State *g, lua_State *th) {
   UpVal *uv;
   StkId o = th->stack.p;
   if (isold(th) || g->gcstate == GCSpropagate)
     linkgclist(th, g->grayagain);  /* insert into 'grayagain' list */
   if (o == NULL)
-    return;  /* stack not completely built yet */
+    return 0;  /* stack not completely built yet */
   lua_assert(g->gcstate == GCSatomic ||
              th->openupval == NULL || isintwups(th));
   for (; o < th->top.p; o++)  /* mark live elements in the stack */
@@ -652,35 +707,33 @@ static void traversethread (global_State *g, lua_State *th) {
       g->twups = th;
     }
   }
+  return 1 + (th->top.p - th->stack.p);
 }
 
 
 /*
-** traverse one gray object, turning it to black.
+** traverse one gray object, turning it to black. Return an estimate
+** of the number of slots traversed.
 */
-static void propagatemark (global_State *g) {
+static l_mem propagatemark (global_State *g) {
   GCObject *o = g->gray;
   nw2black(o);
   g->gray = *getgclist(o);  /* remove from 'gray' list */
   switch (o->tt) {
-    case LUA_VTABLE: traversetable(g, gco2t(o)); break;
-    case LUA_VUSERDATA: traverseudata(g, gco2u(o)); break;
-    case LUA_VLCL: traverseLclosure(g, gco2lcl(o)); break;
-    case LUA_VCCL: traverseCclosure(g, gco2ccl(o)); break;
-    case LUA_VPROTO: traverseproto(g, gco2p(o)); break;
-    case LUA_VTHREAD: traversethread(g, gco2th(o)); break;
-    default: lua_assert(0);
+    case LUA_VTABLE: return traversetable(g, gco2t(o));
+    case LUA_VUSERDATA: return traverseudata(g, gco2u(o));
+    case LUA_VLCL: return traverseLclosure(g, gco2lcl(o));
+    case LUA_VCCL: return traverseCclosure(g, gco2ccl(o));
+    case LUA_VPROTO: return traverseproto(g, gco2p(o));
+    case LUA_VTHREAD: return traversethread(g, gco2th(o));
+    default: lua_assert(0); return 0;
   }
 }
 
 
-static l_obj propagateall (global_State *g) {
-  l_obj work = 0;
-  while (g->gray) {
+static void propagateall (global_State *g) {
+  while (g->gray)
     propagatemark(g);
-    work++;
-  }
-  return work;
 }
 
 
@@ -690,9 +743,8 @@ static l_obj propagateall (global_State *g) {
 ** inverts the direction of the traversals, trying to speed up
 ** convergence on chains in the same table.
 */
-static l_obj convergeephemerons (global_State *g) {
+static void convergeephemerons (global_State *g) {
   int changed;
-  l_obj work = 0;
   int dir = 0;
   do {
     GCObject *w;
@@ -707,11 +759,9 @@ static l_obj convergeephemerons (global_State *g) {
         propagateall(g);  /* propagate changes */
         changed = 1;  /* will have to revisit all ephemeron tables */
       }
-      work++;
     }
     dir = !dir;  /* invert direction next time */
   } while (changed);  /* repeat until no more changes */
-  return work;
 }
 
 /* }====================================================== */
@@ -727,8 +777,7 @@ static l_obj convergeephemerons (global_State *g) {
 /*
 ** clear entries with unmarked keys from all weaktables in list 'l'
 */
-static l_obj clearbykeys (global_State *g, GCObject *l) {
-  l_obj work = 0;
+static void clearbykeys (global_State *g, GCObject *l) {
   for (; l; l = gco2t(l)->gclist) {
     Table *h = gco2t(l);
     Node *limit = gnodelast(h);
@@ -739,9 +788,7 @@ static l_obj clearbykeys (global_State *g, GCObject *l) {
       if (isempty(gval(n)))  /* is entry empty? */
         clearkey(n);  /* clear its key */
     }
-    work++;
   }
-  return work;
 }
 
 
@@ -749,8 +796,7 @@ static l_obj clearbykeys (global_State *g, GCObject *l) {
 ** clear entries with unmarked values from all weaktables in list 'l' up
 ** to element 'f'
 */
-static l_obj clearbyvalues (global_State *g, GCObject *l, GCObject *f) {
-  l_obj work = 0;
+static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) {
   for (; l != f; l = gco2t(l)->gclist) {
     Table *h = gco2t(l);
     Node *n, *limit = gnodelast(h);
@@ -767,9 +813,7 @@ static l_obj clearbyvalues (global_State *g, GCObject *l, GCObject *f) {
       if (isempty(gval(n)))  /* is entry empty? */
         clearkey(n);  /* clear its key */
     }
-    work++;
   }
-  return work;
 }
 
 
@@ -781,7 +825,6 @@ static void freeupval (lua_State *L, UpVal *uv) {
 
 
 static void freeobj (lua_State *L, GCObject *o) {
-  G(L)->GCtotalobjs--;
   switch (o->tt) {
     case LUA_VPROTO:
       luaF_freeproto(L, gco2p(o));
@@ -835,12 +878,11 @@ static void freeobj (lua_State *L, GCObject *o) {
 ** for next collection cycle. Return where to continue the traversal or
 ** NULL if list is finished.
 */
-static GCObject **sweeplist (lua_State *L, GCObject **p, l_obj countin) {
+static GCObject **sweeplist (lua_State *L, GCObject **p, l_mem countin) {
   global_State *g = G(L);
   int ow = otherwhite(g);
-  l_obj i;
   int white = luaC_white(g);  /* current white */
-  for (i = 0; *p != NULL && i < countin; i++) {
+  while (*p != NULL && countin-- > 0) {
     GCObject *curr = *p;
     int marked = curr->marked;
     if (isdeadm(ow, marked)) {  /* is 'curr' dead? */
@@ -1052,8 +1094,8 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
 ** approximately (marked * pause / 100).
 */
 static void setpause (global_State *g) {
-  l_obj threshold = applygcparam(g, PAUSE, g->GCmarked);
-  l_obj debt = threshold - gettotalobjs(g);
+  l_mem threshold = applygcparam(g, PAUSE, g->GCmarked);
+  l_mem debt = threshold - gettotalbytes(g);
   if (debt < 0) debt = 0;
   luaE_setdebt(g, debt);
 }
@@ -1103,7 +1145,7 @@ static void sweep2old (lua_State *L, GCObject **p) {
 */
 static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
                             GCObject *limit, GCObject **pfirstold1,
-                            l_obj *paddedold) {
+                            l_mem *paddedold) {
   static const lu_byte nextage[] = {
     G_SURVIVAL,  /* from G_NEW */
     G_OLD1,      /* from G_SURVIVAL */
@@ -1113,7 +1155,7 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
     G_TOUCHED1,  /* from G_TOUCHED1 (do not change) */
     G_TOUCHED2   /* from G_TOUCHED2 (do not change) */
   };
-  l_obj addedold = 0;
+  l_mem addedold = 0;
   int white = luaC_white(g);
   GCObject *curr;
   while ((curr = *p) != limit) {
@@ -1132,7 +1174,7 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
         lua_assert(age != G_OLD1);  /* advanced in 'markold' */
         setage(curr, nextage[age]);
         if (getage(curr) == G_OLD1) {
-          addedold++;  /* one more object becoming old */
+          addedold += cast(l_mem, objsize(curr));  /* bytes becoming old */
           if (*pfirstold1 == NULL)
             *pfirstold1 = curr;  /* first OLD1 object in the list */
         }
@@ -1257,9 +1299,9 @@ static void minor2inc (lua_State *L, global_State *g, lu_byte kind) {
 ** than 'minormajor'% of the number of lived objects after the last
 ** major collection. (That percentage is computed in 'limit'.)
 */
-static int checkminormajor (global_State *g, l_obj addedold1) {
-  l_obj step = applygcparam(g, MINORMUL, g->GCmajorminor);
-  l_obj limit = applygcparam(g, MINORMAJOR, g->GCmajorminor);
+static int checkminormajor (global_State *g, l_mem addedold1) {
+  l_mem step = applygcparam(g, MINORMUL, g->GCmajorminor);
+  l_mem limit = applygcparam(g, MINORMAJOR, g->GCmajorminor);
   return (addedold1 >= (step >> 1) || g->GCmarked >= limit);
 }
 
@@ -1269,8 +1311,8 @@ static int checkminormajor (global_State *g, l_obj addedold1) {
 ** sweep all lists and advance pointers. Finally, finish the collection.
 */
 static void youngcollection (lua_State *L, global_State *g) {
-  l_obj addedold1 = 0;
-  l_obj marked = g->GCmarked;  /* preserve 'g->GCmarked' */
+  l_mem addedold1 = 0;
+  l_mem marked = g->GCmarked;  /* preserve 'g->GCmarked' */
   GCObject **psurvival;  /* to point to first non-dead survival object */
   GCObject *dummy;  /* dummy out parameter to 'sweepgen' */
   lua_assert(g->gcstate == GCSpropagate);
@@ -1346,7 +1388,9 @@ static void atomic2gen (lua_State *L, global_State *g) {
 
 /*
 ** Set debt for the next minor collection, which will happen when
-** total number of objects grows 'genminormul'%.
+** total number of bytes grows 'genminormul'% in relation to
+** the base, GCmajorminor, which is the number of bytes being used
+** after the last major collection.
 */
 static void setminordebt (global_State *g) {
   luaE_setdebt(g, applygcparam(g, MINORMUL, g->GCmajorminor));
@@ -1404,18 +1448,18 @@ static void fullgen (lua_State *L, global_State *g) {
 */
 static int checkmajorminor (lua_State *L, global_State *g) {
   if (g->gckind == KGC_GENMAJOR) {  /* generational mode? */
-    l_obj numobjs = gettotalobjs(g);
-    l_obj addedobjs = numobjs - g->GCmajorminor;
-    l_obj limit = applygcparam(g, MAJORMINOR, addedobjs);
-    l_obj tobecollected = numobjs - g->GCmarked;
+    l_mem numbytes = gettotalbytes(g);
+    l_mem addedobjs = numbytes - g->GCmajorminor;
+    l_mem limit = applygcparam(g, MAJORMINOR, addedobjs);
+    l_mem tobecollected = numbytes - g->GCmarked;
     if (tobecollected > limit) {
       atomic2gen(L, g);  /* return to generational mode */
       setminordebt(g);
-      return 0;  /* exit incremental collection */
+      return 1;  /* exit incremental collection */
     }
   }
   g->GCmajorminor = g->GCmarked;  /* prepare for next collection */
-  return 1;  /* stay doing incremental collections */
+  return 0;  /* stay doing incremental collections */
 }
 
 /* }====================================================== */
@@ -1474,8 +1518,7 @@ void luaC_freeallobjects (lua_State *L) {
 }
 
 
-static l_obj atomic (lua_State *L) {
-  l_obj work = 0;
+static void atomic (lua_State *L) {
   global_State *g = G(L);
   GCObject *origweak, *origall;
   GCObject *grayagain = g->grayagain;  /* save original list */
@@ -1487,33 +1530,32 @@ static l_obj atomic (lua_State *L) {
   /* registry and global metatables may be changed by API */
   markvalue(g, &g->l_registry);
   markmt(g);  /* mark global metatables */
-  work += propagateall(g);  /* empties 'gray' list */
+  propagateall(g);  /* empties 'gray' list */
   /* remark occasional upvalues of (maybe) dead threads */
-  work += remarkupvals(g);
-  work += propagateall(g);  /* propagate changes */
+  remarkupvals(g);
+  propagateall(g);  /* propagate changes */
   g->gray = grayagain;
-  work += propagateall(g);  /* traverse 'grayagain' list */
-  work += convergeephemerons(g);
+  propagateall(g);  /* traverse 'grayagain' list */
+  convergeephemerons(g);
   /* at this point, all strongly accessible objects are marked. */
   /* Clear values from weak tables, before checking finalizers */
-  work += clearbyvalues(g, g->weak, NULL);
-  work += clearbyvalues(g, g->allweak, NULL);
+  clearbyvalues(g, g->weak, NULL);
+  clearbyvalues(g, g->allweak, NULL);
   origweak = g->weak; origall = g->allweak;
   separatetobefnz(g, 0);  /* separate objects to be finalized */
-  work += markbeingfnz(g);  /* mark objects that will be finalized */
-  work += propagateall(g);  /* remark, to propagate 'resurrection' */
-  work += convergeephemerons(g);
+  markbeingfnz(g);  /* mark objects that will be finalized */
+  propagateall(g);  /* remark, to propagate 'resurrection' */
+  convergeephemerons(g);
   /* at this point, all resurrected objects are marked. */
   /* remove dead objects from weak tables */
-  work += clearbykeys(g, g->ephemeron);  /* clear keys from all ephemeron */
-  work += clearbykeys(g, g->allweak);  /* clear keys from all 'allweak' */
+  clearbykeys(g, g->ephemeron);  /* clear keys from all ephemeron */
+  clearbykeys(g, g->allweak);  /* clear keys from all 'allweak' */
   /* clear values from resurrected weak tables */
-  work += clearbyvalues(g, g->weak, origweak);
-  work += clearbyvalues(g, g->allweak, origall);
+  clearbyvalues(g, g->weak, origweak);
+  clearbyvalues(g, g->allweak, origall);
   luaS_clearcache(g);
   g->currentwhite = cast_byte(otherwhite(g));  /* flip current white */
   lua_assert(g->gray == NULL);
-  return work;
 }
 
 
@@ -1524,7 +1566,7 @@ static l_obj atomic (lua_State *L) {
 static void sweepstep (lua_State *L, global_State *g,
                        lu_byte nextstate, GCObject **nextlist, int fast) {
   if (g->sweepgc)
-    g->sweepgc = sweeplist(L, g->sweepgc, fast ? MAX_LOBJ : GCSWEEPMAX);
+    g->sweepgc = sweeplist(L, g->sweepgc, fast ? MAX_LMEM : GCSWEEPMAX);
   else {  /* enter next state */
     g->gcstate = nextstate;
     g->sweepgc = nextlist;
@@ -1544,72 +1586,80 @@ static void sweepstep (lua_State *L, global_State *g,
 ** That avoids traversing twice some objects, such as threads and
 ** weak tables.
 */
-static l_obj singlestep (lua_State *L, int fast) {
+
+#define step2pause	-3  /* finished collection; entered pause state */
+#define atomicstep	-2  /* atomic step */
+#define step2minor	-1  /* moved to minor collections */
+
+
+static l_mem singlestep (lua_State *L, int fast) {
   global_State *g = G(L);
-  l_obj work;
+  l_mem stepresult;
   lua_assert(!g->gcstopem);  /* collector is not reentrant */
   g->gcstopem = 1;  /* no emergency collections while collecting */
   switch (g->gcstate) {
     case GCSpause: {
       restartcollection(g);
       g->gcstate = GCSpropagate;
-      work = 1;
+      stepresult = 1;
       break;
     }
     case GCSpropagate: {
       if (fast || g->gray == NULL) {
         g->gcstate = GCSenteratomic;  /* finish propagate phase */
-        work = 0;
-      }
-      else {
-        propagatemark(g);  /* traverse one gray object */
-        work = 1;
+        stepresult = 1;
       }
+      else
+        stepresult = propagatemark(g);  /* traverse one gray object */
       break;
     }
     case GCSenteratomic: {
-      work = atomic(L);
+      atomic(L);
       if (checkmajorminor(L, g))
+        stepresult = step2minor;
+      else {
         entersweep(L);
+        stepresult = atomicstep;
+      }
       break;
     }
     case GCSswpallgc: {  /* sweep "regular" objects */
       sweepstep(L, g, GCSswpfinobj, &g->finobj, fast);
-      work = GCSWEEPMAX;
+      stepresult = GCSWEEPMAX;
       break;
     }
     case GCSswpfinobj: {  /* sweep objects with finalizers */
       sweepstep(L, g, GCSswptobefnz, &g->tobefnz, fast);
-      work = GCSWEEPMAX;
+      stepresult = GCSWEEPMAX;
       break;
     }
     case GCSswptobefnz: {  /* sweep objects to be finalized */
       sweepstep(L, g, GCSswpend, NULL, fast);
-      work = GCSWEEPMAX;
+      stepresult = GCSWEEPMAX;
       break;
     }
     case GCSswpend: {  /* finish sweeps */
       checkSizes(L, g);
       g->gcstate = GCScallfin;
-      work = 0;
+      stepresult = GCSWEEPMAX;
       break;
     }
     case GCScallfin: {  /* call finalizers */
       if (g->tobefnz && !g->gcemergency) {
         g->gcstopem = 0;  /* ok collections during finalizers */
         GCTM(L);  /* call one finalizer */
-        work = 1;
+        stepresult = CWUFIN;
       }
       else {  /* emergency mode or no more finalizers */
         g->gcstate = GCSpause;  /* finish collection */
-        work = 0;
+        stepresult = step2pause;
       }
       break;
     }
     default: lua_assert(0); return 0;
   }
   g->gcstopem = 0;
-  return work;
+  return stepresult;
 }
 
 
@@ -1635,25 +1685,26 @@ void luaC_runtilstate (lua_State *L, int state, int fast) {
 ** controls when next step will be performed.
 */
 static void incstep (lua_State *L, global_State *g) {
-  l_obj stepsize = applygcparam(g, STEPSIZE, 100);
-  l_obj work2do = applygcparam(g, STEPMUL, stepsize);
-  int fast = 0;
-  if (work2do == 0) {  /* special case: do a full collection */
-    work2do = MAX_LOBJ;  /* do unlimited work */
-    fast = 1;
-  }
-  do {  /* repeat until pause or enough work */
-    l_obj work = singlestep(L, fast);  /* perform one single step */
-    if (g->gckind == KGC_GENMINOR)  /* returned to minor collections? */
+  l_mem stepsize = applygcparam(g, STEPSIZE, 100);
+  l_mem work2do = applygcparam(g, STEPMUL, stepsize);
+  l_mem stres;
+  int fast = (work2do == 0);  /* special case: do a full collection */
+  do {  /* repeat until enough work */
+    stres = singlestep(L, fast);  /* perform one single step */
+    if (stres == step2minor)  /* returned to minor collections? */
       return;  /* nothing else to be done here */
-    work2do -= work;
-  } while (work2do > 0 && g->gcstate != GCSpause);
+    else if (stres == step2pause || (stres == atomicstep && !fast))
+      break;  /* end of cycle or atomic */
+    else
+      work2do -= stres;
+  } while (fast || work2do > 0);
   if (g->gcstate == GCSpause)
     setpause(g);  /* pause until next cycle */
   else
     luaE_setdebt(g, stepsize);
 }
 
+
 /*
 ** Performs a basic GC step if collector is running. (If collector is
 ** not running, set a reasonable debt to avoid it being called at
@@ -1663,17 +1714,23 @@ void luaC_step (lua_State *L) {
   global_State *g = G(L);
   lua_assert(!g->gcemergency);
   if (!gcrunning(g))  /* not running? */
-    luaE_setdebt(g, 2000);
+    luaE_setdebt(g, 20000);
   else {
+// printf("mem: %ld  kind: %s  ", gettotalbytes(g),
+//   g->gckind == KGC_INC ? "inc" : g->gckind == KGC_GENMAJOR ? "genmajor" :
+//     "genminor");
     switch (g->gckind) {
       case KGC_INC: case KGC_GENMAJOR:
+// printf("(%d -> ", g->gcstate);
         incstep(L, g);
+// printf("%d) ", g->gcstate);
         break;
       case KGC_GENMINOR:
         youngcollection(L, g);
         setminordebt(g);
         break;
     }
+// printf("-> mem: %ld  debt: %ld\n", gettotalbytes(g), g->GCdebt);
   }
 }
 
@@ -1692,7 +1749,7 @@ static void fullinc (lua_State *L, global_State *g) {
   luaC_runtilstate(L, GCSpause, 1);
   luaC_runtilstate(L, GCScallfin, 1);  /* run up to finalizers */
   /* 'marked' must be correct after a full GC cycle */
-  lua_assert(g->GCmarked == gettotalobjs(g));
+  /* lua_assert(g->GCmarked == gettotalobjs(g)); ??? */
   luaC_runtilstate(L, GCSpause, 1);  /* finish collection */
   setpause(g);
 }
diff --git a/lgc.h b/lgc.h
index a30755d0..0b16ac7f 100644
--- a/lgc.h
+++ b/lgc.h
@@ -23,8 +23,9 @@
 ** never point to a white one. Moreover, any gray object must be in a
 ** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it
 ** can be visited again before finishing the collection cycle. (Open
-** upvalues are an exception to this rule.)  These lists have no meaning
-** when the invariant is not being enforced (e.g., sweep phase).
+** upvalues are an exception to this rule, as they are attached to
+** a corresponding thread.)  These lists have no meaning when the
+** invariant is not being enforced (e.g., sweep phase).
 */
 
 
@@ -48,10 +49,10 @@
 
 /*
 ** macro to tell when main invariant (white objects cannot point to black
-** ones) must be kept. During a collection, the sweep
-** phase may break the invariant, as objects turned white may point to
-** still-black objects. The invariant is restored when sweep ends and
-** all objects are white again.
+** ones) must be kept. During a collection, the sweep phase may break
+** the invariant, as objects turned white may point to still-black
+** objects. The invariant is restored when sweep ends and all objects
+** are white again.
 */
 
 #define keepinvariant(g)	((g)->gcstate <= GCSatomic)
@@ -163,34 +164,37 @@
 
 /*
 ** Minor collections will shift to major ones after LUAI_MINORMAJOR%
-** objects become old.
+** bytes become old.
 */
 #define LUAI_MINORMAJOR         100
 
 /*
 ** Major collections will shift to minor ones after a collection
-** collects at least LUAI_MAJORMINOR% of the new objects.
+** collects at least LUAI_MAJORMINOR% of the new bytes.
 */
 #define LUAI_MAJORMINOR         50
 
 /*
 ** A young (minor) collection will run after creating LUAI_GENMINORMUL%
-** new objects.
+** new bytes.
 */
 #define LUAI_GENMINORMUL         25
 
 
 /* incremental */
 
-/* Number of objects must be LUAI_GCPAUSE% before starting new cycle */
+/* Number of bytes must be LUAI_GCPAUSE% before starting new cycle */
 #define LUAI_GCPAUSE    200
 
-/* Step multiplier. (Roughly, the collector handles LUAI_GCMUL% objects
-   for each new allocated object.) */
-#define LUAI_GCMUL      200
+/*
+** Step multiplier: The collector handles LUAI_GCMUL% work units for
+** each new allocated byte. (Each "work unit" corresponds roughly to
+** sweeping or marking one object.)
+*/
+#define LUAI_GCMUL      20  /* ??? */
 
-/* How many objects to allocate before next GC step */
-#define LUAI_GCSTEPSIZE	250
+/* How many bytes to allocate before next GC step */
+#define LUAI_GCSTEPSIZE	(250 * sizeof(void*))
 
 
 #define setgcparam(g,p,v)  (g->gcparams[LUA_GCP##p] = luaO_codeparam(v))
diff --git a/llimits.h b/llimits.h
index d7ae065b..f189048c 100644
--- a/llimits.h
+++ b/llimits.h
@@ -16,25 +16,24 @@
 
 
 /*
-** 'lu_mem' is an unsigned integer big enough to count the total memory
-** used by Lua (in bytes). 'l_obj' is a signed integer big enough to
-** count the total number of objects used by Lua. (It is signed due
-** to the use of debt in several computations.)  Usually, 'size_t' and
-** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines.
+** 'l_mem' is a signed integer big enough to count the total memory
+** used by Lua.  (It is signed due to the use of debt in several
+** computations.)  Usually, 'ptrdiff_t' should work, but we use 'long'
+** for 16-bit machines.
 */
 #if defined(LUAI_MEM)		/* { external definitions? */
+typedef LUAI_MEM l_mem;
 typedef LUAI_UMEM lu_mem;
-typedef LUAI_MEM l_obj;
 #elif LUAI_IS32INT	/* }{ */
+typedef ptrdiff_t l_mem;
 typedef size_t lu_mem;
-typedef ptrdiff_t l_obj;
 #else  /* 16-bit ints */	/* }{ */
+typedef long l_mem;
 typedef unsigned long lu_mem;
-typedef long l_obj;
 #endif				/* } */
 
-#define MAX_LOBJ  \
-	cast(l_obj, (cast(lu_mem, 1) << (sizeof(l_obj) * CHAR_BIT - 1)) - 1)
+#define MAX_LMEM  \
+	cast(l_mem, (cast(lu_mem, 1) << (sizeof(l_mem) * 8 - 1)) - 1)
 
 
 /* chars used as small naturals (so that 'char' is reserved for characters) */
diff --git a/lmem.c b/lmem.c
index f18ea172..de8503d9 100644
--- a/lmem.c
+++ b/lmem.c
@@ -151,7 +151,7 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
   global_State *g = G(L);
   lua_assert((osize == 0) == (block == NULL));
   callfrealloc(g, block, osize, 0);
-  g->GCtotalbytes -= osize;
+  g->GCdebt += cast(l_mem, osize);
 }
 
 
@@ -181,10 +181,10 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
   if (l_unlikely(newblock == NULL && nsize > 0)) {
     newblock = tryagain(L, block, osize, nsize);
     if (newblock == NULL)  /* still no memory? */
-      return NULL;  /* do not update 'GCtotalbytes' */
+      return NULL;  /* do not update 'GCdebt' */
   }
   lua_assert((nsize == 0) == (newblock == NULL));
-  g->GCtotalbytes += nsize - osize;
+  g->GCdebt -= cast(l_mem, nsize) - cast(l_mem, osize);
   return newblock;
 }
 
@@ -209,7 +209,7 @@ void *luaM_malloc_ (lua_State *L, size_t size, int tag) {
       if (newblock == NULL)
         luaM_error(L);
     }
-    g->GCtotalbytes += size;
+    g->GCdebt -= cast(l_mem, size);
     return newblock;
   }
 }
diff --git a/lobject.c b/lobject.c
index f7159547..1ca03e76 100644
--- a/lobject.c
+++ b/lobject.c
@@ -85,7 +85,7 @@ lu_byte luaO_codeparam (unsigned int p) {
 ** more significant bits, as long as the multiplication does not
 ** overflow, so we check which order is best.
 */
-l_obj luaO_applyparam (lu_byte p, l_obj x) {
+l_mem luaO_applyparam (lu_byte p, l_mem x) {
   unsigned int m = p & 0xF;  /* mantissa */
   int e = (p >> 4);  /* exponent */
   if (e > 0) {  /* normalized? */
@@ -94,19 +94,19 @@ l_obj luaO_applyparam (lu_byte p, l_obj x) {
   }
   e -= 7;  /* correct excess-7 */
   if (e >= 0) {
-    if (x < (MAX_LOBJ / 0x1F) >> e)  /* no overflow? */
+    if (x < (MAX_LMEM / 0x1F) >> e)  /* no overflow? */
       return (x * m) << e;  /* order doesn't matter here */
     else  /* real overflow */
-      return MAX_LOBJ;
+      return MAX_LMEM;
   }
   else {  /* negative exponent */
     e = -e;
-    if (x < MAX_LOBJ / 0x1F)  /* multiplication cannot overflow? */
+    if (x < MAX_LMEM / 0x1F)  /* multiplication cannot overflow? */
       return (x * m) >> e;  /* multiplying first gives more precision */
-    else if ((x >> e) <  MAX_LOBJ / 0x1F)  /* cannot overflow after shift? */
+    else if ((x >> e) <  MAX_LMEM / 0x1F)  /* cannot overflow after shift? */
       return (x >> e) * m;
     else  /* real overflow */
-      return MAX_LOBJ;
+      return MAX_LMEM;
   }
 }
 
diff --git a/lobject.h b/lobject.h
index fb66dff7..2411410b 100644
--- a/lobject.h
+++ b/lobject.h
@@ -838,7 +838,7 @@ typedef struct Table {
 LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x);
 LUAI_FUNC lu_byte luaO_ceillog2 (unsigned int x);
 LUAI_FUNC lu_byte luaO_codeparam (unsigned int p);
-LUAI_FUNC l_obj luaO_applyparam (lu_byte p, l_obj x);
+LUAI_FUNC l_mem luaO_applyparam (lu_byte p, l_mem x);
 
 LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1,
                              const TValue *p2, TValue *res);
diff --git a/lstate.c b/lstate.c
index f4c9081d..8e7c8b86 100644
--- a/lstate.c
+++ b/lstate.c
@@ -77,12 +77,12 @@ typedef struct LG {
 ** objects (GCtotalobjs - GCdebt) invariant and avoiding overflows in
 ** 'GCtotalobjs'.
 */
-void luaE_setdebt (global_State *g, l_obj debt) {
-  l_obj tb = gettotalobjs(g);
+void luaE_setdebt (global_State *g, l_mem debt) {
+  l_mem tb = gettotalbytes(g);
   lua_assert(tb > 0);
-  if (debt > MAX_LOBJ - tb)
-    debt = MAX_LOBJ - tb;  /* will make GCtotalobjs == MAX_LOBJ */
-  g->GCtotalobjs = tb + debt;
+  if (debt > MAX_LMEM - tb)
+    debt = MAX_LMEM - tb;  /* will make GCtotalbytes == MAX_LMEM */
+  g->GCtotalbytes = tb + debt;
   g->GCdebt = debt;
 }
 
@@ -269,8 +269,7 @@ static void close_state (lua_State *L) {
   }
   luaM_freearray(L, G(L)->strt.hash, cast_sizet(G(L)->strt.size));
   freestack(L);
-  lua_assert(g->GCtotalbytes == sizeof(LG));
-  lua_assert(gettotalobjs(g) == 1);
+  lua_assert(gettotalbytes(g) == sizeof(LG));
   (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0);  /* free main block */
 }
 
@@ -379,7 +378,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud, unsigned seed) {
   g->weak = g->ephemeron = g->allweak = NULL;
   g->twups = NULL;
   g->GCtotalbytes = sizeof(LG);
-  g->GCtotalobjs = 1;
   g->GCmarked = 0;
   g->GCdebt = 0;
   setivalue(&g->nilvalue, 0);  /* to signal that state is not yet built */
diff --git a/lstate.h b/lstate.h
index 6aa02889..2a03576d 100644
--- a/lstate.h
+++ b/lstate.h
@@ -274,11 +274,10 @@ struct CallInfo {
 typedef struct global_State {
   lua_Alloc frealloc;  /* function to reallocate memory */
   void *ud;         /* auxiliary data to 'frealloc' */
-  lu_mem GCtotalbytes;  /* number of bytes currently allocated */
-  l_obj GCtotalobjs;  /* total number of objects allocated + GCdebt */
-  l_obj GCdebt;  /* objects counted but not yet allocated */
-  l_obj GCmarked;  /* number of objects marked in a GC cycle */
-  l_obj GCmajorminor;  /* auxiliary counter to control major-minor shifts */
+  l_mem GCtotalbytes;  /* number of bytes currently allocated + debt */
+  l_mem GCdebt;  /* bytes counted but not yet allocated */
+  l_mem GCmarked;  /* number of objects marked in a GC cycle */
+  l_mem GCmajorminor;  /* auxiliary counter to control major-minor shifts */
   stringtable strt;  /* hash table for strings */
   TValue l_registry;
   TValue nilvalue;  /* a nil value */
@@ -411,11 +410,11 @@ union GCUnion {
 #define obj2gco(v)	check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc))
 
 
-/* actual number of total objects allocated */
-#define gettotalobjs(g)	((g)->GCtotalobjs - (g)->GCdebt)
+/* actual number of total memory allocated */
+#define gettotalbytes(g)	((g)->GCtotalbytes - (g)->GCdebt)
 
 
-LUAI_FUNC void luaE_setdebt (global_State *g, l_obj debt);
+LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
 LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
 LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
 LUAI_FUNC void luaE_shrinkCI (lua_State *L);
diff --git a/ltests.c b/ltests.c
index 7d134e2d..91bce2a1 100644
--- a/ltests.c
+++ b/ltests.c
@@ -537,7 +537,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead,
 }
 
 
-static l_obj checkgraylist (global_State *g, GCObject *o) {
+static l_mem checkgraylist (global_State *g, GCObject *o) {
   int total = 0;  /* count number of elements in the list */
   cast_void(g);  /* better to keep it if we need to print an object */
   while (o) {
@@ -566,8 +566,8 @@ static l_obj checkgraylist (global_State *g, GCObject *o) {
 /*
 ** Check objects in gray lists.
 */
-static l_obj checkgrays (global_State *g) {
-  l_obj total = 0;  /* count number of elements in all lists */
+static l_mem checkgrays (global_State *g) {
+  l_mem total = 0;  /* count number of elements in all lists */
   if (!keepinvariant(g)) return total;
   total += checkgraylist(g, g->gray);
   total += checkgraylist(g, g->grayagain);
@@ -583,7 +583,7 @@ static l_obj checkgrays (global_State *g) {
 ** 'count' and check its TESTBIT. (It must have been previously set by
 ** 'checkgraylist'.)
 */
-static void incifingray (global_State *g, GCObject *o, l_obj *count) {
+static void incifingray (global_State *g, GCObject *o, l_mem *count) {
   if (!keepinvariant(g))
     return;  /* gray lists not being kept in these phases */
   if (o->tt == LUA_VUPVAL) {
@@ -600,10 +600,10 @@ static void incifingray (global_State *g, GCObject *o, l_obj *count) {
 }
 
 
-static l_obj checklist (global_State *g, int maybedead, int tof,
+static l_mem checklist (global_State *g, int maybedead, int tof,
   GCObject *newl, GCObject *survival, GCObject *old, GCObject *reallyold) {
   GCObject *o;
-  l_obj total = 0;  /* number of object that should be in  gray lists */
+  l_mem total = 0;  /* number of object that should be in  gray lists */
   for (o = newl; o != survival; o = o->next) {
     checkobject(g, o, maybedead, G_NEW);
     incifingray(g, o, &total);
@@ -632,8 +632,8 @@ int lua_checkmemory (lua_State *L) {
   global_State *g = G(L);
   GCObject *o;
   int maybedead;
-  l_obj totalin;  /* total of objects that are in gray lists */
-  l_obj totalshould;  /* total of objects that should be in gray lists */
+  l_mem totalin;  /* total of objects that are in gray lists */
+  l_mem totalshould;  /* total of objects that should be in gray lists */
   if (keepinvariant(g)) {
     assert(!iswhite(g->mainthread));
     assert(!iswhite(gcvalue(&g->l_registry)));
@@ -1040,7 +1040,7 @@ static int table_query (lua_State *L) {
 
 static int query_GCparams (lua_State *L) {
   global_State *g = G(L);
-  lua_pushinteger(L, cast(lua_Integer, gettotalobjs(g)));
+  lua_pushinteger(L, cast(lua_Integer, gettotalbytes(g)));
   lua_pushinteger(L, cast(lua_Integer, g->GCdebt));
   lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MINORMUL, 100)));
   lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MAJORMINOR, 100)));