Commits

Laurens Rodriguez committed e9c4cf1

merging changes from Lua 5.2.2

  • Participants
  • Parent commits 7fe5e9a

Comments (0)

Files changed (43)

File src/libraries/lua52/lapi.c

 /*
-** $Id: lapi.c,v 2.159 2011/11/30 12:32:05 roberto Exp $
+** $Id: lapi.c,v 2.171 2013/03/16 21:10:18 roberto Exp $
 ** Lua API
 ** See Copyright Notice in lua.h
 */
 /* corresponding test */
 #define isvalid(o)	((o) != luaO_nilobject)
 
-#define api_checkvalidindex(L, i)  api_check(L, isvalid(i), "invalid index")
+/* test for pseudo index */
+#define ispseudo(i)		((i) <= LUA_REGISTRYINDEX)
+
+/* test for valid but not pseudo index */
+#define isstackindex(i, o)	(isvalid(o) && !ispseudo(i))
+
+#define api_checkvalidindex(L, o)  api_check(L, isvalid(o), "invalid index")
+
+#define api_checkstackindex(L, i, o)  \
+	api_check(L, isstackindex(i, o), "index not in the stack")
 
 
 static TValue *index2addr (lua_State *L, int idx) {
     if (o >= L->top) return NONVALIDVALUE;
     else return o;
   }
-  else if (idx > LUA_REGISTRYINDEX) {
+  else if (!ispseudo(idx)) {  /* negative index */
     api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
     return L->top + idx;
   }
 ** convert an acceptable stack index into an absolute index
 */
 LUA_API int lua_absindex (lua_State *L, int idx) {
-  return (idx > 0 || idx <= LUA_REGISTRYINDEX)
+  return (idx > 0 || ispseudo(idx))
          ? idx
          : cast_int(L->top - L->ci->func + idx);
 }
   StkId p;
   lua_lock(L);
   p = index2addr(L, idx);
-  api_checkvalidindex(L, p);
+  api_checkstackindex(L, idx, p);
   while (++p < L->top) setobjs2s(L, p-1, p);
   L->top--;
   lua_unlock(L);
   StkId q;
   lua_lock(L);
   p = index2addr(L, idx);
-  api_checkvalidindex(L, p);
-  for (q = L->top; q>p; q--) setobjs2s(L, q, q-1);
+  api_checkstackindex(L, idx, p);
+  for (q = L->top; q > p; q--)  /* use L->top as a temporary */
+    setobjs2s(L, q, q - 1);
   setobjs2s(L, p, L->top);
   lua_unlock(L);
 }
   TValue *fr;
   lua_lock(L);
   fr = index2addr(L, fromidx);
-  api_checkvalidindex(L, fr);
   moveto(L, fr, toidx);
   lua_unlock(L);
 }
 }
 
 
-LUA_API void  lua_arith (lua_State *L, int op) {
+LUA_API void lua_arith (lua_State *L, int op) {
   StkId o1;  /* 1st operand */
   StkId o2;  /* 2nd operand */
   lua_lock(L);
   o1 = L->top - 2;
   o2 = L->top - 1;
   if (ttisnumber(o1) && ttisnumber(o2)) {
-    changenvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2)));
+    setnvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2)));
   }
   else
     luaV_arith(L, o1, o1, o2, cast(TMS, op - LUA_OPADD + TM_ADD));
   StkId t;
   lua_lock(L);
   t = index2addr(L, idx);
-  api_checkvalidindex(L, t);
   luaV_gettable(L, t, L->top - 1, L->top - 1);
   lua_unlock(L);
 }
   StkId t;
   lua_lock(L);
   t = index2addr(L, idx);
-  api_checkvalidindex(L, t);
   setsvalue2s(L, L->top, luaS_new(L, k));
   api_incr_top(L);
   luaV_gettable(L, t, L->top - 1, L->top - 1);
   StkId o;
   lua_lock(L);
   o = index2addr(L, idx);
-  api_checkvalidindex(L, o);
   api_check(L, ttisuserdata(o), "userdata expected");
   if (uvalue(o)->env) {
     sethvalue(L, L->top, uvalue(o)->env);
   lua_lock(L);
   api_checknelems(L, 2);
   t = index2addr(L, idx);
-  api_checkvalidindex(L, t);
   luaV_settable(L, t, L->top - 2, L->top - 1);
   L->top -= 2;  /* pop index and value */
   lua_unlock(L);
   lua_lock(L);
   api_checknelems(L, 1);
   t = index2addr(L, idx);
-  api_checkvalidindex(L, t);
   setsvalue2s(L, L->top++, luaS_new(L, k));
   luaV_settable(L, t, L->top - 1, L->top - 2);
   L->top -= 2;  /* pop value and key */
   lua_lock(L);
   api_checknelems(L, 1);
   obj = index2addr(L, objindex);
-  api_checkvalidindex(L, obj);
   if (ttisnil(L->top - 1))
     mt = NULL;
   else {
   switch (ttypenv(obj)) {
     case LUA_TTABLE: {
       hvalue(obj)->metatable = mt;
-      if (mt)
+      if (mt) {
         luaC_objbarrierback(L, gcvalue(obj), mt);
         luaC_checkfinalizer(L, gcvalue(obj), mt);
+      }
       break;
     }
     case LUA_TUSERDATA: {
   lua_lock(L);
   api_checknelems(L, 1);
   o = index2addr(L, idx);
-  api_checkvalidindex(L, o);
   api_check(L, ttisuserdata(o), "userdata expected");
   if (ttisnil(L->top - 1))
     uvalue(o)->env = NULL;
     func = 0;
   else {
     StkId o = index2addr(L, errfunc);
-    api_checkvalidindex(L, o);
+    api_checkstackindex(L, errfunc, o);
     func = savestack(L, o);
   }
   c.func = L->top - (nargs+1);  /* function to be called */
     ci->u.c.k = k;  /* save continuation */
     ci->u.c.ctx = ctx;  /* save context */
     /* save information for error recovery */
-    ci->u.c.extra = savestack(L, c.func);
+    ci->extra = savestack(L, c.func);
     ci->u.c.old_allowhook = L->allowhook;
     ci->u.c.old_errfunc = L->errfunc;
     L->errfunc = func;
 }
 
 
-LUA_API int  lua_status (lua_State *L) {
+LUA_API int lua_status (lua_State *L) {
   return L->status;
 }
 
     }
     case LUA_GCSTEP: {
       if (g->gckind == KGC_GEN) {  /* generational mode? */
-        res = (g->lastmajormem == 0);  /* 1 if will do major collection */
+        res = (g->GCestimate == 0);  /* true if it will do major collection */
         luaC_forcestep(L);  /* do a single step */
       }
       else {
-        while (data-- >= 0) {
-          luaC_forcestep(L);
-          if (g->gcstate == GCSpause) {  /* end of cycle? */
-            res = 1;  /* signal it */
-            break;
-          }
-        }
+       lu_mem debt = cast(lu_mem, data) * 1024 - GCSTEPSIZE;
+       if (g->gcrunning)
+         debt += g->GCdebt;  /* include current debt */
+       luaE_setdebt(g, debt);
+       luaC_forcestep(L);
+       if (g->gcstate == GCSpause)  /* end of cycle? */
+         res = 1;  /* signal it */
       }
       break;
     }
   lua_lock(L);
   api_checknelems(L, 1);
   luaG_errormsg(L);
-  lua_unlock(L);
+  /* code unreachable; will unlock when control actually leaves the kernel */
   return 0;  /* to avoid warnings */
 }
 

File src/libraries/lua52/lauxlib.c

 /*
-** $Id: lauxlib.c,v 1.240 2011/12/06 16:33:55 roberto Exp $
+** $Id: lauxlib.c,v 1.248 2013/03/21 13:54:57 roberto Exp $
 ** Auxiliary functions for building Lua libraries
 ** See Copyright Notice in lua.h
 */
   if (*ar->namewhat != '\0')  /* is there a name? */
     lua_pushfstring(L, "function " LUA_QS, ar->name);
   else if (*ar->what == 'm')  /* main? */
-      lua_pushfstring(L, "main chunk");
+      lua_pushliteral(L, "main chunk");
   else if (*ar->what == 'C') {
     if (pushglobalfuncname(L, ar)) {
       lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1));
   if (strcmp(ar.namewhat, "method") == 0) {
     narg--;  /* do not count `self' */
     if (narg == 0)  /* error is in the self argument itself? */
-      return luaL_error(L, "calling " LUA_QS " on bad self", ar.name);
+      return luaL_error(L, "calling " LUA_QS " on bad self (%s)",
+                           ar.name, extramsg);
   }
   if (ar.name == NULL)
     ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
     if (fname)
       lua_pushfstring(L, "%s: %s", fname, strerror(en));
     else
-      lua_pushfstring(L, "%s", strerror(en));
+      lua_pushstring(L, strerror(en));
     lua_pushinteger(L, en);
     return 3;
   }
   if (B->size - B->n < sz) {  /* not enough space? */
     char *newbuff;
     size_t newsize = B->size * 2;  /* double buffer size */
-    if (newsize - B->n < sz)  /* not bit enough? */
+    if (newsize - B->n < sz)  /* not big enough? */
       newsize = B->n + sz;
     if (newsize < B->n || newsize - B->n < sz)
       luaL_error(L, "buffer too large");
 
 LUALIB_API int luaL_ref (lua_State *L, int t) {
   int ref;
-  t = lua_absindex(L, t);
   if (lua_isnil(L, -1)) {
     lua_pop(L, 1);  /* remove from stack */
     return LUA_REFNIL;  /* `nil' has a unique fixed reference */
   }
+  t = lua_absindex(L, t);
   lua_rawgeti(L, t, freelist);  /* get first free element */
   ref = (int)lua_tointeger(L, -1);  /* ref = t[freelist] */
   lua_pop(L, 1);  /* remove it from stack */
   lf->n = 0;
   do {
     c = getc(lf->f);
-    if (c == EOF || c != *(unsigned char *)p++) return c;
+    if (c == EOF || c != *(const unsigned char *)p++) return c;
     lf->buff[lf->n++] = c;  /* to be read by the parser */
   } while (*p != '\0');
   lf->n = 0;  /* prefix matched; discard it */
 static int skipcomment (LoadF *lf, int *cp) {
   int c = *cp = skipBOM(lf);
   if (c == '#') {  /* first line is a comment (Unix exec. file)? */
-    while ((c = getc(lf->f)) != EOF && c != '\n') ;  /* skip first line */
-    *cp = getc(lf->f);  /* skip end-of-line */
+    do {  /* skip first line */
+      c = getc(lf->f);
+    } while (c != EOF && c != '\n') ;
+    *cp = getc(lf->f);  /* skip end-of-line, if present */
     return 1;  /* there was a comment */
   }
   else return 0;  /* no comment */
 ** Returns with only the table at the stack.
 */
 LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
+  luaL_checkversion(L);
   luaL_checkstack(L, nup, "too many upvalues");
   for (; l->name != NULL; l++) {  /* fill the table with given functions */
     int i;
   lua_getfield(L, idx, fname);
   if (lua_istable(L, -1)) return 1;  /* table already there */
   else {
+    lua_pop(L, 1);  /* remove previous result */
     idx = lua_absindex(L, idx);
-    lua_pop(L, 1);  /* remove previous result */
     lua_newtable(L);
     lua_pushvalue(L, -1);  /* copy to be left at top */
     lua_setfield(L, idx, fname);  /* assign new table to field */
   lua_setfield(L, -2, modname);  /* _LOADED[modname] = module */
   lua_pop(L, 1);  /* remove _LOADED table */
   if (glb) {
-    lua_pushglobaltable(L);
-    lua_pushvalue(L, -2);  /* copy of 'mod' */
-    lua_setfield(L, -2, modname);  /* _G[modname] = module */
-    lua_pop(L, 1);  /* remove _G table */
+    lua_pushvalue(L, -1);  /* copy of 'mod' */
+    lua_setglobal(L, modname);  /* _G[modname] = module */
   }
 }
 
   lua_pop(L, 1);
 }
 
-
-LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) {
-  const char *msg = lua_pushfstring(L, "%s expected, got %s",
-                                    tname, luaL_typename(L, narg));
-  return luaL_argerror(L, narg, msg);
-}
-
-

File src/libraries/lua52/lauxlib.h

 #endif
 
 
-LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
-
 #endif
 
 

File src/libraries/lua52/lbaselib.c

 /*
-** $Id: lbaselib.c,v 1.273 2011/11/30 13:03:24 roberto Exp $
+** $Id: lbaselib.c,v 1.276 2013/02/21 13:44:53 roberto Exp $
 ** Basic library
 ** See Copyright Notice in lua.h
 */
 }
 
 
-static int load_aux (lua_State *L, int status) {
-  if (status == LUA_OK)
+static int load_aux (lua_State *L, int status, int envidx) {
+  if (status == LUA_OK) {
+    if (envidx != 0) {  /* 'env' parameter? */
+      lua_pushvalue(L, envidx);  /* environment for loaded function */
+      if (!lua_setupvalue(L, -2, 1))  /* set it as 1st upvalue */
+        lua_pop(L, 1);  /* remove 'env' if not used by previous call */
+    }
     return 1;
-  else {
+  }
+  else {  /* error (message is on top of the stack) */
     lua_pushnil(L);
     lua_insert(L, -2);  /* put before error message */
     return 2;  /* return nil plus error message */
 static int luaB_loadfile (lua_State *L) {
   const char *fname = luaL_optstring(L, 1, NULL);
   const char *mode = luaL_optstring(L, 2, NULL);
-  int env = !lua_isnone(L, 3);  /* 'env' parameter? */
+  int env = (!lua_isnone(L, 3) ? 3 : 0);  /* 'env' index or 0 if no 'env' */
   int status = luaL_loadfilex(L, fname, mode);
-  if (status == LUA_OK && env) {  /* 'env' parameter? */
-    lua_pushvalue(L, 3);
-    lua_setupvalue(L, -2, 1);  /* set it as 1st upvalue of loaded chunk */
-  }
-  return load_aux(L, status);
+  return load_aux(L, status, env);
 }
 
 
   lua_pushvalue(L, 1);  /* get function */
   lua_call(L, 0, 1);  /* call it */
   if (lua_isnil(L, -1)) {
+    lua_pop(L, 1);  /* pop result */
     *size = 0;
     return NULL;
   }
 static int luaB_load (lua_State *L) {
   int status;
   size_t l;
-  int top = lua_gettop(L);
   const char *s = lua_tolstring(L, 1, &l);
   const char *mode = luaL_optstring(L, 3, "bt");
+  int env = (!lua_isnone(L, 4) ? 4 : 0);  /* 'env' index or 0 if no 'env' */
   if (s != NULL) {  /* loading a string? */
     const char *chunkname = luaL_optstring(L, 2, s);
     status = luaL_loadbufferx(L, s, l, chunkname, mode);
     lua_settop(L, RESERVEDSLOT);  /* create reserved slot */
     status = lua_load(L, generic_reader, NULL, chunkname, mode);
   }
-  if (status == LUA_OK && top >= 4) {  /* is there an 'env' argument */
-    lua_pushvalue(L, 4);  /* environment for loaded function */
-    lua_setupvalue(L, -2, 1);  /* set it as 1st upvalue */
-  }
-  return load_aux(L, status);
+  return load_aux(L, status, env);
 }
 
 /* }====================================================== */
 static int luaB_dofile (lua_State *L) {
   const char *fname = luaL_optstring(L, 1, NULL);
   lua_settop(L, 1);
-  if (luaL_loadfile(L, fname) != LUA_OK) lua_error(L);
+  if (luaL_loadfile(L, fname) != LUA_OK)
+    return lua_error(L);
   lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
   return dofilecont(L);
 }

File src/libraries/lua52/lbitlib.c

 /*
-** $Id: lbitlib.c,v 1.16 2011/06/20 16:35:23 roberto Exp $
+** $Id: lbitlib.c,v 1.18 2013/03/19 13:19:12 roberto Exp $
 ** Standard library for bitwise operations
 ** See Copyright Notice in lua.h
 */
 
 /*
 ** get field and width arguments for field-manipulation functions,
-** checking whether they are valid
+** checking whether they are valid.
+** ('luaL_error' called without 'return' to avoid later warnings about
+** 'width' being used uninitialized.)
 */
 static int fieldargs (lua_State *L, int farg, int *width) {
   int f = luaL_checkint(L, farg);

File src/libraries/lua52/lcode.c

 /*
-** $Id: lcode.c,v 2.60 2011/08/30 16:26:41 roberto Exp $
+** $Id: lcode.c,v 2.62 2012/08/16 17:34:28 roberto Exp $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
   setnvalue(&o, r);
   if (r == 0 || luai_numisnan(NULL, r)) {  /* handle -0 and NaN */
     /* use raw representation as key to avoid numeric problems */
-    setsvalue(L, L->top, luaS_newlstr(L, (char *)&r, sizeof(r)));
-     incr_top(L);
-     n = addk(fs, L->top - 1, &o);
-     L->top--;
+    setsvalue(L, L->top++, luaS_newlstr(L, (char *)&r, sizeof(r)));
+    n = addk(fs, L->top - 1, &o);
+    L->top--;
   }
   else
     n = addk(fs, &o, &o);  /* regular case */
       luaK_nil(fs, reg, 1);
       break;
     }
-    case VFALSE:  case VTRUE: {
+    case VFALSE: case VTRUE: {
       luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
       break;
     }

File src/libraries/lua52/lcorolib.c

 /*
-** $Id: lcorolib.c,v 1.3 2011/08/23 17:24:34 roberto Exp $
+** $Id: lcorolib.c,v 1.5 2013/02/21 13:44:53 roberto Exp $
 ** Coroutine Library
 ** See Copyright Notice in lua.h
 */
       lua_insert(L, -2);
       lua_concat(L, 2);
     }
-    lua_error(L);  /* propagate error */
+    return lua_error(L);  /* propagate error */
   }
   return r;
 }
 
 
 static int luaB_cocreate (lua_State *L) {
-  lua_State *NL = lua_newthread(L);
+  lua_State *NL;
   luaL_checktype(L, 1, LUA_TFUNCTION);
+  NL = lua_newthread(L);
   lua_pushvalue(L, 1);  /* move function to top */
   lua_xmove(L, NL, 1);  /* move function from L to NL */
   return 1;

File src/libraries/lua52/ldblib.c

 /*
-** $Id: ldblib.c,v 1.131 2011/10/24 14:54:05 roberto Exp $
+** $Id: ldblib.c,v 1.132 2012/01/19 20:14:44 roberto Exp $
 ** Interface from Lua to its debug API
 ** See Copyright Notice in lua.h
 */
 }
 
 
-#define gethooktable(L)	luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY);
+#define gethooktable(L)	luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)
 
 
 static void hookf (lua_State *L, lua_Debug *ar) {
   static const char *const hooknames[] =
     {"call", "return", "line", "count", "tail call"};
   gethooktable(L);
-  lua_rawgetp(L, -1, L);
+  lua_pushthread(L);
+  lua_rawget(L, -2);
   if (lua_isfunction(L, -1)) {
     lua_pushstring(L, hooknames[(int)ar->event]);
     if (ar->currentline >= 0)
     count = luaL_optint(L, arg+3, 0);
     func = hookf; mask = makemask(smask, count);
   }
-  gethooktable(L);
+  if (gethooktable(L) == 0) {  /* creating hook table? */
+    lua_pushstring(L, "k");
+    lua_setfield(L, -2, "__mode");  /** hooktable.__mode = "k" */
+    lua_pushvalue(L, -1);
+    lua_setmetatable(L, -2);  /* setmetatable(hooktable) = hooktable */
+  }
+  lua_pushthread(L1); lua_xmove(L1, L, 1);
   lua_pushvalue(L, arg+1);
-  lua_rawsetp(L, -2, L1);  /* set new hook */
-  lua_pop(L, 1);  /* remove hook table */
+  lua_rawset(L, -3);  /* set new hook */
   lua_sethook(L1, func, mask, count);  /* set hooks */
   return 0;
 }
     lua_pushliteral(L, "external hook");
   else {
     gethooktable(L);
-    lua_rawgetp(L, -1, L1);   /* get hook */
+    lua_pushthread(L1); lua_xmove(L1, L, 1);
+    lua_rawget(L, -2);   /* get hook */
     lua_remove(L, -2);  /* remove hook table */
   }
   lua_pushstring(L, unmakemask(mask, buff));

File src/libraries/lua52/ldebug.c

 /*
-** $Id: ldebug.c,v 2.88 2011/11/30 12:43:51 roberto Exp $
+** $Id: ldebug.c,v 2.90 2012/08/16 17:34:28 roberto Exp $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
 
 
 
+#define noLuaClosure(f)		((f) == NULL || (f)->c.tt == LUA_TCCL)
+
+
 static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
 
 
 
 
 static void funcinfo (lua_Debug *ar, Closure *cl) {
-  if (cl == NULL || cl->c.isC) {
+  if (noLuaClosure(cl)) {
     ar->source = "=[C]";
     ar->linedefined = -1;
     ar->lastlinedefined = -1;
 
 
 static void collectvalidlines (lua_State *L, Closure *f) {
-  if (f == NULL || f->c.isC) {
+  if (noLuaClosure(f)) {
     setnilvalue(L->top);
-    incr_top(L);
+    api_incr_top(L);
   }
   else {
     int i;
     int *lineinfo = f->l.p->lineinfo;
     Table *t = luaH_new(L);  /* new table to store active lines */
     sethvalue(L, L->top, t);  /* push it on stack */
-    incr_top(L);
+    api_incr_top(L);
     setbvalue(&v, 1);  /* boolean 'true' to be the value of all indices */
     for (i = 0; i < f->l.p->sizelineinfo; i++)  /* for all lines with code */
       luaH_setint(L, t, lineinfo[i], &v);  /* table[line] = true */
 
 
 static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
-                    Closure *f, CallInfo *ci) {
+                       Closure *f, CallInfo *ci) {
   int status = 1;
   for (; *what; what++) {
     switch (*what) {
       }
       case 'u': {
         ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
-        if (f == NULL || f->c.isC) {
+        if (noLuaClosure(f)) {
           ar->isvararg = 1;
           ar->nparams = 0;
         }
   status = auxgetinfo(L, what, ar, cl, ci);
   if (strchr(what, 'f')) {
     setobjs2s(L, L->top, func);
-    incr_top(L);
+    api_incr_top(L);
   }
   if (strchr(what, 'L'))
     collectvalidlines(L, cl);
     if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR);
     setobjs2s(L, L->top, L->top - 1);  /* move argument */
     setobjs2s(L, L->top - 1, errfunc);  /* push function */
-    incr_top(L);
+    L->top++;
     luaD_call(L, L->top - 2, 1, 0);  /* call it */
   }
   luaD_throw(L, LUA_ERRRUN);

File src/libraries/lua52/ldo.c

 /*
-** $Id: ldo.c,v 2.102 2011/11/29 15:55:08 roberto Exp $
+** $Id: ldo.c,v 2.108 2012/10/01 14:05:04 roberto Exp $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
       ci->top = L->top + LUA_MINSTACK;
       lua_assert(ci->top <= L->stack_last);
       ci->callstatus = 0;
+      luaC_checkGC(L);  /* stack grow uses memory */
       if (L->hookmask & LUA_MASKCALL)
         luaD_hook(L, LUA_HOOKCALL, -1);
       lua_unlock(L);
       ci->u.l.savedpc = p->code;  /* starting point */
       ci->callstatus = CIST_LUA;
       L->top = ci->top;
+      luaC_checkGC(L);  /* stack grow uses memory */
       if (L->hookmask & LUA_MASKCALL)
         callhook(L, ci);
       return 0;
     luaV_execute(L);  /* call it */
   if (!allowyield) L->nny--;
   L->nCcalls--;
-  luaC_checkGC(L);
 }
 
 
   int n;
   lua_assert(ci->u.c.k != NULL);  /* must have a continuation */
   lua_assert(L->nny == 0);
-  /* finish 'luaD_call' */
-  L->nCcalls--;
-  /* finish 'lua_callk' */
+  if (ci->callstatus & CIST_YPCALL) {  /* was inside a pcall? */
+    ci->callstatus &= ~CIST_YPCALL;  /* finish 'lua_pcall' */
+    L->errfunc = ci->u.c.old_errfunc;
+  }
+  /* finish 'lua_callk'/'lua_pcall' */
   adjustresults(L, ci->nresults);
   /* call continuation function */
   if (!(ci->callstatus & CIST_STAT))  /* no call status? */
   CallInfo *ci = findpcall(L);
   if (ci == NULL) return 0;  /* no recovery point */
   /* "finish" luaD_pcall */
-  oldtop = restorestack(L, ci->u.c.extra);
+  oldtop = restorestack(L, ci->extra);
   luaF_close(L, oldtop);
   seterrorobj(L, status, oldtop);
   L->ci = ci;
 static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
   L->top = firstArg;  /* remove args from the stack */
   setsvalue2s(L, L->top, luaS_new(L, msg));  /* push error message */
-  incr_top(L);
+  api_incr_top(L);
   luaD_throw(L, -1);  /* jump back to 'lua_resume' */
 }
 
 ** do the work for 'lua_resume' in protected mode
 */
 static void resume (lua_State *L, void *ud) {
+  int nCcalls = L->nCcalls;
   StkId firstArg = cast(StkId, ud);
   CallInfo *ci = L->ci;
-  if (L->nCcalls >= LUAI_MAXCCALLS)
+  if (nCcalls >= LUAI_MAXCCALLS)
     resume_error(L, "C stack overflow", firstArg);
   if (L->status == LUA_OK) {  /* may be starting a coroutine */
     if (ci != &L->base_ci)  /* not in base level? */
     resume_error(L, "cannot resume dead coroutine", firstArg);
   else {  /* resuming from previous yield */
     L->status = LUA_OK;
+    ci->func = restorestack(L, ci->extra);
     if (isLua(ci))  /* yielded inside a hook? */
       luaV_execute(L);  /* just continue running Lua code */
     else {  /* 'common' yield */
-      ci->func = restorestack(L, ci->u.c.extra);
       if (ci->u.c.k != NULL) {  /* does it have a continuation? */
         int n;
         ci->u.c.status = LUA_YIELD;  /* 'default' status */
         api_checknelems(L, n);
         firstArg = L->top - n;  /* yield results come from continuation */
       }
-      L->nCcalls--;  /* finish 'luaD_call' */
       luaD_poscall(L, firstArg);  /* finish 'luaD_precall' */
     }
     unroll(L, NULL);
   }
+  lua_assert(nCcalls == L->nCcalls);
 }
 
 
   api_checknelems(L, nresults);
   if (L->nny > 0) {
     if (L != G(L)->mainthread)
-      luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
+      luaG_runerror(L, "attempt to yield across a C-call boundary");
     else
       luaG_runerror(L, "attempt to yield from outside a coroutine");
   }
   L->status = LUA_YIELD;
+  ci->extra = savestack(L, ci->func);  /* save current 'func' */
   if (isLua(ci)) {  /* inside a hook? */
     api_check(L, k == NULL, "hooks cannot continue after yielding");
   }
   else {
     if ((ci->u.c.k = k) != NULL)  /* is there a continuation? */
       ci->u.c.ctx = ctx;  /* save context */
-    ci->u.c.extra = savestack(L, ci->func);  /* save current 'func' */
     ci->func = L->top - nresults - 1;  /* protect stack below results */
     luaD_throw(L, LUA_YIELD);
   }
 
 static void f_parser (lua_State *L, void *ud) {
   int i;
-  Proto *tf;
   Closure *cl;
   struct SParser *p = cast(struct SParser *, ud);
   int c = zgetc(p->z);  /* read first character */
   if (c == LUA_SIGNATURE[0]) {
     checkmode(L, p->mode, "binary");
-    tf = luaU_undump(L, p->z, &p->buff, p->name);
+    cl = luaU_undump(L, p->z, &p->buff, p->name);
   }
   else {
     checkmode(L, p->mode, "text");
-    tf = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
+    cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
   }
-  setptvalue2s(L, L->top, tf);
-  incr_top(L);
-  cl = luaF_newLclosure(L, tf);
-  setclLvalue(L, L->top - 1, cl);
-  for (i = 0; i < tf->sizeupvalues; i++)  /* initialize upvalues */
-    cl->l.upvals[i] = luaF_newupval(L);
+  lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);
+  for (i = 0; i < cl->l.nupvalues; i++) {  /* initialize upvalues */
+    UpVal *up = luaF_newupval(L);
+    cl->l.upvals[i] = up;
+    luaC_objbarrier(L, cl, up);
+  }
 }
 
 

File src/libraries/lua52/ldump.c

 /*
-** $Id: ldump.c,v 1.19 2011/11/23 17:48:18 lhf Exp $
+** $Id: ldump.c,v 2.17 2012/01/23 23:02:10 roberto Exp $
 ** save precompiled Lua chunks
 ** See Copyright Notice in lua.h
 */
  for (i=0; i<n; i++)
  {
   const TValue* o=&f->k[i];
-  DumpChar(ttype(o),D);
-  switch (ttype(o))
+  DumpChar(ttypenv(o),D);
+  switch (ttypenv(o))
   {
    case LUA_TNIL:
 	break;
    case LUA_TSTRING:
 	DumpString(rawtsvalue(o),D);
 	break;
+    default: lua_assert(0);
   }
  }
  n=f->sizep;

File src/libraries/lua52/lfunc.c

 /*
-** $Id: lfunc.c,v 2.27 2010/06/30 14:11:17 roberto Exp $
+** $Id: lfunc.c,v 2.30 2012/10/03 12:36:46 roberto Exp $
 ** Auxiliary functions to manipulate prototypes and closures
 ** See Copyright Notice in lua.h
 */
 
 
 Closure *luaF_newCclosure (lua_State *L, int n) {
-  Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeCclosure(n), NULL, 0)->cl;
-  c->c.isC = 1;
+  Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl;
   c->c.nupvalues = cast_byte(n);
   return c;
 }
 
 
-Closure *luaF_newLclosure (lua_State *L, Proto *p) {
-  int n = p->sizeupvalues;
-  Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeLclosure(n), NULL, 0)->cl;
-  c->l.isC = 0;
-  c->l.p = p;
+Closure *luaF_newLclosure (lua_State *L, int n) {
+  Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl;
+  c->l.p = NULL;
   c->l.nupvalues = cast_byte(n);
   while (n--) c->l.upvals[n] = NULL;
   return c;
   while (*pp != NULL && (p = gco2uv(*pp))->v >= level) {
     GCObject *o = obj2gco(p);
     lua_assert(p->v != &p->u.value);
+    lua_assert(!isold(o) || isold(obj2gco(L)));
     if (p->v == level) {  /* found a corresponding upvalue? */
       if (isdead(g, o))  /* is it dead? */
         changewhite(o);  /* resurrect it */
       return p;
     }
-    resetoldbit(o);  /* may create a newer upval after this one */
     pp = &p->next;
   }
   /* not found: create a new one */
 }
 
 
-void luaF_freeclosure (lua_State *L, Closure *c) {
-  int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) :
-                          sizeLclosure(c->l.nupvalues);
-  luaM_freemem(L, c, size);
-}
-
-
 /*
 ** Look for n-th local variable at line `line' in function `func'.
 ** Returns NULL if not found.

File src/libraries/lua52/lfunc.h

 /*
-** $Id: lfunc.h,v 2.6 2010/06/04 13:06:15 roberto Exp $
+** $Id: lfunc.h,v 2.8 2012/05/08 13:53:33 roberto Exp $
 ** Auxiliary functions to manipulate prototypes and closures
 ** See Copyright Notice in lua.h
 */
 
 LUAI_FUNC Proto *luaF_newproto (lua_State *L);
 LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems);
-LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, Proto *p);
+LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems);
 LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
 LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
 LUAI_FUNC void luaF_close (lua_State *L, StkId level);
 LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
-LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c);
 LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv);
 LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
                                          int pc);

File src/libraries/lua52/lgc.c

 /*
-** $Id: lgc.c,v 2.116 2011/12/02 13:18:41 roberto Exp $
+** $Id: lgc.c,v 2.140 2013/03/16 21:10:18 roberto Exp $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
 
 
 
-/* how much to allocate before next GC step */
-#define GCSTEPSIZE	1024
+/*
+** cost of sweeping one element (the size of a small object divided
+** by some adjust for the sweep speed)
+*/
+#define GCSWEEPCOST	((sizeof(TString) + 4) / 4)
 
 /* maximum number of elements to sweep in each single step */
-#define GCSWEEPMAX	40
-
-/* cost of sweeping one element */
-#define GCSWEEPCOST	1
+#define GCSWEEPMAX	(cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4))
 
 /* maximum number of finalizers to call in each GC step */
 #define GCFINALIZENUM	4
 
-/* cost of marking the root set */
-#define GCROOTCOST	10
-
-/* cost of atomic step */
-#define GCATOMICCOST	1000
-
-/* basic cost to traverse one object (to be added to the links the
-   object may have) */
-#define TRAVCOST	5
-
 
 /*
-** standard negative debt for GC; a reasonable "time" to wait before
-** starting a new cycle
+** macro to adjust 'stepmul': 'stepmul' is actually used like
+** 'stepmul / STEPMULADJ' (value chosen by tests)
 */
-#define stddebt(g)	(-cast(l_mem, gettotalbytes(g)/100) * g->gcpause)
+#define STEPMULADJ		200
+
+
+/*
+** macro to adjust 'pause': 'pause' is actually used like
+** 'pause / PAUSEADJ' (value chosen by tests)
+*/
+#define PAUSEADJ		100
 
 
 /*
 #define white2gray(x)	resetbits(gch(x)->marked, WHITEBITS)
 #define black2gray(x)	resetbit(gch(x)->marked, BLACKBIT)
 
-#define stringmark(s)	((void)((s) && resetbits((s)->tsv.marked, WHITEBITS)))
-
 
 #define isfinalized(x)		testbit(gch(x)->marked, FINALIZEDBIT)
 
 ** other objects: if really collected, cannot keep them; for objects
 ** being finalized, keep them in keys, but not in values
 */
-static int iscleared (const TValue *o) {
+static int iscleared (global_State *g, const TValue *o) {
   if (!iscollectable(o)) return 0;
   else if (ttisstring(o)) {
-    stringmark(rawtsvalue(o));  /* strings are `values', so are never weak */
+    markobject(g, rawtsvalue(o));  /* strings are `values', so are never weak */
     return 0;
   }
   else return iswhite(gcvalue(o));
 void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
   global_State *g = G(L);
   lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
-  lua_assert(isgenerational(g) || g->gcstate != GCSpause);
+  lua_assert(g->gcstate != GCSpause);
   lua_assert(gch(o)->tt != LUA_TTABLE);
-  if (keepinvariant(g))  /* must keep invariant? */
+  if (keepinvariantout(g))  /* must keep invariant? */
     reallymarkobject(g, v);  /* restore invariant */
   else {  /* sweep phase */
     lua_assert(issweepphase(g));
 GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
                        int offset) {
   global_State *g = G(L);
-  GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset);
+  char *raw = cast(char *, luaM_newobject(L, novariant(tt), sz));
+  GCObject *o = obj2gco(raw + offset);
   if (list == NULL)
     list = &g->allgc;  /* standard list for collectable objects */
   gch(o)->marked = luaC_white(g);
 
 
 /*
-** mark an object. Userdata and closed upvalues are visited and turned
-** black here. Strings remain gray (it is the same as making them
-** black). Other objects are marked gray and added to appropriate list
-** to be visited (and turned black) later. (Open upvalues are already
-** linked in 'headuv' list.)
+** mark an object. Userdata, strings, and closed upvalues are visited
+** and turned black here. Other objects are marked gray and added
+** to appropriate list to be visited (and turned black) later. (Open
+** upvalues are already linked in 'headuv' list.)
 */
 static void reallymarkobject (global_State *g, GCObject *o) {
-  lua_assert(iswhite(o) && !isdead(g, o));
+  lu_mem size;
   white2gray(o);
   switch (gch(o)->tt) {
-    case LUA_TSTRING: {
-      return;  /* for strings, gray is as good as black */
+    case LUA_TSHRSTR:
+    case LUA_TLNGSTR: {
+      size = sizestring(gco2ts(o));
+      break;  /* nothing else to mark; make it black */
     }
     case LUA_TUSERDATA: {
       Table *mt = gco2u(o)->metatable;
       markobject(g, mt);
       markobject(g, gco2u(o)->env);
-      gray2black(o);  /* all pointers marked */
-      return;
+      size = sizeudata(gco2u(o));
+      break;
     }
     case LUA_TUPVAL: {
       UpVal *uv = gco2uv(o);
       markvalue(g, uv->v);
-      if (uv->v == &uv->u.value)  /* closed? (open upvalues remain gray) */
-        gray2black(o);  /* make it black */
+      if (uv->v != &uv->u.value)  /* open? */
+        return;  /* open upvalues remain gray */
+      size = sizeof(UpVal);
+      break;
+    }
+    case LUA_TLCL: {
+      gco2lcl(o)->gclist = g->gray;
+      g->gray = o;
       return;
     }
-    case LUA_TFUNCTION: {
-      gco2cl(o)->c.gclist = g->gray;
+    case LUA_TCCL: {
+      gco2ccl(o)->gclist = g->gray;
       g->gray = o;
-      break;
+      return;
     }
     case LUA_TTABLE: {
       linktable(gco2t(o), &g->gray);
-      break;
+      return;
     }
     case LUA_TTHREAD: {
       gco2th(o)->gclist = g->gray;
       g->gray = o;
-      break;
+      return;
     }
     case LUA_TPROTO: {
       gco2p(o)->gclist = g->gray;
       g->gray = o;
-      break;
+      return;
     }
-    default: lua_assert(0);
+    default: lua_assert(0); return;
   }
+  gray2black(o);
+  g->GCmemtrav += size;
 }
 
 
 ** mark root set and reset all gray lists, to start a new
 ** incremental (or full) collection
 */
-static void markroot (global_State *g) {
+static void restartcollection (global_State *g) {
   g->gray = g->grayagain = NULL;
   g->weak = g->allweak = g->ephemeron = NULL;
   markobject(g, g->mainthread);
     else {
       lua_assert(!ttisnil(gkey(n)));
       markvalue(g, gkey(n));  /* mark key */
-      if (!hasclears && iscleared(gval(n)))  /* is there a white value? */
+      if (!hasclears && iscleared(g, gval(n)))  /* is there a white value? */
         hasclears = 1;  /* table will have to be cleared */
     }
   }
     checkdeadkey(n);
     if (ttisnil(gval(n)))  /* entry is empty? */
       removeentry(n);  /* remove it */
-    else if (iscleared(gkey(n))) {  /* key is not marked (yet)? */
+    else if (iscleared(g, gkey(n))) {  /* key is not marked (yet)? */
       hasclears = 1;  /* table must be cleared */
       if (valiswhite(gval(n)))  /* value not marked yet? */
         prop = 1;  /* must propagate again */
 }
 
 
-static int traversetable (global_State *g, Table *h) {
+static lu_mem traversetable (global_State *g, Table *h) {
+  const char *weakkey, *weakvalue;
   const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
   markobject(g, h->metatable);
-  if (mode && ttisstring(mode)) {  /* is there a weak mode? */
-    int weakkey = (strchr(svalue(mode), 'k') != NULL);
-    int weakvalue = (strchr(svalue(mode), 'v') != NULL);
-    if (weakkey || weakvalue) {  /* is really weak? */
-      black2gray(obj2gco(h));  /* keep table gray */
-      if (!weakkey) {  /* strong keys? */
-        traverseweakvalue(g, h);
-        return TRAVCOST + sizenode(h);
-      }
-      else if (!weakvalue) {  /* strong values? */
-        traverseephemeron(g, h);
-        return TRAVCOST + h->sizearray + sizenode(h);
-      }
-      else {
-        linktable(h, &g->allweak);  /* nothing to traverse now */
-        return TRAVCOST;
-      }
-    }  /* else go through */
+  if (mode && ttisstring(mode) &&  /* is there a weak mode? */
+      ((weakkey = strchr(svalue(mode), 'k')),
+       (weakvalue = strchr(svalue(mode), 'v')),
+       (weakkey || weakvalue))) {  /* is really weak? */
+    black2gray(obj2gco(h));  /* keep table gray */
+    if (!weakkey)  /* strong keys? */
+      traverseweakvalue(g, h);
+    else if (!weakvalue)  /* strong values? */
+      traverseephemeron(g, h);
+    else  /* all weak */
+      linktable(h, &g->allweak);  /* nothing to traverse now */
   }
-  traversestrongtable(g, h);
-  return TRAVCOST + h->sizearray + (2 * sizenode(h));
+  else  /* not weak */
+    traversestrongtable(g, h);
+  return sizeof(Table) + sizeof(TValue) * h->sizearray +
+                         sizeof(Node) * cast(size_t, sizenode(h));
 }
 
 
   int i;
   if (f->cache && iswhite(obj2gco(f->cache)))
     f->cache = NULL;  /* allow cache to be collected */
-  stringmark(f->source);
+  markobject(g, f->source);
   for (i = 0; i < f->sizek; i++)  /* mark literals */
     markvalue(g, &f->k[i]);
   for (i = 0; i < f->sizeupvalues; i++)  /* mark upvalue names */
-    stringmark(f->upvalues[i].name);
+    markobject(g, f->upvalues[i].name);
   for (i = 0; i < f->sizep; i++)  /* mark nested protos */
     markobject(g, f->p[i]);
   for (i = 0; i < f->sizelocvars; i++)  /* mark local-variable names */
-    stringmark(f->locvars[i].varname);
-  return TRAVCOST + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars;
+    markobject(g, f->locvars[i].varname);
+  return sizeof(Proto) + sizeof(Instruction) * f->sizecode +
+                         sizeof(Proto *) * f->sizep +
+                         sizeof(TValue) * f->sizek +
+                         sizeof(int) * f->sizelineinfo +
+                         sizeof(LocVar) * f->sizelocvars +
+                         sizeof(Upvaldesc) * f->sizeupvalues;
 }
 
 
-static int traverseclosure (global_State *g, Closure *cl) {
-  if (cl->c.isC) {
-    int i;
-    for (i=0; i<cl->c.nupvalues; i++)  /* mark its upvalues */
-      markvalue(g, &cl->c.upvalue[i]);
-  }
-  else {
-    int i;
-    lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);
-    markobject(g, cl->l.p);  /* mark its prototype */
-    for (i=0; i<cl->l.nupvalues; i++)  /* mark its upvalues */
-      markobject(g, cl->l.upvals[i]);
-  }
-  return TRAVCOST + cl->c.nupvalues;
+static lu_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 sizeCclosure(cl->nupvalues);
 }
 
+static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
+  int i;
+  markobject(g, cl->p);  /* mark its prototype */
+  for (i = 0; i < cl->nupvalues; i++)  /* mark its upvalues */
+    markobject(g, cl->upvals[i]);
+  return sizeLclosure(cl->nupvalues);
+}
 
-static int traversestack (global_State *g, lua_State *L) {
-  StkId o = L->stack;
+
+static lu_mem traversestack (global_State *g, lua_State *th) {
+  StkId o = th->stack;
   if (o == NULL)
     return 1;  /* stack not completely built yet */
-  for (; o < L->top; o++)
+  for (; o < th->top; o++)
     markvalue(g, o);
   if (g->gcstate == GCSatomic) {  /* final traversal? */
-    StkId lim = L->stack + L->stacksize;  /* real end of stack */
+    StkId lim = th->stack + th->stacksize;  /* real end of stack */
     for (; o < lim; o++)  /* clear not-marked stack slice */
       setnilvalue(o);
   }
-  return TRAVCOST + cast_int(o - L->stack);
+  return sizeof(lua_State) + sizeof(TValue) * th->stacksize;
 }
 
 
 /*
 ** traverse one gray object, turning it to black (except for threads,
 ** which are always gray).
-** Returns number of values traversed.
 */
-static int propagatemark (global_State *g) {
+static void propagatemark (global_State *g) {
+  lu_mem size;
   GCObject *o = g->gray;
   lua_assert(isgray(o));
   gray2black(o);
   switch (gch(o)->tt) {
     case LUA_TTABLE: {
       Table *h = gco2t(o);
-      g->gray = h->gclist;
-      return traversetable(g, h);
+      g->gray = h->gclist;  /* remove from 'gray' list */
+      size = traversetable(g, h);
+      break;
     }
-    case LUA_TFUNCTION: {
-      Closure *cl = gco2cl(o);
-      g->gray = cl->c.gclist;
-      return traverseclosure(g, cl);
+    case LUA_TLCL: {
+      LClosure *cl = gco2lcl(o);
+      g->gray = cl->gclist;  /* remove from 'gray' list */
+      size = traverseLclosure(g, cl);
+      break;
+    }
+    case LUA_TCCL: {
+      CClosure *cl = gco2ccl(o);
+      g->gray = cl->gclist;  /* remove from 'gray' list */
+      size = traverseCclosure(g, cl);
+      break;
     }
     case LUA_TTHREAD: {
       lua_State *th = gco2th(o);
-      g->gray = th->gclist;
+      g->gray = th->gclist;  /* remove from 'gray' list */
       th->gclist = g->grayagain;
-      g->grayagain = o;
+      g->grayagain = o;  /* insert into 'grayagain' list */
       black2gray(o);
-      return traversestack(g, th);
+      size = traversestack(g, th);
+      break;
     }
     case LUA_TPROTO: {
       Proto *p = gco2p(o);
-      g->gray = p->gclist;
-      return traverseproto(g, p);
+      g->gray = p->gclist;  /* remove from 'gray' list */
+      size = traverseproto(g, p);
+      break;
     }
-    default: lua_assert(0); return 0;
+    default: lua_assert(0); return;
   }
+  g->GCmemtrav += size;
 }
 
 
 ** clear entries with unmarked keys from all weaktables in list 'l' up
 ** to element 'f'
 */
-static void clearkeys (GCObject *l, GCObject *f) {
+static void clearkeys (global_State *g, GCObject *l, GCObject *f) {
   for (; l != f; l = gco2t(l)->gclist) {
     Table *h = gco2t(l);
     Node *n, *limit = gnodelast(h);
     for (n = gnode(h, 0); n < limit; n++) {
-      if (!ttisnil(gval(n)) && (iscleared(gkey(n)))) {
+      if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) {
         setnilvalue(gval(n));  /* remove value ... */
         removeentry(n);  /* and remove entry from table */
       }
 ** clear entries with unmarked values from all weaktables in list 'l' up
 ** to element 'f'
 */
-static void clearvalues (GCObject *l, GCObject *f) {
+static void clearvalues (global_State *g, GCObject *l, GCObject *f) {
   for (; l != f; l = gco2t(l)->gclist) {
     Table *h = gco2t(l);
     Node *n, *limit = gnodelast(h);
     int i;
     for (i = 0; i < h->sizearray; i++) {
       TValue *o = &h->array[i];
-      if (iscleared(o))  /* value was collected? */
+      if (iscleared(g, o))  /* value was collected? */
         setnilvalue(o);  /* remove value */
     }
     for (n = gnode(h, 0); n < limit; n++) {
-      if (!ttisnil(gval(n)) && iscleared(gval(n))) {
+      if (!ttisnil(gval(n)) && iscleared(g, gval(n))) {
         setnilvalue(gval(n));  /* remove value ... */
         removeentry(n);  /* and remove entry from table */
       }
 static void freeobj (lua_State *L, GCObject *o) {
   switch (gch(o)->tt) {
     case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
-    case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break;
+    case LUA_TLCL: {
+      luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues));
+      break;
+    }
+    case LUA_TCCL: {
+      luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues));
+      break;
+    }
     case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
     case LUA_TTABLE: luaH_free(L, gco2t(o)); break;
     case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break;
     case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;
-    case LUA_TSTRING: {
+    case LUA_TSHRSTR:
       G(L)->strt.nuse--;
+      /* go through */
+    case LUA_TLNGSTR: {
       luaM_freemem(L, o, sizestring(gco2ts(o)));
       break;
     }
   int ow = otherwhite(g);
   int toclear, toset;  /* bits to clear and to set in all live objects */
   int tostop;  /* stop sweep when this is true */
-  l_mem debt = g->GCdebt;  /* current debt */
   if (isgenerational(g)) {  /* generational mode? */
     toclear = ~0;  /* clear nothing */
     toset = bitmask(OLDBIT);  /* set the old bit of all surviving objects */
       freeobj(L, curr);  /* erase 'curr' */
     }
     else {
+      if (testbits(marked, tostop))
+        return NULL;  /* stop sweeping this list */
       if (gch(curr)->tt == LUA_TTHREAD)
         sweepthread(L, gco2th(curr));  /* sweep thread's upvalues */
-      if (testbits(marked, tostop)) {
-        static GCObject *nullp = NULL;
-        p = &nullp;  /* stop sweeping this list */
-        break;
-      }
       /* update marks */
       gch(curr)->marked = cast_byte((marked & toclear) | toset);
       p = &gch(curr)->next;  /* go to next element */
     }
   }
-  luaE_setdebt(g, debt);  /* sweeping should not change debt */
+  return (*p == NULL) ? NULL : p;
+}
+
+
+/*
+** sweep a list until a live object (or end of list)
+*/
+static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
+  GCObject ** old = p;
+  int i = 0;
+  do {
+    i++;
+    p = sweeplist(L, p, 1);
+  } while (p == old);
+  if (n) *n += i;
   return p;
 }
 
   g->allgc = o;
   resetbit(gch(o)->marked, SEPARATED);  /* mark that it is not in 'tobefnz' */
   lua_assert(!isold(o));  /* see MOVE OLD rule */
-  if (!keepinvariant(g))  /* not keeping invariant? */
+  if (!keepinvariantout(g))  /* not keeping invariant? */
     makewhite(g, o);  /* "sweep" object */
   return o;
 }
     L->allowhook = oldah;  /* restore hooks */
     g->gcrunning = running;  /* restore state */
     if (status != LUA_OK && propagateerrors) {  /* error while running __gc? */
-      if (status == LUA_ERRRUN) {  /* is there an error msg.? */
-        luaO_pushfstring(L, "error in __gc metamethod (%s)",
-                                        lua_tostring(L, -1));
+      if (status == LUA_ERRRUN) {  /* is there an error object? */
+        const char *msg = (ttisstring(L->top - 1))
+                            ? svalue(L->top - 1)
+                            : "no message";
+        luaO_pushfstring(L, "error in __gc metamethod (%s)", msg);
         status = LUA_ERRGCMM;  /* error in __gc metamethod */
       }
-      luaD_throw(L, status);  /* re-send error */
+      luaD_throw(L, status);  /* re-throw error */
     }
   }
 }
   while ((curr = *p) != NULL) {  /* traverse all finalizable objects */
     lua_assert(!isfinalized(curr));
     lua_assert(testbit(gch(curr)->marked, SEPARATED));
-    if (!(all || iswhite(curr)))  /* not being collected? */
+    if (!(iswhite(curr) || all))  /* not being collected? */
       p = &gch(curr)->next;  /* don't bother with it */
     else {
       l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */
     return;  /* nothing to be done */
   else {  /* move 'o' to 'finobj' list */
     GCObject **p;
-    for (p = &g->allgc; *p != o; p = &gch(*p)->next) ;
-    *p = gch(o)->next;  /* remove 'o' from root list */
-    gch(o)->next = g->finobj;  /* link it in list 'finobj' */
+    GCheader *ho = gch(o);
+    if (g->sweepgc == &ho->next) {  /* avoid removing current sweep object */
+      lua_assert(issweepphase(g));
+      g->sweepgc = sweeptolive(L, g->sweepgc, NULL);
+    }
+    /* search for pointer pointing to 'o' */
+    for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ }
+    *p = ho->next;  /* remove 'o' from root list */
+    ho->next = g->finobj;  /* link it in list 'finobj' */
     g->finobj = o;
-    l_setbit(gch(o)->marked, SEPARATED);  /* mark it as such */
-    resetoldbit(o);  /* see MOVE OLD rule */
+    l_setbit(ho->marked, SEPARATED);  /* mark it as such */
+    if (!keepinvariantout(g))  /* not keeping invariant? */
+      makewhite(g, o);  /* "sweep" object */
+    else
+      resetoldbit(o);  /* see MOVE OLD rule */
   }
 }
 
 */
 
 
+/*
+** set a reasonable "time" to wait before starting a new GC cycle;
+** cycle will start when memory use hits threshold
+*/
+static void setpause (global_State *g, l_mem estimate) {
+  l_mem debt, threshold;
+  estimate = estimate / PAUSEADJ;  /* adjust 'estimate' */
+  threshold = (g->gcpause < MAX_LMEM / estimate)  /* overflow? */
+            ? estimate * g->gcpause  /* no overflow */
+            : MAX_LMEM;  /* overflow; truncate to maximum */
+  debt = -cast(l_mem, threshold - gettotalbytes(g));
+  luaE_setdebt(g, debt);
+}
+
+
 #define sweepphases  \
 	(bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep))
 
+
+/*
+** enter first sweep phase (strings) and prepare pointers for other
+** sweep phases.  The calls to 'sweeptolive' make pointers point to an
+** object inside the list (instead of to the header), so that the real
+** sweep do not need to skip objects created between "now" and the start
+** of the real sweep.
+** Returns how many objects it swept.
+*/
+static int entersweep (lua_State *L) {
+  global_State *g = G(L);
+  int n = 0;
+  g->gcstate = GCSsweepstring;
+  lua_assert(g->sweepgc == NULL && g->sweepfin == NULL);
+  /* prepare to sweep strings, finalizable objects, and regular objects */
+  g->sweepstrgc = 0;
+  g->sweepfin = sweeptolive(L, &g->finobj, &n);
+  g->sweepgc = sweeptolive(L, &g->allgc, &n);
+  return n;
+}
+
+
 /*
 ** change GC mode
 */
   if (mode == KGC_GEN) {  /* change to generational mode */
     /* make sure gray lists are consistent */
     luaC_runtilstate(L, bitmask(GCSpropagate));
-    g->lastmajormem = gettotalbytes(g);
+    g->GCestimate = gettotalbytes(g);
     g->gckind = KGC_GEN;
   }
   else {  /* change to incremental mode */
     /* sweep all objects to turn them back to white
        (as white has not changed, nothing extra will be collected) */
-    g->sweepstrgc = 0;
-    g->gcstate = GCSsweepstring;
     g->gckind = KGC_NORMAL;
+    entersweep(L);
     luaC_runtilstate(L, ~sweepphases);
   }
 }
 }
 
 
-static void atomic (lua_State *L) {
+static l_mem atomic (lua_State *L) {
   global_State *g = G(L);
+  l_mem work = -cast(l_mem, g->GCmemtrav);  /* start counting work */
   GCObject *origweak, *origall;
   lua_assert(!iswhite(obj2gco(g->mainthread)));
   markobject(g, L);  /* mark running thread */
   markmt(g);  /* mark basic metatables */
   /* remark occasional upvalues of (maybe) dead threads */
   remarkupvals(g);
+  propagateall(g);  /* propagate changes */
+  work += g->GCmemtrav;  /* stop counting (do not (re)count grays) */
   /* traverse objects caught by write barrier and by 'remarkupvals' */
   retraversegrays(g);
+  work -= g->GCmemtrav;  /* restart counting */
   convergeephemerons(g);
   /* at this point, all strongly accessible objects are marked. */
   /* clear values from weak tables, before checking finalizers */
-  clearvalues(g->weak, NULL);
-  clearvalues(g->allweak, NULL);
+  clearvalues(g, g->weak, NULL);
+  clearvalues(g, g->allweak, NULL);
   origweak = g->weak; origall = g->allweak;
+  work += g->GCmemtrav;  /* stop counting (objects being finalized) */
   separatetobefnz(L, 0);  /* separate objects to be finalized */
-  markbeingfnz(g);  /* mark userdata that will be finalized */
+  markbeingfnz(g);  /* mark objects that will be finalized */
   propagateall(g);  /* remark, to propagate `preserveness' */
+  work -= g->GCmemtrav;  /* restart counting */
   convergeephemerons(g);
   /* at this point, all resurrected objects are marked. */
   /* remove dead objects from weak tables */
-  clearkeys(g->ephemeron, NULL);  /* clear keys from all ephemeron tables */
-  clearkeys(g->allweak, NULL);  /* clear keys from all allweak tables */
+  clearkeys(g, g->ephemeron, NULL);  /* clear keys from all ephemeron tables */
+  clearkeys(g, g->allweak, NULL);  /* clear keys from all allweak tables */
   /* clear values from resurrected weak tables */
-  clearvalues(g->weak, origweak);
-  clearvalues(g->allweak, origall);
-  g->sweepstrgc = 0;  /* prepare to sweep strings */
-  g->gcstate = GCSsweepstring;
+  clearvalues(g, g->weak, origweak);
+  clearvalues(g, g->allweak, origall);
   g->currentwhite = cast_byte(otherwhite(g));  /* flip current white */
-  /*lua_checkmemory(L);*/
+  work += g->GCmemtrav;  /* complete counting */
+  return work;  /* estimate of memory marked by 'atomic' */
 }
 
 
-static l_mem singlestep (lua_State *L) {
+static lu_mem singlestep (lua_State *L) {
   global_State *g = G(L);
   switch (g->gcstate) {
     case GCSpause: {
-      if (!isgenerational(g))
-        markroot(g);  /* start a new collection */
-      /* in any case, root must be marked */
-      lua_assert(!iswhite(obj2gco(g->mainthread))
-              && !iswhite(gcvalue(&g->l_registry)));
+      /* start to count memory traversed */
+      g->GCmemtrav = g->strt.size * sizeof(GCObject*);
+      lua_assert(!isgenerational(g));
+      restartcollection(g);
       g->gcstate = GCSpropagate;
-      return GCROOTCOST;
+      return g->GCmemtrav;
     }
     case GCSpropagate: {
-      if (g->gray)
-        return propagatemark(g);
+      if (g->gray) {
+        lu_mem oldtrav = g->GCmemtrav;
+        propagatemark(g);
+        return g->GCmemtrav - oldtrav;  /* memory traversed in this step */
+      }
       else {  /* no more `gray' objects */
+        lu_mem work;
+        int sw;
         g->gcstate = GCSatomic;  /* finish mark phase */
-        atomic(L);
-        return GCATOMICCOST;
+        g->GCestimate = g->GCmemtrav;  /* save what was counted */;
+        work = atomic(L);  /* add what was traversed by 'atomic' */
+        g->GCestimate += work;  /* estimate of total memory traversed */ 
+        sw = entersweep(L);
+        return work + sw * GCSWEEPCOST;
       }
     }
     case GCSsweepstring: {
-      if (g->sweepstrgc < g->strt.size) {
-        sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
-        return GCSWEEPCOST;
+      int i;
+      for (i = 0; i < GCSWEEPMAX && g->sweepstrgc + i < g->strt.size; i++)
+        sweepwholelist(L, &g->strt.hash[g->sweepstrgc + i]);
+      g->sweepstrgc += i;
+      if (g->sweepstrgc >= g->strt.size)  /* no more strings to sweep? */
+        g->gcstate = GCSsweepudata;
+      return i * GCSWEEPCOST;
+    }
+    case GCSsweepudata: {
+      if (g->sweepfin) {
+        g->sweepfin = sweeplist(L, g->sweepfin, GCSWEEPMAX);
+        return GCSWEEPMAX*GCSWEEPCOST;
       }
-      else {  /* no more strings to sweep */
-        g->sweepgc = &g->finobj;  /* prepare to sweep finalizable objects */
-        g->gcstate = GCSsweepudata;
+      else {
+        g->gcstate = GCSsweep;
         return 0;
       }
     }
-    case GCSsweepudata: {
-      if (*g->sweepgc) {
-        g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
-        return GCSWEEPMAX*GCSWEEPCOST;
-      }
-      else {
-        g->sweepgc = &g->allgc;  /* go to next phase */
-        g->gcstate = GCSsweep;
-        return GCSWEEPCOST;
-      }
-    }
     case GCSsweep: {
-      if (*g->sweepgc) {
+      if (g->sweepgc) {
         g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
         return GCSWEEPMAX*GCSWEEPCOST;
       }
 
 static void generationalcollection (lua_State *L) {
   global_State *g = G(L);
-  if (g->lastmajormem == 0) {  /* signal for another major collection? */
+  lua_assert(g->gcstate == GCSpropagate);
+  if (g->GCestimate == 0) {  /* signal for another major collection? */
     luaC_fullgc(L, 0);  /* perform a full regular collection */
-    g->lastmajormem = gettotalbytes(g);  /* update control */
+    g->GCestimate = gettotalbytes(g);  /* update control */
   }
   else {
-    luaC_runtilstate(L, ~bitmask(GCSpause));  /* run complete cycle */
-    luaC_runtilstate(L, bitmask(GCSpause));
-    if (gettotalbytes(g) > g->lastmajormem/100 * g->gcmajorinc)
-      g->lastmajormem = 0;  /* signal for a major collection */
+    lu_mem estimate = g->GCestimate;
+    luaC_runtilstate(L, bitmask(GCSpause));  /* run complete (minor) cycle */
+    g->gcstate = GCSpropagate;  /* skip restart */
+    if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc)
+      g->GCestimate = 0;  /* signal for a major collection */
+    else
+      g->GCestimate = estimate;  /* keep estimate from last major coll. */
+
   }
-  luaE_setdebt(g, stddebt(g));
+  setpause(g, gettotalbytes(g));
+  lua_assert(g->gcstate == GCSpropagate);
 }
 
 
-static void step (lua_State *L) {
+static void incstep (lua_State *L) {
   global_State *g = G(L);
-  l_mem lim = g->gcstepmul;  /* how much to work */
+  l_mem debt = g->GCdebt;
+  int stepmul = g->gcstepmul;
+  if (stepmul < 40) stepmul = 40;  /* avoid ridiculous low values (and 0) */
+  /* convert debt from Kb to 'work units' (avoid zero debt and overflows) */
+  debt = (debt / STEPMULADJ) + 1;
+  debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
   do {  /* always perform at least one single step */
-    lim -= singlestep(L);
-  } while (lim > 0 && g->gcstate != GCSpause);
-  if (g->gcstate != GCSpause)
-    luaE_setdebt(g, g->GCdebt - GCSTEPSIZE);
-  else
-    luaE_setdebt(g, stddebt(g));
+    lu_mem work = singlestep(L);  /* do some work */
+    debt -= work;
+  } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause);
+  if (g->gcstate == GCSpause)
+    setpause(g, g->GCestimate);  /* pause until next cycle */
+  else {
+    debt = (debt / stepmul) * STEPMULADJ;  /* convert 'work units' to Kb */
+    luaE_setdebt(g, debt);
+  }
 }
 
 
 /*
-** performs a basic GC step even if the collector is stopped
+** performs a basic GC step
 */
 void luaC_forcestep (lua_State *L) {
   global_State *g = G(L);
   int i;
   if (isgenerational(g)) generationalcollection(L);
-  else step(L);
-  for (i = 0; i < GCFINALIZENUM && g->tobefnz; i++)
-    GCTM(L, 1);  /* Call a few pending finalizers */
+  else incstep(L);
+  /* run a few finalizers (or all of them at the end of a collect cycle) */
+  for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++)
+    GCTM(L, 1);  /* call one finalizer */
 }
 
 
 ** performs a basic GC step only if collector is running
 */
 void luaC_step (lua_State *L) {
-  if (G(L)->gcrunning) luaC_forcestep(L);
+  global_State *g = G(L);
+  if (g->gcrunning) luaC_forcestep(L);
+  else luaE_setdebt(g, -GCSTEPSIZE);  /* avoid being called too often */
 }
 
 
+
 /*
 ** performs a full GC cycle; if "isemergency", does not call
 ** finalizers (which could change stack positions)
   global_State *g = G(L);
   int origkind = g->gckind;
   lua_assert(origkind != KGC_EMERGENCY);
-  if (!isemergency)   /* do not run finalizers during emergency GC */
+  if (isemergency)  /* do not run finalizers during emergency GC */
+    g->gckind = KGC_EMERGENCY;
+  else {
+    g->gckind = KGC_NORMAL;
     callallpendingfinalizers(L, 1);
-  if (keepinvariant(g)) {  /* marking phase? */
+  }
+  if (keepinvariant(g)) {  /* may there be some black objects? */
     /* must sweep all objects to turn them back to white
        (as white has not changed, nothing will be collected) */
-    g->sweepstrgc = 0;
-    g->gcstate = GCSsweepstring;
+    entersweep(L);
   }
-  g->gckind = isemergency ? KGC_EMERGENCY : KGC_NORMAL;
   /* finish any pending sweep phase to start a new cycle */
   luaC_runtilstate(L, bitmask(GCSpause));
-  /* run entire collector */
-  luaC_runtilstate(L, ~bitmask(GCSpause));
-  luaC_runtilstate(L, bitmask(GCSpause));
+  luaC_runtilstate(L, ~bitmask(GCSpause));  /* start new collection */
+  luaC_runtilstate(L, bitmask(GCSpause));  /* run entire collection */
   if (origkind == KGC_GEN) {  /* generational mode? */
-    /* generational mode must always start in propagate phase */
+    /* generational mode must be kept in propagate phase */
     luaC_runtilstate(L, bitmask(GCSpropagate));
   }
   g->gckind = origkind;
-  luaE_setdebt(g, stddebt(g));
+  setpause(g, gettotalbytes(g));
   if (!isemergency)   /* do not run finalizers during emergency GC */
     callallpendingfinalizers(L, 1);
 }

File src/libraries/lua52/lgc.h

 /*
-** $Id: lgc.h,v 2.52 2011/10/03 17:54:25 roberto Exp $
+** $Id: lgc.h,v 2.58 2012/09/11 12:53:08 roberto Exp $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
 */
 
 
+
+/* how much to allocate before next GC step */
+#if !defined(GCSTEPSIZE)
+/* ~100 small strings */
+#define GCSTEPSIZE	(cast_int(100 * sizeof(TString)))
+#endif
+
+
 /*
 ** Possible states of the Garbage Collector
 */
 #define isgenerational(g)	((g)->gckind == KGC_GEN)
 
 /*
-** macro to tell when main invariant (white objects cannot point to black
+** macros to tell when main invariant (white objects cannot point to black
 ** ones) must be kept. During a non-generational 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. During a generational collection, the
 ** invariant must be kept all times.
 */
-#define keepinvariant(g)  (isgenerational(g) || g->gcstate <= GCSatomic)
+
+#define keepinvariant(g)	(isgenerational(g) || g->gcstate <= GCSatomic)
+
+
+/*
+** Outside the collector, the state in generational mode is kept in
+** 'propagate', so 'keepinvariant' is always true.
+*/
+#define keepinvariantout(g)  \
+  check_exp(g->gcstate == GCSpropagate || !isgenerational(g),  \
+            g->gcstate <= GCSatomic)
 
 
 /*

File src/libraries/lua52/liolib.c

 /*
-** $Id: liolib.c,v 2.108 2011/11/25 12:50:03 roberto Exp $
+** $Id: liolib.c,v 2.111 2013/03/21 13:57:27 roberto Exp $
 ** Standard I/O (and system) library
 ** See Copyright Notice in lua.h
 */
 #include "lualib.h"
 
 
+#if !defined(lua_checkmode)
+
+/*
+** Check whether 'mode' matches '[rwa]%+?b?'.
+** Change this macro to accept other modes for 'fopen' besides
+** the standard ones.
+*/
+#define lua_checkmode(mode) \
+	(*mode != '\0' && strchr("rwa", *(mode++)) != NULL &&	\
+	(*mode != '+' || ++mode) &&  /* skip if char is '+' */	\
+	(*mode != 'b' || ++mode) &&  /* skip if char is 'b' */	\
+	(*mode == '\0'))
+
+#endif
 
 /*
 ** {======================================================
   const char *filename = luaL_checkstring(L, 1);
   const char *mode = luaL_optstring(L, 2, "r");
   LStream *p = newfile(L);
-  int i = 0;
-  /* check whether 'mode' matches '[rwa]%+?b?' */
-  if (!(mode[i] != '\0' && strchr("rwa", mode[i++]) != NULL &&
-       (mode[i] != '+' || ++i) &&  /* skip if char is '+' */
-       (mode[i] != 'b' || ++i) &&  /* skip if char is 'b' */
-       (mode[i] == '\0')))
-    return luaL_error(L, "invalid mode " LUA_QS
-                         " (should match " LUA_QL("[rwa]%%+?b?") ")", mode);
+  const char *md = mode;  /* to traverse/check mode */
+  luaL_argcheck(L, lua_checkmode(md), 2, "invalid mode");
   p->f = fopen(filename, mode);
   return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
 }

File src/libraries/lua52/llex.c

 /*
-** $Id: llex.c,v 2.59 2011/11/30 12:43:51 roberto Exp $
+** $Id: llex.c,v 2.63 2013/03/16 21:10:18 roberto Exp $
 ** Lexical Analyzer
 ** See Copyright Notice in lua.h
 */
   for (i=0; i<NUM_RESERVED; i++) {
     TString *ts = luaS_new(L, luaX_tokens[i]);
     luaS_fix(ts);  /* reserved words are never collected */
-    ts->tsv.reserved = cast_byte(i+1);  /* reserved word */
+    ts->tsv.extra = cast_byte(i+1);  /* reserved word */
   }
 }
 
 
 const char *luaX_token2str (LexState *ls, int token) {
-  if (token < FIRST_RESERVED) {
+  if (token < FIRST_RESERVED) {  /* single-byte symbols? */
     lua_assert(token == cast(unsigned char, token));
     return (lisprint(token)) ? luaO_pushfstring(ls->L, LUA_QL("%c"), token) :
                               luaO_pushfstring(ls->L, "char(%d)", token);
   }
   else {
     const char *s = luaX_tokens[token - FIRST_RESERVED];
-    if (token < TK_EOS)
+    if (token < TK_EOS)  /* fixed format (symbols and reserved words)? */
       return luaO_pushfstring(ls->L, LUA_QS, s);
-    else
+    else  /* names, strings, and numerals */
       return s;
   }
 }
 
 
 /* LUA_NUMBER */
+/*
+** this function is quite liberal in what it accepts, as 'luaO_str2d'
+** will reject ill-formed numerals.
+*/
 static void read_numeral (LexState *ls, SemInfo *seminfo) {
+  const char *expo = "Ee";
+  int first = ls->current;
   lua_assert(lisdigit(ls->current));
-  do {
-    save_and_next(ls);
-    if (check_next(ls, "EePp"))  /* exponent part? */
+  save_and_next(ls);
+  if (first == '0' && check_next(ls, "Xx"))  /* hexadecimal? */
+    expo = "Pp";
+  for (;;) {
+    if (check_next(ls, expo))  /* exponent part? */
       check_next(ls, "+-");  /* optional exponent sign */
-  } while (lislalnum(ls->current) || ls->current == '.');
+    if (lisxdigit(ls->current) || ls->current == '.')
+      save_and_next(ls);
+    else  break;
+  }
   save(ls, '\0');
   buffreplace(ls, '.', ls->decpoint);  /* follow locale for decimal point */
   if (!buff2d(ls->buff, &seminfo->r))  /* format error? */
   int c[3], i;  /* keep input for error message */
   int r = 0;  /* result accumulator */
   c[0] = 'x';  /* for error message */
-  for (i = 1; i < 3; i++) {  /* read two hexa digits */
+  for (i = 1; i < 3; i++) {  /* read two hexadecimal digits */
     c[i] = next(ls);
     if (!lisxdigit(c[i]))
       escerror(ls, c, i + 1, "hexadecimal digit expected");
           ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
                                   luaZ_bufflen(ls->buff));
           seminfo->ts = ts;
-          if (ts->tsv.reserved > 0)  /* reserved word? */
-            return ts->tsv.reserved - 1 + FIRST_RESERVED;
+          if (isreserved(ts))  /* reserved word? */
+            return ts->tsv.extra - 1 + FIRST_RESERVED;
           else {
             return TK_NAME;
           }

File src/libraries/lua52/llimits.h

 /*
-** $Id: llimits.h,v 1.95 2011/12/06 16:58:36 roberto Exp $
+** $Id: llimits.h,v 1.103 2013/02/20 14:08:56 roberto Exp $