2
0
Hugo Musso Gualandi 4 жил өмнө
parent
commit
3510dad9e7
58 өөрчлөгдсөн 3042 нэмэгдсэн , 2245 устгасан
  1. 25 20
      src/Makefile
  2. 114 72
      src/lapi.c
  3. 3 1
      src/lapi.h
  4. 105 55
      src/lauxlib.c
  5. 22 3
      src/lauxlib.h
  6. 8 7
      src/lbaselib.c
  7. 73 59
      src/lcode.c
  8. 1 1
      src/lcode.h
  9. 12 8
      src/lcorolib.c
  10. 25 16
      src/lctype.c
  11. 10 4
      src/lctype.h
  12. 26 20
      src/ldblib.c
  13. 112 74
      src/ldebug.c
  14. 16 0
      src/ldebug.h
  15. 322 188
      src/ldo.c
  16. 7 3
      src/ldo.h
  17. 84 87
      src/ldump.c
  18. 97 103
      src/lfunc.c
  19. 6 11
      src/lfunc.h
  20. 334 222
      src/lgc.c
  21. 16 13
      src/lgc.h
  22. 25 10
      src/liolib.c
  23. 4 2
      src/ljumptab.h
  24. 30 27
      src/llex.c
  25. 7 1
      src/llex.h
  26. 24 20
      src/llimits.h
  27. 20 17
      src/lmathlib.c
  28. 17 18
      src/lmem.c
  29. 27 15
      src/loadlib.c
  30. 30 21
      src/lobject.c
  31. 132 90
      src/lobject.h
  32. 3 3
      src/lopcodes.c
  33. 109 103
      src/lopcodes.h
  34. 6 1
      src/lopnames.h
  35. 10 8
      src/loslib.c
  36. 75 102
      src/lparser.c
  37. 8 7
      src/lparser.h
  38. 1 1
      src/lprefix.h
  39. 86 108
      src/lstate.c
  40. 119 79
      src/lstate.h
  41. 12 22
      src/lstring.c
  42. 7 3
      src/lstring.h
  43. 103 68
      src/lstrlib.c
  44. 127 77
      src/ltable.c
  45. 13 4
      src/ltable.h
  46. 6 5
      src/ltablib.c
  47. 15 5
      src/ltm.c
  48. 10 1
      src/ltm.h
  49. 35 10
      src/lua.c
  50. 8 5
      src/lua.h
  51. 50 34
      src/luac.c
  52. 79 62
      src/luaconf.h
  53. 0 6
      src/lualib.h
  54. 106 88
      src/lundump.c
  55. 6 1
      src/lundump.h
  56. 6 6
      src/lutf8lib.c
  57. 289 242
      src/lvm.c
  58. 19 6
      src/lvm.h

+ 25 - 20
src/Makefile

@@ -4,7 +4,7 @@
 # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
 # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
 
 
 # Your platform. See PLATS for possible values.
 # Your platform. See PLATS for possible values.
-PLAT= none
+PLAT= guess
 
 
 CC= gcc -std=gnu99
 CC= gcc -std=gnu99
 CFLAGS= -O2 -Wall -Wextra -DLUA_COMPAT_5_3 $(SYSCFLAGS) $(MYCFLAGS)
 CFLAGS= -O2 -Wall -Wextra -DLUA_COMPAT_5_3 $(SYSCFLAGS) $(MYCFLAGS)
@@ -14,6 +14,7 @@ LIBS= -lm $(SYSLIBS) $(MYLIBS)
 AR= ar rcu
 AR= ar rcu
 RANLIB= ranlib
 RANLIB= ranlib
 RM= rm -f
 RM= rm -f
+UNAME= uname
 
 
 SYSCFLAGS=
 SYSCFLAGS=
 SYSLDFLAGS=
 SYSLDFLAGS=
@@ -24,9 +25,12 @@ MYLDFLAGS=
 MYLIBS=
 MYLIBS=
 MYOBJS=
 MYOBJS=
 
 
+# Special flags for compiler modules; -Os reduces code size.
+CMCFLAGS= 
+
 # == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
 # == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
 
 
-PLATS= aix bsd c89 freebsd generic guess linux linux-readline macosx mingw posix solaris
+PLATS= guess aix bsd c89 freebsd generic linux linux-readline macosx mingw posix solaris
 
 
 LUA_A=	liblua.a
 LUA_A=	liblua.a
 CORE_O=	lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o
 CORE_O=	lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o
@@ -39,11 +43,8 @@ LUA_O=	lua.o
 LUAC_T=	luac
 LUAC_T=	luac
 LUAC_O=	luac.o
 LUAC_O=	luac.o
 
 
-LUAOT_T = luaot
-LUAOT_O = luaot.o
-
-ALL_O= $(BASE_O) $(LUA_O) $(LUAC_O) $(LUAOT_O)
-ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) $(LUAOT_T)
+ALL_O= $(BASE_O) $(LUA_O) $(LUAC_O)
+ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T)
 ALL_A= $(LUA_A)
 ALL_A= $(LUA_A)
 
 
 # Targets start here.
 # Targets start here.
@@ -65,8 +66,8 @@ $(LUA_T): $(LUA_O) $(LUA_A)
 $(LUAC_T): $(LUAC_O) $(LUA_A)
 $(LUAC_T): $(LUAC_O) $(LUA_A)
 	$(CC) -o $@ $(LDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS)
 	$(CC) -o $@ $(LDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS)
 
 
-$(LUAOT_T): $(LUAOT_O) $(LUA_A)
-	$(CC) -o $@ $(LDFLAGS) $(LUAOT_O) $(LUA_A) $(LIBS)
+test:
+	./$(LUA_T) -v
 
 
 clean:
 clean:
 	$(RM) $(ALL_T) $(ALL_O)
 	$(RM) $(ALL_T) $(ALL_O)
@@ -83,17 +84,19 @@ echo:
 	@echo "AR= $(AR)"
 	@echo "AR= $(AR)"
 	@echo "RANLIB= $(RANLIB)"
 	@echo "RANLIB= $(RANLIB)"
 	@echo "RM= $(RM)"
 	@echo "RM= $(RM)"
+	@echo "UNAME= $(UNAME)"
 
 
-# Convenience targets for popular platforms
+# Convenience targets for popular platforms.
 ALL= all
 ALL= all
 
 
-none:
-	@echo "Please do 'make PLATFORM' where PLATFORM is one of these:"
+help:
+	@echo "Do 'make PLATFORM' where PLATFORM is one of these:"
 	@echo "   $(PLATS)"
 	@echo "   $(PLATS)"
+	@echo "See doc/readme.html for complete instructions."
 
 
 guess:
 guess:
-	@echo Guessing `uname`
-	@$(MAKE) `uname`
+	@echo Guessing `$(UNAME)`
+	@$(MAKE) `$(UNAME)`
 
 
 AIX aix:
 AIX aix:
 	$(MAKE) $(ALL) CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl" SYSLDFLAGS="-brtl -bexpall"
 	$(MAKE) $(ALL) CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl" SYSLDFLAGS="-brtl -bexpall"
@@ -105,6 +108,8 @@ c89:
 	$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_C89" CC="gcc -std=c89"
 	$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_C89" CC="gcc -std=c89"
 	@echo ''
 	@echo ''
 	@echo '*** C89 does not guarantee 64-bit integers for Lua.'
 	@echo '*** C89 does not guarantee 64-bit integers for Lua.'
+	@echo '*** Make sure to compile all external Lua libraries'
+	@echo '*** with LUA_USE_C89 to ensure consistency'
 	@echo ''
 	@echo ''
 
 
 FreeBSD NetBSD OpenBSD freebsd:
 FreeBSD NetBSD OpenBSD freebsd:
@@ -135,17 +140,18 @@ posix:
 SunOS solaris:
 SunOS solaris:
 	$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN -D_REENTRANT" SYSLIBS="-ldl"
 	$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN -D_REENTRANT" SYSLIBS="-ldl"
 
 
-# list targets that do not create files (but not all makes understand .PHONY)
-.PHONY: all $(PLATS) default o a clean depend echo none
+# Targets that do not create files (not all makes understand .PHONY).
+.PHONY: all $(PLATS) help test clean default o a depend echo
 
 
+# Compiler modules may use special flags.
 llex.o:
 llex.o:
-	$(CC) $(CFLAGS) -Os -c llex.c
+	$(CC) $(CFLAGS) $(CMCFLAGS) -c llex.c
 
 
 lparser.o:
 lparser.o:
-	$(CC) $(CFLAGS) -Os -c lparser.c
+	$(CC) $(CFLAGS) $(CMCFLAGS) -c lparser.c
 
 
 lcode.o:
 lcode.o:
-	$(CC) $(CFLAGS) -Os -c lcode.c
+	$(CC) $(CFLAGS) $(CMCFLAGS) -c lcode.c
 
 
 # DO NOT DELETE
 # DO NOT DELETE
 
 
@@ -212,6 +218,5 @@ lvm.o: lvm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
  ltable.h lvm.h ljumptab.h
  ltable.h lvm.h ljumptab.h
 lzio.o: lzio.c lprefix.h lua.h luaconf.h llimits.h lmem.h lstate.h \
 lzio.o: lzio.c lprefix.h lua.h luaconf.h llimits.h lmem.h lstate.h \
  lobject.h ltm.h lzio.h
  lobject.h ltm.h lzio.h
-luaot.o: lua.h lauxlib.h ldebug.h lobject.h lopcodes.h lopnames.h lstate.h lundump.h
 
 
 # (end of Makefile)
 # (end of Makefile)

+ 114 - 72
src/lapi.c

@@ -39,7 +39,7 @@ const char lua_ident[] =
 
 
 
 
 /*
 /*
-** Test for a valid index.
+** Test for a valid index (one that is not the 'nilvalue').
 ** '!ttisnil(o)' implies 'o != &G(L)->nilvalue', so it is not needed.
 ** '!ttisnil(o)' implies 'o != &G(L)->nilvalue', so it is not needed.
 ** However, it covers the most common cases in a faster way.
 ** However, it covers the most common cases in a faster way.
 */
 */
@@ -74,7 +74,8 @@ static TValue *index2value (lua_State *L, int idx) {
       return &G(L)->nilvalue;  /* it has no upvalues */
       return &G(L)->nilvalue;  /* it has no upvalues */
     else {
     else {
       CClosure *func = clCvalue(s2v(ci->func));
       CClosure *func = clCvalue(s2v(ci->func));
-      return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : &G(L)->nilvalue;
+      return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
+                                      : &G(L)->nilvalue;
     }
     }
   }
   }
 }
 }
@@ -97,8 +98,9 @@ static StkId index2stack (lua_State *L, int idx) {
 
 
 LUA_API int lua_checkstack (lua_State *L, int n) {
 LUA_API int lua_checkstack (lua_State *L, int n) {
   int res;
   int res;
-  CallInfo *ci = L->ci;
+  CallInfo *ci;
   lua_lock(L);
   lua_lock(L);
+  ci = L->ci;
   api_check(L, n >= 0, "negative 'n'");
   api_check(L, n >= 0, "negative 'n'");
   if (L->stack_last - L->top > n)  /* stack large enough? */
   if (L->stack_last - L->top > n)  /* stack large enough? */
     res = 1;  /* yes; check is OK */
     res = 1;  /* yes; check is OK */
@@ -170,10 +172,12 @@ LUA_API int lua_gettop (lua_State *L) {
 
 
 
 
 LUA_API void lua_settop (lua_State *L, int idx) {
 LUA_API void lua_settop (lua_State *L, int idx) {
-  CallInfo *ci = L->ci;
-  StkId func = ci->func;
+  CallInfo *ci;
+  StkId func, newtop;
   ptrdiff_t diff;  /* difference for new top */
   ptrdiff_t diff;  /* difference for new top */
   lua_lock(L);
   lua_lock(L);
+  ci = L->ci;
+  func = ci->func;
   if (idx >= 0) {
   if (idx >= 0) {
     api_check(L, idx <= ci->top - (func + 1), "new top too large");
     api_check(L, idx <= ci->top - (func + 1), "new top too large");
     diff = ((func + 1) + idx) - L->top;
     diff = ((func + 1) + idx) - L->top;
@@ -184,9 +188,26 @@ LUA_API void lua_settop (lua_State *L, int idx) {
     api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
     api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
     diff = idx + 1;  /* will "subtract" index (as it is negative) */
     diff = idx + 1;  /* will "subtract" index (as it is negative) */
   }
   }
-  if (diff < 0 && hastocloseCfunc(ci->nresults))
-    luaF_close(L, L->top + diff, LUA_OK);
-  L->top += diff;  /* correct top only after closing any upvalue */
+  api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot");
+  newtop = L->top + diff;
+  if (diff < 0 && L->tbclist >= newtop) {
+    lua_assert(hastocloseCfunc(ci->nresults));
+    luaF_close(L, newtop, CLOSEKTOP, 0);
+  }
+  L->top = newtop;  /* correct top only after closing any upvalue */
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_closeslot (lua_State *L, int idx) {
+  StkId level;
+  lua_lock(L);
+  level = index2stack(L, idx);
+  api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level,
+     "no variable to close at given level");
+  luaF_close(L, level, CLOSEKTOP, 0);
+  level = index2stack(L, idx);  /* stack may be moved */
+  setnilvalue(s2v(level));
   lua_unlock(L);
   lua_unlock(L);
 }
 }
 
 
@@ -230,7 +251,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
   lua_lock(L);
   lua_lock(L);
   fr = index2value(L, fromidx);
   fr = index2value(L, fromidx);
   to = index2value(L, toidx);
   to = index2value(L, toidx);
-  api_check(l, isvalid(L, to), "invalid index");
+  api_check(L, isvalid(L, to), "invalid index");
   setobj(L, to, fr);
   setobj(L, to, fr);
   if (isupvalue(toidx))  /* function upvalue? */
   if (isupvalue(toidx))  /* function upvalue? */
     luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr);
     luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr);
@@ -262,7 +283,7 @@ LUA_API int lua_type (lua_State *L, int idx) {
 
 
 LUA_API const char *lua_typename (lua_State *L, int t) {
 LUA_API const char *lua_typename (lua_State *L, int t) {
   UNUSED(L);
   UNUSED(L);
-  api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag");
+  api_check(L, LUA_TNONE <= t && t < LUA_NUMTYPES, "invalid type");
   return ttypename(t);
   return ttypename(t);
 }
 }
 
 
@@ -350,23 +371,21 @@ LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
 
 
 
 
 LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *pisnum) {
 LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *pisnum) {
-  lua_Number n;
+  lua_Number n = 0;
   const TValue *o = index2value(L, idx);
   const TValue *o = index2value(L, idx);
   int isnum = tonumber(o, &n);
   int isnum = tonumber(o, &n);
-  if (!isnum)
-    n = 0;  /* call to 'tonumber' may change 'n' even if it fails */
-  if (pisnum) *pisnum = isnum;
+  if (pisnum)
+    *pisnum = isnum;
   return n;
   return n;
 }
 }
 
 
 
 
 LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) {
 LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) {
-  lua_Integer res;
+  lua_Integer res = 0;
   const TValue *o = index2value(L, idx);
   const TValue *o = index2value(L, idx);
   int isnum = tointeger(o, &res);
   int isnum = tointeger(o, &res);
-  if (!isnum)
-    res = 0;  /* call to 'tointeger' may change 'n' even if it fails */
-  if (pisnum) *pisnum = isnum;
+  if (pisnum)
+    *pisnum = isnum;
   return res;
   return res;
 }
 }
 
 
@@ -378,20 +397,22 @@ LUA_API int lua_toboolean (lua_State *L, int idx) {
 
 
 
 
 LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
 LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
-  TValue *o = index2value(L, idx);
+  TValue *o;
+  lua_lock(L);
+  o = index2value(L, idx);
   if (!ttisstring(o)) {
   if (!ttisstring(o)) {
     if (!cvt2str(o)) {  /* not convertible? */
     if (!cvt2str(o)) {  /* not convertible? */
       if (len != NULL) *len = 0;
       if (len != NULL) *len = 0;
+      lua_unlock(L);
       return NULL;
       return NULL;
     }
     }
-    lua_lock(L);  /* 'luaO_tostring' may create a new string */
     luaO_tostring(L, o);
     luaO_tostring(L, o);
     luaC_checkGC(L);
     luaC_checkGC(L);
     o = index2value(L, idx);  /* previous call may reallocate the stack */
     o = index2value(L, idx);  /* previous call may reallocate the stack */
-    lua_unlock(L);
   }
   }
   if (len != NULL)
   if (len != NULL)
     *len = vslen(o);
     *len = vslen(o);
+  lua_unlock(L);
   return svalue(o);
   return svalue(o);
 }
 }
 
 
@@ -399,10 +420,10 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
 LUA_API lua_Unsigned lua_rawlen (lua_State *L, int idx) {
 LUA_API lua_Unsigned lua_rawlen (lua_State *L, int idx) {
   const TValue *o = index2value(L, idx);
   const TValue *o = index2value(L, idx);
   switch (ttypetag(o)) {
   switch (ttypetag(o)) {
-    case LUA_TSHRSTR: return tsvalue(o)->shrlen;
-    case LUA_TLNGSTR: return tsvalue(o)->u.lnglen;
-    case LUA_TUSERDATA: return uvalue(o)->len;
-    case LUA_TTABLE: return luaH_getn(hvalue(o));
+    case LUA_VSHRSTR: return tsvalue(o)->shrlen;
+    case LUA_VLNGSTR: return tsvalue(o)->u.lnglen;
+    case LUA_VUSERDATA: return uvalue(o)->len;
+    case LUA_VTABLE: return luaH_getn(hvalue(o));
     default: return 0;
     default: return 0;
   }
   }
 }
 }
@@ -448,8 +469,8 @@ LUA_API lua_State *lua_tothread (lua_State *L, int idx) {
 LUA_API const void *lua_topointer (lua_State *L, int idx) {
 LUA_API const void *lua_topointer (lua_State *L, int idx) {
   const TValue *o = index2value(L, idx);
   const TValue *o = index2value(L, idx);
   switch (ttypetag(o)) {
   switch (ttypetag(o)) {
-    case LUA_TLCF: return cast_voidp(cast_sizet(fvalue(o)));
-    case LUA_TUSERDATA: case LUA_TLIGHTUSERDATA:
+    case LUA_VLCF: return cast_voidp(cast_sizet(fvalue(o)));
+    case LUA_VUSERDATA: case LUA_VLIGHTUSERDATA:
       return touserdata(o);
       return touserdata(o);
     default: {
     default: {
       if (iscollectable(o))
       if (iscollectable(o))
@@ -565,6 +586,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
     while (n--) {
     while (n--) {
       setobj2n(L, &cl->upvalue[n], s2v(L->top + n));
       setobj2n(L, &cl->upvalue[n], s2v(L->top + n));
       /* does not need barrier because closure is white */
       /* does not need barrier because closure is white */
+      lua_assert(iswhite(cl));
     }
     }
     setclCvalue(L, s2v(L->top), cl);
     setclCvalue(L, s2v(L->top), cl);
     api_incr_top(L);
     api_incr_top(L);
@@ -576,7 +598,10 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
 
 
 LUA_API void lua_pushboolean (lua_State *L, int b) {
 LUA_API void lua_pushboolean (lua_State *L, int b) {
   lua_lock(L);
   lua_lock(L);
-  setbvalue(s2v(L->top), (b != 0));  /* ensure that true is 1 */
+  if (b)
+    setbtvalue(s2v(L->top));
+  else
+    setbfvalue(s2v(L->top));
   api_incr_top(L);
   api_incr_top(L);
   lua_unlock(L);
   lua_unlock(L);
 }
 }
@@ -622,10 +647,21 @@ static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
 }
 }
 
 
 
 
+/*
+** Get the global table in the registry. Since all predefined
+** indices in the registry were inserted right when the registry
+** was created and never removed, they must always be in the array
+** part of the registry.
+*/
+#define getGtable(L)  \
+	(&hvalue(&G(L)->l_registry)->array[LUA_RIDX_GLOBALS - 1])
+
+
 LUA_API int lua_getglobal (lua_State *L, const char *name) {
 LUA_API int lua_getglobal (lua_State *L, const char *name) {
-  Table *reg = hvalue(&G(L)->l_registry);
+  const TValue *G;
   lua_lock(L);
   lua_lock(L);
-  return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
+  G = getGtable(L);
+  return auxgetstr(L, G, name);
 }
 }
 
 
 
 
@@ -803,9 +839,10 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
 
 
 
 
 LUA_API void lua_setglobal (lua_State *L, const char *name) {
 LUA_API void lua_setglobal (lua_State *L, const char *name) {
-  Table *reg = hvalue(&G(L)->l_registry);
+  const TValue *G;
   lua_lock(L);  /* unlock done in 'auxsetstr' */
   lua_lock(L);  /* unlock done in 'auxsetstr' */
-  auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
+  G = getGtable(L);
+  auxsetstr(L, G, name);
 }
 }
 
 
 
 
@@ -850,42 +887,37 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
 }
 }
 
 
 
 
-LUA_API void lua_rawset (lua_State *L, int idx) {
+static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
   Table *t;
   Table *t;
-  TValue *slot;
   lua_lock(L);
   lua_lock(L);
-  api_checknelems(L, 2);
+  api_checknelems(L, n);
   t = gettable(L, idx);
   t = gettable(L, idx);
-  slot = luaH_set(L, t, s2v(L->top - 2));
-  setobj2t(L, slot, s2v(L->top - 1));
+  luaH_set(L, t, key, s2v(L->top - 1));
   invalidateTMcache(t);
   invalidateTMcache(t);
   luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
   luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
-  L->top -= 2;
+  L->top -= n;
   lua_unlock(L);
   lua_unlock(L);
 }
 }
 
 
 
 
-LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
-  Table *t;
-  lua_lock(L);
-  api_checknelems(L, 1);
-  t = gettable(L, idx);
-  luaH_setint(L, t, n, s2v(L->top - 1));
-  luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
-  L->top--;
-  lua_unlock(L);
+LUA_API void lua_rawset (lua_State *L, int idx) {
+  aux_rawset(L, idx, s2v(L->top - 2), 2);
 }
 }
 
 
 
 
 LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
 LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
+  TValue k;
+  setpvalue(&k, cast_voidp(p));
+  aux_rawset(L, idx, &k, 1);
+}
+
+
+LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
   Table *t;
   Table *t;
-  TValue k, *slot;
   lua_lock(L);
   lua_lock(L);
   api_checknelems(L, 1);
   api_checknelems(L, 1);
   t = gettable(L, idx);
   t = gettable(L, idx);
-  setpvalue(&k, cast_voidp(p));
-  slot = luaH_set(L, t, &k);
-  setobj2t(L, slot, s2v(L->top - 1));
+  luaH_setint(L, t, n, s2v(L->top - 1));
   luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
   luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
   L->top--;
   L->top--;
   lua_unlock(L);
   lua_unlock(L);
@@ -1057,8 +1089,7 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
     LClosure *f = clLvalue(s2v(L->top - 1));  /* get newly created function */
     LClosure *f = clLvalue(s2v(L->top - 1));  /* get newly created function */
     if (f->nupvalues >= 1) {  /* does it have an upvalue? */
     if (f->nupvalues >= 1) {  /* does it have an upvalue? */
       /* get global table from registry */
       /* get global table from registry */
-      Table *reg = hvalue(&G(L)->l_registry);
-      const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
+      const TValue *gt = getGtable(L);
       /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
       /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
       setobj(L, f->upvals[0]->v, gt);
       setobj(L, f->upvals[0]->v, gt);
       luaC_barrier(L, f->upvals[0], gt);
       luaC_barrier(L, f->upvals[0], gt);
@@ -1095,8 +1126,9 @@ LUA_API int lua_status (lua_State *L) {
 LUA_API int lua_gc (lua_State *L, int what, ...) {
 LUA_API int lua_gc (lua_State *L, int what, ...) {
   va_list argp;
   va_list argp;
   int res = 0;
   int res = 0;
-  global_State *g = G(L);
+  global_State *g;
   lua_lock(L);
   lua_lock(L);
+  g = G(L);
   va_start(argp, what);
   va_start(argp, what);
   switch (what) {
   switch (what) {
     case LUA_GCSTOP: {
     case LUA_GCSTOP: {
@@ -1196,9 +1228,15 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
 
 
 
 
 LUA_API int lua_error (lua_State *L) {
 LUA_API int lua_error (lua_State *L) {
+  TValue *errobj;
   lua_lock(L);
   lua_lock(L);
+  errobj = s2v(L->top - 1);
   api_checknelems(L, 1);
   api_checknelems(L, 1);
-  luaG_errormsg(L);
+  /* error object is the memory error message? */
+  if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
+    luaM_error(L);  /* raise a memory error */
+  else
+    luaG_errormsg(L);  /* raise a regular error */
   /* code unreachable; will unlock when control actually leaves the kernel */
   /* code unreachable; will unlock when control actually leaves the kernel */
   return 0;  /* to avoid warnings */
   return 0;  /* to avoid warnings */
 }
 }
@@ -1227,8 +1265,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
   lua_lock(L);
   lua_lock(L);
   o = index2stack(L, idx);
   o = index2stack(L, idx);
   nresults = L->ci->nresults;
   nresults = L->ci->nresults;
-  api_check(L, L->openupval == NULL || uplevel(L->openupval) <= o,
-               "marked index below or equal new one");
+  api_check(L, L->tbclist < o, "given index below or equal a marked one");
   luaF_newtbcupval(L, o);  /* create new to-be-closed upvalue */
   luaF_newtbcupval(L, o);  /* create new to-be-closed upvalue */
   if (!hastocloseCfunc(nresults))  /* function not marked yet? */
   if (!hastocloseCfunc(nresults))  /* function not marked yet? */
     L->ci->nresults = codeNresults(nresults);  /* mark it */
     L->ci->nresults = codeNresults(nresults);  /* mark it */
@@ -1240,14 +1277,12 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
 LUA_API void lua_concat (lua_State *L, int n) {
 LUA_API void lua_concat (lua_State *L, int n) {
   lua_lock(L);
   lua_lock(L);
   api_checknelems(L, n);
   api_checknelems(L, n);
-  if (n >= 2) {
+  if (n > 0)
     luaV_concat(L, n);
     luaV_concat(L, n);
-  }
-  else if (n == 0) {  /* push empty string */
-    setsvalue2s(L, L->top, luaS_newlstr(L, "", 0));
+  else {  /* nothing to concatenate */
+    setsvalue2s(L, L->top, luaS_newlstr(L, "", 0));  /* push empty string */
     api_incr_top(L);
     api_incr_top(L);
   }
   }
-  /* else n == 1; nothing to do */
   luaC_checkGC(L);
   luaC_checkGC(L);
   lua_unlock(L);
   lua_unlock(L);
 }
 }
@@ -1314,7 +1349,7 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
 static const char *aux_upvalue (TValue *fi, int n, TValue **val,
 static const char *aux_upvalue (TValue *fi, int n, TValue **val,
                                 GCObject **owner) {
                                 GCObject **owner) {
   switch (ttypetag(fi)) {
   switch (ttypetag(fi)) {
-    case LUA_TCCL: {  /* C closure */
+    case LUA_VCCL: {  /* C closure */
       CClosure *f = clCvalue(fi);
       CClosure *f = clCvalue(fi);
       if (!(cast_uint(n) - 1u < cast_uint(f->nupvalues)))
       if (!(cast_uint(n) - 1u < cast_uint(f->nupvalues)))
         return NULL;  /* 'n' not in [1, f->nupvalues] */
         return NULL;  /* 'n' not in [1, f->nupvalues] */
@@ -1322,7 +1357,7 @@ static const char *aux_upvalue (TValue *fi, int n, TValue **val,
       if (owner) *owner = obj2gco(f);
       if (owner) *owner = obj2gco(f);
       return "";
       return "";
     }
     }
-    case LUA_TLCL: {  /* Lua closure */
+    case LUA_VLCL: {  /* Lua closure */
       LClosure *f = clLvalue(fi);
       LClosure *f = clLvalue(fi);
       TString *name;
       TString *name;
       Proto *p = f->p;
       Proto *p = f->p;
@@ -1372,29 +1407,35 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
 
 
 
 
 static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) {
 static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) {
+  static const UpVal *const nullup = NULL;
   LClosure *f;
   LClosure *f;
   TValue *fi = index2value(L, fidx);
   TValue *fi = index2value(L, fidx);
   api_check(L, ttisLclosure(fi), "Lua function expected");
   api_check(L, ttisLclosure(fi), "Lua function expected");
   f = clLvalue(fi);
   f = clLvalue(fi);
-  api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index");
   if (pf) *pf = f;
   if (pf) *pf = f;
-  return &f->upvals[n - 1];  /* get its upvalue pointer */
+  if (1 <= n && n <= f->p->sizeupvalues)
+    return &f->upvals[n - 1];  /* get its upvalue pointer */
+  else
+    return (UpVal**)&nullup;
 }
 }
 
 
 
 
 LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) {
 LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) {
   TValue *fi = index2value(L, fidx);
   TValue *fi = index2value(L, fidx);
   switch (ttypetag(fi)) {
   switch (ttypetag(fi)) {
-    case LUA_TLCL: {  /* lua closure */
+    case LUA_VLCL: {  /* lua closure */
       return *getupvalref(L, fidx, n, NULL);
       return *getupvalref(L, fidx, n, NULL);
     }
     }
-    case LUA_TCCL: {  /* C closure */
+    case LUA_VCCL: {  /* C closure */
       CClosure *f = clCvalue(fi);
       CClosure *f = clCvalue(fi);
-      api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index");
-      return &f->upvalue[n - 1];
-    }
+      if (1 <= n && n <= f->nupvalues)
+        return &f->upvalue[n - 1];
+      /* else */
+    }  /* FALLTHROUGH */
+    case LUA_VLCF:
+      return NULL;  /* light C functions have no upvalues */
     default: {
     default: {
-      api_check(L, 0, "closure expected");
+      api_check(L, 0, "function expected");
       return NULL;
       return NULL;
     }
     }
   }
   }
@@ -1406,6 +1447,7 @@ LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
   LClosure *f1;
   LClosure *f1;
   UpVal **up1 = getupvalref(L, fidx1, n1, &f1);
   UpVal **up1 = getupvalref(L, fidx1, n1, &f1);
   UpVal **up2 = getupvalref(L, fidx2, n2, NULL);
   UpVal **up2 = getupvalref(L, fidx2, n2, NULL);
+  api_check(L, *up1 != NULL && *up2 != NULL, "invalid upvalue index");
   *up1 = *up2;
   *up1 = *up2;
   luaC_objbarrier(L, f1, *up1);
   luaC_objbarrier(L, f1, *up1);
 }
 }

+ 3 - 1
src/lapi.h

@@ -19,7 +19,7 @@
 
 
 /*
 /*
 ** If a call returns too many multiple returns, the callee may not have
 ** If a call returns too many multiple returns, the callee may not have
-** stack space to accomodate all results. In this case, this macro
+** stack space to accommodate all results. In this case, this macro
 ** increases its stack space ('L->ci->top').
 ** increases its stack space ('L->ci->top').
 */
 */
 #define adjustresults(L,nres) \
 #define adjustresults(L,nres) \
@@ -42,6 +42,8 @@
 
 
 #define hastocloseCfunc(n)	((n) < LUA_MULTRET)
 #define hastocloseCfunc(n)	((n) < LUA_MULTRET)
 
 
+/* Map [-1, inf) (range of 'nresults') into (-inf, -2] */
 #define codeNresults(n)		(-(n) - 3)
 #define codeNresults(n)		(-(n) - 3)
+#define decodeNresults(n)	(-(n) - 3)
 
 
 #endif
 #endif

+ 105 - 55
src/lauxlib.c

@@ -87,7 +87,7 @@ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
       lua_remove(L, -2);  /* remove original name */
       lua_remove(L, -2);  /* remove original name */
     }
     }
     lua_copy(L, -1, top + 1);  /* copy name to proper place */
     lua_copy(L, -1, top + 1);  /* copy name to proper place */
-    lua_settop(L, top + 1);  /* remove table "loaded" an name copy */
+    lua_settop(L, top + 1);  /* remove table "loaded" and name copy */
     return 1;
     return 1;
   }
   }
   else {
   else {
@@ -190,7 +190,7 @@ LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) {
 }
 }
 
 
 
 
-int luaL_typeerror (lua_State *L, int arg, const char *tname) {
+LUALIB_API int luaL_typeerror (lua_State *L, int arg, const char *tname) {
   const char *msg;
   const char *msg;
   const char *typearg;  /* name for the type of the actual argument */
   const char *typearg;  /* name for the type of the actual argument */
   if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING)
   if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING)
@@ -283,10 +283,10 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
 
 
 
 
 LUALIB_API int luaL_execresult (lua_State *L, int stat) {
 LUALIB_API int luaL_execresult (lua_State *L, int stat) {
-  const char *what = "exit";  /* type of termination */
-  if (stat == -1)  /* error? */
+  if (stat != 0 && errno != 0)  /* error with an 'errno'? */
     return luaL_fileresult(L, 0, NULL);
     return luaL_fileresult(L, 0, NULL);
   else {
   else {
+    const char *what = "exit";  /* type of termination */
     l_inspectstat(stat, what);  /* interpret result */
     l_inspectstat(stat, what);  /* interpret result */
     if (*what == 'e' && stat == 0)  /* successful termination? */
     if (*what == 'e' && stat == 0)  /* successful termination? */
       lua_pushboolean(L, 1);
       lua_pushboolean(L, 1);
@@ -378,7 +378,7 @@ LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def,
 ** but without 'msg'.)
 ** but without 'msg'.)
 */
 */
 LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
 LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
-  if (!lua_checkstack(L, space)) {
+  if (l_unlikely(!lua_checkstack(L, space))) {
     if (msg)
     if (msg)
       luaL_error(L, "stack overflow (%s)", msg);
       luaL_error(L, "stack overflow (%s)", msg);
     else
     else
@@ -388,20 +388,20 @@ LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
 
 
 
 
 LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) {
 LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) {
-  if (lua_type(L, arg) != t)
+  if (l_unlikely(lua_type(L, arg) != t))
     tag_error(L, arg, t);
     tag_error(L, arg, t);
 }
 }
 
 
 
 
 LUALIB_API void luaL_checkany (lua_State *L, int arg) {
 LUALIB_API void luaL_checkany (lua_State *L, int arg) {
-  if (lua_type(L, arg) == LUA_TNONE)
+  if (l_unlikely(lua_type(L, arg) == LUA_TNONE))
     luaL_argerror(L, arg, "value expected");
     luaL_argerror(L, arg, "value expected");
 }
 }
 
 
 
 
 LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) {
 LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) {
   const char *s = lua_tolstring(L, arg, len);
   const char *s = lua_tolstring(L, arg, len);
-  if (!s) tag_error(L, arg, LUA_TSTRING);
+  if (l_unlikely(!s)) tag_error(L, arg, LUA_TSTRING);
   return s;
   return s;
 }
 }
 
 
@@ -420,7 +420,7 @@ LUALIB_API const char *luaL_optlstring (lua_State *L, int arg,
 LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) {
 LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) {
   int isnum;
   int isnum;
   lua_Number d = lua_tonumberx(L, arg, &isnum);
   lua_Number d = lua_tonumberx(L, arg, &isnum);
-  if (!isnum)
+  if (l_unlikely(!isnum))
     tag_error(L, arg, LUA_TNUMBER);
     tag_error(L, arg, LUA_TNUMBER);
   return d;
   return d;
 }
 }
@@ -442,7 +442,7 @@ static void interror (lua_State *L, int arg) {
 LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) {
 LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) {
   int isnum;
   int isnum;
   lua_Integer d = lua_tointegerx(L, arg, &isnum);
   lua_Integer d = lua_tointegerx(L, arg, &isnum);
-  if (!isnum) {
+  if (l_unlikely(!isnum)) {
     interror(L, arg);
     interror(L, arg);
   }
   }
   return d;
   return d;
@@ -475,8 +475,10 @@ static void *resizebox (lua_State *L, int idx, size_t newsize) {
   lua_Alloc allocf = lua_getallocf(L, &ud);
   lua_Alloc allocf = lua_getallocf(L, &ud);
   UBox *box = (UBox *)lua_touserdata(L, idx);
   UBox *box = (UBox *)lua_touserdata(L, idx);
   void *temp = allocf(ud, box->box, box->bsize, newsize);
   void *temp = allocf(ud, box->box, box->bsize, newsize);
-  if (temp == NULL && newsize > 0)  /* allocation error? */
-    luaL_error(L, "not enough memory for buffer allocation");
+  if (l_unlikely(temp == NULL && newsize > 0)) {  /* allocation error? */
+    lua_pushliteral(L, "not enough memory");
+    lua_error(L);  /* raise a memory error */
+  }
   box->box = temp;
   box->box = temp;
   box->bsize = newsize;
   box->bsize = newsize;
   return temp;
   return temp;
@@ -513,13 +515,22 @@ static void newbox (lua_State *L) {
 #define buffonstack(B)	((B)->b != (B)->init.b)
 #define buffonstack(B)	((B)->b != (B)->init.b)
 
 
 
 
+/*
+** Whenever buffer is accessed, slot 'idx' must either be a box (which
+** cannot be NULL) or it is a placeholder for the buffer.
+*/
+#define checkbufferlevel(B,idx)  \
+  lua_assert(buffonstack(B) ? lua_touserdata(B->L, idx) != NULL  \
+                            : lua_touserdata(B->L, idx) == (void*)B)
+
+
 /*
 /*
 ** Compute new size for buffer 'B', enough to accommodate extra 'sz'
 ** Compute new size for buffer 'B', enough to accommodate extra 'sz'
 ** bytes.
 ** bytes.
 */
 */
 static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
 static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
   size_t newsize = B->size * 2;  /* double buffer size */
   size_t newsize = B->size * 2;  /* double buffer size */
-  if (MAX_SIZET - sz < B->n)  /* overflow in (B->n + sz)? */
+  if (l_unlikely(MAX_SIZET - sz < B->n))  /* overflow in (B->n + sz)? */
     return luaL_error(B->L, "buffer too large");
     return luaL_error(B->L, "buffer too large");
   if (newsize < B->n + sz)  /* double is not big enough? */
   if (newsize < B->n + sz)  /* double is not big enough? */
     newsize = B->n + sz;
     newsize = B->n + sz;
@@ -529,10 +540,11 @@ static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
 
 
 /*
 /*
 ** Returns a pointer to a free area with at least 'sz' bytes in buffer
 ** Returns a pointer to a free area with at least 'sz' bytes in buffer
-** 'B'. 'boxidx' is the relative position in the stack where the
-** buffer's box is or should be.
+** 'B'. 'boxidx' is the relative position in the stack where is the
+** buffer's box or its placeholder.
 */
 */
 static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) {
 static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) {
+  checkbufferlevel(B, boxidx);
   if (B->size - B->n >= sz)  /* enough space? */
   if (B->size - B->n >= sz)  /* enough space? */
     return B->b + B->n;
     return B->b + B->n;
   else {
   else {
@@ -543,10 +555,9 @@ static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) {
     if (buffonstack(B))  /* buffer already has a box? */
     if (buffonstack(B))  /* buffer already has a box? */
       newbuff = (char *)resizebox(L, boxidx, newsize);  /* resize it */
       newbuff = (char *)resizebox(L, boxidx, newsize);  /* resize it */
     else {  /* no box yet */
     else {  /* no box yet */
-      lua_pushnil(L);  /* reserve slot for final result */
+      lua_remove(L, boxidx);  /* remove placeholder */
       newbox(L);  /* create a new box */
       newbox(L);  /* create a new box */
-      /* move box (and slot) to its intended position */
-      lua_rotate(L, boxidx - 1, 2);
+      lua_insert(L, boxidx);  /* move box to its intended position */
       lua_toclose(L, boxidx);
       lua_toclose(L, boxidx);
       newbuff = (char *)resizebox(L, boxidx, newsize);
       newbuff = (char *)resizebox(L, boxidx, newsize);
       memcpy(newbuff, B->b, B->n * sizeof(char));  /* copy original content */
       memcpy(newbuff, B->b, B->n * sizeof(char));  /* copy original content */
@@ -581,11 +592,11 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
 
 
 LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
 LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
   lua_State *L = B->L;
   lua_State *L = B->L;
+  checkbufferlevel(B, -1);
   lua_pushlstring(L, B->b, B->n);
   lua_pushlstring(L, B->b, B->n);
-  if (buffonstack(B)) {
-    lua_copy(L, -1, -3);  /* move string to reserved slot */
-    lua_pop(L, 2);  /* pop string and box (closing the box) */
-  }
+  if (buffonstack(B))
+    lua_closeslot(L, -2);  /* close the box */
+  lua_remove(L, -2);  /* remove box or placeholder from the stack */
 }
 }
 
 
 
 
@@ -620,6 +631,7 @@ LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
   B->b = B->init.b;
   B->b = B->init.b;
   B->n = 0;
   B->n = 0;
   B->size = LUAL_BUFFERSIZE;
   B->size = LUAL_BUFFERSIZE;
+  lua_pushlightuserdata(L, (void*)B);  /* push placeholder */
 }
 }
 
 
 
 
@@ -637,10 +649,14 @@ LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {
 ** =======================================================
 ** =======================================================
 */
 */
 
 
-/* index of free-list header */
-#define freelist	0
-
+/* index of free-list header (after the predefined values) */
+#define freelist	(LUA_RIDX_LAST + 1)
 
 
+/*
+** The previously freed references form a linked list:
+** t[freelist] is the index of a first free index, or zero if list is
+** empty; t[t[freelist]] is the index of the second element; etc.
+*/
 LUALIB_API int luaL_ref (lua_State *L, int t) {
 LUALIB_API int luaL_ref (lua_State *L, int t) {
   int ref;
   int ref;
   if (lua_isnil(L, -1)) {
   if (lua_isnil(L, -1)) {
@@ -648,9 +664,16 @@ LUALIB_API int luaL_ref (lua_State *L, int t) {
     return LUA_REFNIL;  /* 'nil' has a unique fixed reference */
     return LUA_REFNIL;  /* 'nil' has a unique fixed reference */
   }
   }
   t = lua_absindex(L, t);
   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 */
+  if (lua_rawgeti(L, t, freelist) == LUA_TNIL) {  /* first access? */
+    ref = 0;  /* list is empty */
+    lua_pushinteger(L, 0);  /* initialize as an empty list */
+    lua_rawseti(L, t, freelist);  /* ref = t[freelist] = 0 */
+  }
+  else {  /* already initialized */
+    lua_assert(lua_isinteger(L, -1));
+    ref = (int)lua_tointeger(L, -1);  /* ref = t[freelist] */
+  }
+  lua_pop(L, 1);  /* remove element from stack */
   if (ref != 0) {  /* any free element? */
   if (ref != 0) {  /* any free element? */
     lua_rawgeti(L, t, ref);  /* remove it from list */
     lua_rawgeti(L, t, ref);  /* remove it from list */
     lua_rawseti(L, t, freelist);  /* (t[freelist] = t[ref]) */
     lua_rawseti(L, t, freelist);  /* (t[freelist] = t[ref]) */
@@ -666,6 +689,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
   if (ref >= 0) {
   if (ref >= 0) {
     t = lua_absindex(L, t);
     t = lua_absindex(L, t);
     lua_rawgeti(L, t, freelist);
     lua_rawgeti(L, t, freelist);
+    lua_assert(lua_isinteger(L, -1));
     lua_rawseti(L, t, ref);  /* t[ref] = t[freelist] */
     lua_rawseti(L, t, ref);  /* t[ref] = t[freelist] */
     lua_pushinteger(L, ref);
     lua_pushinteger(L, ref);
     lua_rawseti(L, t, freelist);  /* t[freelist] = ref */
     lua_rawseti(L, t, freelist);  /* t[freelist] = ref */
@@ -849,7 +873,7 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
   int isnum;
   int isnum;
   lua_len(L, idx);
   lua_len(L, idx);
   l = lua_tointegerx(L, -1, &isnum);
   l = lua_tointegerx(L, -1, &isnum);
-  if (!isnum)
+  if (l_unlikely(!isnum))
     luaL_error(L, "object length is not an integer");
     luaL_error(L, "object length is not an integer");
   lua_pop(L, 1);  /* remove object */
   lua_pop(L, 1);  /* remove object */
   return l;
   return l;
@@ -902,10 +926,10 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
 LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
 LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
   luaL_checkstack(L, nup, "too many upvalues");
   luaL_checkstack(L, nup, "too many upvalues");
   for (; l->name != NULL; l++) {  /* fill the table with given functions */
   for (; l->name != NULL; l++) {  /* fill the table with given functions */
-    int i;
     if (l->func == NULL)  /* place holder? */
     if (l->func == NULL)  /* place holder? */
       lua_pushboolean(L, 0);
       lua_pushboolean(L, 0);
     else {
     else {
+      int i;
       for (i = 0; i < nup; i++)  /* copy upvalues to the top */
       for (i = 0; i < nup; i++)  /* copy upvalues to the top */
         lua_pushvalue(L, -nup);
         lua_pushvalue(L, -nup);
       lua_pushcclosure(L, l->func, nup);  /* closure with those upvalues */
       lua_pushcclosure(L, l->func, nup);  /* closure with those upvalues */
@@ -995,50 +1019,76 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
 
 
 
 
 static int panic (lua_State *L) {
 static int panic (lua_State *L) {
+  const char *msg = lua_tostring(L, -1);
+  if (msg == NULL) msg = "error object is not a string";
   lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
   lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
-                        lua_tostring(L, -1));
+                        msg);
   return 0;  /* return to Lua to abort */
   return 0;  /* return to Lua to abort */
 }
 }
 
 
 
 
 /*
 /*
-** Emit a warning. '*warnstate' means:
-** 0 - warning system is off;
-** 1 - ready to start a new message;
-** 2 - previous message is to be continued.
+** Warning functions:
+** warnfoff: warning system is off
+** warnfon: ready to start a new message
+** warnfcont: previous message is to be continued
+*/
+static void warnfoff (void *ud, const char *message, int tocont);
+static void warnfon (void *ud, const char *message, int tocont);
+static void warnfcont (void *ud, const char *message, int tocont);
+
+
+/*
+** Check whether message is a control message. If so, execute the
+** control or ignore it if unknown.
 */
 */
-static void warnf (void *ud, const char *message, int tocont) {
-  int *warnstate = (int *)ud;
-  if (*warnstate != 2 && !tocont && *message == '@') {  /* control message? */
-    if (strcmp(message, "@off") == 0)
-      *warnstate = 0;
-    else if (strcmp(message, "@on") == 0)
-      *warnstate = 1;
-    return;
+static int checkcontrol (lua_State *L, const char *message, int tocont) {
+  if (tocont || *(message++) != '@')  /* not a control message? */
+    return 0;
+  else {
+    if (strcmp(message, "off") == 0)
+      lua_setwarnf(L, warnfoff, L);  /* turn warnings off */
+    else if (strcmp(message, "on") == 0)
+      lua_setwarnf(L, warnfon, L);   /* turn warnings on */
+    return 1;  /* it was a control message */
   }
   }
-  else if (*warnstate == 0)  /* warnings off? */
-    return;
-  if (*warnstate == 1)  /* previous message was the last? */
-    lua_writestringerror("%s", "Lua warning: ");  /* start a new warning */
+}
+
+
+static void warnfoff (void *ud, const char *message, int tocont) {
+  checkcontrol((lua_State *)ud, message, tocont);
+}
+
+
+/*
+** Writes the message and handle 'tocont', finishing the message
+** if needed and setting the next warn function.
+*/
+static void warnfcont (void *ud, const char *message, int tocont) {
+  lua_State *L = (lua_State *)ud;
   lua_writestringerror("%s", message);  /* write message */
   lua_writestringerror("%s", message);  /* write message */
   if (tocont)  /* not the last part? */
   if (tocont)  /* not the last part? */
-    *warnstate = 2;  /* to be continued */
+    lua_setwarnf(L, warnfcont, L);  /* to be continued */
   else {  /* last part */
   else {  /* last part */
     lua_writestringerror("%s", "\n");  /* finish message with end-of-line */
     lua_writestringerror("%s", "\n");  /* finish message with end-of-line */
-    *warnstate = 1;  /* ready to start a new message */
+    lua_setwarnf(L, warnfon, L);  /* next call is a new message */
   }
   }
 }
 }
 
 
 
 
+static void warnfon (void *ud, const char *message, int tocont) {
+  if (checkcontrol((lua_State *)ud, message, tocont))  /* control message? */
+    return;  /* nothing else to be done */
+  lua_writestringerror("%s", "Lua warning: ");  /* start a new warning */
+  warnfcont(ud, message, tocont);  /* finish processing */
+}
+
+
 LUALIB_API lua_State *luaL_newstate (void) {
 LUALIB_API lua_State *luaL_newstate (void) {
   lua_State *L = lua_newstate(l_alloc, NULL);
   lua_State *L = lua_newstate(l_alloc, NULL);
-  if (L) {
-    int *warnstate;  /* space for warning state */
+  if (l_likely(L)) {
     lua_atpanic(L, &panic);
     lua_atpanic(L, &panic);
-    warnstate = (int *)lua_newuserdatauv(L, sizeof(int), 0);
-    luaL_ref(L, LUA_REGISTRYINDEX);  /* make sure it won't be collected */
-    *warnstate = 0;  /* default is warnings off */
-    lua_setwarnf(L, warnf, warnstate);
+    lua_setwarnf(L, warnfoff, L);  /* default is warnings off */
   }
   }
   return L;
   return L;
 }
 }

+ 22 - 3
src/lauxlib.h

@@ -12,11 +12,12 @@
 #include <stddef.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdio.h>
 
 
+#include "luaconf.h"
 #include "lua.h"
 #include "lua.h"
 
 
 
 
 /* global table */
 /* global table */
-#define	LUA_GNAME	"_G"
+#define LUA_GNAME	"_G"
 
 
 
 
 typedef struct luaL_Buffer luaL_Buffer;
 typedef struct luaL_Buffer luaL_Buffer;
@@ -130,10 +131,10 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
   (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
   (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
 
 
 #define luaL_argcheck(L, cond,arg,extramsg)	\
 #define luaL_argcheck(L, cond,arg,extramsg)	\
-		((void)((cond) || luaL_argerror(L, (arg), (extramsg))))
+	((void)(luai_likely(cond) || luaL_argerror(L, (arg), (extramsg))))
 
 
 #define luaL_argexpected(L,cond,arg,tname)	\
 #define luaL_argexpected(L,cond,arg,tname)	\
-		((void)((cond) || luaL_typeerror(L, (arg), (tname))))
+	((void)(luai_likely(cond) || luaL_typeerror(L, (arg), (tname))))
 
 
 #define luaL_checkstring(L,n)	(luaL_checklstring(L, (n), NULL))
 #define luaL_checkstring(L,n)	(luaL_checklstring(L, (n), NULL))
 #define luaL_optstring(L,n,d)	(luaL_optlstring(L, (n), (d), NULL))
 #define luaL_optstring(L,n,d)	(luaL_optlstring(L, (n), (d), NULL))
@@ -157,6 +158,22 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
 #define luaL_pushfail(L)	lua_pushnil(L)
 #define luaL_pushfail(L)	lua_pushnil(L)
 
 
 
 
+/*
+** Internal assertions for in-house debugging
+*/
+#if !defined(lua_assert)
+
+#if defined LUAI_ASSERT
+  #include <assert.h>
+  #define lua_assert(c)		assert(c)
+#else
+  #define lua_assert(c)		((void)0)
+#endif
+
+#endif
+
+
+
 /*
 /*
 ** {======================================================
 ** {======================================================
 ** Generic Buffer manipulation
 ** Generic Buffer manipulation
@@ -185,6 +202,8 @@ struct luaL_Buffer {
 
 
 #define luaL_addsize(B,s)	((B)->n += (s))
 #define luaL_addsize(B,s)	((B)->n += (s))
 
 
+#define luaL_buffsub(B,s)	((B)->n -= (s))
+
 LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
 LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
 LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
 LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
 LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
 LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);

+ 8 - 7
src/lbaselib.c

@@ -138,7 +138,7 @@ static int luaB_setmetatable (lua_State *L) {
   int t = lua_type(L, 2);
   int t = lua_type(L, 2);
   luaL_checktype(L, 1, LUA_TTABLE);
   luaL_checktype(L, 1, LUA_TTABLE);
   luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table");
   luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table");
-  if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL)
+  if (l_unlikely(luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL))
     return luaL_error(L, "cannot change a protected metatable");
     return luaL_error(L, "cannot change a protected metatable");
   lua_settop(L, 2);
   lua_settop(L, 2);
   lua_setmetatable(L, 1);
   lua_setmetatable(L, 1);
@@ -182,7 +182,8 @@ static int luaB_rawset (lua_State *L) {
 
 
 
 
 static int pushmode (lua_State *L, int oldmode) {
 static int pushmode (lua_State *L, int oldmode) {
-  lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" : "generational");
+  lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
+                                           : "generational");
   return 1;
   return 1;
 }
 }
 
 
@@ -299,7 +300,7 @@ static int luaB_ipairs (lua_State *L) {
 
 
 
 
 static int load_aux (lua_State *L, int status, int envidx) {
 static int load_aux (lua_State *L, int status, int envidx) {
-  if (status == LUA_OK) {
+  if (l_likely(status == LUA_OK)) {
     if (envidx != 0) {  /* 'env' parameter? */
     if (envidx != 0) {  /* 'env' parameter? */
       lua_pushvalue(L, envidx);  /* environment for loaded function */
       lua_pushvalue(L, envidx);  /* environment for loaded function */
       if (!lua_setupvalue(L, -2, 1))  /* set it as 1st upvalue */
       if (!lua_setupvalue(L, -2, 1))  /* set it as 1st upvalue */
@@ -355,7 +356,7 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
     *size = 0;
     *size = 0;
     return NULL;
     return NULL;
   }
   }
-  else if (!lua_isstring(L, -1))
+  else if (l_unlikely(!lua_isstring(L, -1)))
     luaL_error(L, "reader function must return a string");
     luaL_error(L, "reader function must return a string");
   lua_replace(L, RESERVEDSLOT);  /* save string in reserved slot */
   lua_replace(L, RESERVEDSLOT);  /* save string in reserved slot */
   return lua_tolstring(L, RESERVEDSLOT, size);
   return lua_tolstring(L, RESERVEDSLOT, size);
@@ -393,7 +394,7 @@ static int dofilecont (lua_State *L, int d1, lua_KContext d2) {
 static int luaB_dofile (lua_State *L) {
 static int luaB_dofile (lua_State *L) {
   const char *fname = luaL_optstring(L, 1, NULL);
   const char *fname = luaL_optstring(L, 1, NULL);
   lua_settop(L, 1);
   lua_settop(L, 1);
-  if (luaL_loadfile(L, fname) != LUA_OK)
+  if (l_unlikely(luaL_loadfile(L, fname) != LUA_OK))
     return lua_error(L);
     return lua_error(L);
   lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
   lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
   return dofilecont(L, 0, 0);
   return dofilecont(L, 0, 0);
@@ -401,7 +402,7 @@ static int luaB_dofile (lua_State *L) {
 
 
 
 
 static int luaB_assert (lua_State *L) {
 static int luaB_assert (lua_State *L) {
-  if (lua_toboolean(L, 1))  /* condition is true? */
+  if (l_likely(lua_toboolean(L, 1)))  /* condition is true? */
     return lua_gettop(L);  /* return all arguments */
     return lua_gettop(L);  /* return all arguments */
   else {  /* error */
   else {  /* error */
     luaL_checkany(L, 1);  /* there must be a condition */
     luaL_checkany(L, 1);  /* there must be a condition */
@@ -437,7 +438,7 @@ static int luaB_select (lua_State *L) {
 ** ignored).
 ** ignored).
 */
 */
 static int finishpcall (lua_State *L, int status, lua_KContext extra) {
 static int finishpcall (lua_State *L, int status, lua_KContext extra) {
-  if (status != LUA_OK && status != LUA_YIELD) {  /* error? */
+  if (l_unlikely(status != LUA_OK && status != LUA_YIELD)) {  /* error? */
     lua_pushboolean(L, 0);  /* first result (false) */
     lua_pushboolean(L, 0);  /* first result (false) */
     lua_pushvalue(L, -2);  /* error message */
     lua_pushvalue(L, -2);  /* error message */
     return 2;  /* return false, msg */
     return 2;  /* return false, msg */

+ 73 - 59
src/lcode.c

@@ -84,8 +84,11 @@ int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v) {
   if (hasjumps(e))
   if (hasjumps(e))
     return 0;  /* not a constant */
     return 0;  /* not a constant */
   switch (e->k) {
   switch (e->k) {
-    case VFALSE: case VTRUE:
-      setbvalue(v, e->k == VTRUE);
+    case VFALSE:
+      setbfvalue(v);
+      return 1;
+    case VTRUE:
+      setbtvalue(v);
       return 1;
       return 1;
     case VNIL:
     case VNIL:
       setnilvalue(v);
       setnilvalue(v);
@@ -110,7 +113,7 @@ int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v) {
 ** optimizations).
 ** optimizations).
 */
 */
 static Instruction *previousinstruction (FuncState *fs) {
 static Instruction *previousinstruction (FuncState *fs) {
-  static const Instruction invalidinstruction = -1;
+  static const Instruction invalidinstruction = ~(Instruction)0;
   if (fs->pc > fs->lasttarget)
   if (fs->pc > fs->lasttarget)
     return &fs->f->code[fs->pc - 1];  /* previous instruction */
     return &fs->f->code[fs->pc - 1];  /* previous instruction */
   else
   else
@@ -311,15 +314,6 @@ void luaK_patchtohere (FuncState *fs, int list) {
 }
 }
 
 
 
 
-/*
-** MAXimum number of successive Instructions WiTHout ABSolute line
-** information.
-*/
-#if !defined(MAXIWTHABS)
-#define MAXIWTHABS	120
-#endif
-
-
 /* limit for difference between lines in relative line info. */
 /* limit for difference between lines in relative line info. */
 #define LIMLINEDIFF	0x80
 #define LIMLINEDIFF	0x80
 
 
@@ -334,13 +328,13 @@ void luaK_patchtohere (FuncState *fs, int list) {
 static void savelineinfo (FuncState *fs, Proto *f, int line) {
 static void savelineinfo (FuncState *fs, Proto *f, int line) {
   int linedif = line - fs->previousline;
   int linedif = line - fs->previousline;
   int pc = fs->pc - 1;  /* last instruction coded */
   int pc = fs->pc - 1;  /* last instruction coded */
-  if (abs(linedif) >= LIMLINEDIFF || fs->iwthabs++ > MAXIWTHABS) {
+  if (abs(linedif) >= LIMLINEDIFF || fs->iwthabs++ >= MAXIWTHABS) {
     luaM_growvector(fs->ls->L, f->abslineinfo, fs->nabslineinfo,
     luaM_growvector(fs->ls->L, f->abslineinfo, fs->nabslineinfo,
                     f->sizeabslineinfo, AbsLineInfo, MAX_INT, "lines");
                     f->sizeabslineinfo, AbsLineInfo, MAX_INT, "lines");
     f->abslineinfo[fs->nabslineinfo].pc = pc;
     f->abslineinfo[fs->nabslineinfo].pc = pc;
     f->abslineinfo[fs->nabslineinfo++].line = line;
     f->abslineinfo[fs->nabslineinfo++].line = line;
     linedif = ABSLINEINFO;  /* signal that there is absolute information */
     linedif = ABSLINEINFO;  /* signal that there is absolute information */
-    fs->iwthabs = 0;  /* restart counter */
+    fs->iwthabs = 1;  /* restart counter */
   }
   }
   luaM_growvector(fs->ls->L, f->lineinfo, pc, f->sizelineinfo, ls_byte,
   luaM_growvector(fs->ls->L, f->lineinfo, pc, f->sizelineinfo, ls_byte,
                   MAX_INT, "opcodes");
                   MAX_INT, "opcodes");
@@ -542,11 +536,14 @@ static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) {
 ** and try to reuse constants. Because some values should not be used
 ** and try to reuse constants. Because some values should not be used
 ** as keys (nil cannot be a key, integer keys can collapse with float
 ** as keys (nil cannot be a key, integer keys can collapse with float
 ** keys), the caller must provide a useful 'key' for indexing the cache.
 ** keys), the caller must provide a useful 'key' for indexing the cache.
+** Note that all functions share the same table, so entering or exiting
+** a function can make some indices wrong.
 */
 */
 static int addk (FuncState *fs, TValue *key, TValue *v) {
 static int addk (FuncState *fs, TValue *key, TValue *v) {
+  TValue val;
   lua_State *L = fs->ls->L;
   lua_State *L = fs->ls->L;
   Proto *f = fs->f;
   Proto *f = fs->f;
-  TValue *idx = luaH_set(L, fs->ls->h, key);  /* index scanner table */
+  const TValue *idx = luaH_get(fs->ls->h, key);  /* query scanner table */
   int k, oldsize;
   int k, oldsize;
   if (ttisinteger(idx)) {  /* is there an index there? */
   if (ttisinteger(idx)) {  /* is there an index there? */
     k = cast_int(ivalue(idx));
     k = cast_int(ivalue(idx));
@@ -560,7 +557,8 @@ static int addk (FuncState *fs, TValue *key, TValue *v) {
   k = fs->nk;
   k = fs->nk;
   /* numerical value does not need GC barrier;
   /* numerical value does not need GC barrier;
      table has no metatable, so it does not need to invalidate cache */
      table has no metatable, so it does not need to invalidate cache */
-  setivalue(idx, k);
+  setivalue(&val, k);
+  luaH_finishset(L, fs->ls->h, key, idx, &val);
   luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants");
   luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants");
   while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
   while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
   setobj(L, &f->k[k], v);
   setobj(L, &f->k[k], v);
@@ -604,11 +602,21 @@ static int luaK_numberK (FuncState *fs, lua_Number r) {
 
 
 
 
 /*
 /*
-** Add a boolean to list of constants and return its index.
+** Add a false to list of constants and return its index.
+*/
+static int boolF (FuncState *fs) {
+  TValue o;
+  setbfvalue(&o);
+  return addk(fs, &o, &o);  /* use boolean itself as key */
+}
+
+
+/*
+** Add a true to list of constants and return its index.
 */
 */
-static int boolK (FuncState *fs, int b) {
+static int boolT (FuncState *fs) {
   TValue o;
   TValue o;
-  setbvalue(&o, b);
+  setbtvalue(&o);
   return addk(fs, &o, &o);  /* use boolean itself as key */
   return addk(fs, &o, &o);  /* use boolean itself as key */
 }
 }
 
 
@@ -653,7 +661,7 @@ void luaK_int (FuncState *fs, int reg, lua_Integer i) {
 
 
 static void luaK_float (FuncState *fs, int reg, lua_Number f) {
 static void luaK_float (FuncState *fs, int reg, lua_Number f) {
   lua_Integer fi;
   lua_Integer fi;
-  if (luaV_flttointeger(f, &fi, 0) && fitsBx(fi))
+  if (luaV_flttointeger(f, &fi, F2Ieq) && fitsBx(fi))
     luaK_codeAsBx(fs, OP_LOADF, reg, cast_int(fi));
     luaK_codeAsBx(fs, OP_LOADF, reg, cast_int(fi));
   else
   else
     luaK_codek(fs, reg, luaK_numberK(fs, f));
     luaK_codek(fs, reg, luaK_numberK(fs, f));
@@ -665,19 +673,22 @@ static void luaK_float (FuncState *fs, int reg, lua_Number f) {
 */
 */
 static void const2exp (TValue *v, expdesc *e) {
 static void const2exp (TValue *v, expdesc *e) {
   switch (ttypetag(v)) {
   switch (ttypetag(v)) {
-    case LUA_TNUMINT:
+    case LUA_VNUMINT:
       e->k = VKINT; e->u.ival = ivalue(v);
       e->k = VKINT; e->u.ival = ivalue(v);
       break;
       break;
-    case LUA_TNUMFLT:
+    case LUA_VNUMFLT:
       e->k = VKFLT; e->u.nval = fltvalue(v);
       e->k = VKFLT; e->u.nval = fltvalue(v);
       break;
       break;
-    case LUA_TBOOLEAN:
-      e->k = bvalue(v) ? VTRUE : VFALSE;
+    case LUA_VFALSE:
+      e->k = VFALSE;
       break;
       break;
-    case LUA_TNIL:
+    case LUA_VTRUE:
+      e->k = VTRUE;
+      break;
+    case LUA_VNIL:
       e->k = VNIL;
       e->k = VNIL;
       break;
       break;
-    case LUA_TSHRSTR:  case LUA_TLNGSTR:
+    case LUA_VSHRSTR:  case LUA_VLNGSTR:
       e->k = VKSTR; e->u.strval = tsvalue(v);
       e->k = VKSTR; e->u.strval = tsvalue(v);
       break;
       break;
     default: lua_assert(0);
     default: lua_assert(0);
@@ -687,19 +698,18 @@ static void const2exp (TValue *v, expdesc *e) {
 
 
 /*
 /*
 ** Fix an expression to return the number of results 'nresults'.
 ** Fix an expression to return the number of results 'nresults'.
-** Either 'e' is a multi-ret expression (function call or vararg)
-** or 'nresults' is LUA_MULTRET (as any expression can satisfy that).
+** 'e' must be a multi-ret expression (function call or vararg).
 */
 */
 void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
 void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
   Instruction *pc = &getinstruction(fs, e);
   Instruction *pc = &getinstruction(fs, e);
   if (e->k == VCALL)  /* expression is an open function call? */
   if (e->k == VCALL)  /* expression is an open function call? */
     SETARG_C(*pc, nresults + 1);
     SETARG_C(*pc, nresults + 1);
-  else if (e->k == VVARARG) {
+  else {
+    lua_assert(e->k == VVARARG);
     SETARG_C(*pc, nresults + 1);
     SETARG_C(*pc, nresults + 1);
     SETARG_A(*pc, fs->freereg);
     SETARG_A(*pc, fs->freereg);
     luaK_reserveregs(fs, 1);
     luaK_reserveregs(fs, 1);
   }
   }
-  else lua_assert(nresults == LUA_MULTRET);
 }
 }
 
 
 
 
@@ -738,7 +748,7 @@ void luaK_setoneret (FuncState *fs, expdesc *e) {
 
 
 
 
 /*
 /*
-** Ensure that expression 'e' is not a variable (nor a constant).
+** Ensure that expression 'e' is not a variable (nor a <const>).
 ** (Expression still may have jump lists.)
 ** (Expression still may have jump lists.)
 */
 */
 void luaK_dischargevars (FuncState *fs, expdesc *e) {
 void luaK_dischargevars (FuncState *fs, expdesc *e) {
@@ -748,7 +758,7 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
       break;
       break;
     }
     }
     case VLOCAL: {  /* already in a register */
     case VLOCAL: {  /* already in a register */
-      e->u.info = e->u.var.sidx;
+      e->u.info = e->u.var.ridx;
       e->k = VNONRELOC;  /* becomes a non-relocatable value */
       e->k = VNONRELOC;  /* becomes a non-relocatable value */
       break;
       break;
     }
     }
@@ -790,8 +800,8 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
 
 
 
 
 /*
 /*
-** Ensures expression value is in register 'reg' (and therefore
-** 'e' will become a non-relocatable expression).
+** Ensure expression value is in register 'reg', making 'e' a
+** non-relocatable expression.
 ** (Expression still may have jump lists.)
 ** (Expression still may have jump lists.)
 */
 */
 static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
 static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
@@ -801,8 +811,12 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
       luaK_nil(fs, reg, 1);
       luaK_nil(fs, reg, 1);
       break;
       break;
     }
     }
-    case VFALSE: case VTRUE: {
-      luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
+    case VFALSE: {
+      luaK_codeABC(fs, OP_LOADFALSE, reg, 0, 0);
+      break;
+    }
+    case VTRUE: {
+      luaK_codeABC(fs, OP_LOADTRUE, reg, 0, 0);
       break;
       break;
     }
     }
     case VKSTR: {
     case VKSTR: {
@@ -841,7 +855,8 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
 
 
 
 
 /*
 /*
-** Ensures expression value is in any register.
+** Ensure expression value is in a register, making 'e' a
+** non-relocatable expression.
 ** (Expression still may have jump lists.)
 ** (Expression still may have jump lists.)
 */
 */
 static void discharge2anyreg (FuncState *fs, expdesc *e) {
 static void discharge2anyreg (FuncState *fs, expdesc *e) {
@@ -852,9 +867,9 @@ static void discharge2anyreg (FuncState *fs, expdesc *e) {
 }
 }
 
 
 
 
-static int code_loadbool (FuncState *fs, int A, int b, int jump) {
+static int code_loadbool (FuncState *fs, int A, OpCode op) {
   luaK_getlabel(fs);  /* those instructions may be jump targets */
   luaK_getlabel(fs);  /* those instructions may be jump targets */
-  return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
+  return luaK_codeABC(fs, op, A, 0, 0);
 }
 }
 
 
 
 
@@ -888,8 +903,8 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) {
     int p_t = NO_JUMP;  /* position of an eventual LOAD true */
     int p_t = NO_JUMP;  /* position of an eventual LOAD true */
     if (need_value(fs, e->t) || need_value(fs, e->f)) {
     if (need_value(fs, e->t) || need_value(fs, e->f)) {
       int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
       int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
-      p_f = code_loadbool(fs, reg, 0, 1);  /* load false and skip next i. */
-      p_t = code_loadbool(fs, reg, 1, 0);  /* load true */
+      p_f = code_loadbool(fs, reg, OP_LFALSESKIP);  /* skip next inst. */
+      p_t = code_loadbool(fs, reg, OP_LOADTRUE);
       /* jump around these booleans if 'e' is not a test */
       /* jump around these booleans if 'e' is not a test */
       luaK_patchtohere(fs, fj);
       luaK_patchtohere(fs, fj);
     }
     }
@@ -927,8 +942,11 @@ int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
       exp2reg(fs, e, e->u.info);  /* put final result in it */
       exp2reg(fs, e, e->u.info);  /* put final result in it */
       return e->u.info;
       return e->u.info;
     }
     }
+    /* else expression has jumps and cannot change its register
+       to hold the jump values, because it is a local variable.
+       Go through to the default case. */
   }
   }
-  luaK_exp2nextreg(fs, e);  /* otherwise, use next available register */
+  luaK_exp2nextreg(fs, e);  /* default: use next available register */
   return e->u.info;
   return e->u.info;
 }
 }
 
 
@@ -963,8 +981,8 @@ static int luaK_exp2K (FuncState *fs, expdesc *e) {
   if (!hasjumps(e)) {
   if (!hasjumps(e)) {
     int info;
     int info;
     switch (e->k) {  /* move constants to 'k' */
     switch (e->k) {  /* move constants to 'k' */
-      case VTRUE: info = boolK(fs, 1); break;
-      case VFALSE: info = boolK(fs, 0); break;
+      case VTRUE: info = boolT(fs); break;
+      case VFALSE: info = boolF(fs); break;
       case VNIL: info = nilK(fs); break;
       case VNIL: info = nilK(fs); break;
       case VKINT: info = luaK_intK(fs, e->u.ival); break;
       case VKINT: info = luaK_intK(fs, e->u.ival); break;
       case VKFLT: info = luaK_numberK(fs, e->u.nval); break;
       case VKFLT: info = luaK_numberK(fs, e->u.nval); break;
@@ -1013,7 +1031,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
   switch (var->k) {
   switch (var->k) {
     case VLOCAL: {
     case VLOCAL: {
       freeexp(fs, ex);
       freeexp(fs, ex);
-      exp2reg(fs, ex, var->u.var.sidx);  /* compute 'ex' into proper place */
+      exp2reg(fs, ex, var->u.var.ridx);  /* compute 'ex' into proper place */
       return;
       return;
     }
     }
     case VUPVAL: {
     case VUPVAL: {
@@ -1220,7 +1238,7 @@ static int isSCnumber (expdesc *e, int *pi, int *isfloat) {
   lua_Integer i;
   lua_Integer i;
   if (e->k == VKINT)
   if (e->k == VKINT)
     i = e->u.ival;
     i = e->u.ival;
-  else if (e->k == VKFLT && luaV_flttointeger(e->u.nval, &i, 0))
+  else if (e->k == VKFLT && luaV_flttointeger(e->u.nval, &i, F2Ieq))
     *isfloat = 1;
     *isfloat = 1;
   else
   else
     return 0;  /* not a number */
     return 0;  /* not a number */
@@ -1253,7 +1271,7 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
   }
   }
   else {
   else {
     /* register index of the table */
     /* register index of the table */
-    t->u.ind.t = (t->k == VLOCAL) ? t->u.var.sidx: t->u.info;
+    t->u.ind.t = (t->k == VLOCAL) ? t->u.var.ridx: t->u.info;
     if (isKstr(fs, k)) {
     if (isKstr(fs, k)) {
       t->u.ind.idx = k->u.info;  /* literal string */
       t->u.ind.idx = k->u.info;  /* literal string */
       t->k = VINDEXSTR;
       t->k = VINDEXSTR;
@@ -1280,7 +1298,8 @@ static int validop (int op, TValue *v1, TValue *v2) {
     case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:
     case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:
     case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: {  /* conversion errors */
     case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: {  /* conversion errors */
       lua_Integer i;
       lua_Integer i;
-      return (tointegerns(v1, &i) && tointegerns(v2, &i));
+      return (luaV_tointegerns(v1, &i, LUA_FLOORN2I) &&
+              luaV_tointegerns(v2, &i, LUA_FLOORN2I));
     }
     }
     case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD:  /* division by 0 */
     case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD:  /* division by 0 */
       return (nvalue(v2) != 0);
       return (nvalue(v2) != 0);
@@ -1509,7 +1528,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
     lua_assert(e1->k == VK || e1->k == VKINT || e1->k == VKFLT);
     lua_assert(e1->k == VK || e1->k == VKINT || e1->k == VKFLT);
     swapexps(e1, e2);
     swapexps(e1, e2);
   }
   }
-  r1 = luaK_exp2anyreg(fs, e1);  /* 1nd expression must be in register */
+  r1 = luaK_exp2anyreg(fs, e1);  /* 1st expression must be in register */
   if (isSCnumber(e2, &im, &isfloat)) {
   if (isSCnumber(e2, &im, &isfloat)) {
     op = OP_EQI;
     op = OP_EQI;
     r2 = im;  /* immediate operand */
     r2 = im;  /* immediate operand */
@@ -1710,17 +1729,12 @@ void luaK_fixline (FuncState *fs, int line) {
 }
 }
 
 
 
 
-void luaK_settablesize (FuncState *fs, int pc, int ra, int rc, int rb) {
+void luaK_settablesize (FuncState *fs, int pc, int ra, int asize, int hsize) {
   Instruction *inst = &fs->f->code[pc];
   Instruction *inst = &fs->f->code[pc];
-  int extra = 0;
-  int k = 0;
-  if (rb != 0)
-    rb = luaO_ceillog2(rb) + 1;  /* hash size */
-  if (rc > MAXARG_C) {  /* does it need the extra argument? */
-    extra = rc / (MAXARG_C + 1);
-    rc %= (MAXARG_C + 1);
-    k = 1;
-  }
+  int rb = (hsize != 0) ? luaO_ceillog2(hsize) + 1 : 0;  /* hash size */
+  int extra = asize / (MAXARG_C + 1);  /* higher bits of array size */
+  int rc = asize % (MAXARG_C + 1);  /* lower bits of array size */
+  int k = (extra > 0);  /* true iff needs extra argument */
   *inst = CREATE_ABCk(OP_NEWTABLE, ra, rb, rc, k);
   *inst = CREATE_ABCk(OP_NEWTABLE, ra, rb, rc, k);
   *(inst + 1) = CREATE_Ax(OP_EXTRAARG, extra);
   *(inst + 1) = CREATE_Ax(OP_EXTRAARG, extra);
 }
 }

+ 1 - 1
src/lcode.h

@@ -95,7 +95,7 @@ LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
 LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1,
 LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1,
                             expdesc *v2, int line);
                             expdesc *v2, int line);
 LUAI_FUNC void luaK_settablesize (FuncState *fs, int pc,
 LUAI_FUNC void luaK_settablesize (FuncState *fs, int pc,
-                                                 int ra, int rb, int rc);
+                                  int ra, int asize, int hsize);
 LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
 LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
 LUAI_FUNC void luaK_finish (FuncState *fs);
 LUAI_FUNC void luaK_finish (FuncState *fs);
 LUAI_FUNC l_noret luaK_semerror (LexState *ls, const char *msg);
 LUAI_FUNC l_noret luaK_semerror (LexState *ls, const char *msg);

+ 12 - 8
src/lcorolib.c

@@ -31,14 +31,14 @@ static lua_State *getco (lua_State *L) {
 */
 */
 static int auxresume (lua_State *L, lua_State *co, int narg) {
 static int auxresume (lua_State *L, lua_State *co, int narg) {
   int status, nres;
   int status, nres;
-  if (!lua_checkstack(co, narg)) {
+  if (l_unlikely(!lua_checkstack(co, narg))) {
     lua_pushliteral(L, "too many arguments to resume");
     lua_pushliteral(L, "too many arguments to resume");
     return -1;  /* error flag */
     return -1;  /* error flag */
   }
   }
   lua_xmove(L, co, narg);
   lua_xmove(L, co, narg);
   status = lua_resume(co, L, narg, &nres);
   status = lua_resume(co, L, narg, &nres);
-  if (status == LUA_OK || status == LUA_YIELD) {
-    if (!lua_checkstack(L, nres + 1)) {
+  if (l_likely(status == LUA_OK || status == LUA_YIELD)) {
+    if (l_unlikely(!lua_checkstack(L, nres + 1))) {
       lua_pop(co, nres);  /* remove results anyway */
       lua_pop(co, nres);  /* remove results anyway */
       lua_pushliteral(L, "too many results to resume");
       lua_pushliteral(L, "too many results to resume");
       return -1;  /* error flag */
       return -1;  /* error flag */
@@ -57,7 +57,7 @@ static int luaB_coresume (lua_State *L) {
   lua_State *co = getco(L);
   lua_State *co = getco(L);
   int r;
   int r;
   r = auxresume(L, co, lua_gettop(L) - 1);
   r = auxresume(L, co, lua_gettop(L) - 1);
-  if (r < 0) {
+  if (l_unlikely(r < 0)) {
     lua_pushboolean(L, 0);
     lua_pushboolean(L, 0);
     lua_insert(L, -2);
     lua_insert(L, -2);
     return 2;  /* return false + error message */
     return 2;  /* return false + error message */
@@ -73,11 +73,15 @@ static int luaB_coresume (lua_State *L) {
 static int luaB_auxwrap (lua_State *L) {
 static int luaB_auxwrap (lua_State *L) {
   lua_State *co = lua_tothread(L, lua_upvalueindex(1));
   lua_State *co = lua_tothread(L, lua_upvalueindex(1));
   int r = auxresume(L, co, lua_gettop(L));
   int r = auxresume(L, co, lua_gettop(L));
-  if (r < 0) {
+  if (l_unlikely(r < 0)) {  /* error? */
     int stat = lua_status(co);
     int stat = lua_status(co);
-    if (stat != LUA_OK && stat != LUA_YIELD)
-      lua_resetthread(co);  /* close variables in case of errors */
-    if (lua_type(L, -1) == LUA_TSTRING) {  /* error object is a string? */
+    if (stat != LUA_OK && stat != LUA_YIELD) {  /* error in the coroutine? */
+      stat = lua_resetthread(co);  /* close its tbc variables */
+      lua_assert(stat != LUA_OK);
+      lua_xmove(co, L, 1);  /* copy error message */
+    }
+    if (stat != LUA_ERRMEM &&  /* not a memory error and ... */
+        lua_type(L, -1) == LUA_TSTRING) {  /* ... error object is a string? */
       luaL_where(L, 1);  /* add extra info, if available */
       luaL_where(L, 1);  /* add extra info, if available */
       lua_insert(L, -2);
       lua_insert(L, -2);
       lua_concat(L, 2);
       lua_concat(L, 2);

+ 25 - 16
src/lctype.c

@@ -16,6 +16,15 @@
 
 
 #include <limits.h>
 #include <limits.h>
 
 
+
+#if defined (LUA_UCID)		/* accept UniCode IDentifiers? */
+/* consider all non-ascii codepoints to be alphabetic */
+#define NONA		0x01
+#else
+#define NONA		0x00	/* default */
+#endif
+
+
 LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = {
 LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = {
   0x00,  /* EOZ */
   0x00,  /* EOZ */
   0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* 0. */
   0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* 0. */
@@ -34,22 +43,22 @@ LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = {
   0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,
   0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,
   0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,	/* 7. */
   0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,	/* 7. */
   0x05,  0x05,  0x05,  0x04,  0x04,  0x04,  0x04,  0x00,
   0x05,  0x05,  0x05,  0x04,  0x04,  0x04,  0x04,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* 8. */
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* 9. */
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* a. */
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* b. */
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* c. */
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* d. */
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* e. */
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* f. */
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,	/* 8. */
+  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,
+  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,	/* 9. */
+  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,
+  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,	/* a. */
+  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,
+  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,	/* b. */
+  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,
+  0x00,  0x00,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,	/* c. */
+  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,
+  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,	/* d. */
+  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,
+  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,	/* e. */
+  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,  NONA,
+  NONA,  NONA,  NONA,  NONA,  NONA,  0x00,  0x00,  0x00,	/* f. */
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00
 };
 };
 
 
 #endif			/* } */
 #endif			/* } */

+ 10 - 4
src/lctype.h

@@ -13,7 +13,7 @@
 /*
 /*
 ** WARNING: the functions defined here do not necessarily correspond
 ** WARNING: the functions defined here do not necessarily correspond
 ** to the similar functions in the standard C ctype.h. They are
 ** to the similar functions in the standard C ctype.h. They are
-** optimized for the specific needs of Lua
+** optimized for the specific needs of Lua.
 */
 */
 
 
 #if !defined(LUA_USE_CTYPE)
 #if !defined(LUA_USE_CTYPE)
@@ -61,13 +61,19 @@
 #define lisprint(c)	testprop(c, MASK(PRINTBIT))
 #define lisprint(c)	testprop(c, MASK(PRINTBIT))
 #define lisxdigit(c)	testprop(c, MASK(XDIGITBIT))
 #define lisxdigit(c)	testprop(c, MASK(XDIGITBIT))
 
 
+
 /*
 /*
-** this 'ltolower' only works for alphabetic characters
+** In ASCII, this 'ltolower' is correct for alphabetic characters and
+** for '.'. That is enough for Lua needs. ('check_exp' ensures that
+** the character either is an upper-case letter or is unchanged by
+** the transformation, which holds for lower-case letters and '.'.)
 */
 */
-#define ltolower(c)	((c) | ('A' ^ 'a'))
+#define ltolower(c)  \
+  check_exp(('A' <= (c) && (c) <= 'Z') || (c) == ((c) | ('A' ^ 'a')),  \
+            (c) | ('A' ^ 'a'))
 
 
 
 
-/* two more entries for 0 and -1 (EOZ) */
+/* one entry for each character and for -1 (EOZ) */
 LUAI_DDEC(const lu_byte luai_ctype_[UCHAR_MAX + 2];)
 LUAI_DDEC(const lu_byte luai_ctype_[UCHAR_MAX + 2];)
 
 
 
 

+ 26 - 20
src/ldblib.c

@@ -33,7 +33,7 @@ static const char *const HOOKKEY = "_HOOKKEY";
 ** checked.
 ** checked.
 */
 */
 static void checkstack (lua_State *L, lua_State *L1, int n) {
 static void checkstack (lua_State *L, lua_State *L1, int n) {
-  if (L != L1 && !lua_checkstack(L1, n))
+  if (l_unlikely(L != L1 && !lua_checkstack(L1, n)))
     luaL_error(L, "stack overflow");
     luaL_error(L, "stack overflow");
 }
 }
 
 
@@ -152,6 +152,7 @@ static int db_getinfo (lua_State *L) {
   lua_State *L1 = getthread(L, &arg);
   lua_State *L1 = getthread(L, &arg);
   const char *options = luaL_optstring(L, arg+2, "flnSrtu");
   const char *options = luaL_optstring(L, arg+2, "flnSrtu");
   checkstack(L, L1, 3);
   checkstack(L, L1, 3);
+  luaL_argcheck(L, options[0] != '>', arg + 2, "invalid option '>'");
   if (lua_isfunction(L, arg + 1)) {  /* info about a function? */
   if (lua_isfunction(L, arg + 1)) {  /* info about a function? */
     options = lua_pushfstring(L, ">%s", options);  /* add '>' to 'options' */
     options = lua_pushfstring(L, ">%s", options);  /* add '>' to 'options' */
     lua_pushvalue(L, arg + 1);  /* move function to 'L1' stack */
     lua_pushvalue(L, arg + 1);  /* move function to 'L1' stack */
@@ -202,8 +203,6 @@ static int db_getinfo (lua_State *L) {
 static int db_getlocal (lua_State *L) {
 static int db_getlocal (lua_State *L) {
   int arg;
   int arg;
   lua_State *L1 = getthread(L, &arg);
   lua_State *L1 = getthread(L, &arg);
-  lua_Debug ar;
-  const char *name;
   int nvar = (int)luaL_checkinteger(L, arg + 2);  /* local-variable index */
   int nvar = (int)luaL_checkinteger(L, arg + 2);  /* local-variable index */
   if (lua_isfunction(L, arg + 1)) {  /* function argument? */
   if (lua_isfunction(L, arg + 1)) {  /* function argument? */
     lua_pushvalue(L, arg + 1);  /* push function */
     lua_pushvalue(L, arg + 1);  /* push function */
@@ -211,8 +210,10 @@ static int db_getlocal (lua_State *L) {
     return 1;  /* return only name (there is no value) */
     return 1;  /* return only name (there is no value) */
   }
   }
   else {  /* stack-level argument */
   else {  /* stack-level argument */
+    lua_Debug ar;
+    const char *name;
     int level = (int)luaL_checkinteger(L, arg + 1);
     int level = (int)luaL_checkinteger(L, arg + 1);
-    if (!lua_getstack(L1, level, &ar))  /* out of range? */
+    if (l_unlikely(!lua_getstack(L1, level, &ar)))  /* out of range? */
       return luaL_argerror(L, arg+1, "level out of range");
       return luaL_argerror(L, arg+1, "level out of range");
     checkstack(L, L1, 1);
     checkstack(L, L1, 1);
     name = lua_getlocal(L1, &ar, nvar);
     name = lua_getlocal(L1, &ar, nvar);
@@ -237,7 +238,7 @@ static int db_setlocal (lua_State *L) {
   lua_Debug ar;
   lua_Debug ar;
   int level = (int)luaL_checkinteger(L, arg + 1);
   int level = (int)luaL_checkinteger(L, arg + 1);
   int nvar = (int)luaL_checkinteger(L, arg + 2);
   int nvar = (int)luaL_checkinteger(L, arg + 2);
-  if (!lua_getstack(L1, level, &ar))  /* out of range? */
+  if (l_unlikely(!lua_getstack(L1, level, &ar)))  /* out of range? */
     return luaL_argerror(L, arg+1, "level out of range");
     return luaL_argerror(L, arg+1, "level out of range");
   luaL_checkany(L, arg+3);
   luaL_checkany(L, arg+3);
   lua_settop(L, arg+3);
   lua_settop(L, arg+3);
@@ -281,25 +282,33 @@ static int db_setupvalue (lua_State *L) {
 ** Check whether a given upvalue from a given closure exists and
 ** Check whether a given upvalue from a given closure exists and
 ** returns its index
 ** returns its index
 */
 */
-static int checkupval (lua_State *L, int argf, int argnup) {
+static void *checkupval (lua_State *L, int argf, int argnup, int *pnup) {
+  void *id;
   int nup = (int)luaL_checkinteger(L, argnup);  /* upvalue index */
   int nup = (int)luaL_checkinteger(L, argnup);  /* upvalue index */
   luaL_checktype(L, argf, LUA_TFUNCTION);  /* closure */
   luaL_checktype(L, argf, LUA_TFUNCTION);  /* closure */
-  luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup,
-                   "invalid upvalue index");
-  return nup;
+  id = lua_upvalueid(L, argf, nup);
+  if (pnup) {
+    luaL_argcheck(L, id != NULL, argnup, "invalid upvalue index");
+    *pnup = nup;
+  }
+  return id;
 }
 }
 
 
 
 
 static int db_upvalueid (lua_State *L) {
 static int db_upvalueid (lua_State *L) {
-  int n = checkupval(L, 1, 2);
-  lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));
+  void *id = checkupval(L, 1, 2, NULL);
+  if (id != NULL)
+    lua_pushlightuserdata(L, id);
+  else
+    luaL_pushfail(L);
   return 1;
   return 1;
 }
 }
 
 
 
 
 static int db_upvaluejoin (lua_State *L) {
 static int db_upvaluejoin (lua_State *L) {
-  int n1 = checkupval(L, 1, 2);
-  int n2 = checkupval(L, 3, 4);
+  int n1, n2;
+  checkupval(L, 1, 2, &n1);
+  checkupval(L, 3, 4, &n2);
   luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
   luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
   luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
   luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
   lua_upvaluejoin(L, 1, n1, 3, n2);
   lua_upvaluejoin(L, 1, n1, 3, n2);
@@ -369,7 +378,7 @@ static int db_sethook (lua_State *L) {
   }
   }
   if (!luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)) {
   if (!luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)) {
     /* table just created; initialize it */
     /* table just created; initialize it */
-    lua_pushstring(L, "k");
+    lua_pushliteral(L, "k");
     lua_setfield(L, -2, "__mode");  /** hooktable.__mode = "k" */
     lua_setfield(L, -2, "__mode");  /** hooktable.__mode = "k" */
     lua_pushvalue(L, -1);
     lua_pushvalue(L, -1);
     lua_setmetatable(L, -2);  /* metatable(hooktable) = hooktable */
     lua_setmetatable(L, -2);  /* metatable(hooktable) = hooktable */
@@ -412,12 +421,12 @@ static int db_debug (lua_State *L) {
   for (;;) {
   for (;;) {
     char buffer[250];
     char buffer[250];
     lua_writestringerror("%s", "lua_debug> ");
     lua_writestringerror("%s", "lua_debug> ");
-    if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
+    if (fgets(buffer, sizeof(buffer), stdin) == NULL ||
         strcmp(buffer, "cont\n") == 0)
         strcmp(buffer, "cont\n") == 0)
       return 0;
       return 0;
     if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
     if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
         lua_pcall(L, 0, 0, 0))
         lua_pcall(L, 0, 0, 0))
-      lua_writestringerror("%s\n", lua_tostring(L, -1));
+      lua_writestringerror("%s\n", luaL_tolstring(L, -1, NULL));
     lua_settop(L, 0);  /* remove eventual returns */
     lua_settop(L, 0);  /* remove eventual returns */
   }
   }
 }
 }
@@ -440,10 +449,7 @@ static int db_traceback (lua_State *L) {
 static int db_setcstacklimit (lua_State *L) {
 static int db_setcstacklimit (lua_State *L) {
   int limit = (int)luaL_checkinteger(L, 1);
   int limit = (int)luaL_checkinteger(L, 1);
   int res = lua_setcstacklimit(L, limit);
   int res = lua_setcstacklimit(L, limit);
-  if (res == 0)
-    lua_pushboolean(L, 0);
-  else
-    lua_pushinteger(L, res);
+  lua_pushinteger(L, res);
   return 1;
   return 1;
 }
 }
 
 

+ 112 - 74
src/ldebug.c

@@ -31,11 +31,7 @@
 
 
 
 
 
 
-#define noLuaClosure(f)		((f) == NULL || (f)->c.tt == LUA_TCCL)
-
-
-/* Active Lua function (given call info) */
-#define ci_func(ci)		(clLvalue(s2v((ci)->func)))
+#define noLuaClosure(f)		((f) == NULL || (f)->c.tt == LUA_VCCL)
 
 
 
 
 static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
 static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
@@ -50,10 +46,16 @@ static int currentpc (CallInfo *ci) {
 
 
 /*
 /*
 ** Get a "base line" to find the line corresponding to an instruction.
 ** Get a "base line" to find the line corresponding to an instruction.
-** For that, search the array of absolute line info for the largest saved
-** instruction smaller or equal to the wanted instruction. A special
-** case is when there is no absolute info or the instruction is before
-** the first absolute one.
+** Base lines are regularly placed at MAXIWTHABS intervals, so usually
+** an integer division gets the right place. When the source file has
+** large sequences of empty/comment lines, it may need extra entries,
+** so the original estimate needs a correction.
+** If the original estimate is -1, the initial 'if' ensures that the
+** 'while' will run at least once.
+** The assertion that the estimate is a lower bound for the correct base
+** is valid as long as the debug info has been generated with the same
+** value for MAXIWTHABS or smaller. (Previous releases use a little
+** smaller value.)
 */
 */
 static int getbaseline (const Proto *f, int pc, int *basepc) {
 static int getbaseline (const Proto *f, int pc, int *basepc) {
   if (f->sizeabslineinfo == 0 || pc < f->abslineinfo[0].pc) {
   if (f->sizeabslineinfo == 0 || pc < f->abslineinfo[0].pc) {
@@ -61,20 +63,12 @@ static int getbaseline (const Proto *f, int pc, int *basepc) {
     return f->linedefined;
     return f->linedefined;
   }
   }
   else {
   else {
-    unsigned int i;
-    if (pc >= f->abslineinfo[f->sizeabslineinfo - 1].pc)
-      i = f->sizeabslineinfo - 1;  /* instruction is after last saved one */
-    else {  /* binary search */
-      unsigned int j = f->sizeabslineinfo - 1;  /* pc < anchorlines[j] */
-      i = 0;  /* abslineinfo[i] <= pc */
-      while (i < j - 1) {
-        unsigned int m = (j + i) / 2;
-        if (pc >= f->abslineinfo[m].pc)
-          i = m;
-        else
-          j = m;
-      }
-    }
+    int i = cast_uint(pc) / MAXIWTHABS - 1;  /* get an estimate */
+    /* estimate must be a lower bond of the correct base */
+    lua_assert(i < 0 ||
+              (i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
+    while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc)
+      i++;  /* low estimate; adjust it */
     *basepc = f->abslineinfo[i].pc;
     *basepc = f->abslineinfo[i].pc;
     return f->abslineinfo[i].line;
     return f->abslineinfo[i].line;
   }
   }
@@ -101,19 +95,21 @@ int luaG_getfuncline (const Proto *f, int pc) {
 }
 }
 
 
 
 
-static int currentline (CallInfo *ci) {
+static int getcurrentline (CallInfo *ci) {
   return luaG_getfuncline(ci_func(ci)->p, currentpc(ci));
   return luaG_getfuncline(ci_func(ci)->p, currentpc(ci));
 }
 }
 
 
 
 
 /*
 /*
-** This function can be called asynchronously (e.g. during a signal),
-** under "reasonable" assumptions. A new 'ci' is completely linked
-** in the list before it becomes part of the "active" list, and
-** we assume that pointers are atomic (see comment in next function).
-** (If we traverse one more item, there is no problem. If we traverse
-** one less item, the worst that can happen is that the signal will
-** not interrupt the script.)
+** Set 'trap' for all active Lua frames.
+** This function can be called during a signal, under "reasonable"
+** assumptions. A new 'ci' is completely linked in the list before it
+** becomes part of the "active" list, and we assume that pointers are
+** atomic; see comment in next function.
+** (A compiler doing interprocedural optimizations could, theoretically,
+** reorder memory writes in such a way that the list could be
+** temporarily broken while inserting a new element. We simply assume it
+** has no good reasons to do that.)
 */
 */
 static void settraps (CallInfo *ci) {
 static void settraps (CallInfo *ci) {
   for (; ci != NULL; ci = ci->previous)
   for (; ci != NULL; ci = ci->previous)
@@ -123,22 +119,20 @@ static void settraps (CallInfo *ci) {
 
 
 
 
 /*
 /*
-** This function can be called asynchronously (e.g. during a signal),
-** under "reasonable" assumptions.
-** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by
-** 'resethookcount') are for debug only, and it is no problem if they
-** get arbitrary values (causes at most one wrong hook call). 'hookmask'
-** is an atomic value. We assume that pointers are atomic too (e.g., gcc
-** ensures that for all platforms where it runs). Moreover, 'hook' is
-** always checked before being called (see 'luaD_hook').
+** This function can be called during a signal, under "reasonable"
+** assumptions.
+** Fields 'basehookcount' and 'hookcount' (set by 'resethookcount')
+** are for debug only, and it is no problem if they get arbitrary
+** values (causes at most one wrong hook call). 'hookmask' is an atomic
+** value. We assume that pointers are atomic too (e.g., gcc ensures that
+** for all platforms where it runs). Moreover, 'hook' is always checked
+** before being called (see 'luaD_hook').
 */
 */
 LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
 LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
   if (func == NULL || mask == 0) {  /* turn off hooks? */
   if (func == NULL || mask == 0) {  /* turn off hooks? */
     mask = 0;
     mask = 0;
     func = NULL;
     func = NULL;
   }
   }
-  if (isLua(L->ci))
-    L->oldpc = L->ci->u.l.savedpc;
   L->hook = func;
   L->hook = func;
   L->basehookcount = count;
   L->basehookcount = count;
   resethookcount(L);
   resethookcount(L);
@@ -190,8 +184,8 @@ static const char *upvalname (const Proto *p, int uv) {
 static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
 static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
   if (clLvalue(s2v(ci->func))->p->is_vararg) {
   if (clLvalue(s2v(ci->func))->p->is_vararg) {
     int nextra = ci->u.l.nextraargs;
     int nextra = ci->u.l.nextraargs;
-    if (n <= nextra) {
-      *pos = ci->func - nextra + (n - 1);
+    if (n >= -nextra) {  /* 'n' is negative */
+      *pos = ci->func - nextra - (n + 1);
       return "(vararg)";  /* generic name for any vararg */
       return "(vararg)";  /* generic name for any vararg */
     }
     }
   }
   }
@@ -204,7 +198,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
   const char *name = NULL;
   const char *name = NULL;
   if (isLua(ci)) {
   if (isLua(ci)) {
     if (n < 0)  /* access to vararg values? */
     if (n < 0)  /* access to vararg values? */
-      return findvararg(ci, -n, pos);
+      return findvararg(ci, n, pos);
     else
     else
       name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
       name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
   }
   }
@@ -306,9 +300,9 @@ static void collectvalidlines (lua_State *L, Closure *f) {
     Table *t = luaH_new(L);  /* new table to store active lines */
     Table *t = luaH_new(L);  /* new table to store active lines */
     sethvalue2s(L, L->top, t);  /* push it on stack */
     sethvalue2s(L, L->top, t);  /* push it on stack */
     api_incr_top(L);
     api_incr_top(L);
-    setbvalue(&v, 1);  /* boolean 'true' to be the value of all indices */
-    for (i = 0; i < p->sizelineinfo; i++) {  /* for all lines with code */
-      currentline = nextline(p, currentline, i);
+    setbtvalue(&v);  /* boolean 'true' to be the value of all indices */
+    for (i = 0; i < p->sizelineinfo; i++) {  /* for all instructions */
+      currentline = nextline(p, currentline, i);  /* get its line */
       luaH_setint(L, t, currentline, &v);  /* table[line] = true */
       luaH_setint(L, t, currentline, &v);  /* table[line] = true */
     }
     }
   }
   }
@@ -339,7 +333,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
         break;
         break;
       }
       }
       case 'l': {
       case 'l': {
-        ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1;
+        ar->currentline = (ci && isLua(ci)) ? getcurrentline(ci) : -1;
         break;
         break;
       }
       }
       case 'u': {
       case 'u': {
@@ -631,12 +625,10 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
     case OP_LEN: tm = TM_LEN; break;
     case OP_LEN: tm = TM_LEN; break;
     case OP_CONCAT: tm = TM_CONCAT; break;
     case OP_CONCAT: tm = TM_CONCAT; break;
     case OP_EQ: tm = TM_EQ; break;
     case OP_EQ: tm = TM_EQ; break;
-    case OP_LT: case OP_LE: case OP_LTI: case OP_LEI:
-      *name = "order";  /* '<=' can call '__lt', etc. */
-      return "metamethod";
-    case OP_CLOSE: case OP_RETURN:
-      *name = "close";
-      return "metamethod";
+    /* no cases for OP_EQI and OP_EQK, as they don't call metamethods */
+    case OP_LT: case OP_LTI: case OP_GTI: tm = TM_LT; break;
+    case OP_LE: case OP_LEI: case OP_GEI: tm = TM_LE; break;
+    case OP_CLOSE: case OP_RETURN: tm = TM_CLOSE; break;
     default:
     default:
       return NULL;  /* cannot find a reasonable name */
       return NULL;  /* cannot find a reasonable name */
   }
   }
@@ -649,14 +641,18 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
 
 
 
 
 /*
 /*
-** The subtraction of two potentially unrelated pointers is
-** not ISO C, but it should not crash a program; the subsequent
-** checks are ISO C and ensure a correct result.
+** Check whether pointer 'o' points to some value in the stack
+** frame of the current function. Because 'o' may not point to a
+** value in this stack, we cannot compare it with the region
+** boundaries (undefined behaviour in ISO C).
 */
 */
 static int isinstack (CallInfo *ci, const TValue *o) {
 static int isinstack (CallInfo *ci, const TValue *o) {
-  StkId base = ci->func + 1;
-  ptrdiff_t i = cast(StkId, o) - base;
-  return (0 <= i && i < (ci->top - base) && s2v(base + i) == o);
+  StkId pos;
+  for (pos = ci->func + 1; pos < ci->top; pos++) {
+    if (o == s2v(pos))
+      return 1;
+  }
+  return 0;  /* not found */
 }
 }
 
 
 
 
@@ -699,6 +695,19 @@ l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
 }
 }
 
 
 
 
+l_noret luaG_callerror (lua_State *L, const TValue *o) {
+  CallInfo *ci = L->ci;
+  const char *name = NULL;  /* to avoid warnings */
+  const char *what = (isLua(ci)) ? funcnamefromcode(L, ci, &name) : NULL;
+  if (what != NULL) {
+    const char *t = luaT_objtypename(L, o);
+    luaG_runerror(L, "%s '%s' is not callable (a %s value)", what, name, t);
+  }
+  else
+    luaG_typeerror(L, o, "call");
+}
+
+
 l_noret luaG_forerror (lua_State *L, const TValue *o, const char *what) {
 l_noret luaG_forerror (lua_State *L, const TValue *o, const char *what) {
   luaG_runerror(L, "bad 'for' %s (number expected, got %s)",
   luaG_runerror(L, "bad 'for' %s (number expected, got %s)",
                    what, luaT_objtypename(L, o));
                    what, luaT_objtypename(L, o));
@@ -724,7 +733,7 @@ l_noret luaG_opinterror (lua_State *L, const TValue *p1,
 */
 */
 l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
 l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
   lua_Integer temp;
   lua_Integer temp;
-  if (!tointegerns(p1, &temp))
+  if (!luaV_tointegerns(p1, &temp, LUA_FLOORN2I))
     p2 = p1;
     p2 = p1;
   luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2));
   luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2));
 }
 }
@@ -775,27 +784,56 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
   msg = luaO_pushvfstring(L, fmt, argp);  /* format message */
   msg = luaO_pushvfstring(L, fmt, argp);  /* format message */
   va_end(argp);
   va_end(argp);
   if (isLua(ci))  /* if Lua function, add source:line information */
   if (isLua(ci))  /* if Lua function, add source:line information */
-    luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci));
+    luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
   luaG_errormsg(L);
   luaG_errormsg(L);
 }
 }
 
 
 
 
 /*
 /*
 ** Check whether new instruction 'newpc' is in a different line from
 ** Check whether new instruction 'newpc' is in a different line from
-** previous instruction 'oldpc'.
+** previous instruction 'oldpc'. More often than not, 'newpc' is only
+** one or a few instructions after 'oldpc' (it must be after, see
+** caller), so try to avoid calling 'luaG_getfuncline'. If they are
+** too far apart, there is a good chance of a ABSLINEINFO in the way,
+** so it goes directly to 'luaG_getfuncline'.
 */
 */
 static int changedline (const Proto *p, int oldpc, int newpc) {
 static int changedline (const Proto *p, int oldpc, int newpc) {
-  while (oldpc++ < newpc) {
-    if (p->lineinfo[oldpc] != 0)
-      return (luaG_getfuncline(p, oldpc - 1) != luaG_getfuncline(p, newpc));
+  if (p->lineinfo == NULL)  /* no debug information? */
+    return 0;
+  if (newpc - oldpc < MAXIWTHABS / 2) {  /* not too far apart? */
+    int delta = 0;  /* line diference */
+    int pc = oldpc;
+    for (;;) {
+      int lineinfo = p->lineinfo[++pc];
+      if (lineinfo == ABSLINEINFO)
+        break;  /* cannot compute delta; fall through */
+      delta += lineinfo;
+      if (pc == newpc)
+        return (delta != 0);  /* delta computed successfully */
+    }
   }
   }
-  return 0;  /* no line changes in the way */
+  /* either instructions are too far apart or there is an absolute line
+     info in the way; compute line difference explicitly */
+  return (luaG_getfuncline(p, oldpc) != luaG_getfuncline(p, newpc));
 }
 }
 
 
 
 
+/*
+** Traces the execution of a Lua function. Called before the execution
+** of each opcode, when debug is on. 'L->oldpc' stores the last
+** instruction traced, to detect line changes. When entering a new
+** function, 'npci' will be zero and will test as a new line whatever
+** the value of 'oldpc'.  Some exceptional conditions may return to
+** a function without setting 'oldpc'. In that case, 'oldpc' may be
+** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
+** at most causes an extra call to a line hook.)
+** This function is not "Protected" when called, so it should correct
+** 'L->top' before calling anything that can run the GC.
+*/
 int luaG_traceexec (lua_State *L, const Instruction *pc) {
 int luaG_traceexec (lua_State *L, const Instruction *pc) {
   CallInfo *ci = L->ci;
   CallInfo *ci = L->ci;
   lu_byte mask = L->hookmask;
   lu_byte mask = L->hookmask;
+  const Proto *p = ci_func(ci)->p;
   int counthook;
   int counthook;
   if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) {  /* no hooks? */
   if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) {  /* no hooks? */
     ci->u.l.trap = 0;  /* don't need to stop again */
     ci->u.l.trap = 0;  /* don't need to stop again */
@@ -812,20 +850,20 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
     ci->callstatus &= ~CIST_HOOKYIELD;  /* erase mark */
     ci->callstatus &= ~CIST_HOOKYIELD;  /* erase mark */
     return 1;  /* do not call hook again (VM yielded, so it did not move) */
     return 1;  /* do not call hook again (VM yielded, so it did not move) */
   }
   }
-  if (!isIT(*(ci->u.l.savedpc - 1)))
-    L->top = ci->top;  /* prepare top */
+  if (!isIT(*(ci->u.l.savedpc - 1)))  /* top not being used? */
+    L->top = ci->top;  /* correct top */
   if (counthook)
   if (counthook)
     luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0);  /* call count hook */
     luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0);  /* call count hook */
   if (mask & LUA_MASKLINE) {
   if (mask & LUA_MASKLINE) {
-    const Proto *p = ci_func(ci)->p;
+    /* 'L->oldpc' may be invalid; use zero in this case */
+    int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0;
     int npci = pcRel(pc, p);
     int npci = pcRel(pc, p);
-    if (npci == 0 ||  /* call linehook when enter a new function, */
-        pc <= L->oldpc ||  /* when jump back (loop), or when */
-        changedline(p, pcRel(L->oldpc, p), npci)) {  /* enter new line */
+    if (npci <= oldpc ||  /* call hook when jump back (loop), */
+        changedline(p, oldpc, npci)) {  /* or when enter new line */
       int newline = luaG_getfuncline(p, npci);
       int newline = luaG_getfuncline(p, npci);
       luaD_hook(L, LUA_HOOKLINE, newline, 0, 0);  /* call line hook */
       luaD_hook(L, LUA_HOOKLINE, newline, 0, 0);  /* call line hook */
     }
     }
-    L->oldpc = pc;  /* 'pc' of last call to line hook */
+    L->oldpc = npci;  /* 'pc' of last call to line hook */
   }
   }
   if (L->status == LUA_YIELD) {  /* did hook yield? */
   if (L->status == LUA_YIELD) {  /* did hook yield? */
     if (counthook)
     if (counthook)

+ 16 - 0
src/ldebug.h

@@ -13,6 +13,11 @@
 
 
 #define pcRel(pc, p)	(cast_int((pc) - (p)->code) - 1)
 #define pcRel(pc, p)	(cast_int((pc) - (p)->code) - 1)
 
 
+
+/* Active Lua function (given call info) */
+#define ci_func(ci)		(clLvalue(s2v((ci)->func)))
+
+
 #define resethookcount(L)	(L->hookcount = L->basehookcount)
 #define resethookcount(L)	(L->hookcount = L->basehookcount)
 
 
 /*
 /*
@@ -21,11 +26,22 @@
 */
 */
 #define ABSLINEINFO	(-0x80)
 #define ABSLINEINFO	(-0x80)
 
 
+
+/*
+** MAXimum number of successive Instructions WiTHout ABSolute line
+** information. (A power of two allows fast divisions.)
+*/
+#if !defined(MAXIWTHABS)
+#define MAXIWTHABS	128
+#endif
+
+
 LUAI_FUNC int luaG_getfuncline (const Proto *f, int pc);
 LUAI_FUNC int luaG_getfuncline (const Proto *f, int pc);
 LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n,
 LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n,
                                                     StkId *pos);
                                                     StkId *pos);
 LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
 LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
                                                 const char *opname);
                                                 const char *opname);
+LUAI_FUNC l_noret luaG_callerror (lua_State *L, const TValue *o);
 LUAI_FUNC l_noret luaG_forerror (lua_State *L, const TValue *o,
 LUAI_FUNC l_noret luaG_forerror (lua_State *L, const TValue *o,
                                                const char *what);
                                                const char *what);
 LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1,
 LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1,

+ 322 - 188
src/ldo.c

@@ -98,11 +98,12 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
       setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
       setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
       break;
       break;
     }
     }
-    case CLOSEPROTECT: {
+    case LUA_OK: {  /* special case only for closing upvalues */
       setnilvalue(s2v(oldtop));  /* no error message */
       setnilvalue(s2v(oldtop));  /* no error message */
       break;
       break;
     }
     }
     default: {
     default: {
+      lua_assert(errorstatus(errcode));  /* real error */
       setobjs2s(L, oldtop, L->top - 1);  /* error message on current top */
       setobjs2s(L, oldtop, L->top - 1);  /* error message on current top */
       break;
       break;
     }
     }
@@ -118,17 +119,13 @@ l_noret luaD_throw (lua_State *L, int errcode) {
   }
   }
   else {  /* thread has no error handler */
   else {  /* thread has no error handler */
     global_State *g = G(L);
     global_State *g = G(L);
-    errcode = luaF_close(L, L->stack, errcode);  /* close all upvalues */
-    L->status = cast_byte(errcode);  /* mark it as dead */
+    errcode = luaE_resetthread(L, errcode);  /* close all upvalues */
     if (g->mainthread->errorJmp) {  /* main thread has a handler? */
     if (g->mainthread->errorJmp) {  /* main thread has a handler? */
       setobjs2s(L, g->mainthread->top++, L->top - 1);  /* copy error obj. */
       setobjs2s(L, g->mainthread->top++, L->top - 1);  /* copy error obj. */
       luaD_throw(g->mainthread, errcode);  /* re-throw in main thread */
       luaD_throw(g->mainthread, errcode);  /* re-throw in main thread */
     }
     }
     else {  /* no handler at all; abort */
     else {  /* no handler at all; abort */
       if (g->panic) {  /* panic function? */
       if (g->panic) {  /* panic function? */
-        luaD_seterrorobj(L, errcode, L->top);  /* assume EXTRA_STACK */
-        if (L->ci->top < L->top)
-          L->ci->top = L->top;  /* pushing msg. can break this invariant */
         lua_unlock(L);
         lua_unlock(L);
         g->panic(L);  /* call panic function (last chance to jump out) */
         g->panic(L);  /* call panic function (last chance to jump out) */
       }
       }
@@ -139,8 +136,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
 
 
 
 
 int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
 int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
-  global_State *g = G(L);
-  l_uint32 oldnCcalls = g->Cstacklimit - (L->nCcalls + L->nci);
+  l_uint32 oldnCcalls = L->nCcalls;
   struct lua_longjmp lj;
   struct lua_longjmp lj;
   lj.status = LUA_OK;
   lj.status = LUA_OK;
   lj.previous = L->errorJmp;  /* chain new error handler */
   lj.previous = L->errorJmp;  /* chain new error handler */
@@ -149,7 +145,7 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
     (*f)(L, ud);
     (*f)(L, ud);
   );
   );
   L->errorJmp = lj.previous;  /* restore old error handler */
   L->errorJmp = lj.previous;  /* restore old error handler */
-  L->nCcalls = g->Cstacklimit - oldnCcalls - L->nci;
+  L->nCcalls = oldnCcalls;
   return lj.status;
   return lj.status;
 }
 }
 
 
@@ -164,9 +160,8 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
 static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
 static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
   CallInfo *ci;
   CallInfo *ci;
   UpVal *up;
   UpVal *up;
-  if (oldstack == newstack)
-    return;  /* stack address did not change */
   L->top = (L->top - oldstack) + newstack;
   L->top = (L->top - oldstack) + newstack;
+  L->tbclist = (L->tbclist - oldstack) + newstack;
   for (up = L->openupval; up != NULL; up = up->u.open.next)
   for (up = L->openupval; up != NULL; up = up->u.open.next)
     up->v = s2v((uplevel(up) - oldstack) + newstack);
     up->v = s2v((uplevel(up) - oldstack) + newstack);
   for (ci = L->ci; ci != NULL; ci = ci->previous) {
   for (ci = L->ci; ci != NULL; ci = ci->previous) {
@@ -182,22 +177,37 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
 #define ERRORSTACKSIZE	(LUAI_MAXSTACK + 200)
 #define ERRORSTACKSIZE	(LUAI_MAXSTACK + 200)
 
 
 
 
+/*
+** Reallocate the stack to a new size, correcting all pointers into
+** it. (There are pointers to a stack from its upvalues, from its list
+** of call infos, plus a few individual pointers.) The reallocation is
+** done in two steps (allocation + free) because the correction must be
+** done while both addresses (the old stack and the new one) are valid.
+** (In ISO C, any pointer use after the pointer has been deallocated is
+** undefined behavior.)
+** In case of allocation error, raise an error or return false according
+** to 'raiseerror'.
+*/
 int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
 int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
-  int lim = L->stacksize;
-  StkId newstack = luaM_reallocvector(L, L->stack, lim, newsize, StackValue);
+  int oldsize = stacksize(L);
+  int i;
+  StkId newstack = luaM_reallocvector(L, NULL, 0,
+                                      newsize + EXTRA_STACK, StackValue);
   lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
   lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
-  lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK);
-  if (unlikely(newstack == NULL)) {  /* reallocation failed? */
+  if (l_unlikely(newstack == NULL)) {  /* reallocation failed? */
     if (raiseerror)
     if (raiseerror)
       luaM_error(L);
       luaM_error(L);
     else return 0;  /* do not raise an error */
     else return 0;  /* do not raise an error */
   }
   }
-  for (; lim < newsize; lim++)
-    setnilvalue(s2v(newstack + lim)); /* erase new segment */
+  /* number of elements to be copied to the new stack */
+  i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK;
+  memcpy(newstack, L->stack, i * sizeof(StackValue));
+  for (; i < newsize + EXTRA_STACK; i++)
+    setnilvalue(s2v(newstack + i)); /* erase new segment */
   correctstack(L, L->stack, newstack);
   correctstack(L, L->stack, newstack);
+  luaM_freearray(L, L->stack, oldsize + EXTRA_STACK);
   L->stack = newstack;
   L->stack = newstack;
-  L->stacksize = newsize;
-  L->stack_last = L->stack + newsize - EXTRA_STACK;
+  L->stack_last = L->stack + newsize;
   return 1;
   return 1;
 }
 }
 
 
@@ -207,52 +217,73 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
 ** is true, raises any error; otherwise, return 0 in case of errors.
 ** is true, raises any error; otherwise, return 0 in case of errors.
 */
 */
 int luaD_growstack (lua_State *L, int n, int raiseerror) {
 int luaD_growstack (lua_State *L, int n, int raiseerror) {
-  int size = L->stacksize;
-  int newsize = 2 * size;  /* tentative new size */
-  if (unlikely(size > LUAI_MAXSTACK)) {  /* need more space after extra size? */
+  int size = stacksize(L);
+  if (l_unlikely(size > LUAI_MAXSTACK)) {
+    /* if stack is larger than maximum, thread is already using the
+       extra space reserved for errors, that is, thread is handling
+       a stack error; cannot grow further than that. */
+    lua_assert(stacksize(L) == ERRORSTACKSIZE);
     if (raiseerror)
     if (raiseerror)
       luaD_throw(L, LUA_ERRERR);  /* error inside message handler */
       luaD_throw(L, LUA_ERRERR);  /* error inside message handler */
-    else return 0;
+    return 0;  /* if not 'raiseerror', just signal it */
   }
   }
   else {
   else {
-    int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK;
+    int newsize = 2 * size;  /* tentative new size */
+    int needed = cast_int(L->top - L->stack) + n;
     if (newsize > LUAI_MAXSTACK)  /* cannot cross the limit */
     if (newsize > LUAI_MAXSTACK)  /* cannot cross the limit */
       newsize = LUAI_MAXSTACK;
       newsize = LUAI_MAXSTACK;
     if (newsize < needed)  /* but must respect what was asked for */
     if (newsize < needed)  /* but must respect what was asked for */
       newsize = needed;
       newsize = needed;
-    if (unlikely(newsize > LUAI_MAXSTACK)) {  /* stack overflow? */
+    if (l_likely(newsize <= LUAI_MAXSTACK))
+      return luaD_reallocstack(L, newsize, raiseerror);
+    else {  /* stack overflow */
       /* add extra size to be able to handle the error message */
       /* add extra size to be able to handle the error message */
       luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
       luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
       if (raiseerror)
       if (raiseerror)
         luaG_runerror(L, "stack overflow");
         luaG_runerror(L, "stack overflow");
-      else return 0;
+      return 0;
     }
     }
-  }  /* else no errors */
-  return luaD_reallocstack(L, newsize, raiseerror);
+  }
 }
 }
 
 
 
 
 static int stackinuse (lua_State *L) {
 static int stackinuse (lua_State *L) {
   CallInfo *ci;
   CallInfo *ci;
+  int res;
   StkId lim = L->top;
   StkId lim = L->top;
   for (ci = L->ci; ci != NULL; ci = ci->previous) {
   for (ci = L->ci; ci != NULL; ci = ci->previous) {
     if (lim < ci->top) lim = ci->top;
     if (lim < ci->top) lim = ci->top;
   }
   }
   lua_assert(lim <= L->stack_last);
   lua_assert(lim <= L->stack_last);
-  return cast_int(lim - L->stack) + 1;  /* part of stack in use */
+  res = cast_int(lim - L->stack) + 1;  /* part of stack in use */
+  if (res < LUA_MINSTACK)
+    res = LUA_MINSTACK;  /* ensure a minimum size */
+  return res;
 }
 }
 
 
 
 
+/*
+** If stack size is more than 3 times the current use, reduce that size
+** to twice the current use. (So, the final stack size is at most 2/3 the
+** previous size, and half of its entries are empty.)
+** As a particular case, if stack was handling a stack overflow and now
+** it is not, 'max' (limited by LUAI_MAXSTACK) will be smaller than
+** stacksize (equal to ERRORSTACKSIZE in this case), and so the stack
+** will be reduced to a "regular" size.
+*/
 void luaD_shrinkstack (lua_State *L) {
 void luaD_shrinkstack (lua_State *L) {
   int inuse = stackinuse(L);
   int inuse = stackinuse(L);
-  int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
-  if (goodsize > LUAI_MAXSTACK)
-    goodsize = LUAI_MAXSTACK;  /* respect stack limit */
+  int nsize = inuse * 2;  /* proposed new size */
+  int max = inuse * 3;  /* maximum "reasonable" size */
+  if (max > LUAI_MAXSTACK) {
+    max = LUAI_MAXSTACK;  /* respect stack limit */
+    if (nsize > LUAI_MAXSTACK)
+      nsize = LUAI_MAXSTACK;
+  }
   /* if thread is currently not handling a stack overflow and its
   /* if thread is currently not handling a stack overflow and its
-     good size is smaller than current size, shrink its stack */
-  if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) &&
-      goodsize < L->stacksize)
-    luaD_reallocstack(L, goodsize, 0);  /* ok if that fails */
+     size is larger than maximum "reasonable" size, shrink it */
+  if (inuse <= LUAI_MAXSTACK && stacksize(L) > max)
+    luaD_reallocstack(L, nsize, 0);  /* ok if that fails */
   else  /* don't change stack */
   else  /* don't change stack */
     condmovestack(L,{},{});  /* (change only for debugging) */
     condmovestack(L,{},{});  /* (change only for debugging) */
   luaE_shrinkCI(L);  /* shrink CI list */
   luaE_shrinkCI(L);  /* shrink CI list */
@@ -278,8 +309,8 @@ void luaD_hook (lua_State *L, int event, int line,
   if (hook && L->allowhook) {  /* make sure there is a hook */
   if (hook && L->allowhook) {  /* make sure there is a hook */
     int mask = CIST_HOOKED;
     int mask = CIST_HOOKED;
     CallInfo *ci = L->ci;
     CallInfo *ci = L->ci;
-    ptrdiff_t top = savestack(L, L->top);
-    ptrdiff_t ci_top = savestack(L, ci->top);
+    ptrdiff_t top = savestack(L, L->top);  /* preserve original 'top' */
+    ptrdiff_t ci_top = savestack(L, ci->top);  /* idem for 'ci->top' */
     lua_Debug ar;
     lua_Debug ar;
     ar.event = event;
     ar.event = event;
     ar.currentline = line;
     ar.currentline = line;
@@ -289,8 +320,10 @@ void luaD_hook (lua_State *L, int event, int line,
       ci->u2.transferinfo.ftransfer = ftransfer;
       ci->u2.transferinfo.ftransfer = ftransfer;
       ci->u2.transferinfo.ntransfer = ntransfer;
       ci->u2.transferinfo.ntransfer = ntransfer;
     }
     }
+    if (isLua(ci) && L->top < ci->top)
+      L->top = ci->top;  /* protect entire activation register */
     luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
     luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
-    if (L->top + LUA_MINSTACK > ci->top)
+    if (ci->top < L->top + LUA_MINSTACK)
       ci->top = L->top + LUA_MINSTACK;
       ci->top = L->top + LUA_MINSTACK;
     L->allowhook = 0;  /* cannot call hooks inside a hook */
     L->allowhook = 0;  /* cannot call hooks inside a hook */
     ci->callstatus |= mask;
     ci->callstatus |= mask;
@@ -312,51 +345,53 @@ void luaD_hook (lua_State *L, int event, int line,
 ** active.
 ** active.
 */
 */
 void luaD_hookcall (lua_State *L, CallInfo *ci) {
 void luaD_hookcall (lua_State *L, CallInfo *ci) {
-  int hook = (ci->callstatus & CIST_TAIL) ? LUA_HOOKTAILCALL : LUA_HOOKCALL;
-  Proto *p;
-  if (!(L->hookmask & LUA_MASKCALL))  /* some other hook? */
-    return;  /* don't call hook */
-  p = clLvalue(s2v(ci->func))->p;
-  L->top = ci->top;  /* prepare top */
-  ci->u.l.savedpc++;  /* hooks assume 'pc' is already incremented */
-  luaD_hook(L, hook, -1, 1, p->numparams);
-  ci->u.l.savedpc--;  /* correct 'pc' */
-}
-
-
-static StkId rethook (lua_State *L, CallInfo *ci, StkId firstres, int nres) {
-  ptrdiff_t oldtop = savestack(L, L->top);  /* hook may change top */
-  int delta = 0;
-  if (isLuacode(ci)) {
-    Proto *p = clLvalue(s2v(ci->func))->p;
-    if (p->is_vararg)
-      delta = ci->u.l.nextraargs + p->numparams + 1;
-    if (L->top < ci->top)
-      L->top = ci->top;  /* correct top to run hook */
+  L->oldpc = 0;  /* set 'oldpc' for new function */
+  if (L->hookmask & LUA_MASKCALL) {  /* is call hook on? */
+    int event = (ci->callstatus & CIST_TAIL) ? LUA_HOOKTAILCALL
+                                             : LUA_HOOKCALL;
+    Proto *p = ci_func(ci)->p;
+    ci->u.l.savedpc++;  /* hooks assume 'pc' is already incremented */
+    luaD_hook(L, event, -1, 1, p->numparams);
+    ci->u.l.savedpc--;  /* correct 'pc' */
   }
   }
+}
+
+
+/*
+** Executes a return hook for Lua and C functions and sets/corrects
+** 'oldpc'. (Note that this correction is needed by the line hook, so it
+** is done even when return hooks are off.)
+*/
+static void rethook (lua_State *L, CallInfo *ci, int nres) {
   if (L->hookmask & LUA_MASKRET) {  /* is return hook on? */
   if (L->hookmask & LUA_MASKRET) {  /* is return hook on? */
+    StkId firstres = L->top - nres;  /* index of first result */
+    int delta = 0;  /* correction for vararg functions */
     int ftransfer;
     int ftransfer;
+    if (isLua(ci)) {
+      Proto *p = ci_func(ci)->p;
+      if (p->is_vararg)
+        delta = ci->u.l.nextraargs + p->numparams + 1;
+    }
     ci->func += delta;  /* if vararg, back to virtual 'func' */
     ci->func += delta;  /* if vararg, back to virtual 'func' */
     ftransfer = cast(unsigned short, firstres - ci->func);
     ftransfer = cast(unsigned short, firstres - ci->func);
     luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres);  /* call it */
     luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres);  /* call it */
     ci->func -= delta;
     ci->func -= delta;
   }
   }
-  if (isLua(ci->previous))
-    L->oldpc = ci->previous->u.l.savedpc;  /* update 'oldpc' */
-  return restorestack(L, oldtop);
+  if (isLua(ci = ci->previous))
+    L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p);  /* set 'oldpc' */
 }
 }
 
 
 
 
 /*
 /*
 ** Check whether 'func' has a '__call' metafield. If so, put it in the
 ** Check whether 'func' has a '__call' metafield. If so, put it in the
-** stack, below original 'func', so that 'luaD_call' can call it. Raise
+** stack, below original 'func', so that 'luaD_precall' can call it. Raise
 ** an error if there is no '__call' metafield.
 ** an error if there is no '__call' metafield.
 */
 */
 void luaD_tryfuncTM (lua_State *L, StkId func) {
 void luaD_tryfuncTM (lua_State *L, StkId func) {
   const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL);
   const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL);
   StkId p;
   StkId p;
-  if (unlikely(ttisnil(tm)))
-    luaG_typeerror(L, s2v(func), "call");  /* nothing to call */
+  if (l_unlikely(ttisnil(tm)))
+    luaG_callerror(L, s2v(func));  /* nothing to call */
   for (p = L->top; p > func; p--)  /* open space for metamethod */
   for (p = L->top; p > func; p--)  /* open space for metamethod */
     setobjs2s(L, p, p-1);
     setobjs2s(L, p, p-1);
   L->top++;  /* stack space pre-allocated by the caller */
   L->top++;  /* stack space pre-allocated by the caller */
@@ -380,27 +415,34 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) {
     case 1:  /* one value needed */
     case 1:  /* one value needed */
       if (nres == 0)   /* no results? */
       if (nres == 0)   /* no results? */
         setnilvalue(s2v(res));  /* adjust with nil */
         setnilvalue(s2v(res));  /* adjust with nil */
-      else
+      else  /* at least one result */
         setobjs2s(L, res, L->top - nres);  /* move it to proper place */
         setobjs2s(L, res, L->top - nres);  /* move it to proper place */
       L->top = res + 1;
       L->top = res + 1;
       return;
       return;
     case LUA_MULTRET:
     case LUA_MULTRET:
       wanted = nres;  /* we want all results */
       wanted = nres;  /* we want all results */
       break;
       break;
-    default:  /* multiple results (or to-be-closed variables) */
+    default:  /* two/more results and/or to-be-closed variables */
       if (hastocloseCfunc(wanted)) {  /* to-be-closed variables? */
       if (hastocloseCfunc(wanted)) {  /* to-be-closed variables? */
         ptrdiff_t savedres = savestack(L, res);
         ptrdiff_t savedres = savestack(L, res);
-        luaF_close(L, res, LUA_OK);  /* may change the stack */
-        res = restorestack(L, savedres);
-        wanted = codeNresults(wanted);  /* correct value */
+        L->ci->callstatus |= CIST_CLSRET;  /* in case of yields */
+        L->ci->u2.nres = nres;
+        luaF_close(L, res, CLOSEKTOP, 1);
+        L->ci->callstatus &= ~CIST_CLSRET;
+        if (L->hookmask)  /* if needed, call hook after '__close's */
+          rethook(L, L->ci, nres);
+        res = restorestack(L, savedres);  /* close and hook can move stack */
+        wanted = decodeNresults(wanted);
         if (wanted == LUA_MULTRET)
         if (wanted == LUA_MULTRET)
-          wanted = nres;
+          wanted = nres;  /* we want all results */
       }
       }
       break;
       break;
   }
   }
+  /* generic case */
   firstresult = L->top - nres;  /* index of first result */
   firstresult = L->top - nres;  /* index of first result */
-  /* move all results to correct place */
-  for (i = 0; i < nres && i < wanted; i++)
+  if (nres > wanted)  /* extra results? */
+    nres = wanted;  /* don't need them */
+  for (i = 0; i < nres; i++)  /* move all results to correct place */
     setobjs2s(L, res + i, firstresult + i);
     setobjs2s(L, res + i, firstresult + i);
   for (; i < wanted; i++)  /* complete wanted number of results */
   for (; i < wanted; i++)  /* complete wanted number of results */
     setnilvalue(s2v(res + i));
     setnilvalue(s2v(res + i));
@@ -409,20 +451,26 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) {
 
 
 
 
 /*
 /*
-** Finishes a function call: calls hook if necessary, removes CallInfo,
-** moves current number of results to proper place.
+** Finishes a function call: calls hook if necessary, moves current
+** number of results to proper place, and returns to previous call
+** info. If function has to close variables, hook must be called after
+** that.
 */
 */
 void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
 void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
-  if (L->hookmask)
-    L->top = rethook(L, ci, L->top - nres, nres);
-  L->ci = ci->previous;  /* back to caller */
+  int wanted = ci->nresults;
+  if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
+    rethook(L, ci, nres);
   /* move results to proper place */
   /* move results to proper place */
-  moveresults(L, ci->func, nres, ci->nresults);
+  moveresults(L, ci->func, nres, wanted);
+  /* function cannot be in any of these cases when returning */
+  lua_assert(!(ci->callstatus &
+        (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
+  L->ci = ci->previous;  /* back to caller (after closing variables) */
 }
 }
 
 
 
 
 
 
-#define next_ci(L)  (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
+#define next_ci(L)  (L->ci->next ? L->ci->next : luaE_extendCI(L))
 
 
 
 
 /*
 /*
@@ -450,31 +498,33 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
 
 
 
 
 /*
 /*
-** Call a function (C or Lua). The function to be called is at *func.
-** The arguments are on the stack, right after the function.
-** When returns, all the results are on the stack, starting at the original
-** function position.
+** Prepares the call to a function (C or Lua). For C functions, also do
+** the call. The function to be called is at '*func'.  The arguments
+** are on the stack, right after the function.  Returns the CallInfo
+** to be executed, if it was a Lua function. Otherwise (a C function)
+** returns NULL, with all the results on the stack, starting at the
+** original function position.
 */
 */
-void luaD_call (lua_State *L, StkId func, int nresults) {
+CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
   lua_CFunction f;
   lua_CFunction f;
  retry:
  retry:
   switch (ttypetag(s2v(func))) {
   switch (ttypetag(s2v(func))) {
-    case LUA_TCCL:  /* C closure */
+    case LUA_VCCL:  /* C closure */
       f = clCvalue(s2v(func))->f;
       f = clCvalue(s2v(func))->f;
       goto Cfunc;
       goto Cfunc;
-    case LUA_TLCF:  /* light C function */
+    case LUA_VLCF:  /* light C function */
       f = fvalue(s2v(func));
       f = fvalue(s2v(func));
      Cfunc: {
      Cfunc: {
       int n;  /* number of returns */
       int n;  /* number of returns */
       CallInfo *ci;
       CallInfo *ci;
-      checkstackp(L, LUA_MINSTACK, func);  /* ensure minimum stack size */
-      ci = next_ci(L);
+      checkstackGCp(L, LUA_MINSTACK, func);  /* ensure minimum stack size */
+      L->ci = ci = next_ci(L);
       ci->nresults = nresults;
       ci->nresults = nresults;
       ci->callstatus = CIST_C;
       ci->callstatus = CIST_C;
       ci->top = L->top + LUA_MINSTACK;
       ci->top = L->top + LUA_MINSTACK;
       ci->func = func;
       ci->func = func;
       lua_assert(ci->top <= L->stack_last);
       lua_assert(ci->top <= L->stack_last);
-      if (L->hookmask & LUA_MASKCALL) {
+      if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
         int narg = cast_int(L->top - func) - 1;
         int narg = cast_int(L->top - func) - 1;
         luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
         luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
       }
       }
@@ -483,36 +533,28 @@ void luaD_call (lua_State *L, StkId func, int nresults) {
       lua_lock(L);
       lua_lock(L);
       api_checknelems(L, n);
       api_checknelems(L, n);
       luaD_poscall(L, ci, n);
       luaD_poscall(L, ci, n);
-      break;
+      return NULL;
     }
     }
-    case LUA_TLCL: {  /* Lua function */
+    case LUA_VLCL: {  /* Lua function */
       CallInfo *ci;
       CallInfo *ci;
       Proto *p = clLvalue(s2v(func))->p;
       Proto *p = clLvalue(s2v(func))->p;
       int narg = cast_int(L->top - func) - 1;  /* number of real arguments */
       int narg = cast_int(L->top - func) - 1;  /* number of real arguments */
       int nfixparams = p->numparams;
       int nfixparams = p->numparams;
       int fsize = p->maxstacksize;  /* frame size */
       int fsize = p->maxstacksize;  /* frame size */
-      checkstackp(L, fsize, func);
-      ci = next_ci(L);
+      checkstackGCp(L, fsize, func);
+      L->ci = ci = next_ci(L);
       ci->nresults = nresults;
       ci->nresults = nresults;
       ci->u.l.savedpc = p->code;  /* starting point */
       ci->u.l.savedpc = p->code;  /* starting point */
-      ci->callstatus = 0;
       ci->top = func + 1 + fsize;
       ci->top = func + 1 + fsize;
       ci->func = func;
       ci->func = func;
+      L->ci = ci;
       for (; narg < nfixparams; narg++)
       for (; narg < nfixparams; narg++)
         setnilvalue(s2v(L->top++));  /* complete missing arguments */
         setnilvalue(s2v(L->top++));  /* complete missing arguments */
       lua_assert(ci->top <= L->stack_last);
       lua_assert(ci->top <= L->stack_last);
-
-      /* run the function */
-      if (p->aot_implementation) {
-          p->aot_implementation(L, ci);
-      } else {
-          luaV_execute(L, ci);
-      }
-
-      break;
+      return ci;
     }
     }
     default: {  /* not a function */
     default: {  /* not a function */
-      checkstackp(L, 1, func);  /* space for metamethod */
+      checkstackGCp(L, 1, func);  /* space for metamethod */
       luaD_tryfuncTM(L, func);  /* try to get '__call' metamethod */
       luaD_tryfuncTM(L, func);  /* try to get '__call' metamethod */
       goto retry;  /* try again with metamethod */
       goto retry;  /* try again with metamethod */
     }
     }
@@ -520,43 +562,109 @@ void luaD_call (lua_State *L, StkId func, int nresults) {
 }
 }
 
 
 
 
+/*
+** Call a function (C or Lua) through C. 'inc' can be 1 (increment
+** number of recursive invocations in the C stack) or nyci (the same
+** plus increment number of non-yieldable calls).
+*/
+static void ccall (lua_State *L, StkId func, int nResults, int inc) {
+  CallInfo *ci;
+  L->nCcalls += inc;
+  if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
+    luaE_checkcstack(L);
+  if ((ci = luaD_precall(L, func, nResults)) != NULL) {  /* Lua function? */
+    ci->callstatus = CIST_FRESH;  /* mark that it is a "fresh" execute */
+    luaV_execute(L, ci);  /* call it */
+  }
+  L->nCcalls -= inc;
+}
+
+
+/*
+** External interface for 'ccall'
+*/
+void luaD_call (lua_State *L, StkId func, int nResults) {
+  ccall(L, func, nResults, 1);
+}
+
+
 /*
 /*
 ** Similar to 'luaD_call', but does not allow yields during the call.
 ** Similar to 'luaD_call', but does not allow yields during the call.
-** If there is a stack overflow, freeing all CI structures will
-** force the subsequent call to invoke 'luaE_extendCI', which then
-** will raise any errors.
 */
 */
 void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
 void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
-  incXCcalls(L);
-  if (getCcalls(L) <= CSTACKERR)  /* possible stack overflow? */
-    luaE_freeCI(L);
-  luaD_call(L, func, nResults);
-  decXCcalls(L);
+  ccall(L, func, nResults, nyci);
 }
 }
 
 
 
 
 /*
 /*
-** Completes the execution of an interrupted C function, calling its
-** continuation function.
+** Finish the job of 'lua_pcallk' after it was interrupted by an yield.
+** (The caller, 'finishCcall', does the final call to 'adjustresults'.)
+** The main job is to complete the 'luaD_pcall' called by 'lua_pcallk'.
+** If a '__close' method yields here, eventually control will be back
+** to 'finishCcall' (when that '__close' method finally returns) and
+** 'finishpcallk' will run again and close any still pending '__close'
+** methods. Similarly, if a '__close' method errs, 'precover' calls
+** 'unroll' which calls ''finishCcall' and we are back here again, to
+** close any pending '__close' methods.
+** Note that, up to the call to 'luaF_close', the corresponding
+** 'CallInfo' is not modified, so that this repeated run works like the
+** first one (except that it has at least one less '__close' to do). In
+** particular, field CIST_RECST preserves the error status across these
+** multiple runs, changing only if there is a new error.
 */
 */
-static void finishCcall (lua_State *L, int status) {
-  CallInfo *ci = L->ci;
-  int n;
-  /* must have a continuation and must be able to call it */
-  lua_assert(ci->u.c.k != NULL && yieldable(L));
-  /* error status can only happen in a protected call */
-  lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD);
-  if (ci->callstatus & CIST_YPCALL) {  /* was inside a pcall? */
-    ci->callstatus &= ~CIST_YPCALL;  /* continuation is also inside it */
-    L->errfunc = ci->u.c.old_errfunc;  /* with the same error function */
-  }
-  /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already
-     handled */
-  adjustresults(L, ci->nresults);
-  lua_unlock(L);
-  n = (*ci->u.c.k)(L, status, ci->u.c.ctx);  /* call continuation function */
-  lua_lock(L);
-  api_checknelems(L, n);
+static int finishpcallk (lua_State *L,  CallInfo *ci) {
+  int status = getcistrecst(ci);  /* get original status */
+  if (l_likely(status == LUA_OK))  /* no error? */
+    status = LUA_YIELD;  /* was interrupted by an yield */
+  else {  /* error */
+    StkId func = restorestack(L, ci->u2.funcidx);
+    L->allowhook = getoah(ci->callstatus);  /* restore 'allowhook' */
+    luaF_close(L, func, status, 1);  /* can yield or raise an error */
+    func = restorestack(L, ci->u2.funcidx);  /* stack may be moved */
+    luaD_seterrorobj(L, status, func);
+    luaD_shrinkstack(L);   /* restore stack size in case of overflow */
+    setcistrecst(ci, LUA_OK);  /* clear original status */
+  }
+  ci->callstatus &= ~CIST_YPCALL;
+  L->errfunc = ci->u.c.old_errfunc;
+  /* if it is here, there were errors or yields; unlike 'lua_pcallk',
+     do not change status */
+  return status;
+}
+
+
+/*
+** Completes the execution of a C function interrupted by an yield.
+** The interruption must have happened while the function was either
+** closing its tbc variables in 'moveresults' or executing
+** 'lua_callk'/'lua_pcallk'. In the first case, it just redoes
+** 'luaD_poscall'. In the second case, the call to 'finishpcallk'
+** finishes the interrupted execution of 'lua_pcallk'.  After that, it
+** calls the continuation of the interrupted function and finally it
+** completes the job of the 'luaD_call' that called the function.  In
+** the call to 'adjustresults', we do not know the number of results
+** of the function called by 'lua_callk'/'lua_pcallk', so we are
+** conservative and use LUA_MULTRET (always adjust).
+*/
+static void finishCcall (lua_State *L, CallInfo *ci) {
+  int n;  /* actual number of results from C function */
+  if (ci->callstatus & CIST_CLSRET) {  /* was returning? */
+    lua_assert(hastocloseCfunc(ci->nresults));
+    n = ci->u2.nres;  /* just redo 'luaD_poscall' */
+    /* don't need to reset CIST_CLSRET, as it will be set again anyway */
+  }
+  else {
+    int status = LUA_YIELD;  /* default if there were no errors */
+    /* must have a continuation and must be able to call it */
+    lua_assert(ci->u.c.k != NULL && yieldable(L));
+    if (ci->callstatus & CIST_YPCALL)   /* was inside a 'lua_pcallk'? */
+      status = finishpcallk(L, ci);  /* finish it */
+    adjustresults(L, LUA_MULTRET);  /* finish 'lua_callk' */
+    lua_unlock(L);
+    n = (*ci->u.c.k)(L, status, ci->u.c.ctx);  /* call continuation */
+    lua_lock(L);
+    api_checknelems(L, n);
+  }
   luaD_poscall(L, ci, n);  /* finish 'luaD_call' */
   luaD_poscall(L, ci, n);  /* finish 'luaD_call' */
 }
 }
 
 
@@ -564,18 +672,14 @@ static void finishCcall (lua_State *L, int status) {
 /*
 /*
 ** Executes "full continuation" (everything in the stack) of a
 ** Executes "full continuation" (everything in the stack) of a
 ** previously interrupted coroutine until the stack is empty (or another
 ** previously interrupted coroutine until the stack is empty (or another
-** interruption long-jumps out of the loop). If the coroutine is
-** recovering from an error, 'ud' points to the error status, which must
-** be passed to the first continuation function (otherwise the default
-** status is LUA_YIELD).
+** interruption long-jumps out of the loop).
 */
 */
 static void unroll (lua_State *L, void *ud) {
 static void unroll (lua_State *L, void *ud) {
   CallInfo *ci;
   CallInfo *ci;
-  if (ud != NULL)  /* error status? */
-    finishCcall(L, *(int *)ud);  /* finish 'lua_pcallk' callee */
+  UNUSED(ud);
   while ((ci = L->ci) != &L->base_ci) {  /* something in the stack */
   while ((ci = L->ci) != &L->base_ci) {  /* something in the stack */
     if (!isLua(ci))  /* C function? */
     if (!isLua(ci))  /* C function? */
-      finishCcall(L, LUA_YIELD);  /* complete its execution */
+      finishCcall(L, ci);  /* complete its execution */
     else {  /* Lua function */
     else {  /* Lua function */
       luaV_finishOp(L);  /* finish interrupted instruction */
       luaV_finishOp(L);  /* finish interrupted instruction */
       luaV_execute(L, ci);  /* execute down to higher C 'boundary' */
       luaV_execute(L, ci);  /* execute down to higher C 'boundary' */
@@ -598,28 +702,6 @@ static CallInfo *findpcall (lua_State *L) {
 }
 }
 
 
 
 
-/*
-** Recovers from an error in a coroutine. Finds a recover point (if
-** there is one) and completes the execution of the interrupted
-** 'luaD_pcall'. If there is no recover point, returns zero.
-*/
-static int recover (lua_State *L, int status) {
-  StkId oldtop;
-  CallInfo *ci = findpcall(L);
-  if (ci == NULL) return 0;  /* no recovery point */
-  /* "finish" luaD_pcall */
-  oldtop = restorestack(L, ci->u2.funcidx);
-  luaF_close(L, oldtop, status);  /* may change the stack */
-  oldtop = restorestack(L, ci->u2.funcidx);
-  luaD_seterrorobj(L, status, oldtop);
-  L->ci = ci;
-  L->allowhook = getoah(ci->callstatus);  /* restore original 'allowhook' */
-  luaD_shrinkstack(L);
-  L->errfunc = ci->u.c.old_errfunc;
-  return 1;  /* continue running the coroutine */
-}
-
-
 /*
 /*
 ** Signal an error in the call to 'lua_resume', not in the execution
 ** Signal an error in the call to 'lua_resume', not in the execution
 ** of the coroutine itself. (Such errors should not be handled by any
 ** of the coroutine itself. (Such errors should not be handled by any
@@ -645,14 +727,16 @@ static void resume (lua_State *L, void *ud) {
   int n = *(cast(int*, ud));  /* number of arguments */
   int n = *(cast(int*, ud));  /* number of arguments */
   StkId firstArg = L->top - n;  /* first argument */
   StkId firstArg = L->top - n;  /* first argument */
   CallInfo *ci = L->ci;
   CallInfo *ci = L->ci;
-  if (L->status == LUA_OK) {  /* starting a coroutine? */
-    luaD_call(L, firstArg - 1, LUA_MULTRET);
-  }
+  if (L->status == LUA_OK)  /* starting a coroutine? */
+    ccall(L, firstArg - 1, LUA_MULTRET, 1);  /* just call its body */
   else {  /* resuming from previous yield */
   else {  /* resuming from previous yield */
     lua_assert(L->status == LUA_YIELD);
     lua_assert(L->status == LUA_YIELD);
     L->status = LUA_OK;  /* mark that it is running (again) */
     L->status = LUA_OK;  /* mark that it is running (again) */
-    if (isLua(ci))  /* yielded inside a hook? */
+    luaE_incCstack(L);  /* control the C stack */
+    if (isLua(ci)) {  /* yielded inside a hook? */
+      L->top = firstArg;  /* discard arguments */
       luaV_execute(L, ci);  /* just continue running Lua code */
       luaV_execute(L, ci);  /* just continue running Lua code */
+    }
     else {  /* 'common' yield */
     else {  /* 'common' yield */
       if (ci->u.c.k != NULL) {  /* does it have a continuation function? */
       if (ci->u.c.k != NULL) {  /* does it have a continuation function? */
         lua_unlock(L);
         lua_unlock(L);
@@ -666,6 +750,26 @@ static void resume (lua_State *L, void *ud) {
   }
   }
 }
 }
 
 
+
+/*
+** Unrolls a coroutine in protected mode while there are recoverable
+** errors, that is, errors inside a protected call. (Any error
+** interrupts 'unroll', and this loop protects it again so it can
+** continue.) Stops with a normal end (status == LUA_OK), an yield
+** (status == LUA_YIELD), or an unprotected error ('findpcall' doesn't
+** find a recover point).
+*/
+static int precover (lua_State *L, int status) {
+  CallInfo *ci;
+  while (errorstatus(status) && (ci = findpcall(L)) != NULL) {
+    L->ci = ci;  /* go down to recovery functions */
+    setcistrecst(ci, status);  /* status to finish 'pcall' */
+    status = luaD_rawrunprotected(L, unroll, NULL);
+  }
+  return status;
+}
+
+
 LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
 LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
                                       int *nresults) {
                                       int *nresults) {
   int status;
   int status;
@@ -678,21 +782,13 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
   }
   }
   else if (L->status != LUA_YIELD)  /* ended with errors? */
   else if (L->status != LUA_YIELD)  /* ended with errors? */
     return resume_error(L, "cannot resume dead coroutine", nargs);
     return resume_error(L, "cannot resume dead coroutine", nargs);
-  if (from == NULL)
-    L->nCcalls = CSTACKTHREAD;
-  else  /* correct 'nCcalls' for this thread */
-    L->nCcalls = getCcalls(from) + from->nci - L->nci - CSTACKCF;
-  if (L->nCcalls <= CSTACKERR)
-    return resume_error(L, "C stack overflow", nargs);
+  L->nCcalls = (from) ? getCcalls(from) : 0;
   luai_userstateresume(L, nargs);
   luai_userstateresume(L, nargs);
   api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
   api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
   status = luaD_rawrunprotected(L, resume, &nargs);
   status = luaD_rawrunprotected(L, resume, &nargs);
    /* continue running after recoverable errors */
    /* continue running after recoverable errors */
-  while (errorstatus(status) && recover(L, status)) {
-    /* unroll continuation */
-    status = luaD_rawrunprotected(L, unroll, &status);
-  }
-  if (likely(!errorstatus(status)))
+  status = precover(L, status);
+  if (l_likely(!errorstatus(status)))
     lua_assert(status == L->status);  /* normal end or yield */
     lua_assert(status == L->status);  /* normal end or yield */
   else {  /* unrecoverable error */
   else {  /* unrecoverable error */
     L->status = cast_byte(status);  /* mark thread as 'dead' */
     L->status = cast_byte(status);  /* mark thread as 'dead' */
@@ -713,26 +809,27 @@ LUA_API int lua_isyieldable (lua_State *L) {
 
 
 LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
 LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
                         lua_KFunction k) {
                         lua_KFunction k) {
-  CallInfo *ci = L->ci;
+  CallInfo *ci;
   luai_userstateyield(L, nresults);
   luai_userstateyield(L, nresults);
   lua_lock(L);
   lua_lock(L);
+  ci = L->ci;
   api_checknelems(L, nresults);
   api_checknelems(L, nresults);
-  if (unlikely(!yieldable(L))) {
+  if (l_unlikely(!yieldable(L))) {
     if (L != G(L)->mainthread)
     if (L != G(L)->mainthread)
       luaG_runerror(L, "attempt to yield across a C-call boundary");
       luaG_runerror(L, "attempt to yield across a C-call boundary");
     else
     else
       luaG_runerror(L, "attempt to yield from outside a coroutine");
       luaG_runerror(L, "attempt to yield from outside a coroutine");
   }
   }
   L->status = LUA_YIELD;
   L->status = LUA_YIELD;
+  ci->u2.nyield = nresults;  /* save number of results */
   if (isLua(ci)) {  /* inside a hook? */
   if (isLua(ci)) {  /* inside a hook? */
     lua_assert(!isLuacode(ci));
     lua_assert(!isLuacode(ci));
+    api_check(L, nresults == 0, "hooks cannot yield values");
     api_check(L, k == NULL, "hooks cannot continue after yielding");
     api_check(L, k == NULL, "hooks cannot continue after yielding");
-    ci->u2.nyield = 0;  /* no results */
   }
   }
   else {
   else {
     if ((ci->u.c.k = k) != NULL)  /* is there a continuation? */
     if ((ci->u.c.k = k) != NULL)  /* is there a continuation? */
       ci->u.c.ctx = ctx;  /* save context */
       ci->u.c.ctx = ctx;  /* save context */
-    ci->u2.nyield = nresults;  /* save number of results */
     luaD_throw(L, LUA_YIELD);
     luaD_throw(L, LUA_YIELD);
   }
   }
   lua_assert(ci->callstatus & CIST_HOOKED);  /* must be inside a hook */
   lua_assert(ci->callstatus & CIST_HOOKED);  /* must be inside a hook */
@@ -741,6 +838,45 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
 }
 }
 
 
 
 
+/*
+** Auxiliary structure to call 'luaF_close' in protected mode.
+*/
+struct CloseP {
+  StkId level;
+  int status;
+};
+
+
+/*
+** Auxiliary function to call 'luaF_close' in protected mode.
+*/
+static void closepaux (lua_State *L, void *ud) {
+  struct CloseP *pcl = cast(struct CloseP *, ud);
+  luaF_close(L, pcl->level, pcl->status, 0);
+}
+
+
+/*
+** Calls 'luaF_close' in protected mode. Return the original status
+** or, in case of errors, the new status.
+*/
+int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status) {
+  CallInfo *old_ci = L->ci;
+  lu_byte old_allowhooks = L->allowhook;
+  for (;;) {  /* keep closing upvalues until no more errors */
+    struct CloseP pcl;
+    pcl.level = restorestack(L, level); pcl.status = status;
+    status = luaD_rawrunprotected(L, &closepaux, &pcl);
+    if (l_likely(status == LUA_OK))  /* no more errors? */
+      return pcl.status;
+    else {  /* an error occurred; restore saved state and repeat */
+      L->ci = old_ci;
+      L->allowhook = old_allowhooks;
+    }
+  }
+}
+
+
 /*
 /*
 ** Call the C function 'func' in protected mode, restoring basic
 ** Call the C function 'func' in protected mode, restoring basic
 ** thread information ('allowhook', etc.) and in particular
 ** thread information ('allowhook', etc.) and in particular
@@ -754,14 +890,12 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u,
   ptrdiff_t old_errfunc = L->errfunc;
   ptrdiff_t old_errfunc = L->errfunc;
   L->errfunc = ef;
   L->errfunc = ef;
   status = luaD_rawrunprotected(L, func, u);
   status = luaD_rawrunprotected(L, func, u);
-  if (unlikely(status != LUA_OK)) {  /* an error occurred? */
-    StkId oldtop = restorestack(L, old_top);
+  if (l_unlikely(status != LUA_OK)) {  /* an error occurred? */
     L->ci = old_ci;
     L->ci = old_ci;
     L->allowhook = old_allowhooks;
     L->allowhook = old_allowhooks;
-    status = luaF_close(L, oldtop, status);
-    oldtop = restorestack(L, old_top);  /* previous call may change stack */
-    luaD_seterrorobj(L, status, oldtop);
-    luaD_shrinkstack(L);
+    status = luaD_closeprotected(L, old_top, status);
+    luaD_seterrorobj(L, status, restorestack(L, old_top));
+    luaD_shrinkstack(L);   /* restore stack size in case of overflow */
   }
   }
   L->errfunc = old_errfunc;
   L->errfunc = old_errfunc;
   return status;
   return status;

+ 7 - 3
src/ldo.h

@@ -17,11 +17,13 @@
 ** Macro to check stack size and grow stack if needed.  Parameters
 ** Macro to check stack size and grow stack if needed.  Parameters
 ** 'pre'/'pos' allow the macro to preserve a pointer into the
 ** 'pre'/'pos' allow the macro to preserve a pointer into the
 ** stack across reallocations, doing the work only when needed.
 ** stack across reallocations, doing the work only when needed.
+** It also allows the running of one GC step when the stack is
+** reallocated.
 ** 'condmovestack' is used in heavy tests to force a stack reallocation
 ** 'condmovestack' is used in heavy tests to force a stack reallocation
 ** at every check.
 ** at every check.
 */
 */
 #define luaD_checkstackaux(L,n,pre,pos)  \
 #define luaD_checkstackaux(L,n,pre,pos)  \
-	if (L->stack_last - L->top <= (n)) \
+	if (l_unlikely(L->stack_last - L->top <= (n))) \
 	  { pre; luaD_growstack(L, n, 1); pos; } \
 	  { pre; luaD_growstack(L, n, 1); pos; } \
         else { condmovestack(L,pre,pos); }
         else { condmovestack(L,pre,pos); }
 
 
@@ -35,7 +37,7 @@
 
 
 
 
 /* macro to check stack size, preserving 'p' */
 /* macro to check stack size, preserving 'p' */
-#define checkstackp(L,n,p)  \
+#define checkstackGCp(L,n,p)  \
   luaD_checkstackaux(L, n, \
   luaD_checkstackaux(L, n, \
     ptrdiff_t t__ = savestack(L, p);  /* save 'p' */ \
     ptrdiff_t t__ = savestack(L, p);  /* save 'p' */ \
     luaC_checkGC(L),  /* stack grow uses memory */ \
     luaC_checkGC(L),  /* stack grow uses memory */ \
@@ -44,7 +46,7 @@
 
 
 /* macro to check stack size and GC */
 /* macro to check stack size and GC */
 #define checkstackGC(L,fsize)  \
 #define checkstackGC(L,fsize)  \
-	luaD_checkstackaux(L, (fsize), (void)0, luaC_checkGC(L))
+	luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0)
 
 
 
 
 /* type of protected functions, to be ran by 'runprotected' */
 /* type of protected functions, to be ran by 'runprotected' */
@@ -57,9 +59,11 @@ LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
                                         int fTransfer, int nTransfer);
                                         int fTransfer, int nTransfer);
 LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
 LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
 LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n);
 LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n);
+LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
 LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
 LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
 LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
 LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
 LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func);
 LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func);
+LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status);
 LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
 LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
                                         ptrdiff_t oldtop, ptrdiff_t ef);
                                         ptrdiff_t oldtop, ptrdiff_t ef);
 LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres);
 LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres);

+ 84 - 87
src/ldump.c

@@ -29,15 +29,15 @@ typedef struct {
 
 
 
 
 /*
 /*
-** All high-level dumps go through DumpVector; you can change it to
+** All high-level dumps go through dumpVector; you can change it to
 ** change the endianness of the result
 ** change the endianness of the result
 */
 */
-#define DumpVector(v,n,D)	DumpBlock(v,(n)*sizeof((v)[0]),D)
+#define dumpVector(D,v,n)	dumpBlock(D,v,(n)*sizeof((v)[0]))
 
 
-#define DumpLiteral(s,D)	DumpBlock(s, sizeof(s) - sizeof(char), D)
+#define dumpLiteral(D, s)	dumpBlock(D,s,sizeof(s) - sizeof(char))
 
 
 
 
-static void DumpBlock (const void *b, size_t size, DumpState *D) {
+static void dumpBlock (DumpState *D, const void *b, size_t size) {
   if (D->status == 0 && size > 0) {
   if (D->status == 0 && size > 0) {
     lua_unlock(D->L);
     lua_unlock(D->L);
     D->status = (*D->writer)(D->L, b, size, D->data);
     D->status = (*D->writer)(D->L, b, size, D->data);
@@ -46,19 +46,19 @@ static void DumpBlock (const void *b, size_t size, DumpState *D) {
 }
 }
 
 
 
 
-#define DumpVar(x,D)		DumpVector(&x,1,D)
+#define dumpVar(D,x)		dumpVector(D,&x,1)
 
 
 
 
-static void DumpByte (int y, DumpState *D) {
+static void dumpByte (DumpState *D, int y) {
   lu_byte x = (lu_byte)y;
   lu_byte x = (lu_byte)y;
-  DumpVar(x, D);
+  dumpVar(D, x);
 }
 }
 
 
 
 
-/* DumpInt Buff Size */
+/* dumpInt Buff Size */
 #define DIBS    ((sizeof(size_t) * 8 / 7) + 1)
 #define DIBS    ((sizeof(size_t) * 8 / 7) + 1)
 
 
-static void DumpSize (size_t x, DumpState *D) {
+static void dumpSize (DumpState *D, size_t x) {
   lu_byte buff[DIBS];
   lu_byte buff[DIBS];
   int n = 0;
   int n = 0;
   do {
   do {
@@ -66,147 +66,144 @@ static void DumpSize (size_t x, DumpState *D) {
     x >>= 7;
     x >>= 7;
   } while (x != 0);
   } while (x != 0);
   buff[DIBS - 1] |= 0x80;  /* mark last byte */
   buff[DIBS - 1] |= 0x80;  /* mark last byte */
-  DumpVector(buff + DIBS - n, n, D);
+  dumpVector(D, buff + DIBS - n, n);
 }
 }
 
 
 
 
-static void DumpInt (int x, DumpState *D) {
-  DumpSize(x, D);
+static void dumpInt (DumpState *D, int x) {
+  dumpSize(D, x);
 }
 }
 
 
 
 
-static void DumpNumber (lua_Number x, DumpState *D) {
-  DumpVar(x, D);
+static void dumpNumber (DumpState *D, lua_Number x) {
+  dumpVar(D, x);
 }
 }
 
 
 
 
-static void DumpInteger (lua_Integer x, DumpState *D) {
-  DumpVar(x, D);
+static void dumpInteger (DumpState *D, lua_Integer x) {
+  dumpVar(D, x);
 }
 }
 
 
 
 
-static void DumpString (const TString *s, DumpState *D) {
+static void dumpString (DumpState *D, const TString *s) {
   if (s == NULL)
   if (s == NULL)
-    DumpSize(0, D);
+    dumpSize(D, 0);
   else {
   else {
     size_t size = tsslen(s);
     size_t size = tsslen(s);
     const char *str = getstr(s);
     const char *str = getstr(s);
-    DumpSize(size + 1, D);
-    DumpVector(str, size, D);
+    dumpSize(D, size + 1);
+    dumpVector(D, str, size);
   }
   }
 }
 }
 
 
 
 
-static void DumpCode (const Proto *f, DumpState *D) {
-  DumpInt(f->sizecode, D);
-  DumpVector(f->code, f->sizecode, D);
+static void dumpCode (DumpState *D, const Proto *f) {
+  dumpInt(D, f->sizecode);
+  dumpVector(D, f->code, f->sizecode);
 }
 }
 
 
 
 
-static void DumpFunction(const Proto *f, TString *psource, DumpState *D);
+static void dumpFunction(DumpState *D, const Proto *f, TString *psource);
 
 
-static void DumpConstants (const Proto *f, DumpState *D) {
+static void dumpConstants (DumpState *D, const Proto *f) {
   int i;
   int i;
   int n = f->sizek;
   int n = f->sizek;
-  DumpInt(n, D);
+  dumpInt(D, n);
   for (i = 0; i < n; i++) {
   for (i = 0; i < n; i++) {
     const TValue *o = &f->k[i];
     const TValue *o = &f->k[i];
-    DumpByte(ttypetag(o), D);
-    switch (ttypetag(o)) {
-      case LUA_TNIL:
+    int tt = ttypetag(o);
+    dumpByte(D, tt);
+    switch (tt) {
+      case LUA_VNUMFLT:
+        dumpNumber(D, fltvalue(o));
         break;
         break;
-      case LUA_TBOOLEAN:
-        DumpByte(bvalue(o), D);
+      case LUA_VNUMINT:
+        dumpInteger(D, ivalue(o));
         break;
         break;
-      case LUA_TNUMFLT:
-        DumpNumber(fltvalue(o), D);
+      case LUA_VSHRSTR:
+      case LUA_VLNGSTR:
+        dumpString(D, tsvalue(o));
         break;
         break;
-      case LUA_TNUMINT:
-        DumpInteger(ivalue(o), D);
-        break;
-      case LUA_TSHRSTR:
-      case LUA_TLNGSTR:
-        DumpString(tsvalue(o), D);
-        break;
-      default: lua_assert(0);
+      default:
+        lua_assert(tt == LUA_VNIL || tt == LUA_VFALSE || tt == LUA_VTRUE);
     }
     }
   }
   }
 }
 }
 
 
 
 
-static void DumpProtos (const Proto *f, DumpState *D) {
+static void dumpProtos (DumpState *D, const Proto *f) {
   int i;
   int i;
   int n = f->sizep;
   int n = f->sizep;
-  DumpInt(n, D);
+  dumpInt(D, n);
   for (i = 0; i < n; i++)
   for (i = 0; i < n; i++)
-    DumpFunction(f->p[i], f->source, D);
+    dumpFunction(D, f->p[i], f->source);
 }
 }
 
 
 
 
-static void DumpUpvalues (const Proto *f, DumpState *D) {
+static void dumpUpvalues (DumpState *D, const Proto *f) {
   int i, n = f->sizeupvalues;
   int i, n = f->sizeupvalues;
-  DumpInt(n, D);
+  dumpInt(D, n);
   for (i = 0; i < n; i++) {
   for (i = 0; i < n; i++) {
-    DumpByte(f->upvalues[i].instack, D);
-    DumpByte(f->upvalues[i].idx, D);
-    DumpByte(f->upvalues[i].kind, D);
+    dumpByte(D, f->upvalues[i].instack);
+    dumpByte(D, f->upvalues[i].idx);
+    dumpByte(D, f->upvalues[i].kind);
   }
   }
 }
 }
 
 
 
 
-static void DumpDebug (const Proto *f, DumpState *D) {
+static void dumpDebug (DumpState *D, const Proto *f) {
   int i, n;
   int i, n;
   n = (D->strip) ? 0 : f->sizelineinfo;
   n = (D->strip) ? 0 : f->sizelineinfo;
-  DumpInt(n, D);
-  DumpVector(f->lineinfo, n, D);
+  dumpInt(D, n);
+  dumpVector(D, f->lineinfo, n);
   n = (D->strip) ? 0 : f->sizeabslineinfo;
   n = (D->strip) ? 0 : f->sizeabslineinfo;
-  DumpInt(n, D);
+  dumpInt(D, n);
   for (i = 0; i < n; i++) {
   for (i = 0; i < n; i++) {
-    DumpInt(f->abslineinfo[i].pc, D);
-    DumpInt(f->abslineinfo[i].line, D);
+    dumpInt(D, f->abslineinfo[i].pc);
+    dumpInt(D, f->abslineinfo[i].line);
   }
   }
   n = (D->strip) ? 0 : f->sizelocvars;
   n = (D->strip) ? 0 : f->sizelocvars;
-  DumpInt(n, D);
+  dumpInt(D, n);
   for (i = 0; i < n; i++) {
   for (i = 0; i < n; i++) {
-    DumpString(f->locvars[i].varname, D);
-    DumpInt(f->locvars[i].startpc, D);
-    DumpInt(f->locvars[i].endpc, D);
+    dumpString(D, f->locvars[i].varname);
+    dumpInt(D, f->locvars[i].startpc);
+    dumpInt(D, f->locvars[i].endpc);
   }
   }
   n = (D->strip) ? 0 : f->sizeupvalues;
   n = (D->strip) ? 0 : f->sizeupvalues;
-  DumpInt(n, D);
+  dumpInt(D, n);
   for (i = 0; i < n; i++)
   for (i = 0; i < n; i++)
-    DumpString(f->upvalues[i].name, D);
+    dumpString(D, f->upvalues[i].name);
 }
 }
 
 
 
 
-static void DumpFunction (const Proto *f, TString *psource, DumpState *D) {
+static void dumpFunction (DumpState *D, const Proto *f, TString *psource) {
   if (D->strip || f->source == psource)
   if (D->strip || f->source == psource)
-    DumpString(NULL, D);  /* no debug info or same source as its parent */
+    dumpString(D, NULL);  /* no debug info or same source as its parent */
   else
   else
-    DumpString(f->source, D);
-  DumpInt(f->linedefined, D);
-  DumpInt(f->lastlinedefined, D);
-  DumpByte(f->numparams, D);
-  DumpByte(f->is_vararg, D);
-  DumpByte(f->maxstacksize, D);
-  DumpCode(f, D);
-  DumpConstants(f, D);
-  DumpUpvalues(f, D);
-  DumpProtos(f, D);
-  DumpDebug(f, D);
+    dumpString(D, f->source);
+  dumpInt(D, f->linedefined);
+  dumpInt(D, f->lastlinedefined);
+  dumpByte(D, f->numparams);
+  dumpByte(D, f->is_vararg);
+  dumpByte(D, f->maxstacksize);
+  dumpCode(D, f);
+  dumpConstants(D, f);
+  dumpUpvalues(D, f);
+  dumpProtos(D, f);
+  dumpDebug(D, f);
 }
 }
 
 
 
 
-static void DumpHeader (DumpState *D) {
-  DumpLiteral(LUA_SIGNATURE, D);
-  DumpInt(LUAC_VERSION, D);
-  DumpByte(LUAC_FORMAT, D);
-  DumpLiteral(LUAC_DATA, D);
-  DumpByte(sizeof(Instruction), D);
-  DumpByte(sizeof(lua_Integer), D);
-  DumpByte(sizeof(lua_Number), D);
-  DumpInteger(LUAC_INT, D);
-  DumpNumber(LUAC_NUM, D);
+static void dumpHeader (DumpState *D) {
+  dumpLiteral(D, LUA_SIGNATURE);
+  dumpByte(D, LUAC_VERSION);
+  dumpByte(D, LUAC_FORMAT);
+  dumpLiteral(D, LUAC_DATA);
+  dumpByte(D, sizeof(Instruction));
+  dumpByte(D, sizeof(lua_Integer));
+  dumpByte(D, sizeof(lua_Number));
+  dumpInteger(D, LUAC_INT);
+  dumpNumber(D, LUAC_NUM);
 }
 }
 
 
 
 
@@ -221,9 +218,9 @@ int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data,
   D.data = data;
   D.data = data;
   D.strip = strip;
   D.strip = strip;
   D.status = 0;
   D.status = 0;
-  DumpHeader(&D);
-  DumpByte(f->sizeupvalues, &D);
-  DumpFunction(f, NULL, &D);
+  dumpHeader(&D);
+  dumpByte(&D, f->sizeupvalues);
+  dumpFunction(&D, f, NULL);
   return D.status;
   return D.status;
 }
 }
 
 

+ 97 - 103
src/lfunc.c

@@ -24,20 +24,20 @@
 
 
 
 
 
 
-CClosure *luaF_newCclosure (lua_State *L, int n) {
-  GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n));
+CClosure *luaF_newCclosure (lua_State *L, int nupvals) {
+  GCObject *o = luaC_newobj(L, LUA_VCCL, sizeCclosure(nupvals));
   CClosure *c = gco2ccl(o);
   CClosure *c = gco2ccl(o);
-  c->nupvalues = cast_byte(n);
+  c->nupvalues = cast_byte(nupvals);
   return c;
   return c;
 }
 }
 
 
 
 
-LClosure *luaF_newLclosure (lua_State *L, int n) {
-  GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n));
+LClosure *luaF_newLclosure (lua_State *L, int nupvals) {
+  GCObject *o = luaC_newobj(L, LUA_VLCL, sizeLclosure(nupvals));
   LClosure *c = gco2lcl(o);
   LClosure *c = gco2lcl(o);
   c->p = NULL;
   c->p = NULL;
-  c->nupvalues = cast_byte(n);
-  while (n--) c->upvals[n] = NULL;
+  c->nupvalues = cast_byte(nupvals);
+  while (nupvals--) c->upvals[nupvals] = NULL;
   return c;
   return c;
 }
 }
 
 
@@ -48,12 +48,12 @@ LClosure *luaF_newLclosure (lua_State *L, int n) {
 void luaF_initupvals (lua_State *L, LClosure *cl) {
 void luaF_initupvals (lua_State *L, LClosure *cl) {
   int i;
   int i;
   for (i = 0; i < cl->nupvalues; i++) {
   for (i = 0; i < cl->nupvalues; i++) {
-    GCObject *o = luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal));
+    GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
     UpVal *uv = gco2upv(o);
     UpVal *uv = gco2upv(o);
     uv->v = &uv->u.value;  /* make it closed */
     uv->v = &uv->u.value;  /* make it closed */
     setnilvalue(uv->v);
     setnilvalue(uv->v);
     cl->upvals[i] = uv;
     cl->upvals[i] = uv;
-    luaC_objbarrier(L, cl, o);
+    luaC_objbarrier(L, cl, uv);
   }
   }
 }
 }
 
 
@@ -63,7 +63,7 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
 ** open upvalues of 'L' after entry 'prev'.
 ** open upvalues of 'L' after entry 'prev'.
 **/
 **/
 static UpVal *newupval (lua_State *L, int tbc, StkId level, UpVal **prev) {
 static UpVal *newupval (lua_State *L, int tbc, StkId level, UpVal **prev) {
-  GCObject *o = luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal));
+  GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
   UpVal *uv = gco2upv(o);
   UpVal *uv = gco2upv(o);
   UpVal *next = *prev;
   UpVal *next = *prev;
   uv->v = s2v(level);  /* current value lives in the stack */
   uv->v = s2v(level);  /* current value lives in the stack */
@@ -100,115 +100,83 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
 }
 }
 
 
 
 
-static void callclose (lua_State *L, void *ud) {
-  UNUSED(ud);
-  luaD_callnoyield(L, L->top - 3, 0);
-}
-
-
 /*
 /*
-** Prepare closing method plus its arguments for object 'obj' with
-** error message 'err'. (This function assumes EXTRA_STACK.)
+** Call closing method for object 'obj' with error message 'err'. The
+** boolean 'yy' controls whether the call is yieldable.
+** (This function assumes EXTRA_STACK.)
 */
 */
-static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) {
+static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
   StkId top = L->top;
   StkId top = L->top;
   const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
   const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
-  if (ttisnil(tm))  /* no metamethod? */
-    return 0;  /* nothing to call */
   setobj2s(L, top, tm);  /* will call metamethod... */
   setobj2s(L, top, tm);  /* will call metamethod... */
   setobj2s(L, top + 1, obj);  /* with 'self' as the 1st argument */
   setobj2s(L, top + 1, obj);  /* with 'self' as the 1st argument */
   setobj2s(L, top + 2, err);  /* and error msg. as 2nd argument */
   setobj2s(L, top + 2, err);  /* and error msg. as 2nd argument */
   L->top = top + 3;  /* add function and arguments */
   L->top = top + 3;  /* add function and arguments */
-  return 1;
+  if (yy)
+    luaD_call(L, top, 0);
+  else
+    luaD_callnoyield(L, top, 0);
 }
 }
 
 
 
 
 /*
 /*
-** Raise an error with message 'msg', inserting the name of the
-** local variable at position 'level' in the stack.
+** Check whether object at given level has a close metamethod and raise
+** an error if not.
 */
 */
-static void varerror (lua_State *L, StkId level, const char *msg) {
-  int idx = cast_int(level - L->ci->func);
-  const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
-  if (vname == NULL) vname = "?";
-  luaG_runerror(L, msg, vname);
+static void checkclosemth (lua_State *L, StkId level) {
+  const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
+  if (ttisnil(tm)) {  /* no metamethod? */
+    int idx = cast_int(level - L->ci->func);  /* variable index */
+    const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
+    if (vname == NULL) vname = "?";
+    luaG_runerror(L, "variable '%s' got a non-closable value", vname);
+  }
 }
 }
 
 
 
 
 /*
 /*
-** Prepare and call a closing method. If status is OK, code is still
-** inside the original protected call, and so any error will be handled
-** there. Otherwise, a previous error already activated the original
-** protected call, and so the call to the closing method must be
-** protected here. (A status == CLOSEPROTECT behaves like a previous
-** error, to also run the closing method in protected mode).
-** If status is OK, the call to the closing method will be pushed
-** at the top of the stack. Otherwise, values are pushed after
-** the 'level' of the upvalue being closed, as everything after
-** that won't be used again.
+** Prepare and call a closing method.
+** If status is CLOSEKTOP, the call to the closing method will be pushed
+** at the top of the stack. Otherwise, values can be pushed right after
+** the 'level' of the upvalue being closed, as everything after that
+** won't be used again.
 */
 */
-static int callclosemth (lua_State *L, StkId level, int status) {
+static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
   TValue *uv = s2v(level);  /* value being closed */
   TValue *uv = s2v(level);  /* value being closed */
-  if (likely(status == LUA_OK)) {
-    if (prepclosingmethod(L, uv, &G(L)->nilvalue))  /* something to call? */
-      callclose(L, NULL);  /* call closing method */
-    else if (!l_isfalse(uv))  /* non-closable non-false value? */
-      varerror(L, level, "attempt to close non-closable variable '%s'");
-  }
-  else {  /* must close the object in protected mode */
-    ptrdiff_t oldtop;
-    level++;  /* space for error message */
-    oldtop = savestack(L, level + 1);  /* top will be after that */
-    luaD_seterrorobj(L, status, level);  /* set error message */
-    if (prepclosingmethod(L, uv, s2v(level))) {  /* something to call? */
-      int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0);
-      if (newstatus != LUA_OK && status == CLOSEPROTECT)  /* first error? */
-        status = newstatus;  /* this will be the new error */
-      else {
-        if (newstatus != LUA_OK)  /* supressed error? */
-          luaE_warnerror(L, "__close metamethod");
-        /* leave original error (or nil) on top */
-        L->top = restorestack(L, oldtop);
-      }
-    }
-    /* else no metamethod; ignore this case and keep original error */
+  TValue *errobj;
+  if (status == CLOSEKTOP)
+    errobj = &G(L)->nilvalue;  /* error object is nil */
+  else {  /* 'luaD_seterrorobj' will set top to level + 2 */
+    errobj = s2v(level + 1);  /* error object goes after 'uv' */
+    luaD_seterrorobj(L, status, level + 1);  /* set error object */
   }
   }
-  return status;
+  callclosemethod(L, uv, errobj, yy);
 }
 }
 
 
 
 
 /*
 /*
-** Try to create a to-be-closed upvalue
-** (can raise a memory-allocation error)
+** Maximum value for deltas in 'tbclist', dependent on the type
+** of delta. (This macro assumes that an 'L' is in scope where it
+** is used.)
 */
 */
-static void trynewtbcupval (lua_State *L, void *ud) {
-  newupval(L, 1, cast(StkId, ud), &L->openupval);
-}
+#define MAXDELTA  \
+	((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1)
 
 
 
 
 /*
 /*
-** Create a to-be-closed upvalue. If there is a memory error
-** when creating the upvalue, the closing method must be called here,
-** as there is no upvalue to call it later.
+** Insert a variable in the list of to-be-closed variables.
 */
 */
 void luaF_newtbcupval (lua_State *L, StkId level) {
 void luaF_newtbcupval (lua_State *L, StkId level) {
-  TValue *obj = s2v(level);
-  lua_assert(L->openupval == NULL || uplevel(L->openupval) < level);
-  if (!l_isfalse(obj)) {  /* false doesn't need to be closed */
-    int status;
-    const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
-    if (ttisnil(tm))  /* no metamethod? */
-      varerror(L, level, "variable '%s' got a non-closable value");
-    status = luaD_rawrunprotected(L, trynewtbcupval, level);
-    if (unlikely(status != LUA_OK)) {  /* memory error creating upvalue? */
-      lua_assert(status == LUA_ERRMEM);
-      luaD_seterrorobj(L, LUA_ERRMEM, level + 1);  /* save error message */
-      /* next call must succeed, as object is closable */
-      prepclosingmethod(L, s2v(level), s2v(level + 1));
-      callclose(L, NULL);  /* call closing method */
-      luaD_throw(L, LUA_ERRMEM);  /* throw memory error */
-    }
+  lua_assert(level > L->tbclist);
+  if (l_isfalse(s2v(level)))
+    return;  /* false doesn't need to be closed */
+  checkclosemth(L, level);  /* value must have a close method */
+  while (cast_uint(level - L->tbclist) > MAXDELTA) {
+    L->tbclist += MAXDELTA;  /* create a dummy node at maximum delta */
+    L->tbclist->tbclist.delta = 0;
   }
   }
+  level->tbclist.delta = cast(unsigned short, level - L->tbclist);
+  L->tbclist = level;
 }
 }
 
 
 
 
@@ -220,30 +188,57 @@ void luaF_unlinkupval (UpVal *uv) {
 }
 }
 
 
 
 
-int luaF_close (lua_State *L, StkId level, int status) {
+/*
+** Close all upvalues up to the given stack level.
+*/
+void luaF_closeupval (lua_State *L, StkId level) {
   UpVal *uv;
   UpVal *uv;
-  while ((uv = L->openupval) != NULL && uplevel(uv) >= level) {
+  StkId upl;  /* stack index pointed by 'uv' */
+  while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
     TValue *slot = &uv->u.value;  /* new position for value */
     TValue *slot = &uv->u.value;  /* new position for value */
     lua_assert(uplevel(uv) < L->top);
     lua_assert(uplevel(uv) < L->top);
-    if (uv->tbc && status != NOCLOSINGMETH) {
-      /* must run closing method, which may change the stack */
-      ptrdiff_t levelrel = savestack(L, level);
-      status = callclosemth(L, uplevel(uv), status);
-      level = restorestack(L, levelrel);
-    }
-    luaF_unlinkupval(uv);
+    luaF_unlinkupval(uv);  /* remove upvalue from 'openupval' list */
     setobj(L, slot, uv->v);  /* move value to upvalue slot */
     setobj(L, slot, uv->v);  /* move value to upvalue slot */
     uv->v = slot;  /* now current value lives here */
     uv->v = slot;  /* now current value lives here */
-    if (!iswhite(uv))
-      gray2black(uv);  /* closed upvalues cannot be gray */
-    luaC_barrier(L, uv, slot);
+    if (!iswhite(uv)) {  /* neither white nor dead? */
+      nw2black(uv);  /* closed upvalues cannot be gray */
+      luaC_barrier(L, uv, slot);
+    }
+  }
+}
+
+
+/*
+** Remove firt element from the tbclist plus its dummy nodes.
+*/
+static void poptbclist (lua_State *L) {
+  StkId tbc = L->tbclist;
+  lua_assert(tbc->tbclist.delta > 0);  /* first element cannot be dummy */
+  tbc -= tbc->tbclist.delta;
+  while (tbc > L->stack && tbc->tbclist.delta == 0)
+    tbc -= MAXDELTA;  /* remove dummy nodes */
+  L->tbclist = tbc;
+}
+
+
+/*
+** Close all upvalues and to-be-closed variables up to the given stack
+** level.
+*/
+void luaF_close (lua_State *L, StkId level, int status, int yy) {
+  ptrdiff_t levelrel = savestack(L, level);
+  luaF_closeupval(L, level);  /* first, close the upvalues */
+  while (L->tbclist >= level) {  /* traverse tbc's down to that level */
+    StkId tbc = L->tbclist;  /* get variable index */
+    poptbclist(L);  /* remove it from list */
+    prepcallclosemth(L, tbc, status, yy);  /* close variable */
+    level = restorestack(L, levelrel);
   }
   }
-  return status;
 }
 }
 
 
 
 
 Proto *luaF_newproto (lua_State *L) {
 Proto *luaF_newproto (lua_State *L) {
-  GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto));
+  GCObject *o = luaC_newobj(L, LUA_VPROTO, sizeof(Proto));
   Proto *f = gco2p(o);
   Proto *f = gco2p(o);
   f->k = NULL;
   f->k = NULL;
   f->sizek = 0;
   f->sizek = 0;
@@ -265,7 +260,6 @@ Proto *luaF_newproto (lua_State *L) {
   f->linedefined = 0;
   f->linedefined = 0;
   f->lastlinedefined = 0;
   f->lastlinedefined = 0;
   f->source = NULL;
   f->source = NULL;
-  f->aot_implementation = NULL;
   return f;
   return f;
 }
 }
 
 

+ 6 - 11
src/lfunc.h

@@ -42,24 +42,19 @@
 #define MAXMISS		10
 #define MAXMISS		10
 
 
 
 
-/*
-** Special "status" for 'luaF_close'
-*/
-
-/* close upvalues without running their closing methods */
-#define NOCLOSINGMETH	(-1)
 
 
-/* close upvalues running all closing methods in protected mode */
-#define CLOSEPROTECT	(-2)
+/* special status to close upvalues preserving the top of the stack */
+#define CLOSEKTOP	(-1)
 
 
 
 
 LUAI_FUNC Proto *luaF_newproto (lua_State *L);
 LUAI_FUNC Proto *luaF_newproto (lua_State *L);
-LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems);
-LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems);
+LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nupvals);
+LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nupvals);
 LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
 LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
 LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
 LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
 LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
 LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
-LUAI_FUNC int luaF_close (lua_State *L, StkId level, int status);
+LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
+LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy);
 LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
 LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
 LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
 LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
 LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
 LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 334 - 222
src/lgc.c


+ 16 - 13
src/lgc.h

@@ -12,16 +12,16 @@
 #include "lstate.h"
 #include "lstate.h"
 
 
 /*
 /*
-** Collectable objects may have one of three colors: white, which
-** means the object is not marked; gray, which means the
-** object is marked, but its references may be not marked; and
-** black, which means that the object and all its references are marked.
-** The main invariant of the garbage collector, while marking objects,
-** is that a black object can 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. These lists have no meaning when the invariant
-** is not being enforced (e.g., sweep phase).
+** Collectable objects may have one of three colors: white, which means
+** the object is not marked; gray, which means the object is marked, but
+** its references may be not marked; and black, which means that the
+** object and all its references are marked.  The main invariant of the
+** garbage collector, while marking objects, is that a black object can
+** 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).
 */
 */
 
 
 
 
@@ -69,14 +69,16 @@
 
 
 /*
 /*
 ** Layout for bit use in 'marked' field. First three bits are
 ** Layout for bit use in 'marked' field. First three bits are
-** used for object "age" in generational mode. Last bit is free
-** to be used by respective objects.
+** used for object "age" in generational mode. Last bit is used
+** by tests.
 */
 */
 #define WHITE0BIT	3  /* object is white (type 0) */
 #define WHITE0BIT	3  /* object is white (type 0) */
 #define WHITE1BIT	4  /* object is white (type 1) */
 #define WHITE1BIT	4  /* object is white (type 1) */
 #define BLACKBIT	5  /* object is black */
 #define BLACKBIT	5  /* object is black */
 #define FINALIZEDBIT	6  /* object has been marked for finalization */
 #define FINALIZEDBIT	6  /* object has been marked for finalization */
 
 
+#define TESTBIT		7
+
 
 
 
 
 #define WHITEBITS	bit2mask(WHITE0BIT, WHITE1BIT)
 #define WHITEBITS	bit2mask(WHITE0BIT, WHITE1BIT)
@@ -94,7 +96,8 @@
 #define isdead(g,v)	isdeadm(otherwhite(g), (v)->marked)
 #define isdead(g,v)	isdeadm(otherwhite(g), (v)->marked)
 
 
 #define changewhite(x)	((x)->marked ^= WHITEBITS)
 #define changewhite(x)	((x)->marked ^= WHITEBITS)
-#define gray2black(x)	l_setbit((x)->marked, BLACKBIT)
+#define nw2black(x)  \
+	check_exp(!iswhite(x), l_setbit((x)->marked, BLACKBIT))
 
 
 #define luaC_white(g)	cast_byte((g)->currentwhite & WHITEBITS)
 #define luaC_white(g)	cast_byte((g)->currentwhite & WHITEBITS)
 
 

+ 25 - 10
src/liolib.c

@@ -64,6 +64,12 @@ static int l_checkmode (const char *mode) {
 #define l_popen(L,c,m)		(_popen(c,m))
 #define l_popen(L,c,m)		(_popen(c,m))
 #define l_pclose(L,file)	(_pclose(file))
 #define l_pclose(L,file)	(_pclose(file))
 
 
+#if !defined(l_checkmodep)
+/* Windows accepts "[rw][bt]?" as valid modes */
+#define l_checkmodep(m)	((m[0] == 'r' || m[0] == 'w') && \
+  (m[1] == '\0' || ((m[1] == 'b' || m[1] == 't') && m[2] == '\0')))
+#endif
+
 #else				/* }{ */
 #else				/* }{ */
 
 
 /* ISO C definitions */
 /* ISO C definitions */
@@ -77,6 +83,12 @@ static int l_checkmode (const char *mode) {
 
 
 #endif				/* } */
 #endif				/* } */
 
 
+
+#if !defined(l_checkmodep)
+/* By default, Lua accepts only "r" or "w" as valid modes */
+#define l_checkmodep(m)        ((m[0] == 'r' || m[0] == 'w') && m[1] == '\0')
+#endif
+
 /* }====================================================== */
 /* }====================================================== */
 
 
 
 
@@ -174,7 +186,7 @@ static int f_tostring (lua_State *L) {
 
 
 static FILE *tofile (lua_State *L) {
 static FILE *tofile (lua_State *L) {
   LStream *p = tolstream(L);
   LStream *p = tolstream(L);
-  if (isclosed(p))
+  if (l_unlikely(isclosed(p)))
     luaL_error(L, "attempt to use a closed file");
     luaL_error(L, "attempt to use a closed file");
   lua_assert(p->f);
   lua_assert(p->f);
   return p->f;
   return p->f;
@@ -215,7 +227,7 @@ static int f_close (lua_State *L) {
 
 
 static int io_close (lua_State *L) {
 static int io_close (lua_State *L) {
   if (lua_isnone(L, 1))  /* no argument? */
   if (lua_isnone(L, 1))  /* no argument? */
-    lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT);  /* use standard output */
+    lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT);  /* use default output */
   return f_close(L);
   return f_close(L);
 }
 }
 
 
@@ -249,7 +261,7 @@ static LStream *newfile (lua_State *L) {
 static void opencheck (lua_State *L, const char *fname, const char *mode) {
 static void opencheck (lua_State *L, const char *fname, const char *mode) {
   LStream *p = newfile(L);
   LStream *p = newfile(L);
   p->f = fopen(fname, mode);
   p->f = fopen(fname, mode);
-  if (p->f == NULL)
+  if (l_unlikely(p->f == NULL))
     luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno));
     luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno));
 }
 }
 
 
@@ -270,6 +282,7 @@ static int io_open (lua_State *L) {
 */
 */
 static int io_pclose (lua_State *L) {
 static int io_pclose (lua_State *L) {
   LStream *p = tolstream(L);
   LStream *p = tolstream(L);
+  errno = 0;
   return luaL_execresult(L, l_pclose(L, p->f));
   return luaL_execresult(L, l_pclose(L, p->f));
 }
 }
 
 
@@ -278,6 +291,7 @@ static int io_popen (lua_State *L) {
   const char *filename = luaL_checkstring(L, 1);
   const char *filename = luaL_checkstring(L, 1);
   const char *mode = luaL_optstring(L, 2, "r");
   const char *mode = luaL_optstring(L, 2, "r");
   LStream *p = newprefile(L);
   LStream *p = newprefile(L);
+  luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode");
   p->f = l_popen(L, filename, mode);
   p->f = l_popen(L, filename, mode);
   p->closef = &io_pclose;
   p->closef = &io_pclose;
   return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
   return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
@@ -295,8 +309,8 @@ static FILE *getiofile (lua_State *L, const char *findex) {
   LStream *p;
   LStream *p;
   lua_getfield(L, LUA_REGISTRYINDEX, findex);
   lua_getfield(L, LUA_REGISTRYINDEX, findex);
   p = (LStream *)lua_touserdata(L, -1);
   p = (LStream *)lua_touserdata(L, -1);
-  if (isclosed(p))
-    luaL_error(L, "standard %s file is closed", findex + IOPREF_LEN);
+  if (l_unlikely(isclosed(p)))
+    luaL_error(L, "default %s file is closed", findex + IOPREF_LEN);
   return p->f;
   return p->f;
 }
 }
 
 
@@ -422,7 +436,7 @@ typedef struct {
 ** Add current char to buffer (if not out of space) and read next one
 ** Add current char to buffer (if not out of space) and read next one
 */
 */
 static int nextc (RN *rn) {
 static int nextc (RN *rn) {
-  if (rn->n >= L_MAXLENNUM) {  /* buffer overflow? */
+  if (l_unlikely(rn->n >= L_MAXLENNUM)) {  /* buffer overflow? */
     rn->buff[0] = '\0';  /* invalidate result */
     rn->buff[0] = '\0';  /* invalidate result */
     return 0;  /* fail */
     return 0;  /* fail */
   }
   }
@@ -485,8 +499,8 @@ static int read_number (lua_State *L, FILE *f) {
   ungetc(rn.c, rn.f);  /* unread look-ahead char */
   ungetc(rn.c, rn.f);  /* unread look-ahead char */
   l_unlockfile(rn.f);
   l_unlockfile(rn.f);
   rn.buff[rn.n] = '\0';  /* finish string */
   rn.buff[rn.n] = '\0';  /* finish string */
-  if (lua_stringtonumber(L, rn.buff))  /* is this a valid number? */
-    return 1;  /* ok */
+  if (l_likely(lua_stringtonumber(L, rn.buff)))
+    return 1;  /* ok, it is a valid number */
   else {  /* invalid format */
   else {  /* invalid format */
    lua_pushnil(L);  /* "result" to be removed */
    lua_pushnil(L);  /* "result" to be removed */
    return 0;  /* read fails */
    return 0;  /* read fails */
@@ -662,7 +676,8 @@ static int g_write (lua_State *L, FILE *f, int arg) {
       status = status && (fwrite(s, sizeof(char), l, f) == l);
       status = status && (fwrite(s, sizeof(char), l, f) == l);
     }
     }
   }
   }
-  if (status) return 1;  /* file handle already on stack top */
+  if (l_likely(status))
+    return 1;  /* file handle already on stack top */
   else return luaL_fileresult(L, status, NULL);
   else return luaL_fileresult(L, status, NULL);
 }
 }
 
 
@@ -689,7 +704,7 @@ static int f_seek (lua_State *L) {
   luaL_argcheck(L, (lua_Integer)offset == p3, 3,
   luaL_argcheck(L, (lua_Integer)offset == p3, 3,
                   "not an integer in proper range");
                   "not an integer in proper range");
   op = l_fseek(f, offset, mode[op]);
   op = l_fseek(f, offset, mode[op]);
-  if (op)
+  if (l_unlikely(op))
     return luaL_fileresult(L, 0, NULL);  /* error */
     return luaL_fileresult(L, 0, NULL);  /* error */
   else {
   else {
     lua_pushinteger(L, (lua_Integer)l_ftell(f));
     lua_pushinteger(L, (lua_Integer)l_ftell(f));

+ 4 - 2
src/ljumptab.h

@@ -16,7 +16,7 @@
 #define vmbreak		vmfetch(); vmdispatch(GET_OPCODE(i));
 #define vmbreak		vmfetch(); vmdispatch(GET_OPCODE(i));
 
 
 
 
-static void *disptab[NUM_OPCODES] = {
+static const void *const disptab[NUM_OPCODES] = {
 
 
 #if 0
 #if 0
 ** you can update the following list with this command:
 ** you can update the following list with this command:
@@ -30,7 +30,9 @@ static void *disptab[NUM_OPCODES] = {
 &&L_OP_LOADF,
 &&L_OP_LOADF,
 &&L_OP_LOADK,
 &&L_OP_LOADK,
 &&L_OP_LOADKX,
 &&L_OP_LOADKX,
-&&L_OP_LOADBOOL,
+&&L_OP_LOADFALSE,
+&&L_OP_LFALSESKIP,
+&&L_OP_LOADTRUE,
 &&L_OP_LOADNIL,
 &&L_OP_LOADNIL,
 &&L_OP_GETUPVAL,
 &&L_OP_GETUPVAL,
 &&L_OP_SETUPVAL,
 &&L_OP_SETUPVAL,

+ 30 - 27
src/llex.c

@@ -81,7 +81,6 @@ void luaX_init (lua_State *L) {
 
 
 const char *luaX_token2str (LexState *ls, int token) {
 const char *luaX_token2str (LexState *ls, int token) {
   if (token < FIRST_RESERVED) {  /* single-byte symbols? */
   if (token < FIRST_RESERVED) {  /* single-byte symbols? */
-    lua_assert(token == cast_uchar(token));
     if (lisprint(token))
     if (lisprint(token))
       return luaO_pushfstring(ls->L, "'%c'", token);
       return luaO_pushfstring(ls->L, "'%c'", token);
     else  /* control character */
     else  /* control character */
@@ -123,26 +122,29 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
 
 
 
 
 /*
 /*
-** creates a new string and anchors it in scanner's table so that
-** it will not be collected until the end of the compilation
-** (by that time it should be anchored somewhere)
+** Creates a new string and anchors it in scanner's table so that it
+** will not be collected until the end of the compilation; by that time
+** it should be anchored somewhere. It also internalizes long strings,
+** ensuring there is only one copy of each unique string.  The table
+** here is used as a set: the string enters as the key, while its value
+** is irrelevant. We use the string itself as the value only because it
+** is a TValue readly available. Later, the code generation can change
+** this value.
 */
 */
 TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
 TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
   lua_State *L = ls->L;
   lua_State *L = ls->L;
-  TValue *o;  /* entry for 'str' */
   TString *ts = luaS_newlstr(L, str, l);  /* create new string */
   TString *ts = luaS_newlstr(L, str, l);  /* create new string */
-  setsvalue2s(L, L->top++, ts);  /* temporarily anchor it in stack */
-  o = luaH_set(L, ls->h, s2v(L->top - 1));
-  if (isempty(o)) {  /* not in use yet? */
-    /* boolean value does not need GC barrier;
-       table is not a metatable, so it does not need to invalidate cache */
-    setbvalue(o, 1);  /* t[string] = true */
+  const TValue *o = luaH_getstr(ls->h, ts);
+  if (!ttisnil(o))  /* string already present? */
+    ts = keystrval(nodefromval(o));  /* get saved copy */
+  else {  /* not in use yet */
+    TValue *stv = s2v(L->top++);  /* reserve stack space for string */
+    setsvalue(L, stv, ts);  /* temporarily anchor the string */
+    luaH_finishset(L, ls->h, stv, o, stv);  /* t[string] = string */
+    /* table is not a metatable, so it does not need to invalidate cache */
     luaC_checkGC(L);
     luaC_checkGC(L);
+    L->top--;  /* remove string from stack */
   }
   }
-  else {  /* string already present */
-    ts = keystrval(nodefromval(o));  /* re-use value previously stored */
-  }
-  L->top--;  /* remove string from stack */
   return ts;
   return ts;
 }
 }
 
 
@@ -255,9 +257,10 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) {
 
 
 
 
 /*
 /*
-** reads a sequence '[=*[' or ']=*]', leaving the last bracket.
-** If sequence is well formed, return its number of '='s + 2; otherwise,
-** return 1 if there is no '='s or 0 otherwise (an unfinished '[==...').
+** read a sequence '[=*[' or ']=*]', leaving the last bracket. If
+** sequence is well formed, return its number of '='s + 2; otherwise,
+** return 1 if it is a single bracket (no '='s and no 2nd bracket);
+** otherwise (an unfinished '[==...') return 0.
 */
 */
 static size_t skip_sep (LexState *ls) {
 static size_t skip_sep (LexState *ls) {
   size_t count = 0;
   size_t count = 0;
@@ -482,34 +485,34 @@ static int llex (LexState *ls, SemInfo *seminfo) {
       }
       }
       case '=': {
       case '=': {
         next(ls);
         next(ls);
-        if (check_next1(ls, '=')) return TK_EQ;
+        if (check_next1(ls, '=')) return TK_EQ;  /* '==' */
         else return '=';
         else return '=';
       }
       }
       case '<': {
       case '<': {
         next(ls);
         next(ls);
-        if (check_next1(ls, '=')) return TK_LE;
-        else if (check_next1(ls, '<')) return TK_SHL;
+        if (check_next1(ls, '=')) return TK_LE;  /* '<=' */
+        else if (check_next1(ls, '<')) return TK_SHL;  /* '<<' */
         else return '<';
         else return '<';
       }
       }
       case '>': {
       case '>': {
         next(ls);
         next(ls);
-        if (check_next1(ls, '=')) return TK_GE;
-        else if (check_next1(ls, '>')) return TK_SHR;
+        if (check_next1(ls, '=')) return TK_GE;  /* '>=' */
+        else if (check_next1(ls, '>')) return TK_SHR;  /* '>>' */
         else return '>';
         else return '>';
       }
       }
       case '/': {
       case '/': {
         next(ls);
         next(ls);
-        if (check_next1(ls, '/')) return TK_IDIV;
+        if (check_next1(ls, '/')) return TK_IDIV;  /* '//' */
         else return '/';
         else return '/';
       }
       }
       case '~': {
       case '~': {
         next(ls);
         next(ls);
-        if (check_next1(ls, '=')) return TK_NE;
+        if (check_next1(ls, '=')) return TK_NE;  /* '~=' */
         else return '~';
         else return '~';
       }
       }
       case ':': {
       case ':': {
         next(ls);
         next(ls);
-        if (check_next1(ls, ':')) return TK_DBCOLON;
+        if (check_next1(ls, ':')) return TK_DBCOLON;  /* '::' */
         else return ':';
         else return ':';
       }
       }
       case '"': case '\'': {  /* short literal strings */
       case '"': case '\'': {  /* short literal strings */
@@ -548,7 +551,7 @@ static int llex (LexState *ls, SemInfo *seminfo) {
             return TK_NAME;
             return TK_NAME;
           }
           }
         }
         }
-        else {  /* single-char tokens (+ - / ...) */
+        else {  /* single-char tokens ('+', '*', '%', '{', '}', ...) */
           int c = ls->current;
           int c = ls->current;
           next(ls);
           next(ls);
           return c;
           return c;

+ 7 - 1
src/llex.h

@@ -7,11 +7,17 @@
 #ifndef llex_h
 #ifndef llex_h
 #define llex_h
 #define llex_h
 
 
+#include <limits.h>
+
 #include "lobject.h"
 #include "lobject.h"
 #include "lzio.h"
 #include "lzio.h"
 
 
 
 
-#define FIRST_RESERVED	257
+/*
+** Single-char tokens (terminal symbols) are represented by their own
+** numeric code. Other tokens start at the following value.
+*/
+#define FIRST_RESERVED	(UCHAR_MAX + 1)
 
 
 
 
 #if !defined(LUA_ENV)
 #if !defined(LUA_ENV)

+ 24 - 20
src/llimits.h

@@ -84,7 +84,15 @@ typedef LUAI_UACNUMBER l_uacNumber;
 typedef LUAI_UACINT l_uacInt;
 typedef LUAI_UACINT l_uacInt;
 
 
 
 
-/* internal assertions for in-house debugging */
+/*
+** Internal assertions for in-house debugging
+*/
+#if defined LUAI_ASSERT
+#undef NDEBUG
+#include <assert.h>
+#define lua_assert(c)           assert(c)
+#endif
+
 #if defined(lua_assert)
 #if defined(lua_assert)
 #define check_exp(c,e)		(lua_assert(c), (e))
 #define check_exp(c,e)		(lua_assert(c), (e))
 /* to avoid problems with conditions too long */
 /* to avoid problems with conditions too long */
@@ -99,7 +107,7 @@ typedef LUAI_UACINT l_uacInt;
 ** assertion for checking API calls
 ** assertion for checking API calls
 */
 */
 #if !defined(luai_apicheck)
 #if !defined(luai_apicheck)
-#define luai_apicheck(l,e)	lua_assert(e)
+#define luai_apicheck(l,e)	((void)l, lua_assert(e))
 #endif
 #endif
 
 
 #define api_check(l,e,msg)	luai_apicheck(l,(e) && msg)
 #define api_check(l,e,msg)	luai_apicheck(l,(e) && msg)
@@ -141,22 +149,6 @@ typedef LUAI_UACINT l_uacInt;
 #endif
 #endif
 
 
 
 
-/*
-** macros to improve jump prediction (used mainly for error handling)
-*/
-#if !defined(likely)
-
-#if defined(__GNUC__)
-#define likely(x)	(__builtin_expect(((x) != 0), 1))
-#define unlikely(x)	(__builtin_expect(((x) != 0), 0))
-#else
-#define likely(x)	(x)
-#define unlikely(x)	(x)
-#endif
-
-#endif
-
-
 /*
 /*
 ** non-return type
 ** non-return type
 */
 */
@@ -226,6 +218,17 @@ typedef l_uint32 Instruction;
 #endif
 #endif
 
 
 
 
+/*
+** Maximum depth for nested C calls, syntactical nested non-terminals,
+** and other features implemented through recursion in C. (Value must
+** fit in a 16-bit unsigned integer. It must also be compatible with
+** the size of the C stack.)
+*/
+#if !defined(LUAI_MAXCCALLS)
+#define LUAI_MAXCCALLS		200
+#endif
+
+
 /*
 /*
 ** macros that are executed whenever program enters the Lua core
 ** macros that are executed whenever program enters the Lua core
 ** ('lua_lock') and leaves the core ('lua_unlock')
 ** ('lua_lock') and leaves the core ('lua_unlock')
@@ -307,7 +310,8 @@ typedef l_uint32 Instruction;
 
 
 /* exponentiation */
 /* exponentiation */
 #if !defined(luai_numpow)
 #if !defined(luai_numpow)
-#define luai_numpow(L,a,b)      ((void)L, l_mathop(pow)(a,b))
+#define luai_numpow(L,a,b)  \
+  ((void)L, (b == 2) ? (a)*(a) : l_mathop(pow)(a,b))
 #endif
 #endif
 
 
 /* the others are quite standard operations */
 /* the others are quite standard operations */
@@ -336,7 +340,7 @@ typedef l_uint32 Instruction;
 #else
 #else
 /* realloc stack keeping its size */
 /* realloc stack keeping its size */
 #define condmovestack(L,pre,pos)  \
 #define condmovestack(L,pre,pos)  \
-  { int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_, 0); pos; }
+  { int sz_ = stacksize(L); pre; luaD_reallocstack((L), sz_, 0); pos; }
 #endif
 #endif
 
 
 #if !defined(HARDMEMTESTS)
 #if !defined(HARDMEMTESTS)

+ 20 - 17
src/lmathlib.c

@@ -73,7 +73,7 @@ static int math_atan (lua_State *L) {
 static int math_toint (lua_State *L) {
 static int math_toint (lua_State *L) {
   int valid;
   int valid;
   lua_Integer n = lua_tointegerx(L, 1, &valid);
   lua_Integer n = lua_tointegerx(L, 1, &valid);
-  if (valid)
+  if (l_likely(valid))
     lua_pushinteger(L, n);
     lua_pushinteger(L, n);
   else {
   else {
     luaL_checkany(L, 1);
     luaL_checkany(L, 1);
@@ -175,7 +175,8 @@ static int math_log (lua_State *L) {
     lua_Number base = luaL_checknumber(L, 2);
     lua_Number base = luaL_checknumber(L, 2);
 #if !defined(LUA_USE_C89)
 #if !defined(LUA_USE_C89)
     if (base == l_mathop(2.0))
     if (base == l_mathop(2.0))
-      res = l_mathop(log2)(x); else
+      res = l_mathop(log2)(x);
+    else
 #endif
 #endif
     if (base == l_mathop(10.0))
     if (base == l_mathop(10.0))
       res = l_mathop(log10)(x);
       res = l_mathop(log10)(x);
@@ -249,7 +250,7 @@ static int math_type (lua_State *L) {
 */
 */
 
 
 /* number of binary digits in the mantissa of a float */
 /* number of binary digits in the mantissa of a float */
-#define FIGS	l_mathlim(MANT_DIG)
+#define FIGS	l_floatatt(MANT_DIG)
 
 
 #if FIGS > 64
 #if FIGS > 64
 /* there are only 64 random bits; use them all */
 /* there are only 64 random bits; use them all */
@@ -328,7 +329,7 @@ static Rand64 nextrand (Rand64 *state) {
 */
 */
 
 
 /* must throw out the extra (64 - FIGS) bits */
 /* must throw out the extra (64 - FIGS) bits */
-#define shift64_FIG  	(64 - FIGS)
+#define shift64_FIG	(64 - FIGS)
 
 
 /* to scale to [0, 1), multiply by scaleFIG = 2^(-FIGS) */
 /* to scale to [0, 1), multiply by scaleFIG = 2^(-FIGS) */
 #define scaleFIG	(l_mathop(0.5) / ((Rand64)1 << (FIGS - 1)))
 #define scaleFIG	(l_mathop(0.5) / ((Rand64)1 << (FIGS - 1)))
@@ -522,16 +523,18 @@ typedef struct {
 ** Project the random integer 'ran' into the interval [0, n].
 ** Project the random integer 'ran' into the interval [0, n].
 ** Because 'ran' has 2^B possible values, the projection can only be
 ** Because 'ran' has 2^B possible values, the projection can only be
 ** uniform when the size of the interval is a power of 2 (exact
 ** uniform when the size of the interval is a power of 2 (exact
-** division).  To get a uniform projection into [0, n], we first compute
-** 'lim', the smallest Mersenne number not smaller than 'n'. We then
-** project 'ran' into the interval [0, lim].  If the result is inside
-** [0, n], we are done. Otherwise, we try with another 'ran', until we
-** have a result inside the interval.
+** division). Otherwise, to get a uniform projection into [0, n], we
+** first compute 'lim', the smallest Mersenne number not smaller than
+** 'n'. We then project 'ran' into the interval [0, lim].  If the result
+** is inside [0, n], we are done. Otherwise, we try with another 'ran',
+** until we have a result inside the interval.
 */
 */
 static lua_Unsigned project (lua_Unsigned ran, lua_Unsigned n,
 static lua_Unsigned project (lua_Unsigned ran, lua_Unsigned n,
                              RanState *state) {
                              RanState *state) {
-  lua_Unsigned lim = n;
-  if ((lim & (lim + 1)) > 0) {  /* 'lim + 1' is not a power of 2? */
+  if ((n & (n + 1)) == 0)  /* is 'n + 1' a power of 2? */
+    return ran & n;  /* no bias */
+  else {
+    lua_Unsigned lim = n;
     /* compute the smallest (2^b - 1) not smaller than 'n' */
     /* compute the smallest (2^b - 1) not smaller than 'n' */
     lim |= (lim >> 1);
     lim |= (lim >> 1);
     lim |= (lim >> 2);
     lim |= (lim >> 2);
@@ -541,13 +544,13 @@ static lua_Unsigned project (lua_Unsigned ran, lua_Unsigned n,
 #if (LUA_MAXUNSIGNED >> 31) >= 3
 #if (LUA_MAXUNSIGNED >> 31) >= 3
     lim |= (lim >> 32);  /* integer type has more than 32 bits */
     lim |= (lim >> 32);  /* integer type has more than 32 bits */
 #endif
 #endif
+    lua_assert((lim & (lim + 1)) == 0  /* 'lim + 1' is a power of 2, */
+      && lim >= n  /* not smaller than 'n', */
+      && (lim >> 1) < n);  /* and it is the smallest one */
+    while ((ran &= lim) > n)  /* project 'ran' into [0..lim] */
+      ran = I2UInt(nextrand(state->s));  /* not inside [0..n]? try again */
+    return ran;
   }
   }
-  lua_assert((lim & (lim + 1)) == 0  /* 'lim + 1' is a power of 2, */
-    && lim >= n  /* not smaller than 'n', */
-    && (lim == 0 || (lim >> 1) < n));  /* and it is the smallest one */
-  while ((ran &= lim) > n)  /* project 'ran' into [0..lim] */
-    ran = I2UInt(nextrand(state->s));  /* not inside [0..n]? try again */
-  return ran;
 }
 }
 
 
 
 

+ 17 - 18
src/lmem.c

@@ -22,14 +22,14 @@
 #include "lstate.h"
 #include "lstate.h"
 
 
 
 
-#if defined(HARDMEMTESTS)
+#if defined(EMERGENCYGCTESTS)
 /*
 /*
-** First allocation will fail whenever not building initial state
-** and not shrinking a block. (This fail will trigger 'tryagain' and
-** a full GC cycle at every alocation.)
+** First allocation will fail whenever not building initial state.
+** (This fail will trigger 'tryagain' and a full GC cycle at every
+** allocation.)
 */
 */
 static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
 static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
-  if (ttisnil(&g->nilvalue) && ns > os)
+  if (completestate(g) && ns > 0)  /* frees never fail */
     return NULL;  /* fail */
     return NULL;  /* fail */
   else  /* normal allocation */
   else  /* normal allocation */
     return (*g->frealloc)(g->ud, block, os, ns);
     return (*g->frealloc)(g->ud, block, os, ns);
@@ -83,7 +83,7 @@ void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize,
   if (nelems + 1 <= size)  /* does one extra element still fit? */
   if (nelems + 1 <= size)  /* does one extra element still fit? */
     return block;  /* nothing to be done */
     return block;  /* nothing to be done */
   if (size >= limit / 2) {  /* cannot double it? */
   if (size >= limit / 2) {  /* cannot double it? */
-    if (unlikely(size >= limit))  /* cannot grow even a little? */
+    if (l_unlikely(size >= limit))  /* cannot grow even a little? */
       luaG_runerror(L, "too many %s (limit is %d)", what, limit);
       luaG_runerror(L, "too many %s (limit is %d)", what, limit);
     size = limit;  /* still have at least one free place */
     size = limit;  /* still have at least one free place */
   }
   }
@@ -138,15 +138,17 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
 
 
 
 
 /*
 /*
-** In case of allocation fail, this function will call the GC to try
-** to free some memory and then try the allocation again.
-** (It should not be called when shrinking a block, because then the
-** interpreter may be in the middle of a collection step.)
+** In case of allocation fail, this function will do an emergency
+** collection to free some memory and then try the allocation again.
+** The GC should not be called while state is not fully built, as the
+** collector is not yet fully initialized. Also, it should not be called
+** when 'gcstopem' is true, because then the interpreter is in the
+** middle of a collection step.
 */
 */
 static void *tryagain (lua_State *L, void *block,
 static void *tryagain (lua_State *L, void *block,
                        size_t osize, size_t nsize) {
                        size_t osize, size_t nsize) {
   global_State *g = G(L);
   global_State *g = G(L);
-  if (ttisnil(&g->nilvalue)) {  /* is state fully build? */
+  if (completestate(g) && !g->gcstopem) {
     luaC_fullgc(L, 1);  /* try to free some memory... */
     luaC_fullgc(L, 1);  /* try to free some memory... */
     return (*g->frealloc)(g->ud, block, osize, nsize);  /* try again */
     return (*g->frealloc)(g->ud, block, osize, nsize);  /* try again */
   }
   }
@@ -156,17 +158,14 @@ static void *tryagain (lua_State *L, void *block,
 
 
 /*
 /*
 ** Generic allocation routine.
 ** Generic allocation routine.
-** If allocation fails while shrinking a block, do not try again; the
-** GC shrinks some blocks and it is not reentrant.
 */
 */
 void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
 void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
   void *newblock;
   void *newblock;
   global_State *g = G(L);
   global_State *g = G(L);
   lua_assert((osize == 0) == (block == NULL));
   lua_assert((osize == 0) == (block == NULL));
   newblock = firsttry(g, block, osize, nsize);
   newblock = firsttry(g, block, osize, nsize);
-  if (unlikely(newblock == NULL && nsize > 0)) {
-    if (nsize > osize)  /* not shrinking a block? */
-      newblock = tryagain(L, block, osize, nsize);
+  if (l_unlikely(newblock == NULL && nsize > 0)) {
+    newblock = tryagain(L, block, osize, nsize);
     if (newblock == NULL)  /* still no memory? */
     if (newblock == NULL)  /* still no memory? */
       return NULL;  /* do not update 'GCdebt' */
       return NULL;  /* do not update 'GCdebt' */
   }
   }
@@ -179,7 +178,7 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
 void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize,
 void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize,
                                                     size_t nsize) {
                                                     size_t nsize) {
   void *newblock = luaM_realloc_(L, block, osize, nsize);
   void *newblock = luaM_realloc_(L, block, osize, nsize);
-  if (unlikely(newblock == NULL && nsize > 0))  /* allocation failed? */
+  if (l_unlikely(newblock == NULL && nsize > 0))  /* allocation failed? */
     luaM_error(L);
     luaM_error(L);
   return newblock;
   return newblock;
 }
 }
@@ -191,7 +190,7 @@ void *luaM_malloc_ (lua_State *L, size_t size, int tag) {
   else {
   else {
     global_State *g = G(L);
     global_State *g = G(L);
     void *newblock = firsttry(g, NULL, tag, size);
     void *newblock = firsttry(g, NULL, tag, size);
-    if (unlikely(newblock == NULL)) {
+    if (l_unlikely(newblock == NULL)) {
       newblock = tryagain(L, NULL, tag, size);
       newblock = tryagain(L, NULL, tag, size);
       if (newblock == NULL)
       if (newblock == NULL)
         luaM_error(L);
         luaM_error(L);

+ 27 - 15
src/loadlib.c

@@ -67,6 +67,13 @@ static const char *const CLIBS = "_CLIBS";
 #define setprogdir(L)           ((void)0)
 #define setprogdir(L)           ((void)0)
 
 
 
 
+/*
+** Special type equivalent to '(void*)' for functions in gcc
+** (to suppress warnings when converting function pointers)
+*/
+typedef void (*voidf)(void);
+
+
 /*
 /*
 ** system-dependent functions
 ** system-dependent functions
 */
 */
@@ -125,14 +132,16 @@ static void lsys_unloadlib (void *lib) {
 
 
 static void *lsys_load (lua_State *L, const char *path, int seeglb) {
 static void *lsys_load (lua_State *L, const char *path, int seeglb) {
   void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL));
   void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL));
-  if (lib == NULL) lua_pushstring(L, dlerror());
+  if (l_unlikely(lib == NULL))
+    lua_pushstring(L, dlerror());
   return lib;
   return lib;
 }
 }
 
 
 
 
 static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
 static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
   lua_CFunction f = cast_func(dlsym(lib, sym));
   lua_CFunction f = cast_func(dlsym(lib, sym));
-  if (f == NULL) lua_pushstring(L, dlerror());
+  if (l_unlikely(f == NULL))
+    lua_pushstring(L, dlerror());
   return f;
   return f;
 }
 }
 
 
@@ -206,7 +215,7 @@ static void *lsys_load (lua_State *L, const char *path, int seeglb) {
 
 
 
 
 static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
 static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
-  lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym);
+  lua_CFunction f = (lua_CFunction)(voidf)GetProcAddress((HMODULE)lib, sym);
   if (f == NULL) pusherror(L);
   if (f == NULL) pusherror(L);
   return f;
   return f;
 }
 }
@@ -269,8 +278,6 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
 #endif
 #endif
 
 
 
 
-#define AUXMARK         "\1"	/* auxiliary mark */
-
 
 
 /*
 /*
 ** return registry.LUA_NOENV as a boolean
 ** return registry.LUA_NOENV as a boolean
@@ -405,7 +412,7 @@ static int ll_loadlib (lua_State *L) {
   const char *path = luaL_checkstring(L, 1);
   const char *path = luaL_checkstring(L, 1);
   const char *init = luaL_checkstring(L, 2);
   const char *init = luaL_checkstring(L, 2);
   int stat = lookforfunc(L, path, init);
   int stat = lookforfunc(L, path, init);
-  if (stat == 0)  /* no errors? */
+  if (l_likely(stat == 0))  /* no errors? */
     return 1;  /* return the loaded function */
     return 1;  /* return the loaded function */
   else {  /* error; error message is on stack top */
   else {  /* error; error message is on stack top */
     luaL_pushfail(L);
     luaL_pushfail(L);
@@ -458,13 +465,13 @@ static const char *getnextfilename (char **path, char *end) {
 /*
 /*
 ** Given a path such as ";blabla.so;blublu.so", pushes the string
 ** Given a path such as ";blabla.so;blublu.so", pushes the string
 **
 **
-** 	no file 'blabla.so'
+** no file 'blabla.so'
 **	no file 'blublu.so'
 **	no file 'blublu.so'
 */
 */
 static void pusherrornotfound (lua_State *L, const char *path) {
 static void pusherrornotfound (lua_State *L, const char *path) {
   luaL_Buffer b;
   luaL_Buffer b;
   luaL_buffinit(L, &b);
   luaL_buffinit(L, &b);
-  luaL_addstring(&b, "\n\tno file '");
+  luaL_addstring(&b, "no file '");
   luaL_addgsub(&b, path, LUA_PATH_SEP, "'\n\tno file '");
   luaL_addgsub(&b, path, LUA_PATH_SEP, "'\n\tno file '");
   luaL_addstring(&b, "'");
   luaL_addstring(&b, "'");
   luaL_pushresult(&b);
   luaL_pushresult(&b);
@@ -518,14 +525,14 @@ static const char *findfile (lua_State *L, const char *name,
   const char *path;
   const char *path;
   lua_getfield(L, lua_upvalueindex(1), pname);
   lua_getfield(L, lua_upvalueindex(1), pname);
   path = lua_tostring(L, -1);
   path = lua_tostring(L, -1);
-  if (path == NULL)
+  if (l_unlikely(path == NULL))
     luaL_error(L, "'package.%s' must be a string", pname);
     luaL_error(L, "'package.%s' must be a string", pname);
   return searchpath(L, name, path, ".", dirsep);
   return searchpath(L, name, path, ".", dirsep);
 }
 }
 
 
 
 
 static int checkload (lua_State *L, int stat, const char *filename) {
 static int checkload (lua_State *L, int stat, const char *filename) {
-  if (stat) {  /* module loaded successfully? */
+  if (l_likely(stat)) {  /* module loaded successfully? */
     lua_pushstring(L, filename);  /* will be 2nd argument to module */
     lua_pushstring(L, filename);  /* will be 2nd argument to module */
     return 2;  /* return open function and file name */
     return 2;  /* return open function and file name */
   }
   }
@@ -591,7 +598,7 @@ static int searcher_Croot (lua_State *L) {
     if (stat != ERRFUNC)
     if (stat != ERRFUNC)
       return checkload(L, 0, filename);  /* real error */
       return checkload(L, 0, filename);  /* real error */
     else {  /* open function not found */
     else {  /* open function not found */
-      lua_pushfstring(L, "\n\tno module '%s' in file '%s'", name, filename);
+      lua_pushfstring(L, "no module '%s' in file '%s'", name, filename);
       return 1;
       return 1;
     }
     }
   }
   }
@@ -604,7 +611,7 @@ static int searcher_preload (lua_State *L) {
   const char *name = luaL_checkstring(L, 1);
   const char *name = luaL_checkstring(L, 1);
   lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
   lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
   if (lua_getfield(L, -1, name) == LUA_TNIL) {  /* not found? */
   if (lua_getfield(L, -1, name) == LUA_TNIL) {  /* not found? */
-    lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
+    lua_pushfstring(L, "no field package.preload['%s']", name);
     return 1;
     return 1;
   }
   }
   else {
   else {
@@ -618,13 +625,16 @@ static void findloader (lua_State *L, const char *name) {
   int i;
   int i;
   luaL_Buffer msg;  /* to build error message */
   luaL_Buffer msg;  /* to build error message */
   /* push 'package.searchers' to index 3 in the stack */
   /* push 'package.searchers' to index 3 in the stack */
-  if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE)
+  if (l_unlikely(lua_getfield(L, lua_upvalueindex(1), "searchers")
+                 != LUA_TTABLE))
     luaL_error(L, "'package.searchers' must be a table");
     luaL_error(L, "'package.searchers' must be a table");
   luaL_buffinit(L, &msg);
   luaL_buffinit(L, &msg);
   /*  iterate over available searchers to find a loader */
   /*  iterate over available searchers to find a loader */
   for (i = 1; ; i++) {
   for (i = 1; ; i++) {
-    if (lua_rawgeti(L, 3, i) == LUA_TNIL) {  /* no more searchers? */
+    luaL_addstring(&msg, "\n\t");  /* error-message prefix */
+    if (l_unlikely(lua_rawgeti(L, 3, i) == LUA_TNIL)) {  /* no more searchers? */
       lua_pop(L, 1);  /* remove nil */
       lua_pop(L, 1);  /* remove nil */
+      luaL_buffsub(&msg, 2);  /* remove prefix */
       luaL_pushresult(&msg);  /* create error message */
       luaL_pushresult(&msg);  /* create error message */
       luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1));
       luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1));
     }
     }
@@ -636,8 +646,10 @@ static void findloader (lua_State *L, const char *name) {
       lua_pop(L, 1);  /* remove extra return */
       lua_pop(L, 1);  /* remove extra return */
       luaL_addvalue(&msg);  /* concatenate error message */
       luaL_addvalue(&msg);  /* concatenate error message */
     }
     }
-    else
+    else {  /* no error message */
       lua_pop(L, 2);  /* remove both returns */
       lua_pop(L, 2);  /* remove both returns */
+      luaL_buffsub(&msg, 2);  /* remove prefix */
+    }
   }
   }
 }
 }
 
 

+ 30 - 21
src/lobject.c

@@ -215,37 +215,42 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
 /* }====================================================== */
 /* }====================================================== */
 
 
 
 
-/* maximum length of a numeral */
+/* maximum length of a numeral to be converted to a number */
 #if !defined (L_MAXLENNUM)
 #if !defined (L_MAXLENNUM)
 #define L_MAXLENNUM	200
 #define L_MAXLENNUM	200
 #endif
 #endif
 
 
+/*
+** Convert string 's' to a Lua number (put in 'result'). Return NULL on
+** fail or the address of the ending '\0' on success. ('mode' == 'x')
+** means a hexadecimal numeral.
+*/
 static const char *l_str2dloc (const char *s, lua_Number *result, int mode) {
 static const char *l_str2dloc (const char *s, lua_Number *result, int mode) {
   char *endptr;
   char *endptr;
   *result = (mode == 'x') ? lua_strx2number(s, &endptr)  /* try to convert */
   *result = (mode == 'x') ? lua_strx2number(s, &endptr)  /* try to convert */
                           : lua_str2number(s, &endptr);
                           : lua_str2number(s, &endptr);
   if (endptr == s) return NULL;  /* nothing recognized? */
   if (endptr == s) return NULL;  /* nothing recognized? */
   while (lisspace(cast_uchar(*endptr))) endptr++;  /* skip trailing spaces */
   while (lisspace(cast_uchar(*endptr))) endptr++;  /* skip trailing spaces */
-  return (*endptr == '\0') ? endptr : NULL;  /* OK if no trailing characters */
+  return (*endptr == '\0') ? endptr : NULL;  /* OK iff no trailing chars */
 }
 }
 
 
 
 
 /*
 /*
-** Convert string 's' to a Lua number (put in 'result'). Return NULL
-** on fail or the address of the ending '\0' on success.
-** 'pmode' points to (and 'mode' contains) special things in the string:
-** - 'x'/'X' means a hexadecimal numeral
-** - 'n'/'N' means 'inf' or 'nan' (which should be rejected)
-** - '.' just optimizes the search for the common case (nothing special)
+** Convert string 's' to a Lua number (put in 'result') handling the
+** current locale.
 ** This function accepts both the current locale or a dot as the radix
 ** This function accepts both the current locale or a dot as the radix
 ** mark. If the conversion fails, it may mean number has a dot but
 ** mark. If the conversion fails, it may mean number has a dot but
 ** locale accepts something else. In that case, the code copies 's'
 ** locale accepts something else. In that case, the code copies 's'
 ** to a buffer (because 's' is read-only), changes the dot to the
 ** to a buffer (because 's' is read-only), changes the dot to the
 ** current locale radix mark, and tries to convert again.
 ** current locale radix mark, and tries to convert again.
+** The variable 'mode' checks for special characters in the string:
+** - 'n' means 'inf' or 'nan' (which should be rejected)
+** - 'x' means a hexadecimal numeral
+** - '.' just optimizes the search for the common case (no special chars)
 */
 */
 static const char *l_str2d (const char *s, lua_Number *result) {
 static const char *l_str2d (const char *s, lua_Number *result) {
   const char *endptr;
   const char *endptr;
-  const char *pmode = strpbrk(s, ".xXnN");
+  const char *pmode = strpbrk(s, ".xXnN");  /* look for special chars */
   int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0;
   int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0;
   if (mode == 'n')  /* reject 'inf' and 'nan' */
   if (mode == 'n')  /* reject 'inf' and 'nan' */
     return NULL;
     return NULL;
@@ -253,7 +258,7 @@ static const char *l_str2d (const char *s, lua_Number *result) {
   if (endptr == NULL) {  /* failed? may be a different locale */
   if (endptr == NULL) {  /* failed? may be a different locale */
     char buff[L_MAXLENNUM + 1];
     char buff[L_MAXLENNUM + 1];
     const char *pdot = strchr(s, '.');
     const char *pdot = strchr(s, '.');
-    if (strlen(s) > L_MAXLENNUM || pdot == NULL)
+    if (pdot == NULL || strlen(s) > L_MAXLENNUM)
       return NULL;  /* string too long or no dot; fail */
       return NULL;  /* string too long or no dot; fail */
     strcpy(buff, s);  /* copy string to buffer */
     strcpy(buff, s);  /* copy string to buffer */
     buff[pdot - s] = lua_getlocaledecpoint();  /* correct decimal point */
     buff[pdot - s] = lua_getlocaledecpoint();  /* correct decimal point */
@@ -333,8 +338,15 @@ int luaO_utf8esc (char *buff, unsigned long x) {
 }
 }
 
 
 
 
-/* maximum length of the conversion of a number to a string */
-#define MAXNUMBER2STR	50
+/*
+** Maximum length of the conversion of a number to a string. Must be
+** enough to accommodate both LUA_INTEGER_FMT and LUA_NUMBER_FMT.
+** (For a long long int, this is 19 digits plus a sign and a final '\0',
+** adding to 21. For a long double, it can go to a sign, 33 digits,
+** the dot, an exponent letter, an exponent sign, 5 exponent digits,
+** and a final '\0', adding to 43.)
+*/
+#define MAXNUMBER2STR	44
 
 
 
 
 /*
 /*
@@ -375,7 +387,7 @@ void luaO_tostring (lua_State *L, TValue *obj) {
 */
 */
 
 
 /* size for buffer space used by 'luaO_pushvfstring' */
 /* size for buffer space used by 'luaO_pushvfstring' */
-#define BUFVFS		400
+#define BUFVFS		200
 
 
 /* buffer used by 'luaO_pushvfstring' */
 /* buffer used by 'luaO_pushvfstring' */
 typedef struct BuffFS {
 typedef struct BuffFS {
@@ -387,18 +399,16 @@ typedef struct BuffFS {
 
 
 
 
 /*
 /*
-** Push given string to the stack, as part of the buffer. If the stack
-** is almost full, join all partial strings in the stack into one.
+** Push given string to the stack, as part of the buffer, and
+** join the partial strings in the stack into one.
 */
 */
 static void pushstr (BuffFS *buff, const char *str, size_t l) {
 static void pushstr (BuffFS *buff, const char *str, size_t l) {
   lua_State *L = buff->L;
   lua_State *L = buff->L;
   setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
   setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
   L->top++;  /* may use one extra slot */
   L->top++;  /* may use one extra slot */
   buff->pushed++;
   buff->pushed++;
-  if (buff->pushed > 1 && L->top + 1 >= L->stack_last) {
-    luaV_concat(L, buff->pushed);  /* join all partial results into one */
-    buff->pushed = 1;
-  }
+  luaV_concat(L, buff->pushed);  /* join partial results into one */
+  buff->pushed = 1;
 }
 }
 
 
 
 
@@ -521,8 +531,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
   }
   }
   addstr2buff(&buff, fmt, strlen(fmt));  /* rest of 'fmt' */
   addstr2buff(&buff, fmt, strlen(fmt));  /* rest of 'fmt' */
   clearbuff(&buff);  /* empty buffer into the stack */
   clearbuff(&buff);  /* empty buffer into the stack */
-  if (buff.pushed > 1)
-    luaV_concat(L, buff.pushed);  /* join all partial results */
+  lua_assert(buff.pushed == 1);
   return svalue(s2v(L->top - 1));
   return svalue(s2v(L->top - 1));
 }
 }
 
 

+ 132 - 90
src/lobject.h

@@ -17,24 +17,30 @@
 
 
 
 
 /*
 /*
-** Extra tags for non-values
+** Extra types for collectable non-values
 */
 */
-#define LUA_TUPVAL	LUA_NUMTAGS  /* upvalues */
-#define LUA_TPROTO	(LUA_NUMTAGS+1)  /* function prototypes */
+#define LUA_TUPVAL	LUA_NUMTYPES  /* upvalues */
+#define LUA_TPROTO	(LUA_NUMTYPES+1)  /* function prototypes */
+#define LUA_TDEADKEY	(LUA_NUMTYPES+2)  /* removed keys in tables */
+
+
 
 
 /*
 /*
-** number of all possible tags (including LUA_TNONE)
+** number of all possible types (including LUA_TNONE but excluding DEADKEY)
 */
 */
-#define LUA_TOTALTAGS	(LUA_TPROTO + 2)
+#define LUA_TOTALTYPES		(LUA_TPROTO + 2)
 
 
 
 
 /*
 /*
 ** tags for Tagged Values have the following use of bits:
 ** tags for Tagged Values have the following use of bits:
-** bits 0-3: actual tag (a LUA_T* value)
+** bits 0-3: actual tag (a LUA_T* constant)
 ** bits 4-5: variant bits
 ** bits 4-5: variant bits
 ** bit 6: whether value is collectable
 ** bit 6: whether value is collectable
 */
 */
 
 
+/* add variant bits to a type */
+#define makevariant(t,v)	((t) | ((v) << 4))
+
 
 
 
 
 /*
 /*
@@ -43,7 +49,6 @@
 typedef union Value {
 typedef union Value {
   struct GCObject *gc;    /* collectable objects */
   struct GCObject *gc;    /* collectable objects */
   void *p;         /* light userdata */
   void *p;         /* light userdata */
-  int b;           /* booleans */
   lua_CFunction f; /* light C functions */
   lua_CFunction f; /* light C functions */
   lua_Integer i;   /* integer numbers */
   lua_Integer i;   /* integer numbers */
   lua_Number n;    /* float numbers */
   lua_Number n;    /* float numbers */
@@ -86,24 +91,36 @@ typedef struct TValue {
 
 
 
 
 /* Macros for internal tests */
 /* Macros for internal tests */
+
+/* collectable object has the same tag as the original value */
 #define righttt(obj)		(ttypetag(obj) == gcvalue(obj)->tt)
 #define righttt(obj)		(ttypetag(obj) == gcvalue(obj)->tt)
 
 
+/*
+** Any value being manipulated by the program either is non
+** collectable, or the collectable object has the right tag
+** and it is not dead. The option 'L == NULL' allows other
+** macros using this one to be used where L is not available.
+*/
 #define checkliveness(L,obj) \
 #define checkliveness(L,obj) \
 	((void)L, lua_longassert(!iscollectable(obj) || \
 	((void)L, lua_longassert(!iscollectable(obj) || \
 		(righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj))))))
 		(righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj))))))
 
 
 
 
 /* Macros to set values */
 /* Macros to set values */
+
+/* set a value's tag */
 #define settt_(o,t)	((o)->tt_=(t))
 #define settt_(o,t)	((o)->tt_=(t))
 
 
 
 
+/* main macro to copy values (from 'obj1' to 'obj2') */
 #define setobj(L,obj1,obj2) \
 #define setobj(L,obj1,obj2) \
 	{ TValue *io1=(obj1); const TValue *io2=(obj2); \
 	{ TValue *io1=(obj1); const TValue *io2=(obj2); \
-          io1->value_ = io2->value_; io1->tt_ = io2->tt_; \
-	  checkliveness(L,io1); lua_assert(!isreallyempty(io1)); }
+          io1->value_ = io2->value_; settt_(io1, io2->tt_); \
+	  checkliveness(L,io1); lua_assert(!isnonstrictnil(io1)); }
 
 
 /*
 /*
-** different types of assignments, according to destination
+** Different types of assignments, according to source and destination.
+** (They are mostly equal now, but may be different in the future.)
 */
 */
 
 
 /* from stack to stack */
 /* from stack to stack */
@@ -118,13 +135,25 @@ typedef struct TValue {
 #define setobj2t	setobj
 #define setobj2t	setobj
 
 
 
 
-
+/*
+** Entries in a Lua stack. Field 'tbclist' forms a list of all
+** to-be-closed variables active in this stack. Dummy entries are
+** used when the distance between two tbc variables does not fit
+** in an unsigned short. They are represented by delta==0, and
+** their real delta is always the maximum value that fits in
+** that field.
+*/
 typedef union StackValue {
 typedef union StackValue {
   TValue val;
   TValue val;
+  struct {
+    TValuefields;
+    unsigned short delta;
+  } tbclist;
 } StackValue;
 } StackValue;
 
 
 
 
-typedef StackValue *StkId;  /* index to stack elements */
+/* index to stack elements */
+typedef StackValue *StkId;
 
 
 /* convert a 'StackValue' to a 'TValue' */
 /* convert a 'StackValue' to a 'TValue' */
 #define s2v(o)	(&(o)->val)
 #define s2v(o)	(&(o)->val)
@@ -137,36 +166,34 @@ typedef StackValue *StkId;  /* index to stack elements */
 ** ===================================================================
 ** ===================================================================
 */
 */
 
 
-/* macro to test for (any kind of) nil */
-#define ttisnil(v)		checktype((v), LUA_TNIL)
+/* Standard nil */
+#define LUA_VNIL	makevariant(LUA_TNIL, 0)
 
 
-/* macro to test for a "pure" nil */
-#define ttisstrictnil(o)	checktag((o), LUA_TNIL)
+/* Empty slot (which might be different from a slot containing nil) */
+#define LUA_VEMPTY	makevariant(LUA_TNIL, 1)
 
 
+/* Value returned for a key not found in a table (absent key) */
+#define LUA_VABSTKEY	makevariant(LUA_TNIL, 2)
 
 
-#define setnilvalue(obj) settt_(obj, LUA_TNIL)
 
 
+/* macro to test for (any kind of) nil */
+#define ttisnil(v)		checktype((v), LUA_TNIL)
 
 
-/*
-** Variant tag, used only in tables to signal an empty slot
-** (which might be different from a slot containing nil)
-*/
-#define LUA_TEMPTY	(LUA_TNIL | (1 << 4))
 
 
-/*
-** Variant used only in the value returned for a key not found in a
-** table (absent key).
-*/
-#define LUA_TABSTKEY	(LUA_TNIL | (2 << 4))
+/* macro to test for a standard nil */
+#define ttisstrictnil(o)	checktag((o), LUA_VNIL)
+
 
 
+#define setnilvalue(obj) settt_(obj, LUA_VNIL)
 
 
-#define isabstkey(v)		checktag((v), LUA_TABSTKEY)
+
+#define isabstkey(v)		checktag((v), LUA_VABSTKEY)
 
 
 
 
 /*
 /*
 ** macro to detect non-standard nils (used only in assertions)
 ** macro to detect non-standard nils (used only in assertions)
 */
 */
-#define isreallyempty(v)	(ttisnil(v) && !ttisstrictnil(v))
+#define isnonstrictnil(v)	(ttisnil(v) && !ttisstrictnil(v))
 
 
 
 
 /*
 /*
@@ -178,11 +205,11 @@ typedef StackValue *StkId;  /* index to stack elements */
 
 
 
 
 /* macro defining a value corresponding to an absent key */
 /* macro defining a value corresponding to an absent key */
-#define ABSTKEYCONSTANT		{NULL}, LUA_TABSTKEY
+#define ABSTKEYCONSTANT		{NULL}, LUA_VABSTKEY
 
 
 
 
 /* mark an entry as empty */
 /* mark an entry as empty */
-#define setempty(v)		settt_(v, LUA_TEMPTY)
+#define setempty(v)		settt_(v, LUA_VEMPTY)
 
 
 
 
 
 
@@ -195,16 +222,20 @@ typedef StackValue *StkId;  /* index to stack elements */
 ** ===================================================================
 ** ===================================================================
 */
 */
 
 
-#define ttisboolean(o)		checktag((o), LUA_TBOOLEAN)
 
 
-#define bvalue(o)	check_exp(ttisboolean(o), val_(o).b)
+#define LUA_VFALSE	makevariant(LUA_TBOOLEAN, 0)
+#define LUA_VTRUE	makevariant(LUA_TBOOLEAN, 1)
+
+#define ttisboolean(o)		checktype((o), LUA_TBOOLEAN)
+#define ttisfalse(o)		checktag((o), LUA_VFALSE)
+#define ttistrue(o)		checktag((o), LUA_VTRUE)
+
 
 
-#define bvalueraw(v)	((v).b)
+#define l_isfalse(o)	(ttisfalse(o) || ttisnil(o))
 
 
-#define l_isfalse(o)	(ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
 
 
-#define setbvalue(obj,x) \
-  { TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); }
+#define setbfvalue(obj)		settt_(obj, LUA_VFALSE)
+#define setbtvalue(obj)		settt_(obj, LUA_VTRUE)
 
 
 /* }================================================================== */
 /* }================================================================== */
 
 
@@ -215,13 +246,15 @@ typedef StackValue *StkId;  /* index to stack elements */
 ** ===================================================================
 ** ===================================================================
 */
 */
 
 
-#define ttisthread(o)		checktag((o), ctb(LUA_TTHREAD))
+#define LUA_VTHREAD		makevariant(LUA_TTHREAD, 0)
+
+#define ttisthread(o)		checktag((o), ctb(LUA_VTHREAD))
 
 
 #define thvalue(o)	check_exp(ttisthread(o), gco2th(val_(o).gc))
 #define thvalue(o)	check_exp(ttisthread(o), gco2th(val_(o).gc))
 
 
 #define setthvalue(L,obj,x) \
 #define setthvalue(L,obj,x) \
   { TValue *io = (obj); lua_State *x_ = (x); \
   { TValue *io = (obj); lua_State *x_ = (x); \
-    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \
+    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VTHREAD)); \
     checkliveness(L,io); }
     checkliveness(L,io); }
 
 
 #define setthvalue2s(L,o,t)	setthvalue(L,s2v(o),t)
 #define setthvalue2s(L,o,t)	setthvalue(L,s2v(o),t)
@@ -274,12 +307,12 @@ typedef struct GCObject {
 */
 */
 
 
 /* Variant tags for numbers */
 /* Variant tags for numbers */
-#define LUA_TNUMFLT	(LUA_TNUMBER | (1 << 4))  /* float numbers */
-#define LUA_TNUMINT	(LUA_TNUMBER | (2 << 4))  /* integer numbers */
+#define LUA_VNUMINT	makevariant(LUA_TNUMBER, 0)  /* integer numbers */
+#define LUA_VNUMFLT	makevariant(LUA_TNUMBER, 1)  /* float numbers */
 
 
 #define ttisnumber(o)		checktype((o), LUA_TNUMBER)
 #define ttisnumber(o)		checktype((o), LUA_TNUMBER)
-#define ttisfloat(o)		checktag((o), LUA_TNUMFLT)
-#define ttisinteger(o)		checktag((o), LUA_TNUMINT)
+#define ttisfloat(o)		checktag((o), LUA_VNUMFLT)
+#define ttisinteger(o)		checktag((o), LUA_VNUMINT)
 
 
 #define nvalue(o)	check_exp(ttisnumber(o), \
 #define nvalue(o)	check_exp(ttisnumber(o), \
 	(ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o)))
 	(ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o)))
@@ -290,13 +323,13 @@ typedef struct GCObject {
 #define ivalueraw(v)	((v).i)
 #define ivalueraw(v)	((v).i)
 
 
 #define setfltvalue(obj,x) \
 #define setfltvalue(obj,x) \
-  { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); }
+  { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_VNUMFLT); }
 
 
 #define chgfltvalue(obj,x) \
 #define chgfltvalue(obj,x) \
   { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); }
   { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); }
 
 
 #define setivalue(obj,x) \
 #define setivalue(obj,x) \
-  { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); }
+  { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_VNUMINT); }
 
 
 #define chgivalue(obj,x) \
 #define chgivalue(obj,x) \
   { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); }
   { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); }
@@ -311,12 +344,12 @@ typedef struct GCObject {
 */
 */
 
 
 /* Variant tags for strings */
 /* Variant tags for strings */
-#define LUA_TSHRSTR	(LUA_TSTRING | (1 << 4))  /* short strings */
-#define LUA_TLNGSTR	(LUA_TSTRING | (2 << 4))  /* long strings */
+#define LUA_VSHRSTR	makevariant(LUA_TSTRING, 0)  /* short strings */
+#define LUA_VLNGSTR	makevariant(LUA_TSTRING, 1)  /* long strings */
 
 
 #define ttisstring(o)		checktype((o), LUA_TSTRING)
 #define ttisstring(o)		checktype((o), LUA_TSTRING)
-#define ttisshrstring(o)	checktag((o), ctb(LUA_TSHRSTR))
-#define ttislngstring(o)	checktag((o), ctb(LUA_TLNGSTR))
+#define ttisshrstring(o)	checktag((o), ctb(LUA_VSHRSTR))
+#define ttislngstring(o)	checktag((o), ctb(LUA_VLNGSTR))
 
 
 #define tsvalueraw(v)	(gco2ts((v).gc))
 #define tsvalueraw(v)	(gco2ts((v).gc))
 
 
@@ -335,8 +368,7 @@ typedef struct GCObject {
 
 
 
 
 /*
 /*
-** Header for string value; string bytes follow the end of this structure
-** (aligned according to 'UTString'; see next).
+** Header for a string value.
 */
 */
 typedef struct TString {
 typedef struct TString {
   CommonHeader;
   CommonHeader;
@@ -347,23 +379,22 @@ typedef struct TString {
     size_t lnglen;  /* length for long strings */
     size_t lnglen;  /* length for long strings */
     struct TString *hnext;  /* linked list for hash table */
     struct TString *hnext;  /* linked list for hash table */
   } u;
   } u;
+  char contents[1];
 } TString;
 } TString;
 
 
 
 
 
 
 /*
 /*
 ** Get the actual string (array of bytes) from a 'TString'.
 ** Get the actual string (array of bytes) from a 'TString'.
-** (Access to 'extra' ensures that value is really a 'TString'.)
 */
 */
-#define getstr(ts)  \
-  check_exp(sizeof((ts)->extra), cast_charp((ts)) + sizeof(TString))
+#define getstr(ts)  ((ts)->contents)
 
 
 
 
 /* get the actual string (array of bytes) from a Lua value */
 /* get the actual string (array of bytes) from a Lua value */
 #define svalue(o)       getstr(tsvalue(o))
 #define svalue(o)       getstr(tsvalue(o))
 
 
 /* get string length from 'TString *s' */
 /* get string length from 'TString *s' */
-#define tsslen(s)	((s)->tt == LUA_TSHRSTR ? (s)->shrlen : (s)->u.lnglen)
+#define tsslen(s)	((s)->tt == LUA_VSHRSTR ? (s)->shrlen : (s)->u.lnglen)
 
 
 /* get string length from 'TValue *o' */
 /* get string length from 'TValue *o' */
 #define vslen(o)	tsslen(tsvalue(o))
 #define vslen(o)	tsslen(tsvalue(o))
@@ -377,8 +408,17 @@ typedef struct TString {
 ** ===================================================================
 ** ===================================================================
 */
 */
 
 
-#define ttislightuserdata(o)	checktag((o), LUA_TLIGHTUSERDATA)
-#define ttisfulluserdata(o)	checktype((o), LUA_TUSERDATA)
+
+/*
+** Light userdata should be a variant of userdata, but for compatibility
+** reasons they are also different types.
+*/
+#define LUA_VLIGHTUSERDATA	makevariant(LUA_TLIGHTUSERDATA, 0)
+
+#define LUA_VUSERDATA		makevariant(LUA_TUSERDATA, 0)
+
+#define ttislightuserdata(o)	checktag((o), LUA_VLIGHTUSERDATA)
+#define ttisfulluserdata(o)	checktag((o), ctb(LUA_VUSERDATA))
 
 
 #define pvalue(o)	check_exp(ttislightuserdata(o), val_(o).p)
 #define pvalue(o)	check_exp(ttislightuserdata(o), val_(o).p)
 #define uvalue(o)	check_exp(ttisfulluserdata(o), gco2u(val_(o).gc))
 #define uvalue(o)	check_exp(ttisfulluserdata(o), gco2u(val_(o).gc))
@@ -386,11 +426,11 @@ typedef struct TString {
 #define pvalueraw(v)	((v).p)
 #define pvalueraw(v)	((v).p)
 
 
 #define setpvalue(obj,x) \
 #define setpvalue(obj,x) \
-  { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); }
+  { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_VLIGHTUSERDATA); }
 
 
 #define setuvalue(L,obj,x) \
 #define setuvalue(L,obj,x) \
   { TValue *io = (obj); Udata *x_ = (x); \
   { TValue *io = (obj); Udata *x_ = (x); \
-    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \
+    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VUSERDATA)); \
     checkliveness(L,io); }
     checkliveness(L,io); }
 
 
 
 
@@ -453,6 +493,9 @@ typedef struct Udata0 {
 ** ===================================================================
 ** ===================================================================
 */
 */
 
 
+#define LUA_VPROTO	makevariant(LUA_TPROTO, 0)
+
+
 /*
 /*
 ** Description of an upvalue for function prototypes
 ** Description of an upvalue for function prototypes
 */
 */
@@ -490,11 +533,6 @@ typedef struct AbsLineInfo {
   int line;
   int line;
 } AbsLineInfo;
 } AbsLineInfo;
 
 
-/*
-** AOT implementation
-*/ 
-typedef void (*AotCompiledFunction) (lua_State *L, struct CallInfo *ci);
-
 /*
 /*
 ** Function Prototypes
 ** Function Prototypes
 */
 */
@@ -521,8 +559,6 @@ typedef struct Proto {
   LocVar *locvars;  /* information about local variables (debug information) */
   LocVar *locvars;  /* information about local variables (debug information) */
   TString  *source;  /* used for debug information */
   TString  *source;  /* used for debug information */
   GCObject *gclist;
   GCObject *gclist;
-
-  AotCompiledFunction aot_implementation;
 } Proto;
 } Proto;
 
 
 /* }================================================================== */
 /* }================================================================== */
@@ -530,20 +566,24 @@ typedef struct Proto {
 
 
 /*
 /*
 ** {==================================================================
 ** {==================================================================
-** Closures
+** Functions
 ** ===================================================================
 ** ===================================================================
 */
 */
 
 
+#define LUA_VUPVAL	makevariant(LUA_TUPVAL, 0)
+
+
 /* Variant tags for functions */
 /* Variant tags for functions */
-#define LUA_TLCL	(LUA_TFUNCTION | (1 << 4))  /* Lua closure */
-#define LUA_TLCF	(LUA_TFUNCTION | (2 << 4))  /* light C function */
-#define LUA_TCCL	(LUA_TFUNCTION | (3 << 4))  /* C closure */
+#define LUA_VLCL	makevariant(LUA_TFUNCTION, 0)  /* Lua closure */
+#define LUA_VLCF	makevariant(LUA_TFUNCTION, 1)  /* light C function */
+#define LUA_VCCL	makevariant(LUA_TFUNCTION, 2)  /* C closure */
 
 
 #define ttisfunction(o)		checktype(o, LUA_TFUNCTION)
 #define ttisfunction(o)		checktype(o, LUA_TFUNCTION)
-#define ttisclosure(o)		((rawtt(o) & 0x1F) == LUA_TLCL)
-#define ttisLclosure(o)		checktag((o), ctb(LUA_TLCL))
-#define ttislcf(o)		checktag((o), LUA_TLCF)
-#define ttisCclosure(o)		checktag((o), ctb(LUA_TCCL))
+#define ttisLclosure(o)		checktag((o), ctb(LUA_VLCL))
+#define ttislcf(o)		checktag((o), LUA_VLCF)
+#define ttisCclosure(o)		checktag((o), ctb(LUA_VCCL))
+#define ttisclosure(o)         (ttisLclosure(o) || ttisCclosure(o))
+
 
 
 #define isLfunction(o)	ttisLclosure(o)
 #define isLfunction(o)	ttisLclosure(o)
 
 
@@ -556,17 +596,17 @@ typedef struct Proto {
 
 
 #define setclLvalue(L,obj,x) \
 #define setclLvalue(L,obj,x) \
   { TValue *io = (obj); LClosure *x_ = (x); \
   { TValue *io = (obj); LClosure *x_ = (x); \
-    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \
+    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VLCL)); \
     checkliveness(L,io); }
     checkliveness(L,io); }
 
 
 #define setclLvalue2s(L,o,cl)	setclLvalue(L,s2v(o),cl)
 #define setclLvalue2s(L,o,cl)	setclLvalue(L,s2v(o),cl)
 
 
 #define setfvalue(obj,x) \
 #define setfvalue(obj,x) \
-  { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); }
+  { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_VLCF); }
 
 
 #define setclCvalue(L,obj,x) \
 #define setclCvalue(L,obj,x) \
   { TValue *io = (obj); CClosure *x_ = (x); \
   { TValue *io = (obj); CClosure *x_ = (x); \
-    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \
+    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VCCL)); \
     checkliveness(L,io); }
     checkliveness(L,io); }
 
 
 
 
@@ -622,13 +662,15 @@ typedef union Closure {
 ** ===================================================================
 ** ===================================================================
 */
 */
 
 
-#define ttistable(o)		checktag((o), ctb(LUA_TTABLE))
+#define LUA_VTABLE	makevariant(LUA_TTABLE, 0)
+
+#define ttistable(o)		checktag((o), ctb(LUA_VTABLE))
 
 
 #define hvalue(o)	check_exp(ttistable(o), gco2t(val_(o).gc))
 #define hvalue(o)	check_exp(ttistable(o), gco2t(val_(o).gc))
 
 
 #define sethvalue(L,obj,x) \
 #define sethvalue(L,obj,x) \
   { TValue *io = (obj); Table *x_ = (x); \
   { TValue *io = (obj); Table *x_ = (x); \
-    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \
+    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VTABLE)); \
     checkliveness(L,io); }
     checkliveness(L,io); }
 
 
 #define sethvalue2s(L,o,h)	sethvalue(L,s2v(o),h)
 #define sethvalue2s(L,o,h)	sethvalue(L,s2v(o),h)
@@ -674,9 +716,9 @@ typedef union Node {
 */
 */
 
 
 #define BITRAS		(1 << 7)
 #define BITRAS		(1 << 7)
-#define isrealasize(t)		(!((t)->marked & BITRAS))
-#define setrealasize(t)		((t)->marked &= cast_byte(~BITRAS))
-#define setnorealasize(t)	((t)->marked |= BITRAS)
+#define isrealasize(t)		(!((t)->flags & BITRAS))
+#define setrealasize(t)		((t)->flags &= cast_byte(~BITRAS))
+#define setnorealasize(t)	((t)->flags |= BITRAS)
 
 
 
 
 typedef struct Table {
 typedef struct Table {
@@ -699,9 +741,9 @@ typedef struct Table {
 #define keyval(node)		((node)->u.key_val)
 #define keyval(node)		((node)->u.key_val)
 
 
 #define keyisnil(node)		(keytt(node) == LUA_TNIL)
 #define keyisnil(node)		(keytt(node) == LUA_TNIL)
-#define keyisinteger(node)	(keytt(node) == LUA_TNUMINT)
+#define keyisinteger(node)	(keytt(node) == LUA_VNUMINT)
 #define keyival(node)		(keyval(node).i)
 #define keyival(node)		(keyval(node).i)
-#define keyisshrstr(node)	(keytt(node) == ctb(LUA_TSHRSTR))
+#define keyisshrstr(node)	(keytt(node) == ctb(LUA_VSHRSTR))
 #define keystrval(node)		(gco2ts(keyval(node).gc))
 #define keystrval(node)		(gco2ts(keyval(node).gc))
 
 
 #define setnilkey(node)		(keytt(node) = LUA_TNIL)
 #define setnilkey(node)		(keytt(node) = LUA_TNIL)
@@ -713,13 +755,13 @@ typedef struct Table {
 
 
 
 
 /*
 /*
-** Use a "nil table" to mark dead keys in a table. Those keys serve
-** to keep space for removed entries, which may still be part of
-** chains. Note that the 'keytt' does not have the BIT_ISCOLLECTABLE
-** set, so these values are considered not collectable and are different
-** from any valid value.
+** Dead keys in tables have the tag DEADKEY but keep their original
+** gcvalue. This distinguishes them from regular keys but allows them to
+** be found when searched in a special way. ('next' needs that to find
+** keys removed from a table during a traversal.)
 */
 */
-#define setdeadkey(n)	(keytt(n) = LUA_TTABLE, gckey(n) = NULL)
+#define setdeadkey(node)	(keytt(node) = LUA_TDEADKEY)
+#define keyisdead(node)		(keytt(node) == LUA_TDEADKEY)
 
 
 /* }================================================================== */
 /* }================================================================== */
 
 

+ 3 - 3
src/lopcodes.c

@@ -10,8 +10,6 @@
 #include "lprefix.h"
 #include "lprefix.h"
 
 
 
 
-#include <stddef.h>
-
 #include "lopcodes.h"
 #include "lopcodes.h"
 
 
 
 
@@ -24,7 +22,9 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
  ,opmode(0, 0, 0, 0, 1, iAsBx)		/* OP_LOADF */
  ,opmode(0, 0, 0, 0, 1, iAsBx)		/* OP_LOADF */
  ,opmode(0, 0, 0, 0, 1, iABx)		/* OP_LOADK */
  ,opmode(0, 0, 0, 0, 1, iABx)		/* OP_LOADK */
  ,opmode(0, 0, 0, 0, 1, iABx)		/* OP_LOADKX */
  ,opmode(0, 0, 0, 0, 1, iABx)		/* OP_LOADKX */
- ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_LOADBOOL */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_LOADFALSE */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_LFALSESKIP */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_LOADTRUE */
  ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_LOADNIL */
  ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_LOADNIL */
  ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_GETUPVAL */
  ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_GETUPVAL */
  ,opmode(0, 0, 0, 0, 0, iABC)		/* OP_SETUPVAL */
  ,opmode(0, 0, 0, 0, 0, iABC)		/* OP_SETUPVAL */

+ 109 - 103
src/lopcodes.h

@@ -17,11 +17,11 @@
 
 
         3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
         3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
         1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
         1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
-iABC         C(8)     |      B(8)     |k|     A(8)      |   Op(7)     |
-iABx               Bx(17)               |     A(8)      |   Op(7)     |
-iAsB              sBx (signed)(17)      |     A(8)      |   Op(7)     |
-iAx                           Ax(25)                    |   Op(7)     |
-isJ                          sJ(25)                     |   Op(7)     |
+iABC          C(8)     |      B(8)     |k|     A(8)      |   Op(7)     |
+iABx                Bx(17)               |     A(8)      |   Op(7)     |
+iAsBx              sBx (signed)(17)      |     A(8)      |   Op(7)     |
+iAx                           Ax(25)                     |   Op(7)     |
+isJ                           sJ(25)                     |   Op(7)     |
 
 
   A signed argument is represented in excess K: the represented value is
   A signed argument is represented in excess K: the represented value is
   the written unsigned value minus K, where K is half the maximum for the
   the written unsigned value minus K, where K is half the maximum for the
@@ -133,7 +133,7 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ};  /* basic instruction formats */
 #define GETARG_sC(i)	sC2int(GETARG_C(i))
 #define GETARG_sC(i)	sC2int(GETARG_C(i))
 #define SETARG_C(i,v)	setarg(i, v, POS_C, SIZE_C)
 #define SETARG_C(i,v)	setarg(i, v, POS_C, SIZE_C)
 
 
-#define TESTARG_k(i)	(cast_int(((i) & (1u << POS_k))))
+#define TESTARG_k(i)	check_exp(checkopm(i, iABC), (cast_int(((i) & (1u << POS_k)))))
 #define GETARG_k(i)	check_exp(checkopm(i, iABC), getarg(i, POS_k, 1))
 #define GETARG_k(i)	check_exp(checkopm(i, iABC), getarg(i, POS_k, 1))
 #define SETARG_k(i,v)	setarg(i, v, POS_k, 1)
 #define SETARG_k(i,v)	setarg(i, v, POS_k, 1)
 
 
@@ -183,9 +183,9 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ};  /* basic instruction formats */
 
 
 
 
 /*
 /*
-** R(x) - register
-** K(x) - constant (in constant table)
-** RK(x) == if k(i) then K(x) else R(x)
+** R[x] - register
+** K[x] - constant (in constant table)
+** RK(x) == if k(i) then K[x] else R[x]
 */
 */
 
 
 
 
@@ -195,113 +195,115 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ};  /* basic instruction formats */
 
 
 typedef enum {
 typedef enum {
 /*----------------------------------------------------------------------
 /*----------------------------------------------------------------------
-name		args	description
+  name		args	description
 ------------------------------------------------------------------------*/
 ------------------------------------------------------------------------*/
-OP_MOVE,/*	A B	R(A) := R(B)					*/
-OP_LOADI,/*	A sBx	R(A) := sBx					*/
-OP_LOADF,/*	A sBx	R(A) := (lua_Number)sBx				*/
-OP_LOADK,/*	A Bx	R(A) := K(Bx)					*/
-OP_LOADKX,/*	A 	R(A) := K(extra arg)				*/
-OP_LOADBOOL,/*	A B C	R(A) := (Bool)B; if (C) pc++			*/
-OP_LOADNIL,/*	A B	R(A), R(A+1), ..., R(A+B) := nil		*/
-OP_GETUPVAL,/*	A B	R(A) := UpValue[B]				*/
-OP_SETUPVAL,/*	A B	UpValue[B] := R(A)				*/
-
-OP_GETTABUP,/*	A B C	R(A) := UpValue[B][K(C):string]			*/
-OP_GETTABLE,/*	A B C	R(A) := R(B)[R(C)]				*/
-OP_GETI,/*	A B C	R(A) := R(B)[C]					*/
-OP_GETFIELD,/*	A B C	R(A) := R(B)[K(C):string]			*/
-
-OP_SETTABUP,/*	A B C	UpValue[A][K(B):string] := RK(C)		*/
-OP_SETTABLE,/*	A B C	R(A)[R(B)] := RK(C)				*/
-OP_SETI,/*	A B C	R(A)[B] := RK(C)				*/
-OP_SETFIELD,/*	A B C	R(A)[K(B):string] := RK(C)			*/
-
-OP_NEWTABLE,/*	A B C	R(A) := {}					*/
-
-OP_SELF,/*	A B C	R(A+1) := R(B); R(A) := R(B)[RK(C):string]	*/
-
-OP_ADDI,/*	A B sC	R(A) := R(B) + sC				*/
-
-OP_ADDK,/*	A B C	R(A) := R(B) + K(C)				*/
-OP_SUBK,/*	A B C	R(A) := R(B) - K(C)				*/
-OP_MULK,/*	A B C	R(A) := R(B) * K(C)				*/
-OP_MODK,/*	A B C	R(A) := R(B) % K(C)				*/
-OP_POWK,/*	A B C	R(A) := R(B) ^ K(C)				*/
-OP_DIVK,/*	A B C	R(A) := R(B) / K(C)				*/
-OP_IDIVK,/*	A B C	R(A) := R(B) // K(C)				*/
-
-OP_BANDK,/*	A B C	R(A) := R(B) & K(C):integer			*/
-OP_BORK,/*	A B C	R(A) := R(B) | K(C):integer			*/
-OP_BXORK,/*	A B C	R(A) := R(B) ~ K(C):integer			*/
-
-OP_SHRI,/*	A B sC	R(A) := R(B) >> sC				*/
-OP_SHLI,/*	A B sC	R(A) := sC << R(B)				*/
-
-OP_ADD,/*	A B C	R(A) := R(B) + R(C)				*/
-OP_SUB,/*	A B C	R(A) := R(B) - R(C)				*/
-OP_MUL,/*	A B C	R(A) := R(B) * R(C)				*/
-OP_MOD,/*	A B C	R(A) := R(B) % R(C)				*/
-OP_POW,/*	A B C	R(A) := R(B) ^ R(C)				*/
-OP_DIV,/*	A B C	R(A) := R(B) / R(C)				*/
-OP_IDIV,/*	A B C	R(A) := R(B) // R(C)				*/
-
-OP_BAND,/*	A B C	R(A) := R(B) & R(C)				*/
-OP_BOR,/*	A B C	R(A) := R(B) | R(C)				*/
-OP_BXOR,/*	A B C	R(A) := R(B) ~ R(C)				*/
-OP_SHL,/*	A B C	R(A) := R(B) << R(C)				*/
-OP_SHR,/*	A B C	R(A) := R(B) >> R(C)				*/
-
-OP_MMBIN,/*	A B C	call C metamethod over R(A) and R(B)		*/
-OP_MMBINI,/*	A sB C	call C metamethod over R(A) and sB		*/
-OP_MMBINK,/*	A B C	call C metamethod over R(A) and K(B)		*/
-
-OP_UNM,/*	A B	R(A) := -R(B)					*/
-OP_BNOT,/*	A B	R(A) := ~R(B)					*/
-OP_NOT,/*	A B	R(A) := not R(B)				*/
-OP_LEN,/*	A B	R(A) := length of R(B)				*/
-
-OP_CONCAT,/*	A B  	R(A) := R(A).. ... ..R(A + B - 1)		*/
-
-OP_CLOSE,/*	A	close all upvalues >= R(A)			*/
+OP_MOVE,/*	A B	R[A] := R[B]					*/
+OP_LOADI,/*	A sBx	R[A] := sBx					*/
+OP_LOADF,/*	A sBx	R[A] := (lua_Number)sBx				*/
+OP_LOADK,/*	A Bx	R[A] := K[Bx]					*/
+OP_LOADKX,/*	A	R[A] := K[extra arg]				*/
+OP_LOADFALSE,/*	A	R[A] := false					*/
+OP_LFALSESKIP,/*A	R[A] := false; pc++				*/
+OP_LOADTRUE,/*	A	R[A] := true					*/
+OP_LOADNIL,/*	A B	R[A], R[A+1], ..., R[A+B] := nil		*/
+OP_GETUPVAL,/*	A B	R[A] := UpValue[B]				*/
+OP_SETUPVAL,/*	A B	UpValue[B] := R[A]				*/
+
+OP_GETTABUP,/*	A B C	R[A] := UpValue[B][K[C]:string]			*/
+OP_GETTABLE,/*	A B C	R[A] := R[B][R[C]]				*/
+OP_GETI,/*	A B C	R[A] := R[B][C]					*/
+OP_GETFIELD,/*	A B C	R[A] := R[B][K[C]:string]			*/
+
+OP_SETTABUP,/*	A B C	UpValue[A][K[B]:string] := RK(C)		*/
+OP_SETTABLE,/*	A B C	R[A][R[B]] := RK(C)				*/
+OP_SETI,/*	A B C	R[A][B] := RK(C)				*/
+OP_SETFIELD,/*	A B C	R[A][K[B]:string] := RK(C)			*/
+
+OP_NEWTABLE,/*	A B C k	R[A] := {}					*/
+
+OP_SELF,/*	A B C	R[A+1] := R[B]; R[A] := R[B][RK(C):string]	*/
+
+OP_ADDI,/*	A B sC	R[A] := R[B] + sC				*/
+
+OP_ADDK,/*	A B C	R[A] := R[B] + K[C]:number			*/
+OP_SUBK,/*	A B C	R[A] := R[B] - K[C]:number			*/
+OP_MULK,/*	A B C	R[A] := R[B] * K[C]:number			*/
+OP_MODK,/*	A B C	R[A] := R[B] % K[C]:number			*/
+OP_POWK,/*	A B C	R[A] := R[B] ^ K[C]:number			*/
+OP_DIVK,/*	A B C	R[A] := R[B] / K[C]:number			*/
+OP_IDIVK,/*	A B C	R[A] := R[B] // K[C]:number			*/
+
+OP_BANDK,/*	A B C	R[A] := R[B] & K[C]:integer			*/
+OP_BORK,/*	A B C	R[A] := R[B] | K[C]:integer			*/
+OP_BXORK,/*	A B C	R[A] := R[B] ~ K[C]:integer			*/
+
+OP_SHRI,/*	A B sC	R[A] := R[B] >> sC				*/
+OP_SHLI,/*	A B sC	R[A] := sC << R[B]				*/
+
+OP_ADD,/*	A B C	R[A] := R[B] + R[C]				*/
+OP_SUB,/*	A B C	R[A] := R[B] - R[C]				*/
+OP_MUL,/*	A B C	R[A] := R[B] * R[C]				*/
+OP_MOD,/*	A B C	R[A] := R[B] % R[C]				*/
+OP_POW,/*	A B C	R[A] := R[B] ^ R[C]				*/
+OP_DIV,/*	A B C	R[A] := R[B] / R[C]				*/
+OP_IDIV,/*	A B C	R[A] := R[B] // R[C]				*/
+
+OP_BAND,/*	A B C	R[A] := R[B] & R[C]				*/
+OP_BOR,/*	A B C	R[A] := R[B] | R[C]				*/
+OP_BXOR,/*	A B C	R[A] := R[B] ~ R[C]				*/
+OP_SHL,/*	A B C	R[A] := R[B] << R[C]				*/
+OP_SHR,/*	A B C	R[A] := R[B] >> R[C]				*/
+
+OP_MMBIN,/*	A B C	call C metamethod over R[A] and R[B]		*/
+OP_MMBINI,/*	A sB C k	call C metamethod over R[A] and sB	*/
+OP_MMBINK,/*	A B C k		call C metamethod over R[A] and K[B]	*/
+
+OP_UNM,/*	A B	R[A] := -R[B]					*/
+OP_BNOT,/*	A B	R[A] := ~R[B]					*/
+OP_NOT,/*	A B	R[A] := not R[B]				*/
+OP_LEN,/*	A B	R[A] := #R[B] (length operator)			*/
+
+OP_CONCAT,/*	A B	R[A] := R[A].. ... ..R[A + B - 1]		*/
+
+OP_CLOSE,/*	A	close all upvalues >= R[A]			*/
 OP_TBC,/*	A	mark variable A "to be closed"			*/
 OP_TBC,/*	A	mark variable A "to be closed"			*/
-OP_JMP,/*	k sJ	pc += sJ  (k is used in code generation)	*/
-OP_EQ,/*	A B	if ((R(A) == R(B)) ~= k) then pc++		*/
-OP_LT,/*	A B	if ((R(A) <  R(B)) ~= k) then pc++		*/
-OP_LE,/*	A B	if ((R(A) <= R(B)) ~= k) then pc++		*/
+OP_JMP,/*	sJ	pc += sJ					*/
+OP_EQ,/*	A B k	if ((R[A] == R[B]) ~= k) then pc++		*/
+OP_LT,/*	A B k	if ((R[A] <  R[B]) ~= k) then pc++		*/
+OP_LE,/*	A B k	if ((R[A] <= R[B]) ~= k) then pc++		*/
 
 
-OP_EQK,/*	A B	if ((R(A) == K(B)) ~= k) then pc++		*/
-OP_EQI,/*	A sB	if ((R(A) == sB) ~= k) then pc++		*/
-OP_LTI,/*	A sB	if ((R(A) < sB) ~= k) then pc++			*/
-OP_LEI,/*	A sB	if ((R(A) <= sB) ~= k) then pc++		*/
-OP_GTI,/*	A sB	if ((R(A) > sB) ~= k) then pc++			*/
-OP_GEI,/*	A sB	if ((R(A) >= sB) ~= k) then pc++		*/
+OP_EQK,/*	A B k	if ((R[A] == K[B]) ~= k) then pc++		*/
+OP_EQI,/*	A sB k	if ((R[A] == sB) ~= k) then pc++		*/
+OP_LTI,/*	A sB k	if ((R[A] < sB) ~= k) then pc++			*/
+OP_LEI,/*	A sB k	if ((R[A] <= sB) ~= k) then pc++		*/
+OP_GTI,/*	A sB k	if ((R[A] > sB) ~= k) then pc++			*/
+OP_GEI,/*	A sB k	if ((R[A] >= sB) ~= k) then pc++		*/
 
 
-OP_TEST,/*	A 	if (not R(A) == k) then pc++			*/
-OP_TESTSET,/*	A B	if (not R(B) == k) then pc++ else R(A) := R(B)	*/
+OP_TEST,/*	A k	if (not R[A] == k) then pc++			*/
+OP_TESTSET,/*	A B k	if (not R[B] == k) then pc++ else R[A] := R[B]	*/
 
 
-OP_CALL,/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
-OP_TAILCALL,/*	A B C	return R(A)(R(A+1), ... ,R(A+B-1))		*/
+OP_CALL,/*	A B C	R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) */
+OP_TAILCALL,/*	A B C k	return R[A](R[A+1], ... ,R[A+B-1])		*/
 
 
-OP_RETURN,/*	A B C	return R(A), ... ,R(A+B-2)	(see note)	*/
-OP_RETURN0,/*	  	return 						*/
-OP_RETURN1,/*	A 	return R(A)					*/
+OP_RETURN,/*	A B C k	return R[A], ... ,R[A+B-2]	(see note)	*/
+OP_RETURN0,/*		return						*/
+OP_RETURN1,/*	A	return R[A]					*/
 
 
 OP_FORLOOP,/*	A Bx	update counters; if loop continues then pc-=Bx; */
 OP_FORLOOP,/*	A Bx	update counters; if loop continues then pc-=Bx; */
 OP_FORPREP,/*	A Bx	<check values and prepare counters>;
 OP_FORPREP,/*	A Bx	<check values and prepare counters>;
                         if not to run then pc+=Bx+1;			*/
                         if not to run then pc+=Bx+1;			*/
 
 
-OP_TFORPREP,/*	A Bx	create upvalue for R(A + 3); pc+=Bx		*/
-OP_TFORCALL,/*	A C	R(A+4), ... ,R(A+3+C) := R(A)(R(A+1), R(A+2));	*/
-OP_TFORLOOP,/*	A Bx	if R(A+2) ~= nil then { R(A)=R(A+2); pc -= Bx }	*/
+OP_TFORPREP,/*	A Bx	create upvalue for R[A + 3]; pc+=Bx		*/
+OP_TFORCALL,/*	A C	R[A+4], ... ,R[A+3+C] := R[A](R[A+1], R[A+2]);	*/
+OP_TFORLOOP,/*	A Bx	if R[A+2] ~= nil then { R[A]=R[A+2]; pc -= Bx }	*/
 
 
-OP_SETLIST,/*	A B C	R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B	*/
+OP_SETLIST,/*	A B C k	R[A][C+i] := R[A+i], 1 <= i <= B		*/
 
 
-OP_CLOSURE,/*	A Bx	R(A) := closure(KPROTO[Bx])			*/
+OP_CLOSURE,/*	A Bx	R[A] := closure(KPROTO[Bx])			*/
 
 
-OP_VARARG,/*	A C  	R(A), R(A+1), ..., R(A+C-2) = vararg		*/
+OP_VARARG,/*	A C	R[A], R[A+1], ..., R[A+C-2] = vararg		*/
 
 
-OP_VARARGPREP,/*A 	(adjust vararg parameters)			*/
+OP_VARARGPREP,/*A	(adjust vararg parameters)			*/
 
 
 OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
 OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
 } OpCode;
 } OpCode;
@@ -323,7 +325,7 @@ OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
   (*) In OP_RETURN, if (B == 0) then return up to 'top'.
   (*) In OP_RETURN, if (B == 0) then return up to 'top'.
 
 
   (*) In OP_LOADKX and OP_NEWTABLE, the next instruction is always
   (*) In OP_LOADKX and OP_NEWTABLE, the next instruction is always
-  EXTRAARG.
+  OP_EXTRAARG.
 
 
   (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if k, then
   (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if k, then
   real C = EXTRAARG _ C (the bits of EXTRAARG concatenated with the
   real C = EXTRAARG _ C (the bits of EXTRAARG concatenated with the
@@ -336,6 +338,9 @@ OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
   (*) For comparisons, k specifies what condition the test should accept
   (*) For comparisons, k specifies what condition the test should accept
   (true or false).
   (true or false).
 
 
+  (*) In OP_MMBINI/OP_MMBINK, k means the arguments were flipped
+   (the constant is the first operand).
+
   (*) All 'skips' (pc++) assume that next instruction is a jump.
   (*) All 'skips' (pc++) assume that next instruction is a jump.
 
 
   (*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the
   (*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the
@@ -344,7 +349,8 @@ OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
   returning; in this case, (C - 1) is its number of fixed parameters.
   returning; in this case, (C - 1) is its number of fixed parameters.
 
 
   (*) In comparisons with an immediate operand, C signals whether the
   (*) In comparisons with an immediate operand, C signals whether the
-  original operand was a float.
+  original operand was a float. (It must be corrected in case of
+  metamethods.)
 
 
 ===========================================================================*/
 ===========================================================================*/
 
 

+ 6 - 1
src/lopnames.h

@@ -7,6 +7,9 @@
 #if !defined(lopnames_h)
 #if !defined(lopnames_h)
 #define lopnames_h
 #define lopnames_h
 
 
+#include <stddef.h>
+
+
 /* ORDER OP */
 /* ORDER OP */
 
 
 static const char *const opnames[] = {
 static const char *const opnames[] = {
@@ -15,7 +18,9 @@ static const char *const opnames[] = {
   "LOADF",
   "LOADF",
   "LOADK",
   "LOADK",
   "LOADKX",
   "LOADKX",
-  "LOADBOOL",
+  "LOADFALSE",
+  "LFALSESKIP",
+  "LOADTRUE",
   "LOADNIL",
   "LOADNIL",
   "GETUPVAL",
   "GETUPVAL",
   "SETUPVAL",
   "SETUPVAL",

+ 10 - 8
src/loslib.c

@@ -10,6 +10,7 @@
 #include "lprefix.h"
 #include "lprefix.h"
 
 
 
 
+#include <errno.h>
 #include <locale.h>
 #include <locale.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
@@ -91,7 +92,7 @@
 
 
 /* ISO C definitions */
 /* ISO C definitions */
 #define l_gmtime(t,r)		((void)(r)->tm_sec, gmtime(t))
 #define l_gmtime(t,r)		((void)(r)->tm_sec, gmtime(t))
-#define l_localtime(t,r)  	((void)(r)->tm_sec, localtime(t))
+#define l_localtime(t,r)	((void)(r)->tm_sec, localtime(t))
 
 
 #endif				/* } */
 #endif				/* } */
 
 
@@ -138,10 +139,11 @@
 
 
 
 
 
 
-
 static int os_execute (lua_State *L) {
 static int os_execute (lua_State *L) {
   const char *cmd = luaL_optstring(L, 1, NULL);
   const char *cmd = luaL_optstring(L, 1, NULL);
-  int stat = system(cmd);
+  int stat;
+  errno = 0;
+  stat = system(cmd);
   if (cmd != NULL)
   if (cmd != NULL)
     return luaL_execresult(L, stat);
     return luaL_execresult(L, stat);
   else {
   else {
@@ -168,7 +170,7 @@ static int os_tmpname (lua_State *L) {
   char buff[LUA_TMPNAMBUFSIZE];
   char buff[LUA_TMPNAMBUFSIZE];
   int err;
   int err;
   lua_tmpnam(buff, err);
   lua_tmpnam(buff, err);
-  if (err)
+  if (l_unlikely(err))
     return luaL_error(L, "unable to generate a unique filename");
     return luaL_error(L, "unable to generate a unique filename");
   lua_pushstring(L, buff);
   lua_pushstring(L, buff);
   return 1;
   return 1;
@@ -196,7 +198,7 @@ static int os_clock (lua_State *L) {
 */
 */
 
 
 /*
 /*
-** About the overflow check: an overflow cannot occurr when time
+** About the overflow check: an overflow cannot occur when time
 ** is represented by a lua_Integer, because either lua_Integer is
 ** is represented by a lua_Integer, because either lua_Integer is
 ** large enough to represent all int fields or it is not large enough
 ** large enough to represent all int fields or it is not large enough
 ** to represent a time that cause a field to overflow.  However, if
 ** to represent a time that cause a field to overflow.  However, if
@@ -206,7 +208,7 @@ static int os_clock (lua_State *L) {
 */
 */
 static void setfield (lua_State *L, const char *key, int value, int delta) {
 static void setfield (lua_State *L, const char *key, int value, int delta) {
   #if (defined(LUA_NUMTIME) && LUA_MAXINTEGER <= INT_MAX)
   #if (defined(LUA_NUMTIME) && LUA_MAXINTEGER <= INT_MAX)
-    if (value > LUA_MAXINTEGER - delta)
+    if (l_unlikely(value > LUA_MAXINTEGER - delta))
       luaL_error(L, "field '%s' is out-of-bound", key);
       luaL_error(L, "field '%s' is out-of-bound", key);
   #endif
   #endif
   lua_pushinteger(L, (lua_Integer)value + delta);
   lua_pushinteger(L, (lua_Integer)value + delta);
@@ -251,9 +253,9 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
   int t = lua_getfield(L, -1, key);  /* get field and its type */
   int t = lua_getfield(L, -1, key);  /* get field and its type */
   lua_Integer res = lua_tointegerx(L, -1, &isnum);
   lua_Integer res = lua_tointegerx(L, -1, &isnum);
   if (!isnum) {  /* field is not an integer? */
   if (!isnum) {  /* field is not an integer? */
-    if (t != LUA_TNIL)  /* some other value? */
+    if (l_unlikely(t != LUA_TNIL))  /* some other value? */
       return luaL_error(L, "field '%s' is not an integer", key);
       return luaL_error(L, "field '%s' is not an integer", key);
-    else if (d < 0)  /* absent field; no default? */
+    else if (l_unlikely(d < 0))  /* absent field; no default? */
       return luaL_error(L, "field '%s' missing in date table", key);
       return luaL_error(L, "field '%s' missing in date table", key);
     res = d;
     res = d;
   }
   }

+ 75 - 102
src/lparser.c

@@ -128,7 +128,7 @@ static void checknext (LexState *ls, int c) {
 ** in line 'where' (if that is not the current line).
 ** in line 'where' (if that is not the current line).
 */
 */
 static void check_match (LexState *ls, int what, int who, int where) {
 static void check_match (LexState *ls, int what, int who, int where) {
-  if (unlikely(!testnext(ls, what))) {
+  if (l_unlikely(!testnext(ls, what))) {
     if (where == ls->linenumber)  /* all in the same line? */
     if (where == ls->linenumber)  /* all in the same line? */
       error_expected(ls, what);  /* do not need a complex message */
       error_expected(ls, what);  /* do not need a complex message */
     else {
     else {
@@ -212,43 +212,44 @@ static int new_localvar (LexState *ls, TString *name) {
 
 
 
 
 /*
 /*
-** Return the "variable description" (Vardesc) of a given
-** variable
+** Return the "variable description" (Vardesc) of a given variable.
+** (Unless noted otherwise, all variables are referred to by their
+** compiler indices.)
 */
 */
-static Vardesc *getlocalvardesc (FuncState *fs, int i) {
-  return &fs->ls->dyd->actvar.arr[fs->firstlocal + i];
+static Vardesc *getlocalvardesc (FuncState *fs, int vidx) {
+  return &fs->ls->dyd->actvar.arr[fs->firstlocal + vidx];
 }
 }
 
 
 
 
 /*
 /*
-** Convert 'nvar' (number of active variables at some point) to
-** number of variables in the stack at that point.
+** Convert 'nvar', a compiler index level, to its corresponding
+** register. For that, search for the highest variable below that level
+** that is in a register and uses its register index ('ridx') plus one.
 */
 */
-static int stacklevel (FuncState *fs, int nvar) {
-  while (nvar > 0) {
-    Vardesc *vd = getlocalvardesc(fs, nvar - 1);
-    if (vd->vd.kind != RDKCTC)  /* is in the stack? */
-      return vd->vd.sidx + 1;
-    else
-      nvar--;  /* try previous variable */
+static int reglevel (FuncState *fs, int nvar) {
+  while (nvar-- > 0) {
+    Vardesc *vd = getlocalvardesc(fs, nvar);  /* get previous variable */
+    if (vd->vd.kind != RDKCTC)  /* is in a register? */
+      return vd->vd.ridx + 1;
   }
   }
-  return 0;  /* no variables */
+  return 0;  /* no variables in registers */
 }
 }
 
 
 
 
 /*
 /*
-** Return the number of variables in the stack for function 'fs'
+** Return the number of variables in the register stack for the given
+** function.
 */
 */
 int luaY_nvarstack (FuncState *fs) {
 int luaY_nvarstack (FuncState *fs) {
-  return stacklevel(fs, fs->nactvar);
+  return reglevel(fs, fs->nactvar);
 }
 }
 
 
 
 
 /*
 /*
-** Get the debug-information entry for current variable 'i'.
+** Get the debug-information entry for current variable 'vidx'.
 */
 */
-static LocVar *localdebuginfo (FuncState *fs, int i) {
-  Vardesc *vd = getlocalvardesc(fs, i);
+static LocVar *localdebuginfo (FuncState *fs, int vidx) {
+  Vardesc *vd = getlocalvardesc(fs,  vidx);
   if (vd->vd.kind == RDKCTC)
   if (vd->vd.kind == RDKCTC)
     return NULL;  /* no debug info. for constants */
     return NULL;  /* no debug info. for constants */
   else {
   else {
@@ -259,14 +260,20 @@ static LocVar *localdebuginfo (FuncState *fs, int i) {
 }
 }
 
 
 
 
-static void init_var (FuncState *fs, expdesc *e, int i) {
+/*
+** Create an expression representing variable 'vidx'
+*/
+static void init_var (FuncState *fs, expdesc *e, int vidx) {
   e->f = e->t = NO_JUMP;
   e->f = e->t = NO_JUMP;
   e->k = VLOCAL;
   e->k = VLOCAL;
-  e->u.var.vidx = i;
-  e->u.var.sidx = getlocalvardesc(fs, i)->vd.sidx;
+  e->u.var.vidx = vidx;
+  e->u.var.ridx = getlocalvardesc(fs, vidx)->vd.ridx;
 }
 }
 
 
 
 
+/*
+** Raises an error if variable described by 'e' is read only
+*/
 static void check_readonly (LexState *ls, expdesc *e) {
 static void check_readonly (LexState *ls, expdesc *e) {
   FuncState *fs = ls->fs;
   FuncState *fs = ls->fs;
   TString *varname = NULL;  /* to be set if variable is const */
   TString *varname = NULL;  /* to be set if variable is const */
@@ -303,12 +310,12 @@ static void check_readonly (LexState *ls, expdesc *e) {
 */
 */
 static void adjustlocalvars (LexState *ls, int nvars) {
 static void adjustlocalvars (LexState *ls, int nvars) {
   FuncState *fs = ls->fs;
   FuncState *fs = ls->fs;
-  int stklevel = luaY_nvarstack(fs);
+  int reglevel = luaY_nvarstack(fs);
   int i;
   int i;
   for (i = 0; i < nvars; i++) {
   for (i = 0; i < nvars; i++) {
-    int varidx = fs->nactvar++;
-    Vardesc *var = getlocalvardesc(fs, varidx);
-    var->vd.sidx = stklevel++;
+    int vidx = fs->nactvar++;
+    Vardesc *var = getlocalvardesc(fs, vidx);
+    var->vd.ridx = reglevel++;
     var->vd.pidx = registerlocalvar(ls, fs, var->vd.name);
     var->vd.pidx = registerlocalvar(ls, fs, var->vd.name);
   }
   }
 }
 }
@@ -359,7 +366,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
   FuncState *prev = fs->prev;
   FuncState *prev = fs->prev;
   if (v->k == VLOCAL) {
   if (v->k == VLOCAL) {
     up->instack = 1;
     up->instack = 1;
-    up->idx = v->u.var.sidx;
+    up->idx = v->u.var.ridx;
     up->kind = getlocalvardesc(prev, v->u.var.vidx)->vd.kind;
     up->kind = getlocalvardesc(prev, v->u.var.vidx)->vd.kind;
     lua_assert(eqstr(name, getlocalvardesc(prev, v->u.var.vidx)->vd.name));
     lua_assert(eqstr(name, getlocalvardesc(prev, v->u.var.vidx)->vd.name));
   }
   }
@@ -377,7 +384,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
 
 
 /*
 /*
 ** Look for an active local variable with the name 'n' in the
 ** Look for an active local variable with the name 'n' in the
-** function 'fs'.
+** function 'fs'. If found, initialize 'var' with it and return
+** its expression kind; otherwise return -1.
 */
 */
 static int searchvar (FuncState *fs, TString *n, expdesc *var) {
 static int searchvar (FuncState *fs, TString *n, expdesc *var) {
   int i;
   int i;
@@ -481,12 +489,10 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
 }
 }
 
 
 
 
-/*
-** Macros to limit the maximum recursion depth while parsing
-*/
-#define enterlevel(ls)	luaE_enterCcall((ls)->L)
+#define enterlevel(ls)	luaE_incCstack(ls->L)
+
 
 
-#define leavelevel(ls)	luaE_exitCcall((ls)->L)
+#define leavelevel(ls) ((ls)->L->nCcalls--)
 
 
 
 
 /*
 /*
@@ -511,7 +517,7 @@ static void solvegoto (LexState *ls, int g, Labeldesc *label) {
   Labellist *gl = &ls->dyd->gt;  /* list of goto's */
   Labellist *gl = &ls->dyd->gt;  /* list of goto's */
   Labeldesc *gt = &gl->arr[g];  /* goto to be resolved */
   Labeldesc *gt = &gl->arr[g];  /* goto to be resolved */
   lua_assert(eqstr(gt->name, label->name));
   lua_assert(eqstr(gt->name, label->name));
-  if (unlikely(gt->nactvar < label->nactvar))  /* enter some scope? */
+  if (l_unlikely(gt->nactvar < label->nactvar))  /* enter some scope? */
     jumpscopeerror(ls, gt);
     jumpscopeerror(ls, gt);
   luaK_patchlist(ls->fs, gt->pc, label->pc);
   luaK_patchlist(ls->fs, gt->pc, label->pc);
   for (i = g; i < gl->n - 1; i++)  /* remove goto from pending list */
   for (i = g; i < gl->n - 1; i++)  /* remove goto from pending list */
@@ -614,7 +620,7 @@ static void movegotosout (FuncState *fs, BlockCnt *bl) {
   for (i = bl->firstgoto; i < gl->n; i++) {  /* for each pending goto */
   for (i = bl->firstgoto; i < gl->n; i++) {  /* for each pending goto */
     Labeldesc *gt = &gl->arr[i];
     Labeldesc *gt = &gl->arr[i];
     /* leaving a variable scope? */
     /* leaving a variable scope? */
-    if (stacklevel(fs, gt->nactvar) > stacklevel(fs, bl->nactvar))
+    if (reglevel(fs, gt->nactvar) > reglevel(fs, bl->nactvar))
       gt->close |= bl->upval;  /* jump may need a close */
       gt->close |= bl->upval;  /* jump may need a close */
     gt->nactvar = bl->nactvar;  /* update goto level */
     gt->nactvar = bl->nactvar;  /* update goto level */
   }
   }
@@ -655,7 +661,7 @@ static void leaveblock (FuncState *fs) {
   BlockCnt *bl = fs->bl;
   BlockCnt *bl = fs->bl;
   LexState *ls = fs->ls;
   LexState *ls = fs->ls;
   int hasclose = 0;
   int hasclose = 0;
-  int stklevel = stacklevel(fs, bl->nactvar);  /* level outside the block */
+  int stklevel = reglevel(fs, bl->nactvar);  /* level outside the block */
   if (bl->isloop)  /* fix pending breaks? */
   if (bl->isloop)  /* fix pending breaks? */
     hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
     hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
   if (!hasclose && bl->previous && bl->upval)
   if (!hasclose && bl->previous && bl->upval)
@@ -729,6 +735,7 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
   fs->firstlabel = ls->dyd->label.n;
   fs->firstlabel = ls->dyd->label.n;
   fs->bl = NULL;
   fs->bl = NULL;
   f->source = ls->source;
   f->source = ls->source;
+  luaC_objbarrier(ls->L, f, f->source);
   f->maxstacksize = 2;  /* registers 0/1 are always valid */
   f->maxstacksize = 2;  /* registers 0/1 are always valid */
   enterblock(fs, bl, 0);
   enterblock(fs, bl, 0);
 }
 }
@@ -938,7 +945,7 @@ static void setvararg (FuncState *fs, int nparams) {
 
 
 
 
 static void parlist (LexState *ls) {
 static void parlist (LexState *ls) {
-  /* parlist -> [ param { ',' param } ] */
+  /* parlist -> [ {NAME ','} (NAME | '...') ] */
   FuncState *fs = ls->fs;
   FuncState *fs = ls->fs;
   Proto *f = fs->f;
   Proto *f = fs->f;
   int nparams = 0;
   int nparams = 0;
@@ -946,12 +953,12 @@ static void parlist (LexState *ls) {
   if (ls->t.token != ')') {  /* is 'parlist' not empty? */
   if (ls->t.token != ')') {  /* is 'parlist' not empty? */
     do {
     do {
       switch (ls->t.token) {
       switch (ls->t.token) {
-        case TK_NAME: {  /* param -> NAME */
+        case TK_NAME: {
           new_localvar(ls, str_checkname(ls));
           new_localvar(ls, str_checkname(ls));
           nparams++;
           nparams++;
           break;
           break;
         }
         }
-        case TK_DOTS: {  /* param -> '...' */
+        case TK_DOTS: {
           luaX_next(ls);
           luaX_next(ls);
           isvararg = 1;
           isvararg = 1;
           break;
           break;
@@ -1014,7 +1021,8 @@ static void funcargs (LexState *ls, expdesc *f, int line) {
         args.k = VVOID;
         args.k = VVOID;
       else {
       else {
         explist(ls, &args);
         explist(ls, &args);
-        luaK_setmultret(fs, &args);
+        if (hasmultret(args.k))
+          luaK_setmultret(fs, &args);
       }
       }
       check_match(ls, ')', '(', line);
       check_match(ls, ')', '(', line);
       break;
       break;
@@ -1322,13 +1330,13 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
         }
         }
       }
       }
       else {  /* table is a register */
       else {  /* table is a register */
-        if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.sidx) {
+        if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.ridx) {
           conflict = 1;  /* table is the local being assigned now */
           conflict = 1;  /* table is the local being assigned now */
           lh->v.u.ind.t = extra;  /* assignment will use safe copy */
           lh->v.u.ind.t = extra;  /* assignment will use safe copy */
         }
         }
         /* is index the local being assigned? */
         /* is index the local being assigned? */
         if (lh->v.k == VINDEXED && v->k == VLOCAL &&
         if (lh->v.k == VINDEXED && v->k == VLOCAL &&
-            lh->v.u.ind.idx == v->u.var.sidx) {
+            lh->v.u.ind.idx == v->u.var.ridx) {
           conflict = 1;
           conflict = 1;
           lh->v.u.ind.idx = extra;  /* previous assignment will use safe copy */
           lh->v.u.ind.idx = extra;  /* previous assignment will use safe copy */
         }
         }
@@ -1338,7 +1346,7 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
   if (conflict) {
   if (conflict) {
     /* copy upvalue/local value to a temporary (in position 'extra') */
     /* copy upvalue/local value to a temporary (in position 'extra') */
     if (v->k == VLOCAL)
     if (v->k == VLOCAL)
-      luaK_codeABC(fs, OP_MOVE, extra, v->u.var.sidx, 0);
+      luaK_codeABC(fs, OP_MOVE, extra, v->u.var.ridx, 0);
     else
     else
       luaK_codeABC(fs, OP_GETUPVAL, extra, v->u.info, 0);
       luaK_codeABC(fs, OP_GETUPVAL, extra, v->u.info, 0);
     luaK_reserveregs(fs, 1);
     luaK_reserveregs(fs, 1);
@@ -1403,7 +1411,7 @@ static void gotostat (LexState *ls) {
     newgotoentry(ls, name, line, luaK_jump(fs));
     newgotoentry(ls, name, line, luaK_jump(fs));
   else {  /* found a label */
   else {  /* found a label */
     /* backward jump; will be resolved here */
     /* backward jump; will be resolved here */
-    int lblevel = stacklevel(fs, lb->nactvar);  /* label level */
+    int lblevel = reglevel(fs, lb->nactvar);  /* label level */
     if (luaY_nvarstack(fs) > lblevel)  /* leaving the scope of a variable? */
     if (luaY_nvarstack(fs) > lblevel)  /* leaving the scope of a variable? */
       luaK_codeABC(fs, OP_CLOSE, lblevel, 0, 0);
       luaK_codeABC(fs, OP_CLOSE, lblevel, 0, 0);
     /* create jump and link it to the label */
     /* create jump and link it to the label */
@@ -1427,7 +1435,7 @@ static void breakstat (LexState *ls) {
 */
 */
 static void checkrepeated (LexState *ls, TString *name) {
 static void checkrepeated (LexState *ls, TString *name) {
   Labeldesc *lb = findlabel(ls, name);
   Labeldesc *lb = findlabel(ls, name);
-  if (unlikely(lb != NULL)) {  /* already defined? */
+  if (l_unlikely(lb != NULL)) {  /* already defined? */
     const char *msg = "label '%s' already defined on line %d";
     const char *msg = "label '%s' already defined on line %d";
     msg = luaO_pushfstring(ls->L, msg, getstr(name), lb->line);
     msg = luaO_pushfstring(ls->L, msg, getstr(name), lb->line);
     luaK_semerror(ls, msg);  /* error */
     luaK_semerror(ls, msg);  /* error */
@@ -1480,7 +1488,7 @@ static void repeatstat (LexState *ls, int line) {
   if (bl2.upval) {  /* upvalues? */
   if (bl2.upval) {  /* upvalues? */
     int exit = luaK_jump(fs);  /* normal exit must jump over fix */
     int exit = luaK_jump(fs);  /* normal exit must jump over fix */
     luaK_patchtohere(fs, condexit);  /* repetition must close upvalues */
     luaK_patchtohere(fs, condexit);  /* repetition must close upvalues */
-    luaK_codeABC(fs, OP_CLOSE, stacklevel(fs, bl2.nactvar), 0, 0);
+    luaK_codeABC(fs, OP_CLOSE, reglevel(fs, bl2.nactvar), 0, 0);
     condexit = luaK_jump(fs);  /* repeat after closing upvalues */
     condexit = luaK_jump(fs);  /* repeat after closing upvalues */
     luaK_patchtohere(fs, exit);  /* normal exit comes to here */
     luaK_patchtohere(fs, exit);  /* normal exit comes to here */
   }
   }
@@ -1512,7 +1520,7 @@ static void fixforjump (FuncState *fs, int pc, int dest, int back) {
   int offset = dest - (pc + 1);
   int offset = dest - (pc + 1);
   if (back)
   if (back)
     offset = -offset;
     offset = -offset;
-  if (unlikely(offset > MAXARG_Bx))
+  if (l_unlikely(offset > MAXARG_Bx))
     luaX_syntaxerror(fs->ls, "control structure too long");
     luaX_syntaxerror(fs->ls, "control structure too long");
   SETARG_Bx(*jmp, offset);
   SETARG_Bx(*jmp, offset);
 }
 }
@@ -1591,7 +1599,7 @@ static void forlist (LexState *ls, TString *indexname) {
   line = ls->linenumber;
   line = ls->linenumber;
   adjust_assign(ls, 4, explist(ls, &e), &e);
   adjust_assign(ls, 4, explist(ls, &e), &e);
   adjustlocalvars(ls, 4);  /* control variables */
   adjustlocalvars(ls, 4);  /* control variables */
-  markupval(fs, luaY_nvarstack(fs));  /* state may create an upvalue */
+  markupval(fs, fs->nactvar);  /* last control var. must be closed */
   luaK_checkstack(fs, 3);  /* extra space to call generator */
   luaK_checkstack(fs, 3);  /* extra space to call generator */
   forbody(ls, base, line, nvars - 4, 1);
   forbody(ls, base, line, nvars - 4, 1);
 }
 }
@@ -1615,59 +1623,21 @@ static void forstat (LexState *ls, int line) {
 }
 }
 
 
 
 
-/*
-** Check whether next instruction is a single jump (a 'break', a 'goto'
-** to a forward label, or a 'goto' to a backward label with no variable
-** to close). If so, set the name of the 'label' it is jumping to
-** ("break" for a 'break') or to where it is jumping to ('target') and
-** return true. If not a single jump, leave input unchanged, to be
-** handled as a regular statement.
-*/
-static int issinglejump (LexState *ls, TString **label, int *target) {
-  if (testnext(ls, TK_BREAK)) {  /* a break? */
-    *label = luaS_newliteral(ls->L, "break");
-    return 1;
-  }
-  else if (ls->t.token != TK_GOTO || luaX_lookahead(ls) != TK_NAME)
-    return 0;  /* not a valid goto */
-  else {
-    TString *lname = ls->lookahead.seminfo.ts;  /* label's id */
-    Labeldesc *lb = findlabel(ls, lname);
-    if (lb) {  /* a backward jump? */
-      /* does it need to close variables? */
-      if (luaY_nvarstack(ls->fs) > stacklevel(ls->fs, lb->nactvar))
-        return 0;  /* not a single jump; cannot optimize */
-      *target = lb->pc;
-    }
-    else  /* jump forward */
-      *label = lname;
-    luaX_next(ls);  /* skip goto */
-    luaX_next(ls);  /* skip name */
-    return 1;
-  }
-}
-
-
 static void test_then_block (LexState *ls, int *escapelist) {
 static void test_then_block (LexState *ls, int *escapelist) {
   /* test_then_block -> [IF | ELSEIF] cond THEN block */
   /* test_then_block -> [IF | ELSEIF] cond THEN block */
   BlockCnt bl;
   BlockCnt bl;
-  int line;
   FuncState *fs = ls->fs;
   FuncState *fs = ls->fs;
-  TString *jlb = NULL;
-  int target = NO_JUMP;
   expdesc v;
   expdesc v;
   int jf;  /* instruction to skip 'then' code (if condition is false) */
   int jf;  /* instruction to skip 'then' code (if condition is false) */
   luaX_next(ls);  /* skip IF or ELSEIF */
   luaX_next(ls);  /* skip IF or ELSEIF */
   expr(ls, &v);  /* read condition */
   expr(ls, &v);  /* read condition */
   checknext(ls, TK_THEN);
   checknext(ls, TK_THEN);
-  line = ls->linenumber;
-  if (issinglejump(ls, &jlb, &target)) {  /* 'if x then goto' ? */
-    luaK_goiffalse(ls->fs, &v);  /* will jump to label if condition is true */
+  if (ls->t.token == TK_BREAK) {  /* 'if x then break' ? */
+    int line = ls->linenumber;
+    luaK_goiffalse(ls->fs, &v);  /* will jump if condition is true */
+    luaX_next(ls);  /* skip 'break' */
     enterblock(fs, &bl, 0);  /* must enter block before 'goto' */
     enterblock(fs, &bl, 0);  /* must enter block before 'goto' */
-    if (jlb != NULL)  /* forward jump? */
-      newgotoentry(ls, jlb, line, v.t);  /* will be resolved later */
-    else  /* backward jump */
-      luaK_patchlist(fs, v.t, target);  /* jump directly to 'target' */
+    newgotoentry(ls, luaS_newliteral(ls->L, "break"), line, v.t);
     while (testnext(ls, ';')) {}  /* skip semicolons */
     while (testnext(ls, ';')) {}  /* skip semicolons */
     if (block_follow(ls, 0)) {  /* jump is the entire block? */
     if (block_follow(ls, 0)) {  /* jump is the entire block? */
       leaveblock(fs);
       leaveblock(fs);
@@ -1676,7 +1646,7 @@ static void test_then_block (LexState *ls, int *escapelist) {
     else  /* must skip over 'then' part if condition is false */
     else  /* must skip over 'then' part if condition is false */
       jf = luaK_jump(fs);
       jf = luaK_jump(fs);
   }
   }
-  else {  /* regular case (not a jump) */
+  else {  /* regular case (not a break) */
     luaK_goiftrue(ls->fs, &v);  /* skip over block if condition is false */
     luaK_goiftrue(ls->fs, &v);  /* skip over block if condition is false */
     enterblock(fs, &bl, 0);
     enterblock(fs, &bl, 0);
     jf = v.f;
     jf = v.f;
@@ -1729,7 +1699,7 @@ static int getlocalattribute (LexState *ls) {
       luaK_semerror(ls,
       luaK_semerror(ls,
         luaO_pushfstring(ls->L, "unknown attribute '%s'", attr));
         luaO_pushfstring(ls->L, "unknown attribute '%s'", attr));
   }
   }
-  return VDKREG;
+  return VDKREG;  /* regular variable */
 }
 }
 
 
 
 
@@ -1738,28 +1708,28 @@ static void checktoclose (LexState *ls, int level) {
     FuncState *fs = ls->fs;
     FuncState *fs = ls->fs;
     markupval(fs, level + 1);
     markupval(fs, level + 1);
     fs->bl->insidetbc = 1;  /* in the scope of a to-be-closed variable */
     fs->bl->insidetbc = 1;  /* in the scope of a to-be-closed variable */
-    luaK_codeABC(fs, OP_TBC, level, 0, 0);
+    luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0);
   }
   }
 }
 }
 
 
 
 
 static void localstat (LexState *ls) {
 static void localstat (LexState *ls) {
-  /* stat -> LOCAL ATTRIB NAME {',' ATTRIB NAME} ['=' explist] */
+  /* stat -> LOCAL NAME ATTRIB { ',' NAME ATTRIB } ['=' explist] */
   FuncState *fs = ls->fs;
   FuncState *fs = ls->fs;
   int toclose = -1;  /* index of to-be-closed variable (if any) */
   int toclose = -1;  /* index of to-be-closed variable (if any) */
   Vardesc *var;  /* last variable */
   Vardesc *var;  /* last variable */
-  int ivar, kind;  /* index and kind of last variable */
+  int vidx, kind;  /* index and kind of last variable */
   int nvars = 0;
   int nvars = 0;
   int nexps;
   int nexps;
   expdesc e;
   expdesc e;
   do {
   do {
-    ivar = new_localvar(ls, str_checkname(ls));
+    vidx = new_localvar(ls, str_checkname(ls));
     kind = getlocalattribute(ls);
     kind = getlocalattribute(ls);
-    getlocalvardesc(fs, ivar)->vd.kind = kind;
+    getlocalvardesc(fs, vidx)->vd.kind = kind;
     if (kind == RDKTOCLOSE) {  /* to-be-closed? */
     if (kind == RDKTOCLOSE) {  /* to-be-closed? */
       if (toclose != -1)  /* one already present? */
       if (toclose != -1)  /* one already present? */
         luaK_semerror(ls, "multiple to-be-closed variables in local list");
         luaK_semerror(ls, "multiple to-be-closed variables in local list");
-      toclose = luaY_nvarstack(fs) + nvars;
+      toclose = fs->nactvar + nvars;
     }
     }
     nvars++;
     nvars++;
   } while (testnext(ls, ','));
   } while (testnext(ls, ','));
@@ -1769,7 +1739,7 @@ static void localstat (LexState *ls) {
     e.k = VVOID;
     e.k = VVOID;
     nexps = 0;
     nexps = 0;
   }
   }
-  var = getlocalvardesc(fs, ivar);  /* get last variable */
+  var = getlocalvardesc(fs, vidx);  /* get last variable */
   if (nvars == nexps &&  /* no adjustments? */
   if (nvars == nexps &&  /* no adjustments? */
       var->vd.kind == RDKCONST &&  /* last variable is const? */
       var->vd.kind == RDKCONST &&  /* last variable is const? */
       luaK_exp2const(fs, &e, &var->k)) {  /* compile-time constant? */
       luaK_exp2const(fs, &e, &var->k)) {  /* compile-time constant? */
@@ -1821,8 +1791,9 @@ static void exprstat (LexState *ls) {
     restassign(ls, &v, 1);
     restassign(ls, &v, 1);
   }
   }
   else {  /* stat -> func */
   else {  /* stat -> func */
-    Instruction *inst = &getinstruction(fs, &v.v);
+    Instruction *inst;
     check_condition(ls, v.v.k == VCALL, "syntax error");
     check_condition(ls, v.v.k == VCALL, "syntax error");
+    inst = &getinstruction(fs, &v.v);
     SETARG_C(*inst, 1);  /* call statement uses no results */
     SETARG_C(*inst, 1);  /* call statement uses no results */
   }
   }
 }
 }
@@ -1949,6 +1920,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
   env->idx = 0;
   env->idx = 0;
   env->kind = VDKREG;
   env->kind = VDKREG;
   env->name = ls->envn;
   env->name = ls->envn;
+  luaC_objbarrier(ls->L, fs->f, env->name);
   luaX_next(ls);  /* read first token */
   luaX_next(ls);  /* read first token */
   statlist(ls);  /* parse main body */
   statlist(ls);  /* parse main body */
   check(ls, TK_EOS);
   check(ls, TK_EOS);
@@ -1967,6 +1939,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
   sethvalue2s(L, L->top, lexstate.h);  /* anchor it */
   sethvalue2s(L, L->top, lexstate.h);  /* anchor it */
   luaD_inctop(L);
   luaD_inctop(L);
   funcstate.f = cl->p = luaF_newproto(L);
   funcstate.f = cl->p = luaF_newproto(L);
+  luaC_objbarrier(L, cl, cl->p);
   funcstate.f->source = luaS_new(L, name);  /* create and anchor TString */
   funcstate.f->source = luaS_new(L, name);  /* create and anchor TString */
   luaC_objbarrier(L, funcstate.f, funcstate.f->source);
   luaC_objbarrier(L, funcstate.f, funcstate.f->source);
   lexstate.buff = buff;
   lexstate.buff = buff;

+ 8 - 7
src/lparser.h

@@ -23,7 +23,7 @@
 
 
 /* kinds of variables/expressions */
 /* kinds of variables/expressions */
 typedef enum {
 typedef enum {
-  VVOID,  /* when 'expdesc' describes the last expression a list,
+  VVOID,  /* when 'expdesc' describes the last expression of a list,
              this kind means an empty list (so, no expression) */
              this kind means an empty list (so, no expression) */
   VNIL,  /* constant nil */
   VNIL,  /* constant nil */
   VTRUE,  /* constant true */
   VTRUE,  /* constant true */
@@ -35,10 +35,11 @@ typedef enum {
              (string is fixed by the lexer) */
              (string is fixed by the lexer) */
   VNONRELOC,  /* expression has its value in a fixed register;
   VNONRELOC,  /* expression has its value in a fixed register;
                  info = result register */
                  info = result register */
-  VLOCAL,  /* local variable; var.ridx = local register;
+  VLOCAL,  /* local variable; var.ridx = register index;
               var.vidx = relative index in 'actvar.arr'  */
               var.vidx = relative index in 'actvar.arr'  */
   VUPVAL,  /* upvalue variable; info = index of upvalue in 'upvalues' */
   VUPVAL,  /* upvalue variable; info = index of upvalue in 'upvalues' */
-  VCONST,  /* compile-time constant; info = absolute index in 'actvar.arr'  */
+  VCONST,  /* compile-time <const> variable;
+              info = absolute index in 'actvar.arr'  */
   VINDEXED,  /* indexed variable;
   VINDEXED,  /* indexed variable;
                 ind.t = table register;
                 ind.t = table register;
                 ind.idx = key's R index */
                 ind.idx = key's R index */
@@ -76,8 +77,8 @@ typedef struct expdesc {
       lu_byte t;  /* table (register or upvalue) */
       lu_byte t;  /* table (register or upvalue) */
     } ind;
     } ind;
     struct {  /* for local variables */
     struct {  /* for local variables */
-      lu_byte sidx;  /* index in the stack */
-      unsigned short vidx;  /* index in 'actvar.arr'  */
+      lu_byte ridx;  /* register holding the variable */
+      unsigned short vidx;  /* compiler index (in 'actvar.arr')  */
     } var;
     } var;
   } u;
   } u;
   int t;  /* patch list of 'exit when true' */
   int t;  /* patch list of 'exit when true' */
@@ -96,7 +97,7 @@ typedef union Vardesc {
   struct {
   struct {
     TValuefields;  /* constant value (if it is a compile-time constant) */
     TValuefields;  /* constant value (if it is a compile-time constant) */
     lu_byte kind;
     lu_byte kind;
-    lu_byte sidx;  /* index of the variable in the stack */
+    lu_byte ridx;  /* register holding the variable */
     short pidx;  /* index of the variable in the Proto's 'locvars' array */
     short pidx;  /* index of the variable in the Proto's 'locvars' array */
     TString *name;  /* variable name */
     TString *name;  /* variable name */
   } vd;
   } vd;
@@ -125,7 +126,7 @@ typedef struct Labellist {
 
 
 /* dynamic structures used by the parser */
 /* dynamic structures used by the parser */
 typedef struct Dyndata {
 typedef struct Dyndata {
-  struct {  /* list of active local variables */
+  struct {  /* list of all active local variables */
     Vardesc *arr;
     Vardesc *arr;
     int n;
     int n;
     int size;
     int size;

+ 1 - 1
src/lprefix.h

@@ -33,7 +33,7 @@
 /*
 /*
 ** Windows stuff
 ** Windows stuff
 */
 */
-#if defined(_WIN32) 	/* { */
+#if defined(_WIN32)	/* { */
 
 
 #if !defined(_CRT_SECURE_NO_WARNINGS)
 #if !defined(_CRT_SECURE_NO_WARNINGS)
 #define _CRT_SECURE_NO_WARNINGS  /* avoid warnings about ISO C functions */
 #define _CRT_SECURE_NO_WARNINGS  /* avoid warnings about ISO C functions */

+ 86 - 108
src/lstate.c

@@ -97,66 +97,14 @@ void luaE_setdebt (global_State *g, l_mem debt) {
 
 
 
 
 LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) {
 LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) {
-  global_State *g = G(L);
-  int ccalls;
-  luaE_freeCI(L);  /* release unused CIs */
-  ccalls = getCcalls(L);
-  if (limit >= 40000)
-    return 0;  /* out of bounds */
-  limit += CSTACKERR;
-  if (L != g-> mainthread)
-    return 0;  /* only main thread can change the C stack */
-  else if (ccalls <= CSTACKERR)
-    return 0;  /* handling overflow */
-  else {
-    int diff = limit - g->Cstacklimit;
-    if (ccalls + diff <= CSTACKERR)
-      return 0;  /* new limit would cause an overflow */
-    g->Cstacklimit = limit;  /* set new limit */
-    L->nCcalls += diff;  /* correct 'nCcalls' */
-    return limit - diff - CSTACKERR;  /* success; return previous limit */
-  }
-}
-
-
-/*
-** Decrement count of "C calls" and check for overflows. In case of
-** a stack overflow, check appropriate error ("regular" overflow or
-** overflow while handling stack overflow).  If 'nCcalls' is smaller
-** than CSTACKERR but larger than CSTACKMARK, it means it has just
-** entered the "overflow zone", so the function raises an overflow
-** error.  If 'nCcalls' is smaller than CSTACKMARK (which means it is
-** already handling an overflow) but larger than CSTACKERRMARK, does
-** not report an error (to allow message handling to work). Otherwise,
-** report a stack overflow while handling a stack overflow (probably
-** caused by a repeating error in the message handling function).
-*/
-
-void luaE_enterCcall (lua_State *L) {
-  int ncalls = getCcalls(L);
-  L->nCcalls--;
-  if (ncalls <= CSTACKERR) {  /* possible overflow? */
-    luaE_freeCI(L);  /* release unused CIs */
-    ncalls = getCcalls(L);  /* update call count */
-    if (ncalls <= CSTACKERR) {  /* still overflow? */
-      if (ncalls <= CSTACKERRMARK)  /* below error-handling zone? */
-        luaD_throw(L, LUA_ERRERR);  /* error while handling stack error */
-      else if (ncalls >= CSTACKMARK) {
-        /* not in error-handling zone; raise the error now */
-        L->nCcalls = (CSTACKMARK - 1);  /* enter error-handling zone */
-        luaG_runerror(L, "C stack overflow");
-      }
-      /* else stack is in the error-handling zone;
-         allow message handler to work */
-    }
-  }
+  UNUSED(L); UNUSED(limit);
+  return LUAI_MAXCCALLS;  /* warning?? */
 }
 }
 
 
 
 
 CallInfo *luaE_extendCI (lua_State *L) {
 CallInfo *luaE_extendCI (lua_State *L) {
   CallInfo *ci;
   CallInfo *ci;
   lua_assert(L->ci->next == NULL);
   lua_assert(L->ci->next == NULL);
-  luaE_enterCcall(L);
   ci = luaM_new(L, CallInfo);
   ci = luaM_new(L, CallInfo);
   lua_assert(L->ci->next == NULL);
   lua_assert(L->ci->next == NULL);
   L->ci->next = ci;
   L->ci->next = ci;
@@ -175,44 +123,69 @@ void luaE_freeCI (lua_State *L) {
   CallInfo *ci = L->ci;
   CallInfo *ci = L->ci;
   CallInfo *next = ci->next;
   CallInfo *next = ci->next;
   ci->next = NULL;
   ci->next = NULL;
-  L->nCcalls += L->nci;  /* add removed elements back to 'nCcalls' */
   while ((ci = next) != NULL) {
   while ((ci = next) != NULL) {
     next = ci->next;
     next = ci->next;
     luaM_free(L, ci);
     luaM_free(L, ci);
     L->nci--;
     L->nci--;
   }
   }
-  L->nCcalls -= L->nci;  /* adjust result */
 }
 }
 
 
 
 
 /*
 /*
-** free half of the CallInfo structures not in use by a thread
+** free half of the CallInfo structures not in use by a thread,
+** keeping the first one.
 */
 */
 void luaE_shrinkCI (lua_State *L) {
 void luaE_shrinkCI (lua_State *L) {
-  CallInfo *ci = L->ci;
-  CallInfo *next2;  /* next's next */
-  L->nCcalls += L->nci;  /* add removed elements back to 'nCcalls' */
-  /* while there are two nexts */
-  while (ci->next != NULL && (next2 = ci->next->next) != NULL) {
-    luaM_free(L, ci->next);  /* free next */
+  CallInfo *ci = L->ci->next;  /* first free CallInfo */
+  CallInfo *next;
+  if (ci == NULL)
+    return;  /* no extra elements */
+  while ((next = ci->next) != NULL) {  /* two extra elements? */
+    CallInfo *next2 = next->next;  /* next's next */
+    ci->next = next2;  /* remove next from the list */
     L->nci--;
     L->nci--;
-    ci->next = next2;  /* remove 'next' from the list */
-    next2->previous = ci;
-    ci = next2;  /* keep next's next */
+    luaM_free(L, next);  /* free next */
+    if (next2 == NULL)
+      break;  /* no more elements */
+    else {
+      next2->previous = ci;
+      ci = next2;  /* continue */
+    }
   }
   }
-  L->nCcalls -= L->nci;  /* adjust result */
+}
+
+
+/*
+** Called when 'getCcalls(L)' larger or equal to LUAI_MAXCCALLS.
+** If equal, raises an overflow error. If value is larger than
+** LUAI_MAXCCALLS (which means it is handling an overflow) but
+** not much larger, does not report an error (to allow overflow
+** handling to work).
+*/
+void luaE_checkcstack (lua_State *L) {
+  if (getCcalls(L) == LUAI_MAXCCALLS)
+    luaG_runerror(L, "C stack overflow");
+  else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
+    luaD_throw(L, LUA_ERRERR);  /* error while handing stack error */
+}
+
+
+LUAI_FUNC void luaE_incCstack (lua_State *L) {
+  L->nCcalls++;
+  if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
+    luaE_checkcstack(L);
 }
 }
 
 
 
 
 static void stack_init (lua_State *L1, lua_State *L) {
 static void stack_init (lua_State *L1, lua_State *L) {
   int i; CallInfo *ci;
   int i; CallInfo *ci;
   /* initialize stack array */
   /* initialize stack array */
-  L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, StackValue);
-  L1->stacksize = BASIC_STACK_SIZE;
-  for (i = 0; i < BASIC_STACK_SIZE; i++)
+  L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
+  L1->tbclist = L1->stack;
+  for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
     setnilvalue(s2v(L1->stack + i));  /* erase new stack */
     setnilvalue(s2v(L1->stack + i));  /* erase new stack */
   L1->top = L1->stack;
   L1->top = L1->stack;
-  L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK;
+  L1->stack_last = L1->stack + BASIC_STACK_SIZE;
   /* initialize first ci */
   /* initialize first ci */
   ci = &L1->base_ci;
   ci = &L1->base_ci;
   ci->next = ci->previous = NULL;
   ci->next = ci->previous = NULL;
@@ -233,7 +206,7 @@ static void freestack (lua_State *L) {
   L->ci = &L->base_ci;  /* free the entire 'ci' list */
   L->ci = &L->base_ci;  /* free the entire 'ci' list */
   luaE_freeCI(L);
   luaE_freeCI(L);
   lua_assert(L->nci == 0);
   lua_assert(L->nci == 0);
-  luaM_freearray(L, L->stack, L->stacksize);  /* free stack array */
+  luaM_freearray(L, L->stack, stacksize(L) + EXTRA_STACK);  /* free stack */
 }
 }
 
 
 
 
@@ -241,24 +214,19 @@ static void freestack (lua_State *L) {
 ** Create registry table and its predefined values
 ** Create registry table and its predefined values
 */
 */
 static void init_registry (lua_State *L, global_State *g) {
 static void init_registry (lua_State *L, global_State *g) {
-  TValue temp;
   /* create registry */
   /* create registry */
   Table *registry = luaH_new(L);
   Table *registry = luaH_new(L);
   sethvalue(L, &g->l_registry, registry);
   sethvalue(L, &g->l_registry, registry);
   luaH_resize(L, registry, LUA_RIDX_LAST, 0);
   luaH_resize(L, registry, LUA_RIDX_LAST, 0);
   /* registry[LUA_RIDX_MAINTHREAD] = L */
   /* registry[LUA_RIDX_MAINTHREAD] = L */
-  setthvalue(L, &temp, L);  /* temp = L */
-  luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp);
-  /* registry[LUA_RIDX_GLOBALS] = table of globals */
-  sethvalue(L, &temp, luaH_new(L));  /* temp = new table (global table) */
-  luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp);
+  setthvalue(L, &registry->array[LUA_RIDX_MAINTHREAD - 1], L);
+  /* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */
+  sethvalue(L, &registry->array[LUA_RIDX_GLOBALS - 1], luaH_new(L));
 }
 }
 
 
 
 
 /*
 /*
 ** open parts of the state that may cause memory-allocation errors.
 ** open parts of the state that may cause memory-allocation errors.
-** ('g->nilvalue' being a nil value flags that the state was completely
-** build.)
 */
 */
 static void f_luaopen (lua_State *L, void *ud) {
 static void f_luaopen (lua_State *L, void *ud) {
   global_State *g = G(L);
   global_State *g = G(L);
@@ -269,7 +237,7 @@ static void f_luaopen (lua_State *L, void *ud) {
   luaT_init(L);
   luaT_init(L);
   luaX_init(L);
   luaX_init(L);
   g->gcrunning = 1;  /* allow gc */
   g->gcrunning = 1;  /* allow gc */
-  setnilvalue(&g->nilvalue);
+  setnilvalue(&g->nilvalue);  /* now state is complete */
   luai_userstateopen(L);
   luai_userstateopen(L);
 }
 }
 
 
@@ -283,10 +251,9 @@ static void preinit_thread (lua_State *L, global_State *g) {
   L->stack = NULL;
   L->stack = NULL;
   L->ci = NULL;
   L->ci = NULL;
   L->nci = 0;
   L->nci = 0;
-  L->stacksize = 0;
   L->twups = L;  /* thread has no upvalues */
   L->twups = L;  /* thread has no upvalues */
+  L->nCcalls = 0;
   L->errorJmp = NULL;
   L->errorJmp = NULL;
-  L->nCcalls = CSTACKTHREAD;
   L->hook = NULL;
   L->hook = NULL;
   L->hookmask = 0;
   L->hookmask = 0;
   L->basehookcount = 0;
   L->basehookcount = 0;
@@ -295,15 +262,19 @@ static void preinit_thread (lua_State *L, global_State *g) {
   L->openupval = NULL;
   L->openupval = NULL;
   L->status = LUA_OK;
   L->status = LUA_OK;
   L->errfunc = 0;
   L->errfunc = 0;
+  L->oldpc = 0;
 }
 }
 
 
 
 
 static void close_state (lua_State *L) {
 static void close_state (lua_State *L) {
   global_State *g = G(L);
   global_State *g = G(L);
-  luaF_close(L, L->stack, CLOSEPROTECT);  /* close all upvalues */
-  luaC_freeallobjects(L);  /* collect all objects */
-  if (ttisnil(&g->nilvalue))  /* closing a fully built state? */
+  if (!completestate(g))  /* closing a partially built state? */
+    luaC_freeallobjects(L);  /* jucst collect its objects */
+  else {  /* closing a fully built state */
+    luaD_closeprotected(L, 1, LUA_OK);  /* close all upvalues */
+    luaC_freeallobjects(L);  /* collect all objects */
     luai_userstateclose(L);
     luai_userstateclose(L);
+  }
   luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
   luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
   freestack(L);
   freestack(L);
   lua_assert(gettotalbytes(g) == sizeof(LG));
   lua_assert(gettotalbytes(g) == sizeof(LG));
@@ -312,14 +283,15 @@ static void close_state (lua_State *L) {
 
 
 
 
 LUA_API lua_State *lua_newthread (lua_State *L) {
 LUA_API lua_State *lua_newthread (lua_State *L) {
-  global_State *g = G(L);
+  global_State *g;
   lua_State *L1;
   lua_State *L1;
   lua_lock(L);
   lua_lock(L);
+  g = G(L);
   luaC_checkGC(L);
   luaC_checkGC(L);
   /* create new thread */
   /* create new thread */
   L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;
   L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;
   L1->marked = luaC_white(g);
   L1->marked = luaC_white(g);
-  L1->tt = LUA_TTHREAD;
+  L1->tt = LUA_VTHREAD;
   /* link it on list 'allgc' */
   /* link it on list 'allgc' */
   L1->next = g->allgc;
   L1->next = g->allgc;
   g->allgc = obj2gco(L1);
   g->allgc = obj2gco(L1);
@@ -343,7 +315,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
 
 
 void luaE_freethread (lua_State *L, lua_State *L1) {
 void luaE_freethread (lua_State *L, lua_State *L1) {
   LX *l = fromstate(L1);
   LX *l = fromstate(L1);
-  luaF_close(L1, L1->stack, NOCLOSINGMETH);  /* close all upvalues */
+  luaF_closeupval(L1, L1->stack);  /* close all upvalues */
   lua_assert(L1->openupval == NULL);
   lua_assert(L1->openupval == NULL);
   luai_userstatefree(L, L1);
   luai_userstatefree(L, L1);
   freestack(L1);
   freestack(L1);
@@ -351,24 +323,29 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
 }
 }
 
 
 
 
-int lua_resetthread (lua_State *L) {
-  CallInfo *ci;
-  int status;
-  lua_lock(L);
-  ci = &L->base_ci;
-  status = luaF_close(L, L->stack, CLOSEPROTECT);
+int luaE_resetthread (lua_State *L, int status) {
+  CallInfo *ci = L->ci = &L->base_ci;  /* unwind CallInfo list */
   setnilvalue(s2v(L->stack));  /* 'function' entry for basic 'ci' */
   setnilvalue(s2v(L->stack));  /* 'function' entry for basic 'ci' */
-  if (status != CLOSEPROTECT)  /* real errors? */
-    luaD_seterrorobj(L, status, L->stack + 1);
-  else {
+  ci->func = L->stack;
+  ci->callstatus = CIST_C;
+  if (status == LUA_YIELD)
     status = LUA_OK;
     status = LUA_OK;
+  status = luaD_closeprotected(L, 1, status);
+  if (status != LUA_OK)  /* errors? */
+    luaD_seterrorobj(L, status, L->stack + 1);
+  else
     L->top = L->stack + 1;
     L->top = L->stack + 1;
-  }
-  ci->callstatus = CIST_C;
-  ci->func = L->stack;
   ci->top = L->top + LUA_MINSTACK;
   ci->top = L->top + LUA_MINSTACK;
-  L->ci = ci;
-  L->status = status;
+  L->status = cast_byte(status);
+  luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
+  return status;
+}
+
+
+LUA_API int lua_resetthread (lua_State *L) {
+  int status;
+  lua_lock(L);
+  status = luaE_resetthread(L, L->status);
   lua_unlock(L);
   lua_unlock(L);
   return status;
   return status;
 }
 }
@@ -382,13 +359,13 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   if (l == NULL) return NULL;
   if (l == NULL) return NULL;
   L = &l->l.l;
   L = &l->l.l;
   g = &l->g;
   g = &l->g;
-  L->tt = LUA_TTHREAD;
+  L->tt = LUA_VTHREAD;
   g->currentwhite = bitmask(WHITE0BIT);
   g->currentwhite = bitmask(WHITE0BIT);
   L->marked = luaC_white(g);
   L->marked = luaC_white(g);
   preinit_thread(L, g);
   preinit_thread(L, g);
   g->allgc = obj2gco(L);  /* by now, only object is the main thread */
   g->allgc = obj2gco(L);  /* by now, only object is the main thread */
   L->next = NULL;
   L->next = NULL;
-  g->Cstacklimit = L->nCcalls = LUAI_MAXCSTACK + CSTACKERR;
+  incnny(L);  /* main thread is always non yieldable */
   g->frealloc = f;
   g->frealloc = f;
   g->ud = ud;
   g->ud = ud;
   g->warnf = NULL;
   g->warnf = NULL;
@@ -402,10 +379,11 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   g->panic = NULL;
   g->panic = NULL;
   g->gcstate = GCSpause;
   g->gcstate = GCSpause;
   g->gckind = KGC_INC;
   g->gckind = KGC_INC;
+  g->gcstopem = 0;
   g->gcemergency = 0;
   g->gcemergency = 0;
   g->finobj = g->tobefnz = g->fixedgc = NULL;
   g->finobj = g->tobefnz = g->fixedgc = NULL;
-  g->survival = g->old = g->reallyold = NULL;
-  g->finobjsur = g->finobjold = g->finobjrold = NULL;
+  g->firstold1 = g->survival = g->old1 = g->reallyold = NULL;
+  g->finobjsur = g->finobjold1 = g->finobjrold = NULL;
   g->sweepgc = NULL;
   g->sweepgc = NULL;
   g->gray = g->grayagain = NULL;
   g->gray = g->grayagain = NULL;
   g->weak = g->ephemeron = g->allweak = NULL;
   g->weak = g->ephemeron = g->allweak = NULL;
@@ -430,8 +408,8 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
 
 
 
 
 LUA_API void lua_close (lua_State *L) {
 LUA_API void lua_close (lua_State *L) {
-  L = G(L)->mainthread;  /* only the main thread can be closed */
   lua_lock(L);
   lua_lock(L);
+  L = G(L)->mainthread;  /* only the main thread can be closed */
   close_state(L);
   close_state(L);
 }
 }
 
 

+ 119 - 79
src/lstate.h

@@ -32,13 +32,29 @@
 **
 **
 ** 'allgc' -> 'survival': new objects;
 ** 'allgc' -> 'survival': new objects;
 ** 'survival' -> 'old': objects that survived one collection;
 ** 'survival' -> 'old': objects that survived one collection;
-** 'old' -> 'reallyold': objects that became old in last collection;
+** 'old1' -> 'reallyold': objects that became old in last collection;
 ** 'reallyold' -> NULL: objects old for more than one cycle.
 ** 'reallyold' -> NULL: objects old for more than one cycle.
 **
 **
 ** 'finobj' -> 'finobjsur': new objects marked for finalization;
 ** 'finobj' -> 'finobjsur': new objects marked for finalization;
-** 'finobjsur' -> 'finobjold': survived   """";
-** 'finobjold' -> 'finobjrold': just old  """";
+** 'finobjsur' -> 'finobjold1': survived   """";
+** 'finobjold1' -> 'finobjrold': just old  """";
 ** 'finobjrold' -> NULL: really old       """".
 ** 'finobjrold' -> NULL: really old       """".
+**
+** All lists can contain elements older than their main ages, due
+** to 'luaC_checkfinalizer' and 'udata2finalize', which move
+** objects between the normal lists and the "marked for finalization"
+** lists. Moreover, barriers can age young objects in young lists as
+** OLD0, which then become OLD1. However, a list never contains
+** elements younger than their main ages.
+**
+** The generational collector also uses a pointer 'firstold1', which
+** points to the first OLD1 object in the list. It is used to optimize
+** 'markold'. (Potentially OLD1 objects can be anywhere between 'allgc'
+** and 'reallyold', but often the list has no OLD1 objects or they are
+** after 'old1'.) Note the difference between it and 'old1':
+** 'firstold1': no OLD1 objects before this point; there can be all
+**   ages after it.
+** 'old1': no objects younger than OLD1 after this point.
 */
 */
 
 
 /*
 /*
@@ -47,7 +63,7 @@
 ** can become gray have such a field. The field is not the same
 ** can become gray have such a field. The field is not the same
 ** in all objects, but it always has this name.)  Any gray object
 ** in all objects, but it always has this name.)  Any gray object
 ** must belong to one of these lists, and all objects in these lists
 ** must belong to one of these lists, and all objects in these lists
-** must be gray:
+** must be gray (with two exceptions explained below):
 **
 **
 ** 'gray': regular gray objects, still waiting to be visited.
 ** 'gray': regular gray objects, still waiting to be visited.
 ** 'grayagain': objects that must be revisited at the atomic phase.
 ** 'grayagain': objects that must be revisited at the atomic phase.
@@ -58,53 +74,25 @@
 ** 'weak': tables with weak values to be cleared;
 ** 'weak': tables with weak values to be cleared;
 ** 'ephemeron': ephemeron tables with white->white entries;
 ** 'ephemeron': ephemeron tables with white->white entries;
 ** 'allweak': tables with weak keys and/or weak values to be cleared.
 ** 'allweak': tables with weak keys and/or weak values to be cleared.
-*/
-
-
-
-/*
-** About 'nCcalls': each thread in Lua (a lua_State) keeps a count of
-** how many "C calls" it still can do in the C stack, to avoid C-stack
-** overflow.  This count is very rough approximation; it considers only
-** recursive functions inside the interpreter, as non-recursive calls
-** can be considered using a fixed (although unknown) amount of stack
-** space.
 **
 **
-** The count has two parts: the lower part is the count itself; the
-** higher part counts the number of non-yieldable calls in the stack.
-** (They are together so that we can change both with one instruction.)
-**
-** Because calls to external C functions can use an unknown amount
-** of space (e.g., functions using an auxiliary buffer), calls
-** to these functions add more than one to the count (see CSTACKCF).
-**
-** The proper count excludes the number of CallInfo structures allocated
-** by Lua, as a kind of "potential" calls. So, when Lua calls a function
-** (and "consumes" one CallInfo), it needs neither to decrement nor to
-** check 'nCcalls', as its use of C stack is already accounted for.
+** The exceptions to that "gray rule" are:
+** - TOUCHED2 objects in generational mode stay in a gray list (because
+** they must be visited again at the end of the cycle), but they are
+** marked black because assignments to them must activate barriers (to
+** move them back to TOUCHED1).
+** - Open upvales are kept gray to avoid barriers, but they stay out
+** of gray lists. (They don't even have a 'gclist' field.)
 */
 */
 
 
-/* number of "C stack slots" used by an external C function */
-#define CSTACKCF	10
 
 
 
 
 /*
 /*
-** The C-stack size is sliced in the following zones:
-** - larger than CSTACKERR: normal stack;
-** - [CSTACKMARK, CSTACKERR]: buffer zone to signal a stack overflow;
-** - [CSTACKCF, CSTACKERRMARK]: error-handling zone;
-** - below CSTACKERRMARK: buffer zone to signal overflow during overflow;
-** (Because the counter can be decremented CSTACKCF at once, we need
-** the so called "buffer zones", with at least that size, to properly
-** detect a change from one zone to the next.)
+** About 'nCcalls':  This count has two parts: the lower 16 bits counts
+** the number of recursive invocations in the C stack; the higher
+** 16 bits counts the number of non-yieldable calls in the stack.
+** (They are together so that we can change and save both with one
+** instruction.)
 */
 */
-#define CSTACKERR	(8 * CSTACKCF)
-#define CSTACKMARK	(CSTACKERR - (CSTACKCF + 2))
-#define CSTACKERRMARK	(CSTACKCF + 2)
-
-
-/* initial limit for the C-stack of threads */
-#define CSTACKTHREAD	(2 * CSTACKERR)
 
 
 
 
 /* true if this thread does not have non-yieldable calls in the stack */
 /* true if this thread does not have non-yieldable calls in the stack */
@@ -120,13 +108,8 @@
 /* Decrement the number of non-yieldable calls */
 /* Decrement the number of non-yieldable calls */
 #define decnny(L)	((L)->nCcalls -= 0x10000)
 #define decnny(L)	((L)->nCcalls -= 0x10000)
 
 
-/* Increment the number of non-yieldable calls and decrement nCcalls */
-#define incXCcalls(L)	((L)->nCcalls += 0x10000 - CSTACKCF)
-
-/* Decrement the number of non-yieldable calls and increment nCcalls */
-#define decXCcalls(L)	((L)->nCcalls -= 0x10000 - CSTACKCF)
-
-
+/* Non-yieldable call increment */
+#define nyci	(0x10000 | 1)
 
 
 
 
 
 
@@ -144,12 +127,20 @@ struct lua_longjmp;  /* defined in ldo.c */
 #endif
 #endif
 
 
 
 
-/* extra stack space to handle TM calls and some other extras */
+/*
+** Extra stack space to handle TM calls and some other extras. This
+** space is not included in 'stack_last'. It is used only to avoid stack
+** checks, either because the element will be promptly popped or because
+** there will be a stack check soon after the push. Function frames
+** never use this extra space, so it does not need to be kept clean.
+*/
 #define EXTRA_STACK   5
 #define EXTRA_STACK   5
 
 
 
 
 #define BASIC_STACK_SIZE        (2*LUA_MINSTACK)
 #define BASIC_STACK_SIZE        (2*LUA_MINSTACK)
 
 
+#define stacksize(th)	cast_int((th)->stack_last - (th)->stack)
+
 
 
 /* kinds of Garbage Collection */
 /* kinds of Garbage Collection */
 #define KGC_INC		0	/* incremental gc */
 #define KGC_INC		0	/* incremental gc */
@@ -165,6 +156,18 @@ typedef struct stringtable {
 
 
 /*
 /*
 ** Information about a call.
 ** Information about a call.
+** About union 'u':
+** - field 'l' is used only for Lua functions;
+** - field 'c' is used only for C functions.
+** About union 'u2':
+** - field 'funcidx' is used only by C functions while doing a
+** protected call;
+** - field 'nyield' is used only while a function is "doing" an
+** yield (from the yield until the next resume);
+** - field 'nres' is used only while closing tbc variables when
+** returning from a C function;
+** - field 'transferinfo' is used only during call/returnhooks,
+** before the function starts or after it ends.
 */
 */
 typedef struct CallInfo {
 typedef struct CallInfo {
   StkId func;  /* function index in the stack */
   StkId func;  /* function index in the stack */
@@ -173,7 +176,7 @@ typedef struct CallInfo {
   union {
   union {
     struct {  /* only for Lua functions */
     struct {  /* only for Lua functions */
       const Instruction *savedpc;
       const Instruction *savedpc;
-      l_signalT trap;
+      volatile l_signalT trap;
       int nextraargs;  /* # of extra arguments in vararg functions */
       int nextraargs;  /* # of extra arguments in vararg functions */
     } l;
     } l;
     struct {  /* only for C functions */
     struct {  /* only for C functions */
@@ -185,6 +188,7 @@ typedef struct CallInfo {
   union {
   union {
     int funcidx;  /* called-function index */
     int funcidx;  /* called-function index */
     int nyield;  /* number of values yielded */
     int nyield;  /* number of values yielded */
+    int nres;  /* number of values returned */
     struct {  /* info about transferred values (for call/return hooks) */
     struct {  /* info about transferred values (for call/return hooks) */
       unsigned short ftransfer;  /* offset of first value transferred */
       unsigned short ftransfer;  /* offset of first value transferred */
       unsigned short ntransfer;  /* number of values transferred */
       unsigned short ntransfer;  /* number of values transferred */
@@ -200,16 +204,34 @@ typedef struct CallInfo {
 */
 */
 #define CIST_OAH	(1<<0)	/* original value of 'allowhook' */
 #define CIST_OAH	(1<<0)	/* original value of 'allowhook' */
 #define CIST_C		(1<<1)	/* call is running a C function */
 #define CIST_C		(1<<1)	/* call is running a C function */
-#define CIST_HOOKED	(1<<2)	/* call is running a debug hook */
-#define CIST_YPCALL	(1<<3)	/* call is a yieldable protected call */
-#define CIST_TAIL	(1<<4)	/* call was tail called */
-#define CIST_HOOKYIELD	(1<<5)	/* last hook called yielded */
-#define CIST_FIN	(1<<6)  /* call is running a finalizer */
-#define CIST_TRAN	(1<<7)	/* 'ci' has transfer information */
+#define CIST_FRESH	(1<<2)	/* call is on a fresh "luaV_execute" frame */
+#define CIST_HOOKED	(1<<3)	/* call is running a debug hook */
+#define CIST_YPCALL	(1<<4)	/* doing a yieldable protected call */
+#define CIST_TAIL	(1<<5)	/* call was tail called */
+#define CIST_HOOKYIELD	(1<<6)	/* last hook called yielded */
+#define CIST_FIN	(1<<7)	/* call is running a finalizer */
+#define CIST_TRAN	(1<<8)	/* 'ci' has transfer information */
+#define CIST_CLSRET	(1<<9)  /* function is closing tbc variables */
+/* Bits 10-12 are used for CIST_RECST (see below) */
+#define CIST_RECST	10
 #if defined(LUA_COMPAT_LT_LE)
 #if defined(LUA_COMPAT_LT_LE)
-#define CIST_LEQ	(1<<8)  /* using __lt for __le */
+#define CIST_LEQ	(1<<13)  /* using __lt for __le */
 #endif
 #endif
 
 
+
+/*
+** Field CIST_RECST stores the "recover status", used to keep the error
+** status while closing to-be-closed variables in coroutines, so that
+** Lua can correctly resume after an yield from a __close method called
+** because of an error.  (Three bits are enough for error status.)
+*/
+#define getcistrecst(ci)     (((ci)->callstatus >> CIST_RECST) & 7)
+#define setcistrecst(ci,st)  \
+  check_exp(((st) & 7) == (st),   /* status must fit in three bits */  \
+            ((ci)->callstatus = ((ci)->callstatus & ~(7 << CIST_RECST))  \
+                                                  | ((st) << CIST_RECST)))
+
+
 /* active function is a Lua function */
 /* active function is a Lua function */
 #define isLua(ci)	(!((ci)->callstatus & CIST_C))
 #define isLua(ci)	(!((ci)->callstatus & CIST_C))
 
 
@@ -238,6 +260,7 @@ typedef struct global_State {
   lu_byte currentwhite;
   lu_byte currentwhite;
   lu_byte gcstate;  /* state of garbage collector */
   lu_byte gcstate;  /* state of garbage collector */
   lu_byte gckind;  /* kind of GC running */
   lu_byte gckind;  /* kind of GC running */
+  lu_byte gcstopem;  /* stops emergency collections */
   lu_byte genminormul;  /* control for minor generational collections */
   lu_byte genminormul;  /* control for minor generational collections */
   lu_byte genmajormul;  /* control for major generational collections */
   lu_byte genmajormul;  /* control for major generational collections */
   lu_byte gcrunning;  /* true if GC is running */
   lu_byte gcrunning;  /* true if GC is running */
@@ -257,10 +280,11 @@ typedef struct global_State {
   GCObject *fixedgc;  /* list of objects not to be collected */
   GCObject *fixedgc;  /* list of objects not to be collected */
   /* fields for generational collector */
   /* fields for generational collector */
   GCObject *survival;  /* start of objects that survived one GC cycle */
   GCObject *survival;  /* start of objects that survived one GC cycle */
-  GCObject *old;  /* start of old objects */
-  GCObject *reallyold;  /* old objects with more than one cycle */
+  GCObject *old1;  /* start of old1 objects */
+  GCObject *reallyold;  /* objects more than one cycle old ("really old") */
+  GCObject *firstold1;  /* first OLD1 object in the list (if any) */
   GCObject *finobjsur;  /* list of survival objects with finalizers */
   GCObject *finobjsur;  /* list of survival objects with finalizers */
-  GCObject *finobjold;  /* list of old objects with finalizers */
+  GCObject *finobjold1;  /* list of old1 objects with finalizers */
   GCObject *finobjrold;  /* list of really old objects with finalizers */
   GCObject *finobjrold;  /* list of really old objects with finalizers */
   struct lua_State *twups;  /* list of threads with open upvalues */
   struct lua_State *twups;  /* list of threads with open upvalues */
   lua_CFunction panic;  /* to be called in unprotected errors */
   lua_CFunction panic;  /* to be called in unprotected errors */
@@ -271,7 +295,6 @@ typedef struct global_State {
   TString *strcache[STRCACHE_N][STRCACHE_M];  /* cache for strings in API */
   TString *strcache[STRCACHE_N][STRCACHE_M];  /* cache for strings in API */
   lua_WarnFunction warnf;  /* warning function */
   lua_WarnFunction warnf;  /* warning function */
   void *ud_warn;         /* auxiliary data to 'warnf' */
   void *ud_warn;         /* auxiliary data to 'warnf' */
-  unsigned int Cstacklimit;  /* current limit for the C stack */
 } global_State;
 } global_State;
 
 
 
 
@@ -286,29 +309,41 @@ struct lua_State {
   StkId top;  /* first free slot in the stack */
   StkId top;  /* first free slot in the stack */
   global_State *l_G;
   global_State *l_G;
   CallInfo *ci;  /* call info for current function */
   CallInfo *ci;  /* call info for current function */
-  const Instruction *oldpc;  /* last pc traced */
-  StkId stack_last;  /* last free slot in the stack */
+  StkId stack_last;  /* end of stack (last element + 1) */
   StkId stack;  /* stack base */
   StkId stack;  /* stack base */
   UpVal *openupval;  /* list of open upvalues in this stack */
   UpVal *openupval;  /* list of open upvalues in this stack */
+  StkId tbclist;  /* list of to-be-closed variables */
   GCObject *gclist;
   GCObject *gclist;
   struct lua_State *twups;  /* list of threads with open upvalues */
   struct lua_State *twups;  /* list of threads with open upvalues */
   struct lua_longjmp *errorJmp;  /* current error recover point */
   struct lua_longjmp *errorJmp;  /* current error recover point */
   CallInfo base_ci;  /* CallInfo for first level (C calling Lua) */
   CallInfo base_ci;  /* CallInfo for first level (C calling Lua) */
   volatile lua_Hook hook;
   volatile lua_Hook hook;
   ptrdiff_t errfunc;  /* current error handling function (stack index) */
   ptrdiff_t errfunc;  /* current error handling function (stack index) */
-  l_uint32 nCcalls;  /* number of allowed nested C calls - 'nci' */
-  int stacksize;
+  l_uint32 nCcalls;  /* number of nested (non-yieldable | C)  calls */
+  int oldpc;  /* last pc traced */
   int basehookcount;
   int basehookcount;
   int hookcount;
   int hookcount;
-  l_signalT hookmask;
+  volatile l_signalT hookmask;
 };
 };
 
 
 
 
 #define G(L)	(L->l_G)
 #define G(L)	(L->l_G)
 
 
+/*
+** 'g->nilvalue' being a nil value flags that the state was completely
+** build.
+*/
+#define completestate(g)	ttisnil(&g->nilvalue)
+
 
 
 /*
 /*
 ** Union of all collectable objects (only for conversions)
 ** Union of all collectable objects (only for conversions)
+** ISO C99, 6.5.2.3 p.5:
+** "if a union contains several structures that share a common initial
+** sequence [...], and if the union object currently contains one
+** of these structures, it is permitted to inspect the common initial
+** part of any of them anywhere that a declaration of the complete type
+** of the union is visible."
 */
 */
 union GCUnion {
 union GCUnion {
   GCObject gc;  /* common header */
   GCObject gc;  /* common header */
@@ -322,20 +357,25 @@ union GCUnion {
 };
 };
 
 
 
 
+/*
+** ISO C99, 6.7.2.1 p.14:
+** "A pointer to a union object, suitably converted, points to each of
+** its members [...], and vice versa."
+*/
 #define cast_u(o)	cast(union GCUnion *, (o))
 #define cast_u(o)	cast(union GCUnion *, (o))
 
 
 /* macros to convert a GCObject into a specific value */
 /* macros to convert a GCObject into a specific value */
 #define gco2ts(o)  \
 #define gco2ts(o)  \
 	check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts))
 	check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts))
-#define gco2u(o)  check_exp((o)->tt == LUA_TUSERDATA, &((cast_u(o))->u))
-#define gco2lcl(o)  check_exp((o)->tt == LUA_TLCL, &((cast_u(o))->cl.l))
-#define gco2ccl(o)  check_exp((o)->tt == LUA_TCCL, &((cast_u(o))->cl.c))
+#define gco2u(o)  check_exp((o)->tt == LUA_VUSERDATA, &((cast_u(o))->u))
+#define gco2lcl(o)  check_exp((o)->tt == LUA_VLCL, &((cast_u(o))->cl.l))
+#define gco2ccl(o)  check_exp((o)->tt == LUA_VCCL, &((cast_u(o))->cl.c))
 #define gco2cl(o)  \
 #define gco2cl(o)  \
 	check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl))
 	check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl))
-#define gco2t(o)  check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h))
-#define gco2p(o)  check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p))
-#define gco2th(o)  check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th))
-#define gco2upv(o)	check_exp((o)->tt == LUA_TUPVAL, &((cast_u(o))->upv))
+#define gco2t(o)  check_exp((o)->tt == LUA_VTABLE, &((cast_u(o))->h))
+#define gco2p(o)  check_exp((o)->tt == LUA_VPROTO, &((cast_u(o))->p))
+#define gco2th(o)  check_exp((o)->tt == LUA_VTHREAD, &((cast_u(o))->th))
+#define gco2upv(o)	check_exp((o)->tt == LUA_VUPVAL, &((cast_u(o))->upv))
 
 
 
 
 /*
 /*
@@ -353,12 +393,12 @@ LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
 LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
 LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
 LUAI_FUNC void luaE_freeCI (lua_State *L);
 LUAI_FUNC void luaE_freeCI (lua_State *L);
 LUAI_FUNC void luaE_shrinkCI (lua_State *L);
 LUAI_FUNC void luaE_shrinkCI (lua_State *L);
-LUAI_FUNC void luaE_enterCcall (lua_State *L);
+LUAI_FUNC void luaE_checkcstack (lua_State *L);
+LUAI_FUNC void luaE_incCstack (lua_State *L);
 LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
 LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
 LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
 LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
+LUAI_FUNC int luaE_resetthread (lua_State *L, int status);
 
 
 
 
-#define luaE_exitCcall(L)	((L)->nCcalls++)
-
 #endif
 #endif
 
 

+ 12 - 22
src/lstring.c

@@ -22,16 +22,6 @@
 #include "lstring.h"
 #include "lstring.h"
 
 
 
 
-/*
-** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to
-** compute its hash
-*/
-#if !defined(LUAI_HASHLIMIT)
-#define LUAI_HASHLIMIT		5
-#endif
-
-
-
 /*
 /*
 ** Maximum size for string table.
 ** Maximum size for string table.
 */
 */
@@ -43,7 +33,7 @@
 */
 */
 int luaS_eqlngstr (TString *a, TString *b) {
 int luaS_eqlngstr (TString *a, TString *b) {
   size_t len = a->u.lnglen;
   size_t len = a->u.lnglen;
-  lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR);
+  lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR);
   return (a == b) ||  /* same instance or... */
   return (a == b) ||  /* same instance or... */
     ((len == b->u.lnglen) &&  /* equal length and ... */
     ((len == b->u.lnglen) &&  /* equal length and ... */
      (memcmp(getstr(a), getstr(b), len) == 0));  /* equal contents */
      (memcmp(getstr(a), getstr(b), len) == 0));  /* equal contents */
@@ -52,17 +42,17 @@ int luaS_eqlngstr (TString *a, TString *b) {
 
 
 unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
 unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
   unsigned int h = seed ^ cast_uint(l);
   unsigned int h = seed ^ cast_uint(l);
-  size_t step = (l >> LUAI_HASHLIMIT) + 1;
-  for (; l >= step; l -= step)
+  for (; l > 0; l--)
     h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
     h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
   return h;
   return h;
 }
 }
 
 
 
 
 unsigned int luaS_hashlongstr (TString *ts) {
 unsigned int luaS_hashlongstr (TString *ts) {
-  lua_assert(ts->tt == LUA_TLNGSTR);
+  lua_assert(ts->tt == LUA_VLNGSTR);
   if (ts->extra == 0) {  /* no hash? */
   if (ts->extra == 0) {  /* no hash? */
-    ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash);
+    size_t len = ts->u.lnglen;
+    ts->hash = luaS_hash(getstr(ts), len, ts->hash);
     ts->extra = 1;  /* now it has its hash */
     ts->extra = 1;  /* now it has its hash */
   }
   }
   return ts->hash;
   return ts->hash;
@@ -99,7 +89,7 @@ void luaS_resize (lua_State *L, int nsize) {
   if (nsize < osize)  /* shrinking table? */
   if (nsize < osize)  /* shrinking table? */
     tablerehash(tb->hash, osize, nsize);  /* depopulate shrinking part */
     tablerehash(tb->hash, osize, nsize);  /* depopulate shrinking part */
   newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*);
   newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*);
-  if (unlikely(newvect == NULL)) {  /* reallocation failed? */
+  if (l_unlikely(newvect == NULL)) {  /* reallocation failed? */
     if (nsize < osize)  /* was it shrinking table? */
     if (nsize < osize)  /* was it shrinking table? */
       tablerehash(tb->hash, nsize, osize);  /* restore to original size */
       tablerehash(tb->hash, nsize, osize);  /* restore to original size */
     /* leave table as it was */
     /* leave table as it was */
@@ -165,7 +155,7 @@ static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
 
 
 
 
 TString *luaS_createlngstrobj (lua_State *L, size_t l) {
 TString *luaS_createlngstrobj (lua_State *L, size_t l) {
-  TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed);
+  TString *ts = createstrobj(L, l, LUA_VLNGSTR, G(L)->seed);
   ts->u.lnglen = l;
   ts->u.lnglen = l;
   return ts;
   return ts;
 }
 }
@@ -182,7 +172,7 @@ void luaS_remove (lua_State *L, TString *ts) {
 
 
 
 
 static void growstrtab (lua_State *L, stringtable *tb) {
 static void growstrtab (lua_State *L, stringtable *tb) {
-  if (unlikely(tb->nuse == MAX_INT)) {  /* too many strings? */
+  if (l_unlikely(tb->nuse == MAX_INT)) {  /* too many strings? */
     luaC_fullgc(L, 1);  /* try to free some... */
     luaC_fullgc(L, 1);  /* try to free some... */
     if (tb->nuse == MAX_INT)  /* still too many? */
     if (tb->nuse == MAX_INT)  /* still too many? */
       luaM_error(L);  /* cannot even create a message... */
       luaM_error(L);  /* cannot even create a message... */
@@ -215,7 +205,7 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
     growstrtab(L, tb);
     growstrtab(L, tb);
     list = &tb->hash[lmod(h, tb->size)];  /* rehash with new size */
     list = &tb->hash[lmod(h, tb->size)];  /* rehash with new size */
   }
   }
-  ts = createstrobj(L, l, LUA_TSHRSTR, h);
+  ts = createstrobj(L, l, LUA_VSHRSTR, h);
   memcpy(getstr(ts), str, l * sizeof(char));
   memcpy(getstr(ts), str, l * sizeof(char));
   ts->shrlen = cast_byte(l);
   ts->shrlen = cast_byte(l);
   ts->u.hnext = *list;
   ts->u.hnext = *list;
@@ -233,7 +223,7 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
     return internshrstr(L, str, l);
     return internshrstr(L, str, l);
   else {
   else {
     TString *ts;
     TString *ts;
-    if (unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char)))
+    if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char)))
       luaM_toobig(L);
       luaM_toobig(L);
     ts = luaS_createlngstrobj(L, l);
     ts = luaS_createlngstrobj(L, l);
     memcpy(getstr(ts), str, l * sizeof(char));
     memcpy(getstr(ts), str, l * sizeof(char));
@@ -269,9 +259,9 @@ Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) {
   Udata *u;
   Udata *u;
   int i;
   int i;
   GCObject *o;
   GCObject *o;
-  if (unlikely(s > MAX_SIZE - udatamemoffset(nuvalue)))
+  if (l_unlikely(s > MAX_SIZE - udatamemoffset(nuvalue)))
     luaM_toobig(L);
     luaM_toobig(L);
-  o = luaC_newobj(L, LUA_TUSERDATA, sizeudata(nuvalue, s));
+  o = luaC_newobj(L, LUA_VUSERDATA, sizeudata(nuvalue, s));
   u = gco2u(o);
   u = gco2u(o);
   u->len = s;
   u->len = s;
   u->nuvalue = nuvalue;
   u->nuvalue = nuvalue;

+ 7 - 3
src/lstring.h

@@ -19,7 +19,11 @@
 #define MEMERRMSG       "not enough memory"
 #define MEMERRMSG       "not enough memory"
 
 
 
 
-#define sizelstring(l)  (sizeof(TString) + ((l) + 1) * sizeof(char))
+/*
+** Size of a TString: Size of the header plus space for the string
+** itself (including final '\0').
+*/
+#define sizelstring(l)  (offsetof(TString, contents) + ((l) + 1) * sizeof(char))
 
 
 #define luaS_newliteral(L, s)	(luaS_newlstr(L, "" s, \
 #define luaS_newliteral(L, s)	(luaS_newlstr(L, "" s, \
                                  (sizeof(s)/sizeof(char))-1))
                                  (sizeof(s)/sizeof(char))-1))
@@ -28,13 +32,13 @@
 /*
 /*
 ** test whether a string is a reserved word
 ** test whether a string is a reserved word
 */
 */
-#define isreserved(s)	((s)->tt == LUA_TSHRSTR && (s)->extra > 0)
+#define isreserved(s)	((s)->tt == LUA_VSHRSTR && (s)->extra > 0)
 
 
 
 
 /*
 /*
 ** equality for short strings, which are always internalized
 ** equality for short strings, which are always internalized
 */
 */
-#define eqshrstr(a,b)	check_exp((a)->tt == LUA_TSHRSTR, (a) == (b))
+#define eqshrstr(a,b)	check_exp((a)->tt == LUA_VSHRSTR, (a) == (b))
 
 
 
 
 LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
 LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);

+ 103 - 68
src/lstrlib.c

@@ -152,8 +152,9 @@ static int str_rep (lua_State *L) {
   const char *s = luaL_checklstring(L, 1, &l);
   const char *s = luaL_checklstring(L, 1, &l);
   lua_Integer n = luaL_checkinteger(L, 2);
   lua_Integer n = luaL_checkinteger(L, 2);
   const char *sep = luaL_optlstring(L, 3, "", &lsep);
   const char *sep = luaL_optlstring(L, 3, "", &lsep);
-  if (n <= 0) lua_pushliteral(L, "");
-  else if (l + lsep < l || l + lsep > MAXSIZE / n)  /* may overflow? */
+  if (n <= 0)
+    lua_pushliteral(L, "");
+  else if (l_unlikely(l + lsep < l || l + lsep > MAXSIZE / n))
     return luaL_error(L, "resulting string too large");
     return luaL_error(L, "resulting string too large");
   else {
   else {
     size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep;
     size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep;
@@ -181,7 +182,7 @@ static int str_byte (lua_State *L) {
   size_t pose = getendpos(L, 3, pi, l);
   size_t pose = getendpos(L, 3, pi, l);
   int n, i;
   int n, i;
   if (posi > pose) return 0;  /* empty interval; return no values */
   if (posi > pose) return 0;  /* empty interval; return no values */
-  if (pose - posi >= (size_t)INT_MAX)  /* arithmetic overflow? */
+  if (l_unlikely(pose - posi >= (size_t)INT_MAX))  /* arithmetic overflow? */
     return luaL_error(L, "string slice too long");
     return luaL_error(L, "string slice too long");
   n = (int)(pose -  posi) + 1;
   n = (int)(pose -  posi) + 1;
   luaL_checkstack(L, n, "string slice too long");
   luaL_checkstack(L, n, "string slice too long");
@@ -206,22 +207,38 @@ static int str_char (lua_State *L) {
 }
 }
 
 
 
 
-static int writer (lua_State *L, const void *b, size_t size, void *B) {
-  (void)L;
-  luaL_addlstring((luaL_Buffer *) B, (const char *)b, size);
+/*
+** Buffer to store the result of 'string.dump'. It must be initialized
+** after the call to 'lua_dump', to ensure that the function is on the
+** top of the stack when 'lua_dump' is called. ('luaL_buffinit' might
+** push stuff.)
+*/
+struct str_Writer {
+  int init;  /* true iff buffer has been initialized */
+  luaL_Buffer B;
+};
+
+
+static int writer (lua_State *L, const void *b, size_t size, void *ud) {
+  struct str_Writer *state = (struct str_Writer *)ud;
+  if (!state->init) {
+    state->init = 1;
+    luaL_buffinit(L, &state->B);
+  }
+  luaL_addlstring(&state->B, (const char *)b, size);
   return 0;
   return 0;
 }
 }
 
 
 
 
 static int str_dump (lua_State *L) {
 static int str_dump (lua_State *L) {
-  luaL_Buffer b;
+  struct str_Writer state;
   int strip = lua_toboolean(L, 2);
   int strip = lua_toboolean(L, 2);
   luaL_checktype(L, 1, LUA_TFUNCTION);
   luaL_checktype(L, 1, LUA_TFUNCTION);
-  lua_settop(L, 1);
-  luaL_buffinit(L,&b);
-  if (lua_dump(L, writer, &b, strip) != 0)
+  lua_settop(L, 1);  /* ensure function is on the top of the stack */
+  state.init = 0;
+  if (l_unlikely(lua_dump(L, writer, &state, strip) != 0))
     return luaL_error(L, "unable to dump given function");
     return luaL_error(L, "unable to dump given function");
-  luaL_pushresult(&b);
+  luaL_pushresult(&state.B);
   return 1;
   return 1;
 }
 }
 
 
@@ -259,7 +276,8 @@ static int tonum (lua_State *L, int arg) {
 
 
 static void trymt (lua_State *L, const char *mtname) {
 static void trymt (lua_State *L, const char *mtname) {
   lua_settop(L, 2);  /* back to the original arguments */
   lua_settop(L, 2);  /* back to the original arguments */
-  if (lua_type(L, 2) == LUA_TSTRING || !luaL_getmetafield(L, 2, mtname))
+  if (l_unlikely(lua_type(L, 2) == LUA_TSTRING ||
+                 !luaL_getmetafield(L, 2, mtname)))
     luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2,
     luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2,
                   luaL_typename(L, -2), luaL_typename(L, -1));
                   luaL_typename(L, -2), luaL_typename(L, -1));
   lua_insert(L, -3);  /* put metamethod before arguments */
   lua_insert(L, -3);  /* put metamethod before arguments */
@@ -367,7 +385,8 @@ static const char *match (MatchState *ms, const char *s, const char *p);
 
 
 static int check_capture (MatchState *ms, int l) {
 static int check_capture (MatchState *ms, int l) {
   l -= '1';
   l -= '1';
-  if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
+  if (l_unlikely(l < 0 || l >= ms->level ||
+                 ms->capture[l].len == CAP_UNFINISHED))
     return luaL_error(ms->L, "invalid capture index %%%d", l + 1);
     return luaL_error(ms->L, "invalid capture index %%%d", l + 1);
   return l;
   return l;
 }
 }
@@ -384,14 +403,14 @@ static int capture_to_close (MatchState *ms) {
 static const char *classend (MatchState *ms, const char *p) {
 static const char *classend (MatchState *ms, const char *p) {
   switch (*p++) {
   switch (*p++) {
     case L_ESC: {
     case L_ESC: {
-      if (p == ms->p_end)
+      if (l_unlikely(p == ms->p_end))
         luaL_error(ms->L, "malformed pattern (ends with '%%')");
         luaL_error(ms->L, "malformed pattern (ends with '%%')");
       return p+1;
       return p+1;
     }
     }
     case '[': {
     case '[': {
       if (*p == '^') p++;
       if (*p == '^') p++;
       do {  /* look for a ']' */
       do {  /* look for a ']' */
-        if (p == ms->p_end)
+        if (l_unlikely(p == ms->p_end))
           luaL_error(ms->L, "malformed pattern (missing ']')");
           luaL_error(ms->L, "malformed pattern (missing ']')");
         if (*(p++) == L_ESC && p < ms->p_end)
         if (*(p++) == L_ESC && p < ms->p_end)
           p++;  /* skip escapes (e.g. '%]') */
           p++;  /* skip escapes (e.g. '%]') */
@@ -466,7 +485,7 @@ static int singlematch (MatchState *ms, const char *s, const char *p,
 
 
 static const char *matchbalance (MatchState *ms, const char *s,
 static const char *matchbalance (MatchState *ms, const char *s,
                                    const char *p) {
                                    const char *p) {
-  if (p >= ms->p_end - 1)
+  if (l_unlikely(p >= ms->p_end - 1))
     luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')");
     luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')");
   if (*s != *p) return NULL;
   if (*s != *p) return NULL;
   else {
   else {
@@ -549,7 +568,7 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
 
 
 
 
 static const char *match (MatchState *ms, const char *s, const char *p) {
 static const char *match (MatchState *ms, const char *s, const char *p) {
-  if (ms->matchdepth-- == 0)
+  if (l_unlikely(ms->matchdepth-- == 0))
     luaL_error(ms->L, "pattern too complex");
     luaL_error(ms->L, "pattern too complex");
   init: /* using goto's to optimize tail recursion */
   init: /* using goto's to optimize tail recursion */
   if (p != ms->p_end) {  /* end of pattern? */
   if (p != ms->p_end) {  /* end of pattern? */
@@ -583,7 +602,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
           case 'f': {  /* frontier? */
           case 'f': {  /* frontier? */
             const char *ep; char previous;
             const char *ep; char previous;
             p += 2;
             p += 2;
-            if (*p != '[')
+            if (l_unlikely(*p != '['))
               luaL_error(ms->L, "missing '[' after '%%f' in pattern");
               luaL_error(ms->L, "missing '[' after '%%f' in pattern");
             ep = classend(ms, p);  /* points to what is next */
             ep = classend(ms, p);  /* points to what is next */
             previous = (s == ms->src_init) ? '\0' : *(s - 1);
             previous = (s == ms->src_init) ? '\0' : *(s - 1);
@@ -683,7 +702,7 @@ static const char *lmemfind (const char *s1, size_t l1,
 static size_t get_onecapture (MatchState *ms, int i, const char *s,
 static size_t get_onecapture (MatchState *ms, int i, const char *s,
                               const char *e, const char **cap) {
                               const char *e, const char **cap) {
   if (i >= ms->level) {
   if (i >= ms->level) {
-    if (i != 0)
+    if (l_unlikely(i != 0))
       luaL_error(ms->L, "invalid capture index %%%d", i + 1);
       luaL_error(ms->L, "invalid capture index %%%d", i + 1);
     *cap = s;
     *cap = s;
     return e - s;
     return e - s;
@@ -691,7 +710,7 @@ static size_t get_onecapture (MatchState *ms, int i, const char *s,
   else {
   else {
     ptrdiff_t capl = ms->capture[i].len;
     ptrdiff_t capl = ms->capture[i].len;
     *cap = ms->capture[i].init;
     *cap = ms->capture[i].init;
-    if (capl == CAP_UNFINISHED)
+    if (l_unlikely(capl == CAP_UNFINISHED))
       luaL_error(ms->L, "unfinished capture");
       luaL_error(ms->L, "unfinished capture");
     else if (capl == CAP_POSITION)
     else if (capl == CAP_POSITION)
       lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1);
       lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1);
@@ -910,7 +929,7 @@ static int add_value (MatchState *ms, luaL_Buffer *b, const char *s,
     luaL_addlstring(b, s, e - s);  /* keep original text */
     luaL_addlstring(b, s, e - s);  /* keep original text */
     return 0;  /* no changes */
     return 0;  /* no changes */
   }
   }
-  else if (!lua_isstring(L, -1))
+  else if (l_unlikely(!lua_isstring(L, -1)))
     return luaL_error(L, "invalid replacement value (a %s)",
     return luaL_error(L, "invalid replacement value (a %s)",
                          luaL_typename(L, -1));
                          luaL_typename(L, -1));
   else {
   else {
@@ -988,7 +1007,7 @@ static int str_gsub (lua_State *L) {
 ** to nibble boundaries by making what is left after that first digit a
 ** to nibble boundaries by making what is left after that first digit a
 ** multiple of 4.
 ** multiple of 4.
 */
 */
-#define L_NBFD		((l_mathlim(MANT_DIG) - 1)%4 + 1)
+#define L_NBFD		((l_floatatt(MANT_DIG) - 1)%4 + 1)
 
 
 
 
 /*
 /*
@@ -1042,7 +1061,7 @@ static int lua_number2strx (lua_State *L, char *buff, int sz,
     for (i = 0; i < n; i++)
     for (i = 0; i < n; i++)
       buff[i] = toupper(uchar(buff[i]));
       buff[i] = toupper(uchar(buff[i]));
   }
   }
-  else if (fmt[SIZELENMOD] != 'a')
+  else if (l_unlikely(fmt[SIZELENMOD] != 'a'))
     return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
     return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
   return n;
   return n;
 }
 }
@@ -1056,7 +1075,7 @@ static int lua_number2strx (lua_State *L, char *buff, int sz,
 ** and '\0') + number of decimal digits to represent maxfloat (which
 ** and '\0') + number of decimal digits to represent maxfloat (which
 ** is maximum exponent + 1). (99+3+1, adding some extra, 110)
 ** is maximum exponent + 1). (99+3+1, adding some extra, 110)
 */
 */
-#define MAX_ITEMF	(110 + l_mathlim(MAX_10_EXP))
+#define MAX_ITEMF	(110 + l_floatatt(MAX_10_EXP))
 
 
 
 
 /*
 /*
@@ -1071,7 +1090,10 @@ static int lua_number2strx (lua_State *L, char *buff, int sz,
 
 
 
 
 /* valid flags in a format specification */
 /* valid flags in a format specification */
-#define FLAGS	"-+ #0"
+#if !defined(L_FMTFLAGS)
+#define L_FMTFLAGS	"-+ #0"
+#endif
+
 
 
 /*
 /*
 ** maximum size of each format specification (such as "%-099.99d")
 ** maximum size of each format specification (such as "%-099.99d")
@@ -1169,8 +1191,8 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
 
 
 static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
 static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
   const char *p = strfrmt;
   const char *p = strfrmt;
-  while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++;  /* skip flags */
-  if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char))
+  while (*p != '\0' && strchr(L_FMTFLAGS, *p) != NULL) p++;  /* skip flags */
+  if ((size_t)(p - strfrmt) >= sizeof(L_FMTFLAGS)/sizeof(char))
     luaL_error(L, "invalid format (repeated flags)");
     luaL_error(L, "invalid format (repeated flags)");
   if (isdigit(uchar(*p))) p++;  /* skip width */
   if (isdigit(uchar(*p))) p++;  /* skip width */
   if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
   if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
@@ -1247,11 +1269,15 @@ static int str_format (lua_State *L) {
         case 'e': case 'E': case 'g': case 'G': {
         case 'e': case 'E': case 'g': case 'G': {
           lua_Number n = luaL_checknumber(L, arg);
           lua_Number n = luaL_checknumber(L, arg);
           addlenmod(form, LUA_NUMBER_FRMLEN);
           addlenmod(form, LUA_NUMBER_FRMLEN);
-          nb = snprintf(buff, maxitem, form, (LUAI_UACNUMBER)n);
+          nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n);
           break;
           break;
         }
         }
         case 'p': {
         case 'p': {
           const void *p = lua_topointer(L, arg);
           const void *p = lua_topointer(L, arg);
+          if (p == NULL) {  /* avoid calling 'printf' with argument NULL */
+            p = "(null)";  /* result */
+            form[strlen(form) - 1] = 's';  /* format it as a string */
+          }
           nb = l_sprintf(buff, maxitem, form, p);
           nb = l_sprintf(buff, maxitem, form, p);
           break;
           break;
         }
         }
@@ -1335,17 +1361,6 @@ struct cD {
 #define MAXALIGN	(offsetof(struct cD, u))
 #define MAXALIGN	(offsetof(struct cD, u))
 
 
 
 
-/*
-** Union for serializing floats
-*/
-typedef union Ftypes {
-  float f;
-  double d;
-  lua_Number n;
-  char buff[5 * sizeof(lua_Number)];  /* enough for any float type */
-} Ftypes;
-
-
 /*
 /*
 ** information to pack/unpack stuff
 ** information to pack/unpack stuff
 */
 */
@@ -1362,7 +1377,9 @@ typedef struct Header {
 typedef enum KOption {
 typedef enum KOption {
   Kint,		/* signed integers */
   Kint,		/* signed integers */
   Kuint,	/* unsigned integers */
   Kuint,	/* unsigned integers */
-  Kfloat,	/* floating-point numbers */
+  Kfloat,	/* single-precision floating-point numbers */
+  Knumber,	/* Lua "native" floating-point numbers */
+  Kdouble,	/* double-precision floating-point numbers */
   Kchar,	/* fixed-length strings */
   Kchar,	/* fixed-length strings */
   Kstring,	/* strings with prefixed length */
   Kstring,	/* strings with prefixed length */
   Kzstr,	/* zero-terminated strings */
   Kzstr,	/* zero-terminated strings */
@@ -1397,7 +1414,7 @@ static int getnum (const char **fmt, int df) {
 */
 */
 static int getnumlimit (Header *h, const char **fmt, int df) {
 static int getnumlimit (Header *h, const char **fmt, int df) {
   int sz = getnum(fmt, df);
   int sz = getnum(fmt, df);
-  if (sz > MAXINTSIZE || sz <= 0)
+  if (l_unlikely(sz > MAXINTSIZE || sz <= 0))
     return luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
     return luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
                             sz, MAXINTSIZE);
                             sz, MAXINTSIZE);
   return sz;
   return sz;
@@ -1431,14 +1448,14 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
     case 'J': *size = sizeof(lua_Integer); return Kuint;
     case 'J': *size = sizeof(lua_Integer); return Kuint;
     case 'T': *size = sizeof(size_t); return Kuint;
     case 'T': *size = sizeof(size_t); return Kuint;
     case 'f': *size = sizeof(float); return Kfloat;
     case 'f': *size = sizeof(float); return Kfloat;
-    case 'd': *size = sizeof(double); return Kfloat;
-    case 'n': *size = sizeof(lua_Number); return Kfloat;
+    case 'n': *size = sizeof(lua_Number); return Knumber;
+    case 'd': *size = sizeof(double); return Kdouble;
     case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint;
     case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint;
     case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
     case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
     case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
     case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
     case 'c':
     case 'c':
       *size = getnum(fmt, -1);
       *size = getnum(fmt, -1);
-      if (*size == -1)
+      if (l_unlikely(*size == -1))
         luaL_error(h->L, "missing size for format option 'c'");
         luaL_error(h->L, "missing size for format option 'c'");
       return Kchar;
       return Kchar;
     case 'z': return Kzstr;
     case 'z': return Kzstr;
@@ -1477,7 +1494,7 @@ static KOption getdetails (Header *h, size_t totalsize,
   else {
   else {
     if (align > h->maxalign)  /* enforce maximum alignment */
     if (align > h->maxalign)  /* enforce maximum alignment */
       align = h->maxalign;
       align = h->maxalign;
-    if ((align & (align - 1)) != 0)  /* is 'align' not a power of 2? */
+    if (l_unlikely((align & (align - 1)) != 0))  /* not a power of 2? */
       luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
       luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
     *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);
     *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);
   }
   }
@@ -1512,12 +1529,10 @@ static void packint (luaL_Buffer *b, lua_Unsigned n,
 ** Copy 'size' bytes from 'src' to 'dest', correcting endianness if
 ** Copy 'size' bytes from 'src' to 'dest', correcting endianness if
 ** given 'islittle' is different from native endianness.
 ** given 'islittle' is different from native endianness.
 */
 */
-static void copywithendian (volatile char *dest, volatile const char *src,
+static void copywithendian (char *dest, const char *src,
                             int size, int islittle) {
                             int size, int islittle) {
-  if (islittle == nativeendian.little) {
-    while (size-- != 0)
-      *(dest++) = *(src++);
-  }
+  if (islittle == nativeendian.little)
+    memcpy(dest, src, size);
   else {
   else {
     dest += size - 1;
     dest += size - 1;
     while (size-- != 0)
     while (size-- != 0)
@@ -1560,15 +1575,27 @@ static int str_pack (lua_State *L) {
         packint(&b, (lua_Unsigned)n, h.islittle, size, 0);
         packint(&b, (lua_Unsigned)n, h.islittle, size, 0);
         break;
         break;
       }
       }
-      case Kfloat: {  /* floating-point options */
-        volatile Ftypes u;
-        char *buff = luaL_prepbuffsize(&b, size);
-        lua_Number n = luaL_checknumber(L, arg);  /* get argument */
-        if (size == sizeof(u.f)) u.f = (float)n;  /* copy it into 'u' */
-        else if (size == sizeof(u.d)) u.d = (double)n;
-        else u.n = n;
-        /* move 'u' to final result, correcting endianness if needed */
-        copywithendian(buff, u.buff, size, h.islittle);
+      case Kfloat: {  /* C float */
+        float f = (float)luaL_checknumber(L, arg);  /* get argument */
+        char *buff = luaL_prepbuffsize(&b, sizeof(f));
+        /* move 'f' to final result, correcting endianness if needed */
+        copywithendian(buff, (char *)&f, sizeof(f), h.islittle);
+        luaL_addsize(&b, size);
+        break;
+      }
+      case Knumber: {  /* Lua float */
+        lua_Number f = luaL_checknumber(L, arg);  /* get argument */
+        char *buff = luaL_prepbuffsize(&b, sizeof(f));
+        /* move 'f' to final result, correcting endianness if needed */
+        copywithendian(buff, (char *)&f, sizeof(f), h.islittle);
+        luaL_addsize(&b, size);
+        break;
+      }
+      case Kdouble: {  /* C double */
+        double f = (double)luaL_checknumber(L, arg);  /* get argument */
+        char *buff = luaL_prepbuffsize(&b, sizeof(f));
+        /* move 'f' to final result, correcting endianness if needed */
+        copywithendian(buff, (char *)&f, sizeof(f), h.islittle);
         luaL_addsize(&b, size);
         luaL_addsize(&b, size);
         break;
         break;
       }
       }
@@ -1659,7 +1686,7 @@ static lua_Integer unpackint (lua_State *L, const char *str,
   else if (size > SZINT) {  /* must check unread bytes */
   else if (size > SZINT) {  /* must check unread bytes */
     int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC;
     int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC;
     for (i = limit; i < size; i++) {
     for (i = limit; i < size; i++) {
-      if ((unsigned char)str[islittle ? i : size - 1 - i] != mask)
+      if (l_unlikely((unsigned char)str[islittle ? i : size - 1 - i] != mask))
         luaL_error(L, "%d-byte integer does not fit into Lua Integer", size);
         luaL_error(L, "%d-byte integer does not fit into Lua Integer", size);
     }
     }
   }
   }
@@ -1694,13 +1721,21 @@ static int str_unpack (lua_State *L) {
         break;
         break;
       }
       }
       case Kfloat: {
       case Kfloat: {
-        volatile Ftypes u;
-        lua_Number num;
-        copywithendian(u.buff, data + pos, size, h.islittle);
-        if (size == sizeof(u.f)) num = (lua_Number)u.f;
-        else if (size == sizeof(u.d)) num = (lua_Number)u.d;
-        else num = u.n;
-        lua_pushnumber(L, num);
+        float f;
+        copywithendian((char *)&f, data + pos, sizeof(f), h.islittle);
+        lua_pushnumber(L, (lua_Number)f);
+        break;
+      }
+      case Knumber: {
+        lua_Number f;
+        copywithendian((char *)&f, data + pos, sizeof(f), h.islittle);
+        lua_pushnumber(L, f);
+        break;
+      }
+      case Kdouble: {
+        double f;
+        copywithendian((char *)&f, data + pos, sizeof(f), h.islittle);
+        lua_pushnumber(L, (lua_Number)f);
         break;
         break;
       }
       }
       case Kchar: {
       case Kchar: {
@@ -1715,7 +1750,7 @@ static int str_unpack (lua_State *L) {
         break;
         break;
       }
       }
       case Kzstr: {
       case Kzstr: {
-        size_t len = (int)strlen(data + pos);
+        size_t len = strlen(data + pos);
         luaL_argcheck(L, pos + len < ld, 2,
         luaL_argcheck(L, pos + len < ld, 2,
                          "unfinished string for format 'z'");
                          "unfinished string for format 'z'");
         lua_pushlstring(L, data + pos, len);
         lua_pushlstring(L, data + pos, len);

+ 127 - 77
src/ltable.c

@@ -68,28 +68,33 @@
 #define MAXHSIZE	luaM_limitN(1u << MAXHBITS, Node)
 #define MAXHSIZE	luaM_limitN(1u << MAXHBITS, Node)
 
 
 
 
+/*
+** When the original hash value is good, hashing by a power of 2
+** avoids the cost of '%'.
+*/
 #define hashpow2(t,n)		(gnode(t, lmod((n), sizenode(t))))
 #define hashpow2(t,n)		(gnode(t, lmod((n), sizenode(t))))
 
 
-#define hashstr(t,str)		hashpow2(t, (str)->hash)
-#define hashboolean(t,p)	hashpow2(t, p)
-#define hashint(t,i)		hashpow2(t, i)
-
-
 /*
 /*
-** for some types, it is better to avoid modulus by power of 2, as
-** they tend to have many 2 factors.
+** for other types, it is better to avoid modulo by power of 2, as
+** they can have many 2 factors.
 */
 */
 #define hashmod(t,n)	(gnode(t, ((n) % ((sizenode(t)-1)|1))))
 #define hashmod(t,n)	(gnode(t, ((n) % ((sizenode(t)-1)|1))))
 
 
 
 
+#define hashstr(t,str)		hashpow2(t, (str)->hash)
+#define hashboolean(t,p)	hashpow2(t, p)
+
+#define hashint(t,i)		hashpow2(t, i)
+
+
 #define hashpointer(t,p)	hashmod(t, point2uint(p))
 #define hashpointer(t,p)	hashmod(t, point2uint(p))
 
 
 
 
 #define dummynode		(&dummynode_)
 #define dummynode		(&dummynode_)
 
 
 static const Node dummynode_ = {
 static const Node dummynode_ = {
-  {{NULL}, LUA_TEMPTY,  /* value's value and type */
-   LUA_TNIL, 0, {NULL}}  /* key type, next, and key value */
+  {{NULL}, LUA_VEMPTY,  /* value's value and type */
+   LUA_VNIL, 0, {NULL}}  /* key type, next, and key value */
 };
 };
 
 
 
 
@@ -135,56 +140,86 @@ static int l_hashfloat (lua_Number n) {
 */
 */
 static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
 static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
   switch (withvariant(ktt)) {
   switch (withvariant(ktt)) {
-    case LUA_TNUMINT:
-      return hashint(t, ivalueraw(*kvl));
-    case LUA_TNUMFLT:
-      return hashmod(t, l_hashfloat(fltvalueraw(*kvl)));
-    case LUA_TSHRSTR:
-      return hashstr(t, tsvalueraw(*kvl));
-    case LUA_TLNGSTR:
-      return hashpow2(t, luaS_hashlongstr(tsvalueraw(*kvl)));
-    case LUA_TBOOLEAN:
-      return hashboolean(t, bvalueraw(*kvl));
-    case LUA_TLIGHTUSERDATA:
-      return hashpointer(t, pvalueraw(*kvl));
-    case LUA_TLCF:
-      return hashpointer(t, fvalueraw(*kvl));
-    default:
-      return hashpointer(t, gcvalueraw(*kvl));
+    case LUA_VNUMINT: {
+      lua_Integer key = ivalueraw(*kvl);
+      return hashint(t, key);
+    }
+    case LUA_VNUMFLT: {
+      lua_Number n = fltvalueraw(*kvl);
+      return hashmod(t, l_hashfloat(n));
+    }
+    case LUA_VSHRSTR: {
+      TString *ts = tsvalueraw(*kvl);
+      return hashstr(t, ts);
+    }
+    case LUA_VLNGSTR: {
+      TString *ts = tsvalueraw(*kvl);
+      return hashpow2(t, luaS_hashlongstr(ts));
+    }
+    case LUA_VFALSE:
+      return hashboolean(t, 0);
+    case LUA_VTRUE:
+      return hashboolean(t, 1);
+    case LUA_VLIGHTUSERDATA: {
+      void *p = pvalueraw(*kvl);
+      return hashpointer(t, p);
+    }
+    case LUA_VLCF: {
+      lua_CFunction f = fvalueraw(*kvl);
+      return hashpointer(t, f);
+    }
+    default: {
+      GCObject *o = gcvalueraw(*kvl);
+      return hashpointer(t, o);
+    }
   }
   }
 }
 }
 
 
 
 
+/*
+** Returns the main position of an element given as a 'TValue'
+*/
 static Node *mainpositionTV (const Table *t, const TValue *key) {
 static Node *mainpositionTV (const Table *t, const TValue *key) {
   return mainposition(t, rawtt(key), valraw(key));
   return mainposition(t, rawtt(key), valraw(key));
 }
 }
 
 
 
 
 /*
 /*
-** Check whether key 'k1' is equal to the key in node 'n2'.
-** This equality is raw, so there are no metamethods. Floats
-** with integer values have been normalized, so integers cannot
-** be equal to floats. It is assumed that 'eqshrstr' is simply
-** pointer equality, so that short strings are handled in the
-** default case.
-*/
-static int equalkey (const TValue *k1, const Node *n2) {
-  if (rawtt(k1) != keytt(n2))  /* not the same variants? */
+** Check whether key 'k1' is equal to the key in node 'n2'. This
+** equality is raw, so there are no metamethods. Floats with integer
+** values have been normalized, so integers cannot be equal to
+** floats. It is assumed that 'eqshrstr' is simply pointer equality, so
+** that short strings are handled in the default case.
+** A true 'deadok' means to accept dead keys as equal to their original
+** values. All dead keys are compared in the default case, by pointer
+** identity. (Only collectable objects can produce dead keys.) Note that
+** dead long strings are also compared by identity.
+** Once a key is dead, its corresponding value may be collected, and
+** then another value can be created with the same address. If this
+** other value is given to 'next', 'equalkey' will signal a false
+** positive. In a regular traversal, this situation should never happen,
+** as all keys given to 'next' came from the table itself, and therefore
+** could not have been collected. Outside a regular traversal, we
+** have garbage in, garbage out. What is relevant is that this false
+** positive does not break anything.  (In particular, 'next' will return
+** some other valid item on the table or nil.)
+*/
+static int equalkey (const TValue *k1, const Node *n2, int deadok) {
+  if ((rawtt(k1) != keytt(n2)) &&  /* not the same variants? */
+       !(deadok && keyisdead(n2) && iscollectable(k1)))
    return 0;  /* cannot be same key */
    return 0;  /* cannot be same key */
-  switch (ttypetag(k1)) {
-    case LUA_TNIL:
+  switch (keytt(n2)) {
+    case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE:
       return 1;
       return 1;
-    case LUA_TNUMINT:
+    case LUA_VNUMINT:
       return (ivalue(k1) == keyival(n2));
       return (ivalue(k1) == keyival(n2));
-    case LUA_TNUMFLT:
+    case LUA_VNUMFLT:
       return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2)));
       return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2)));
-    case LUA_TBOOLEAN:
-      return bvalue(k1) == bvalueraw(keyval(n2));
-    case LUA_TLIGHTUSERDATA:
+    case LUA_VLIGHTUSERDATA:
       return pvalue(k1) == pvalueraw(keyval(n2));
       return pvalue(k1) == pvalueraw(keyval(n2));
-    case LUA_TLCF:
+    case LUA_VLCF:
       return fvalue(k1) == fvalueraw(keyval(n2));
       return fvalue(k1) == fvalueraw(keyval(n2));
-    case LUA_TLNGSTR:
+    case ctb(LUA_VLNGSTR):
       return luaS_eqlngstr(tsvalue(k1), keystrval(n2));
       return luaS_eqlngstr(tsvalue(k1), keystrval(n2));
     default:
     default:
       return gcvalue(k1) == gcvalueraw(keyval(n2));
       return gcvalue(k1) == gcvalueraw(keyval(n2));
@@ -248,11 +283,12 @@ static unsigned int setlimittosize (Table *t) {
 /*
 /*
 ** "Generic" get version. (Not that generic: not valid for integers,
 ** "Generic" get version. (Not that generic: not valid for integers,
 ** which may be in array part, nor for floats with integral values.)
 ** which may be in array part, nor for floats with integral values.)
+** See explanation about 'deadok' in function 'equalkey'.
 */
 */
-static const TValue *getgeneric (Table *t, const TValue *key) {
+static const TValue *getgeneric (Table *t, const TValue *key, int deadok) {
   Node *n = mainpositionTV(t, key);
   Node *n = mainpositionTV(t, key);
   for (;;) {  /* check whether 'key' is somewhere in the chain */
   for (;;) {  /* check whether 'key' is somewhere in the chain */
-    if (equalkey(key, n))
+    if (equalkey(key, n, deadok))
       return gval(n);  /* that's it */
       return gval(n);  /* that's it */
     else {
     else {
       int nx = gnext(n);
       int nx = gnext(n);
@@ -289,8 +325,8 @@ static unsigned int findindex (lua_State *L, Table *t, TValue *key,
   if (i - 1u < asize)  /* is 'key' inside array part? */
   if (i - 1u < asize)  /* is 'key' inside array part? */
     return i;  /* yes; that's the index */
     return i;  /* yes; that's the index */
   else {
   else {
-    const TValue *n = getgeneric(t, key);
-    if (unlikely(isabstkey(n)))
+    const TValue *n = getgeneric(t, key, 1);
+    if (l_unlikely(isabstkey(n)))
       luaG_runerror(L, "invalid key to 'next'");  /* key not found */
       luaG_runerror(L, "invalid key to 'next'");  /* key not found */
     i = cast_int(nodefromval(n) - gnode(t, 0));  /* key index in hash table */
     i = cast_int(nodefromval(n) - gnode(t, 0));  /* key index in hash table */
     /* hash elements are numbered after array ones */
     /* hash elements are numbered after array ones */
@@ -468,7 +504,7 @@ static void reinsert (lua_State *L, Table *ot, Table *t) {
          already present in the table */
          already present in the table */
       TValue k;
       TValue k;
       getnodekey(L, &k, old);
       getnodekey(L, &k, old);
-      setobjt2t(L, luaH_set(L, t, &k), gval(old));
+      luaH_set(L, t, &k, gval(old));
     }
     }
   }
   }
 }
 }
@@ -524,7 +560,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
   }
   }
   /* allocate new array */
   /* allocate new array */
   newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue);
   newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue);
-  if (unlikely(newarray == NULL && newasize > 0)) {  /* allocation failed? */
+  if (l_unlikely(newarray == NULL && newasize > 0)) {  /* allocation failed? */
     freehash(L, &newt);  /* release new hash part */
     freehash(L, &newt);  /* release new hash part */
     luaM_error(L);  /* raise error (with array unchanged) */
     luaM_error(L);  /* raise error (with array unchanged) */
   }
   }
@@ -577,10 +613,10 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) {
 
 
 
 
 Table *luaH_new (lua_State *L) {
 Table *luaH_new (lua_State *L) {
-  GCObject *o = luaC_newobj(L, LUA_TTABLE, sizeof(Table));
+  GCObject *o = luaC_newobj(L, LUA_VTABLE, sizeof(Table));
   Table *t = gco2t(o);
   Table *t = gco2t(o);
   t->metatable = NULL;
   t->metatable = NULL;
-  t->flags = cast_byte(~0);
+  t->flags = cast_byte(maskflags);  /* table has no metamethod fields */
   t->array = NULL;
   t->array = NULL;
   t->alimit = 0;
   t->alimit = 0;
   setnodevector(L, t, 0);
   setnodevector(L, t, 0);
@@ -615,21 +651,23 @@ static Node *getfreepos (Table *t) {
 ** put new key in its main position; otherwise (colliding node is in its main
 ** put new key in its main position; otherwise (colliding node is in its main
 ** position), new key goes to an empty position.
 ** position), new key goes to an empty position.
 */
 */
-TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
+void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
   Node *mp;
   Node *mp;
   TValue aux;
   TValue aux;
-  if (unlikely(ttisnil(key)))
+  if (l_unlikely(ttisnil(key)))
     luaG_runerror(L, "table index is nil");
     luaG_runerror(L, "table index is nil");
   else if (ttisfloat(key)) {
   else if (ttisfloat(key)) {
     lua_Number f = fltvalue(key);
     lua_Number f = fltvalue(key);
     lua_Integer k;
     lua_Integer k;
-    if (luaV_flttointeger(f, &k, 0)) {  /* does key fit in an integer? */
+    if (luaV_flttointeger(f, &k, F2Ieq)) {  /* does key fit in an integer? */
       setivalue(&aux, k);
       setivalue(&aux, k);
       key = &aux;  /* insert it as an integer */
       key = &aux;  /* insert it as an integer */
     }
     }
-    else if (unlikely(luai_numisnan(f)))
+    else if (l_unlikely(luai_numisnan(f)))
       luaG_runerror(L, "table index is NaN");
       luaG_runerror(L, "table index is NaN");
   }
   }
+  if (ttisnil(value))
+    return;  /* do not insert nil values */
   mp = mainpositionTV(t, key);
   mp = mainpositionTV(t, key);
   if (!isempty(gval(mp)) || isdummy(t)) {  /* main position is taken? */
   if (!isempty(gval(mp)) || isdummy(t)) {  /* main position is taken? */
     Node *othern;
     Node *othern;
@@ -637,7 +675,8 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
     if (f == NULL) {  /* cannot find a free place? */
     if (f == NULL) {  /* cannot find a free place? */
       rehash(L, t, key);  /* grow table */
       rehash(L, t, key);  /* grow table */
       /* whatever called 'newkey' takes care of TM cache */
       /* whatever called 'newkey' takes care of TM cache */
-      return luaH_set(L, t, key);  /* insert key into grown table */
+      luaH_set(L, t, key, value);  /* insert key into grown table */
+      return;
     }
     }
     lua_assert(!isdummy(t));
     lua_assert(!isdummy(t));
     othern = mainposition(t, keytt(mp), &keyval(mp));
     othern = mainposition(t, keytt(mp), &keyval(mp));
@@ -665,7 +704,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
   setnodekey(L, mp, key);
   setnodekey(L, mp, key);
   luaC_barrierback(L, obj2gco(t), key);
   luaC_barrierback(L, obj2gco(t), key);
   lua_assert(isempty(gval(mp)));
   lua_assert(isempty(gval(mp)));
-  return gval(mp);
+  setobj2t(L, gval(mp), value);
 }
 }
 
 
 
 
@@ -707,7 +746,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
 */
 */
 const TValue *luaH_getshortstr (Table *t, TString *key) {
 const TValue *luaH_getshortstr (Table *t, TString *key) {
   Node *n = hashstr(t, key);
   Node *n = hashstr(t, key);
-  lua_assert(key->tt == LUA_TSHRSTR);
+  lua_assert(key->tt == LUA_VSHRSTR);
   for (;;) {  /* check whether 'key' is somewhere in the chain */
   for (;;) {  /* check whether 'key' is somewhere in the chain */
     if (keyisshrstr(n) && eqshrstr(keystrval(n), key))
     if (keyisshrstr(n) && eqshrstr(keystrval(n), key))
       return gval(n);  /* that's it */
       return gval(n);  /* that's it */
@@ -722,12 +761,12 @@ const TValue *luaH_getshortstr (Table *t, TString *key) {
 
 
 
 
 const TValue *luaH_getstr (Table *t, TString *key) {
 const TValue *luaH_getstr (Table *t, TString *key) {
-  if (key->tt == LUA_TSHRSTR)
+  if (key->tt == LUA_VSHRSTR)
     return luaH_getshortstr(t, key);
     return luaH_getshortstr(t, key);
   else {  /* for long strings, use generic case */
   else {  /* for long strings, use generic case */
     TValue ko;
     TValue ko;
     setsvalue(cast(lua_State *, NULL), &ko, key);
     setsvalue(cast(lua_State *, NULL), &ko, key);
-    return getgeneric(t, &ko);
+    return getgeneric(t, &ko, 0);
   }
   }
 }
 }
 
 
@@ -737,44 +776,55 @@ const TValue *luaH_getstr (Table *t, TString *key) {
 */
 */
 const TValue *luaH_get (Table *t, const TValue *key) {
 const TValue *luaH_get (Table *t, const TValue *key) {
   switch (ttypetag(key)) {
   switch (ttypetag(key)) {
-    case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key));
-    case LUA_TNUMINT: return luaH_getint(t, ivalue(key));
-    case LUA_TNIL: return &absentkey;
-    case LUA_TNUMFLT: {
+    case LUA_VSHRSTR: return luaH_getshortstr(t, tsvalue(key));
+    case LUA_VNUMINT: return luaH_getint(t, ivalue(key));
+    case LUA_VNIL: return &absentkey;
+    case LUA_VNUMFLT: {
       lua_Integer k;
       lua_Integer k;
-      if (luaV_flttointeger(fltvalue(key), &k, 0)) /* index is an integral? */
+      if (luaV_flttointeger(fltvalue(key), &k, F2Ieq)) /* integral index? */
         return luaH_getint(t, k);  /* use specialized version */
         return luaH_getint(t, k);  /* use specialized version */
       /* else... */
       /* else... */
     }  /* FALLTHROUGH */
     }  /* FALLTHROUGH */
     default:
     default:
-      return getgeneric(t, key);
+      return getgeneric(t, key, 0);
   }
   }
 }
 }
 
 
 
 
+/*
+** Finish a raw "set table" operation, where 'slot' is where the value
+** should have been (the result of a previous "get table").
+** Beware: when using this function you probably need to check a GC
+** barrier and invalidate the TM cache.
+*/
+void luaH_finishset (lua_State *L, Table *t, const TValue *key,
+                                   const TValue *slot, TValue *value) {
+  if (isabstkey(slot))
+    luaH_newkey(L, t, key, value);
+  else
+    setobj2t(L, cast(TValue *, slot), value);
+}
+
+
 /*
 /*
 ** beware: when using this function you probably need to check a GC
 ** beware: when using this function you probably need to check a GC
 ** barrier and invalidate the TM cache.
 ** barrier and invalidate the TM cache.
 */
 */
-TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
-  const TValue *p = luaH_get(t, key);
-  if (!isabstkey(p))
-    return cast(TValue *, p);
-  else return luaH_newkey(L, t, key);
+void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) {
+  const TValue *slot = luaH_get(t, key);
+  luaH_finishset(L, t, key, slot, value);
 }
 }
 
 
 
 
 void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
 void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
   const TValue *p = luaH_getint(t, key);
   const TValue *p = luaH_getint(t, key);
-  TValue *cell;
-  if (!isabstkey(p))
-    cell = cast(TValue *, p);
-  else {
+  if (isabstkey(p)) {
     TValue k;
     TValue k;
     setivalue(&k, key);
     setivalue(&k, key);
-    cell = luaH_newkey(L, t, &k);
+    luaH_newkey(L, t, &k, value);
   }
   }
-  setobj2t(L, cell, value);
+  else
+    setobj2t(L, cast(TValue *, p), value);
 }
 }
 
 
 
 

+ 13 - 4
src/ltable.h

@@ -15,7 +15,12 @@
 #define gnext(n)	((n)->u.next)
 #define gnext(n)	((n)->u.next)
 
 
 
 
-#define invalidateTMcache(t)	((t)->flags = 0)
+/*
+** Clear all bits of fast-access metamethods, which means that the table
+** may have any of these metamethods. (First access that fails after the
+** clearing will set the bit again.)
+*/
+#define invalidateTMcache(t)	((t)->flags &= ~maskflags)
 
 
 
 
 /* true when 't' is using 'dummynode' as its hash part */
 /* true when 't' is using 'dummynode' as its hash part */
@@ -27,7 +32,7 @@
 
 
 
 
 /* returns the Node, given the value of a table entry */
 /* returns the Node, given the value of a table entry */
-#define nodefromval(v) 	cast(Node *, (v))
+#define nodefromval(v)	cast(Node *, (v))
 
 
 
 
 LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
 LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
@@ -36,8 +41,12 @@ LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
 LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
 LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
 LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
 LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
 LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
 LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
-LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key);
-LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key);
+LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key,
+                                                    TValue *value);
+LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key,
+                                                 TValue *value);
+LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key,
+                                       const TValue *slot, TValue *value);
 LUAI_FUNC Table *luaH_new (lua_State *L);
 LUAI_FUNC Table *luaH_new (lua_State *L);
 LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
 LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
                                                     unsigned int nhsize);
                                                     unsigned int nhsize);

+ 6 - 5
src/ltablib.c

@@ -145,8 +145,8 @@ static int tmove (lua_State *L) {
 
 
 static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
 static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
   lua_geti(L, 1, i);
   lua_geti(L, 1, i);
-  if (!lua_isstring(L, -1))
-    luaL_error(L, "invalid value (%s) at index %d in table for 'concat'",
+  if (l_unlikely(!lua_isstring(L, -1)))
+    luaL_error(L, "invalid value (%s) at index %I in table for 'concat'",
                   luaL_typename(L, -1), i);
                   luaL_typename(L, -1), i);
   luaL_addvalue(b);
   luaL_addvalue(b);
 }
 }
@@ -196,7 +196,8 @@ static int tunpack (lua_State *L) {
   lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
   lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
   if (i > e) return 0;  /* empty range */
   if (i > e) return 0;  /* empty range */
   n = (lua_Unsigned)e - i;  /* number of elements minus 1 (avoid overflows) */
   n = (lua_Unsigned)e - i;  /* number of elements minus 1 (avoid overflows) */
-  if (n >= (unsigned int)INT_MAX  || !lua_checkstack(L, (int)(++n)))
+  if (l_unlikely(n >= (unsigned int)INT_MAX  ||
+                 !lua_checkstack(L, (int)(++n))))
     return luaL_error(L, "too many results to unpack");
     return luaL_error(L, "too many results to unpack");
   for (; i < e; i++) {  /* push arg[i..e - 1] (to avoid overflows) */
   for (; i < e; i++) {  /* push arg[i..e - 1] (to avoid overflows) */
     lua_geti(L, 1, i);
     lua_geti(L, 1, i);
@@ -300,14 +301,14 @@ static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
   for (;;) {
   for (;;) {
     /* next loop: repeat ++i while a[i] < P */
     /* next loop: repeat ++i while a[i] < P */
     while ((void)lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {
     while ((void)lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {
-      if (i == up - 1)  /* a[i] < P  but a[up - 1] == P  ?? */
+      if (l_unlikely(i == up - 1))  /* a[i] < P  but a[up - 1] == P  ?? */
         luaL_error(L, "invalid order function for sorting");
         luaL_error(L, "invalid order function for sorting");
       lua_pop(L, 1);  /* remove a[i] */
       lua_pop(L, 1);  /* remove a[i] */
     }
     }
     /* after the loop, a[i] >= P and a[lo .. i - 1] < P */
     /* after the loop, a[i] >= P and a[lo .. i - 1] < P */
     /* next loop: repeat --j while P < a[j] */
     /* next loop: repeat --j while P < a[j] */
     while ((void)lua_geti(L, 1, --j), sort_comp(L, -3, -1)) {
     while ((void)lua_geti(L, 1, --j), sort_comp(L, -3, -1)) {
-      if (j < i)  /* j < i  but  a[j] > P ?? */
+      if (l_unlikely(j < i))  /* j < i  but  a[j] > P ?? */
         luaL_error(L, "invalid order function for sorting");
         luaL_error(L, "invalid order function for sorting");
       lua_pop(L, 1);  /* remove a[j] */
       lua_pop(L, 1);  /* remove a[j] */
     }
     }

+ 15 - 5
src/ltm.c

@@ -27,7 +27,7 @@
 
 
 static const char udatatypename[] = "userdata";
 static const char udatatypename[] = "userdata";
 
 
-LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = {
+LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTYPES] = {
   "no value",
   "no value",
   "nil", "boolean", udatatypename, "number",
   "nil", "boolean", udatatypename, "number",
   "string", "table", "function", udatatypename, "thread",
   "string", "table", "function", udatatypename, "thread",
@@ -147,7 +147,7 @@ static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2,
 
 
 void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
 void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
                     StkId res, TMS event) {
                     StkId res, TMS event) {
-  if (!callbinTM(L, p1, p2, res, event)) {
+  if (l_unlikely(!callbinTM(L, p1, p2, res, event))) {
     switch (event) {
     switch (event) {
       case TM_BAND: case TM_BOR: case TM_BXOR:
       case TM_BAND: case TM_BOR: case TM_BXOR:
       case TM_SHL: case TM_SHR: case TM_BNOT: {
       case TM_SHL: case TM_SHR: case TM_BNOT: {
@@ -166,7 +166,8 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
 
 
 void luaT_tryconcatTM (lua_State *L) {
 void luaT_tryconcatTM (lua_State *L) {
   StkId top = L->top;
   StkId top = L->top;
-  if (!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2, TM_CONCAT))
+  if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
+                               TM_CONCAT)))
     luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
     luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
 }
 }
 
 
@@ -188,6 +189,15 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
 }
 }
 
 
 
 
+/*
+** Calls an order tag method.
+** For lessequal, LUA_COMPAT_LT_LE keeps compatibility with old
+** behavior: if there is no '__le', try '__lt', based on l <= r iff
+** !(r < l) (assuming a total order). If the metamethod yields during
+** this substitution, the continuation has to know about it (to negate
+** the result of r<l); bit CIST_LEQ in the call status keeps that
+** information.
+*/
 int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
 int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
                       TMS event) {
                       TMS event) {
   if (callbinTM(L, p1, p2, L->top, event))  /* try original event */
   if (callbinTM(L, p1, p2, L->top, event))  /* try original event */
@@ -231,7 +241,7 @@ void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
   int actual = cast_int(L->top - ci->func) - 1;  /* number of arguments */
   int actual = cast_int(L->top - ci->func) - 1;  /* number of arguments */
   int nextra = actual - nfixparams;  /* number of extra arguments */
   int nextra = actual - nfixparams;  /* number of extra arguments */
   ci->u.l.nextraargs = nextra;
   ci->u.l.nextraargs = nextra;
-  checkstackGC(L, p->maxstacksize + 1);
+  luaD_checkstack(L, p->maxstacksize + 1);
   /* copy function to the top of the stack */
   /* copy function to the top of the stack */
   setobjs2s(L, L->top++, ci->func);
   setobjs2s(L, L->top++, ci->func);
   /* move fixed parameters to the top of the stack */
   /* move fixed parameters to the top of the stack */
@@ -250,7 +260,7 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
   int nextra = ci->u.l.nextraargs;
   int nextra = ci->u.l.nextraargs;
   if (wanted < 0) {
   if (wanted < 0) {
     wanted = nextra;  /* get all extra arguments available */
     wanted = nextra;  /* get all extra arguments available */
-    checkstackp(L, nextra, where);  /* ensure stack space */
+    checkstackGCp(L, nextra, where);  /* ensure stack space */
     L->top = where + nextra;  /* next instruction will need top */
     L->top = where + nextra;  /* next instruction will need top */
   }
   }
   for (i = 0; i < wanted && i < nextra; i++)
   for (i = 0; i < wanted && i < nextra; i++)

+ 10 - 1
src/ltm.h

@@ -45,6 +45,15 @@ typedef enum {
 } TMS;
 } TMS;
 
 
 
 
+/*
+** Mask with 1 in all fast-access methods. A 1 in any of these bits
+** in the flag of a (meta)table means the metatable does not have the
+** corresponding metamethod field. (Bit 7 of the flag is used for
+** 'isrealasize'.)
+*/
+#define maskflags	(~(~0u << (TM_EQ + 1)))
+
+
 /*
 /*
 ** Test whether there is no tagmethod.
 ** Test whether there is no tagmethod.
 ** (Because tagmethods use raw accesses, the result may be an "empty" nil.)
 ** (Because tagmethods use raw accesses, the result may be an "empty" nil.)
@@ -59,7 +68,7 @@ typedef enum {
 
 
 #define ttypename(x)	luaT_typenames_[(x) + 1]
 #define ttypename(x)	luaT_typenames_[(x) + 1]
 
 
-LUAI_DDEC(const char *const luaT_typenames_[LUA_TOTALTAGS];)
+LUAI_DDEC(const char *const luaT_typenames_[LUA_TOTALTYPES];)
 
 
 
 
 LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o);
 LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o);

+ 35 - 10
src/lua.c

@@ -37,6 +37,26 @@ static lua_State *globalL = NULL;
 static const char *progname = LUA_PROGNAME;
 static const char *progname = LUA_PROGNAME;
 
 
 
 
+#if defined(LUA_USE_POSIX)   /* { */
+
+/*
+** Use 'sigaction' when available.
+*/
+static void setsignal (int sig, void (*handler)(int)) {
+  struct sigaction sa;
+  sa.sa_handler = handler;
+  sa.sa_flags = 0;
+  sigemptyset(&sa.sa_mask);  /* do not mask any signal */
+  sigaction(sig, &sa, NULL);
+}
+
+#else           /* }{ */
+
+#define setsignal            signal
+
+#endif                               /* } */
+
+
 /*
 /*
 ** Hook set by signal function to stop the interpreter.
 ** Hook set by signal function to stop the interpreter.
 */
 */
@@ -54,8 +74,9 @@ static void lstop (lua_State *L, lua_Debug *ar) {
 ** interpreter.
 ** interpreter.
 */
 */
 static void laction (int i) {
 static void laction (int i) {
-  signal(i, SIG_DFL); /* if another SIGINT happens, terminate process */
-  lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
+  int flag = LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT;
+  setsignal(i, SIG_DFL); /* if another SIGINT happens, terminate process */
+  lua_sethook(globalL, lstop, flag, 1);
 }
 }
 
 
 
 
@@ -134,9 +155,9 @@ static int docall (lua_State *L, int narg, int nres) {
   lua_pushcfunction(L, msghandler);  /* push message handler */
   lua_pushcfunction(L, msghandler);  /* push message handler */
   lua_insert(L, base);  /* put it under function and args */
   lua_insert(L, base);  /* put it under function and args */
   globalL = L;  /* to be available to 'laction' */
   globalL = L;  /* to be available to 'laction' */
-  signal(SIGINT, laction);  /* set C-signal handler */
+  setsignal(SIGINT, laction);  /* set C-signal handler */
   status = lua_pcall(L, narg, nres, base);
   status = lua_pcall(L, narg, nres, base);
-  signal(SIGINT, SIG_DFL); /* reset C-signal handler */
+  setsignal(SIGINT, SIG_DFL); /* reset C-signal handler */
   lua_remove(L, base);  /* remove message handler from the stack */
   lua_remove(L, base);  /* remove message handler from the stack */
   return status;
   return status;
 }
 }
@@ -415,14 +436,18 @@ static int handle_luainit (lua_State *L) {
 
 
 
 
 /*
 /*
-** Returns the string to be used as a prompt by the interpreter.
+** Return the string to be used as a prompt by the interpreter. Leave
+** the string (or nil, if using the default value) on the stack, to keep
+** it anchored.
 */
 */
 static const char *get_prompt (lua_State *L, int firstline) {
 static const char *get_prompt (lua_State *L, int firstline) {
-  const char *p;
-  lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2");
-  p = lua_tostring(L, -1);
-  if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
-  return p;
+  if (lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2") == LUA_TNIL)
+    return (firstline ? LUA_PROMPT : LUA_PROMPT2);  /* use the default */
+  else {  /* apply 'tostring' over the value */
+    const char *p = luaL_tolstring(L, -1, NULL);
+    lua_remove(L, -2);  /* remove original value */
+    return p;
+  }
 }
 }
 
 
 /* mark in error messages for incomplete statements */
 /* mark in error messages for incomplete statements */

+ 8 - 5
src/lua.h

@@ -18,14 +18,14 @@
 
 
 #define LUA_VERSION_MAJOR	"5"
 #define LUA_VERSION_MAJOR	"5"
 #define LUA_VERSION_MINOR	"4"
 #define LUA_VERSION_MINOR	"4"
-#define LUA_VERSION_RELEASE	"0"
+#define LUA_VERSION_RELEASE	"3"
 
 
 #define LUA_VERSION_NUM			504
 #define LUA_VERSION_NUM			504
 #define LUA_VERSION_RELEASE_NUM		(LUA_VERSION_NUM * 100 + 0)
 #define LUA_VERSION_RELEASE_NUM		(LUA_VERSION_NUM * 100 + 0)
 
 
 #define LUA_VERSION	"Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
 #define LUA_VERSION	"Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
 #define LUA_RELEASE	LUA_VERSION "." LUA_VERSION_RELEASE
 #define LUA_RELEASE	LUA_VERSION "." LUA_VERSION_RELEASE
-#define LUA_COPYRIGHT	LUA_RELEASE "  Copyright (C) 1994-2019 Lua.org, PUC-Rio"
+#define LUA_COPYRIGHT	LUA_RELEASE "  Copyright (C) 1994-2021 Lua.org, PUC-Rio"
 #define LUA_AUTHORS	"R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
 #define LUA_AUTHORS	"R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
 
 
 
 
@@ -72,7 +72,7 @@ typedef struct lua_State lua_State;
 #define LUA_TUSERDATA		7
 #define LUA_TUSERDATA		7
 #define LUA_TTHREAD		8
 #define LUA_TTHREAD		8
 
 
-#define LUA_NUMTAGS		9
+#define LUA_NUMTYPES		9
 
 
 
 
 
 
@@ -347,7 +347,8 @@ LUA_API size_t   (lua_stringtonumber) (lua_State *L, const char *s);
 LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
 LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
 LUA_API void      (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
 LUA_API void      (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
 
 
-LUA_API void  (lua_toclose) (lua_State *L, int idx);
+LUA_API void (lua_toclose) (lua_State *L, int idx);
+LUA_API void (lua_closeslot) (lua_State *L, int idx);
 
 
 
 
 /*
 /*
@@ -412,6 +413,8 @@ LUA_API void  (lua_toclose) (lua_State *L, int idx);
 #define lua_getuservalue(L,idx)	lua_getiuservalue(L,idx,1)
 #define lua_getuservalue(L,idx)	lua_getiuservalue(L,idx,1)
 #define lua_setuservalue(L,idx)	lua_setiuservalue(L,idx,1)
 #define lua_setuservalue(L,idx)	lua_setiuservalue(L,idx,1)
 
 
+#define LUA_NUMTAGS		LUA_NUMTYPES
+
 /* }============================================================== */
 /* }============================================================== */
 
 
 /*
 /*
@@ -489,7 +492,7 @@ struct lua_Debug {
 
 
 
 
 /******************************************************************************
 /******************************************************************************
-* Copyright (C) 1994-2019 Lua.org, PUC-Rio.
+* Copyright (C) 1994-2021 Lua.org, PUC-Rio.
 *
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * a copy of this software and associated documentation files (the

+ 50 - 34
src/luac.c

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $
+** $Id: luac.c $
 ** Lua compiler (saves bytecodes to files; also lists bytecodes)
 ** Lua compiler (saves bytecodes to files; also lists bytecodes)
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -268,21 +268,22 @@ static void PrintType(const Proto* f, int i)
  const TValue* o=&f->k[i];
  const TValue* o=&f->k[i];
  switch (ttypetag(o))
  switch (ttypetag(o))
  {
  {
-  case LUA_TNIL:
-  	printf("N");
+  case LUA_VNIL:
+	printf("N");
 	break;
 	break;
-  case LUA_TBOOLEAN:
-  	printf("B");
+  case LUA_VFALSE:
+  case LUA_VTRUE:
+	printf("B");
 	break;
 	break;
-  case LUA_TNUMFLT:
-  	printf("F");
+  case LUA_VNUMFLT:
+	printf("F");
 	break;
 	break;
-  case LUA_TNUMINT:
-  	printf("I");
+  case LUA_VNUMINT:
+	printf("I");
 	break;
 	break;
-  case LUA_TSHRSTR:
-  case LUA_TLNGSTR:
-  	printf("S");
+  case LUA_VSHRSTR:
+  case LUA_VLNGSTR:
+	printf("S");
 	break;
 	break;
   default:				/* cannot happen */
   default:				/* cannot happen */
 	printf("?%d",ttypetag(o));
 	printf("?%d",ttypetag(o));
@@ -296,13 +297,16 @@ static void PrintConstant(const Proto* f, int i)
  const TValue* o=&f->k[i];
  const TValue* o=&f->k[i];
  switch (ttypetag(o))
  switch (ttypetag(o))
  {
  {
-  case LUA_TNIL:
+  case LUA_VNIL:
 	printf("nil");
 	printf("nil");
 	break;
 	break;
-  case LUA_TBOOLEAN:
-	printf(bvalue(o) ? "true" : "false");
+  case LUA_VFALSE:
+	printf("false");
 	break;
 	break;
-  case LUA_TNUMFLT:
+  case LUA_VTRUE:
+	printf("true");
+	break;
+  case LUA_VNUMFLT:
 	{
 	{
 	char buff[100];
 	char buff[100];
 	sprintf(buff,LUA_NUMBER_FMT,fltvalue(o));
 	sprintf(buff,LUA_NUMBER_FMT,fltvalue(o));
@@ -310,11 +314,11 @@ static void PrintConstant(const Proto* f, int i)
 	if (buff[strspn(buff,"-0123456789")]=='\0') printf(".0");
 	if (buff[strspn(buff,"-0123456789")]=='\0') printf(".0");
 	break;
 	break;
 	}
 	}
-  case LUA_TNUMINT:
+  case LUA_VNUMINT:
 	printf(LUA_INTEGER_FMT,ivalue(o));
 	printf(LUA_INTEGER_FMT,ivalue(o));
 	break;
 	break;
-  case LUA_TSHRSTR:
-  case LUA_TLNGSTR:
+  case LUA_VSHRSTR:
+  case LUA_VLNGSTR:
 	PrintString(tsvalue(o));
 	PrintString(tsvalue(o));
 	break;
 	break;
   default:				/* cannot happen */
   default:				/* cannot happen */
@@ -323,7 +327,10 @@ static void PrintConstant(const Proto* f, int i)
  }
  }
 }
 }
 
 
-#define COMMENT	"\t; "
+#define COMMENT		"\t; "
+#define EXTRAARG	GETARG_Ax(code[pc+1])
+#define EXTRAARGC	(EXTRAARG*(MAXARG_C+1))
+#define ISK		(isk ? "k" : "")
 
 
 static void PrintCode(const Proto* f)
 static void PrintCode(const Proto* f)
 {
 {
@@ -363,10 +370,16 @@ static void PrintCode(const Proto* f)
 	break;
 	break;
    case OP_LOADKX:
    case OP_LOADKX:
 	printf("%d",a);
 	printf("%d",a);
+	printf(COMMENT); PrintConstant(f,EXTRAARG);
 	break;
 	break;
-   case OP_LOADBOOL:
-	printf("%d %d %d",a,b,c);
-	if (c) printf(COMMENT "to %d",pc+2);
+   case OP_LOADFALSE:
+	printf("%d",a);
+	break;
+   case OP_LFALSESKIP:
+	printf("%d",a);
+	break;
+   case OP_LOADTRUE:
+	printf("%d",a);
 	break;
 	break;
    case OP_LOADNIL:
    case OP_LOADNIL:
 	printf("%d %d",a,b);
 	printf("%d %d",a,b);
@@ -396,36 +409,37 @@ static void PrintCode(const Proto* f)
 	printf(COMMENT); PrintConstant(f,c);
 	printf(COMMENT); PrintConstant(f,c);
 	break;
 	break;
    case OP_SETTABUP:
    case OP_SETTABUP:
-	printf("%d %d %d%s",a,b,c, isk ? "k" : "");
+	printf("%d %d %d%s",a,b,c,ISK);
 	printf(COMMENT "%s",UPVALNAME(a));
 	printf(COMMENT "%s",UPVALNAME(a));
 	printf(" "); PrintConstant(f,b);
 	printf(" "); PrintConstant(f,b);
 	if (isk) { printf(" "); PrintConstant(f,c); }
 	if (isk) { printf(" "); PrintConstant(f,c); }
 	break;
 	break;
    case OP_SETTABLE:
    case OP_SETTABLE:
-	printf("%d %d %d%s",a,b,c, isk ? "k" : "");
+	printf("%d %d %d%s",a,b,c,ISK);
 	if (isk) { printf(COMMENT); PrintConstant(f,c); }
 	if (isk) { printf(COMMENT); PrintConstant(f,c); }
 	break;
 	break;
    case OP_SETI:
    case OP_SETI:
-	printf("%d %d %d%s",a,b,c, isk ? "k" : "");
+	printf("%d %d %d%s",a,b,c,ISK);
 	if (isk) { printf(COMMENT); PrintConstant(f,c); }
 	if (isk) { printf(COMMENT); PrintConstant(f,c); }
 	break;
 	break;
    case OP_SETFIELD:
    case OP_SETFIELD:
-	printf("%d %d %d%s",a,b,c, isk ? "k" : "");
+	printf("%d %d %d%s",a,b,c,ISK);
 	printf(COMMENT); PrintConstant(f,b);
 	printf(COMMENT); PrintConstant(f,b);
 	if (isk) { printf(" "); PrintConstant(f,c); }
 	if (isk) { printf(" "); PrintConstant(f,c); }
 	break;
 	break;
    case OP_NEWTABLE:
    case OP_NEWTABLE:
 	printf("%d %d %d",a,b,c);
 	printf("%d %d %d",a,b,c);
+	printf(COMMENT "%d",c+EXTRAARGC);
 	break;
 	break;
    case OP_SELF:
    case OP_SELF:
-	printf("%d %d %d%s",a,b,c, isk ? "k" : "");
+	printf("%d %d %d%s",a,b,c,ISK);
 	if (isk) { printf(COMMENT); PrintConstant(f,c); }
 	if (isk) { printf(COMMENT); PrintConstant(f,c); }
 	break;
 	break;
    case OP_ADDI:
    case OP_ADDI:
-	printf("%d %d %d %s",a,b,sc,isk ? "F" : "");
+	printf("%d %d %d",a,b,sc);
 	break;
 	break;
    case OP_ADDK:
    case OP_ADDK:
-	printf("%d %d %d %s",a,b,c,isk ? "F" : "");
+	printf("%d %d %d",a,b,c);
 	printf(COMMENT); PrintConstant(f,c);
 	printf(COMMENT); PrintConstant(f,c);
 	break;
 	break;
    case OP_SUBK:
    case OP_SUBK:
@@ -433,7 +447,7 @@ static void PrintCode(const Proto* f)
 	printf(COMMENT); PrintConstant(f,c);
 	printf(COMMENT); PrintConstant(f,c);
 	break;
 	break;
    case OP_MULK:
    case OP_MULK:
-	printf("%d %d %d %s",a,b,c,isk ? "F" : "");
+	printf("%d %d %d",a,b,c);
 	printf(COMMENT); PrintConstant(f,c);
 	printf(COMMENT); PrintConstant(f,c);
 	break;
 	break;
    case OP_MODK:
    case OP_MODK:
@@ -511,12 +525,14 @@ static void PrintCode(const Proto* f)
 	printf(COMMENT "%s",eventname(c));
 	printf(COMMENT "%s",eventname(c));
 	break;
 	break;
    case OP_MMBINI:
    case OP_MMBINI:
-	printf("%d %d %d",a,sb,c);
+	printf("%d %d %d %d",a,sb,c,isk);
 	printf(COMMENT "%s",eventname(c));
 	printf(COMMENT "%s",eventname(c));
+	if (isk) printf(" flip");
 	break;
 	break;
    case OP_MMBINK:
    case OP_MMBINK:
-	printf("%d %d %d",a,b,c);
+	printf("%d %d %d %d",a,b,c,isk);
 	printf(COMMENT "%s ",eventname(c)); PrintConstant(f,b);
 	printf(COMMENT "%s ",eventname(c)); PrintConstant(f,b);
+	if (isk) printf(" flip");
 	break;
 	break;
    case OP_UNM:
    case OP_UNM:
 	printf("%d %d",a,b);
 	printf("%d %d",a,b);
@@ -618,6 +634,7 @@ static void PrintCode(const Proto* f)
 	break;
 	break;
    case OP_SETLIST:
    case OP_SETLIST:
 	printf("%d %d %d",a,b,c);
 	printf("%d %d %d",a,b,c);
+	if (isk) printf(COMMENT "%d",c+EXTRAARGC);
 	break;
 	break;
    case OP_CLOSURE:
    case OP_CLOSURE:
 	printf("%d %d",a,bx);
 	printf("%d %d",a,bx);
@@ -633,7 +650,6 @@ static void PrintCode(const Proto* f)
 	break;
 	break;
    case OP_EXTRAARG:
    case OP_EXTRAARG:
 	printf("%d",ax);
 	printf("%d",ax);
-	printf(COMMENT); PrintConstant(f,ax);
 	break;
 	break;
 #if 0
 #if 0
    default:
    default:

+ 79 - 62
src/luaconf.h

@@ -16,13 +16,13 @@
 ** ===================================================================
 ** ===================================================================
 ** General Configuration File for Lua
 ** General Configuration File for Lua
 **
 **
-** Some definitions here can be changed externally, through the
-** compiler (e.g., with '-D' options). Those are protected by
-** '#if !defined' guards. However, several other definitions should
-** be changed directly here, either because they affect the Lua
-** ABI (by making the changes here, you ensure that all software
-** connected to Lua, such as C libraries, will be compiled with the
-** same configuration); or because they are seldom changed.
+** Some definitions here can be changed externally, through the compiler
+** (e.g., with '-D' options): They are commented out or protected
+** by '#if !defined' guards. However, several other definitions
+** should be changed directly here, either because they affect the
+** Lua ABI (by making the changes here, you ensure that all software
+** connected to Lua, such as C libraries, will be compiled with the same
+** configuration); or because they are seldom changed.
 **
 **
 ** Search for "@@" to find all configurable definitions.
 ** Search for "@@" to find all configurable definitions.
 ** ===================================================================
 ** ===================================================================
@@ -36,21 +36,6 @@
 ** =====================================================================
 ** =====================================================================
 */
 */
 
 
-/*
-@@ LUAI_MAXCSTACK defines the maximum depth for nested calls and
-** also limits the maximum depth of other recursive algorithms in
-** the implementation, such as syntactic analysis. A value too
-** large may allow the interpreter to crash (C-stack overflow).
-** The default value seems ok for regular machines, but may be
-** too high for restricted hardware.
-** The test file 'cstack.lua' may help finding a good limit.
-** (It will crash with a limit too high.)
-*/
-#if !defined(LUAI_MAXCSTACK)
-#define LUAI_MAXCSTACK		2000
-#endif
-
-
 /*
 /*
 @@ LUA_USE_C89 controls the use of non-ISO-C89 features.
 @@ LUA_USE_C89 controls the use of non-ISO-C89 features.
 ** Define it if you want Lua to avoid the use of a few C99 features
 ** Define it if you want Lua to avoid the use of a few C99 features
@@ -96,26 +81,12 @@
 
 
 /*
 /*
 ** {==================================================================
 ** {==================================================================
-** Configuration for Number types.
+** Configuration for Number types. These options should not be
+** set externally, because any other code connected to Lua must
+** use the same configuration.
 ** ===================================================================
 ** ===================================================================
 */
 */
 
 
-/*
-@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats.
-*/
-/* #define LUA_32BITS */
-
-
-/*
-@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for
-** C89 ('long' and 'double'); Windows always has '__int64', so it does
-** not need to use this case.
-*/
-#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)
-#define LUA_C89_NUMBERS
-#endif
-
-
 /*
 /*
 @@ LUA_INT_TYPE defines the type for Lua integers.
 @@ LUA_INT_TYPE defines the type for Lua integers.
 @@ LUA_FLOAT_TYPE defines the type for Lua floats.
 @@ LUA_FLOAT_TYPE defines the type for Lua floats.
@@ -136,7 +107,31 @@
 #define LUA_FLOAT_DOUBLE	2
 #define LUA_FLOAT_DOUBLE	2
 #define LUA_FLOAT_LONGDOUBLE	3
 #define LUA_FLOAT_LONGDOUBLE	3
 
 
-#if defined(LUA_32BITS)		/* { */
+
+/* Default configuration ('long long' and 'double', for 64-bit Lua) */
+#define LUA_INT_DEFAULT		LUA_INT_LONGLONG
+#define LUA_FLOAT_DEFAULT	LUA_FLOAT_DOUBLE
+
+
+/*
+@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats.
+*/
+#define LUA_32BITS	0
+
+
+/*
+@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for
+** C89 ('long' and 'double'); Windows always has '__int64', so it does
+** not need to use this case.
+*/
+#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)
+#define LUA_C89_NUMBERS		1
+#else
+#define LUA_C89_NUMBERS		0
+#endif
+
+
+#if LUA_32BITS		/* { */
 /*
 /*
 ** 32-bit integers and 'float'
 ** 32-bit integers and 'float'
 */
 */
@@ -147,26 +142,21 @@
 #endif
 #endif
 #define LUA_FLOAT_TYPE	LUA_FLOAT_FLOAT
 #define LUA_FLOAT_TYPE	LUA_FLOAT_FLOAT
 
 
-#elif defined(LUA_C89_NUMBERS)	/* }{ */
+#elif LUA_C89_NUMBERS	/* }{ */
 /*
 /*
 ** largest types available for C89 ('long' and 'double')
 ** largest types available for C89 ('long' and 'double')
 */
 */
 #define LUA_INT_TYPE	LUA_INT_LONG
 #define LUA_INT_TYPE	LUA_INT_LONG
 #define LUA_FLOAT_TYPE	LUA_FLOAT_DOUBLE
 #define LUA_FLOAT_TYPE	LUA_FLOAT_DOUBLE
 
 
-#endif				/* } */
+#else		/* }{ */
+/* use defaults */
 
 
+#define LUA_INT_TYPE	LUA_INT_DEFAULT
+#define LUA_FLOAT_TYPE	LUA_FLOAT_DEFAULT
 
 
-/*
-** default configuration for 64-bit Lua ('long long' and 'double')
-*/
-#if !defined(LUA_INT_TYPE)
-#define LUA_INT_TYPE	LUA_INT_LONGLONG
-#endif
+#endif				/* } */
 
 
-#if !defined(LUA_FLOAT_TYPE)
-#define LUA_FLOAT_TYPE	LUA_FLOAT_DOUBLE
-#endif
 
 
 /* }================================================================== */
 /* }================================================================== */
 
 
@@ -315,9 +305,12 @@
 ** give a warning about it. To avoid these warnings, change to the
 ** give a warning about it. To avoid these warnings, change to the
 ** default definition.
 ** default definition.
 */
 */
-
-/* AOT: export all internal APIs */
+#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
+    defined(__ELF__)		/* { */
+#define LUAI_FUNC	__attribute__((visibility("internal"))) extern
+#else				/* }{ */
 #define LUAI_FUNC	extern
 #define LUAI_FUNC	extern
+#endif				/* } */
 
 
 #define LUAI_DDEC(dec)	LUAI_FUNC dec
 #define LUAI_DDEC(dec)	LUAI_FUNC dec
 #define LUAI_DDEF	/* empty */
 #define LUAI_DDEF	/* empty */
@@ -385,17 +378,16 @@
 
 
 /*
 /*
 ** {==================================================================
 ** {==================================================================
-** Configuration for Numbers.
+** Configuration for Numbers (low-level part).
 ** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
 ** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
 ** satisfy your needs.
 ** satisfy your needs.
 ** ===================================================================
 ** ===================================================================
 */
 */
 
 
 /*
 /*
-@@ LUA_NUMBER is the floating-point type used by Lua.
 @@ LUAI_UACNUMBER is the result of a 'default argument promotion'
 @@ LUAI_UACNUMBER is the result of a 'default argument promotion'
 @@ over a floating number.
 @@ over a floating number.
-@@ l_mathlim(x) corrects limit name 'x' to the proper float type
+@@ l_floatatt(x) corrects float attribute 'x' to the proper float type
 ** by prefixing it with one of FLT/DBL/LDBL.
 ** by prefixing it with one of FLT/DBL/LDBL.
 @@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
 @@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
 @@ LUA_NUMBER_FMT is the format for writing floats.
 @@ LUA_NUMBER_FMT is the format for writing floats.
@@ -434,7 +426,7 @@
 
 
 #define LUA_NUMBER	float
 #define LUA_NUMBER	float
 
 
-#define l_mathlim(n)		(FLT_##n)
+#define l_floatatt(n)		(FLT_##n)
 
 
 #define LUAI_UACNUMBER	double
 #define LUAI_UACNUMBER	double
 
 
@@ -450,7 +442,7 @@
 
 
 #define LUA_NUMBER	long double
 #define LUA_NUMBER	long double
 
 
-#define l_mathlim(n)		(LDBL_##n)
+#define l_floatatt(n)		(LDBL_##n)
 
 
 #define LUAI_UACNUMBER	long double
 #define LUAI_UACNUMBER	long double
 
 
@@ -465,7 +457,7 @@
 
 
 #define LUA_NUMBER	double
 #define LUA_NUMBER	double
 
 
-#define l_mathlim(n)		(DBL_##n)
+#define l_floatatt(n)		(DBL_##n)
 
 
 #define LUAI_UACNUMBER	double
 #define LUAI_UACNUMBER	double
 
 
@@ -485,10 +477,7 @@
 
 
 
 
 /*
 /*
-@@ LUA_INTEGER is the integer type used by Lua.
-**
 @@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
 @@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
-**
 @@ LUAI_UACINT is the result of a 'default argument promotion'
 @@ LUAI_UACINT is the result of a 'default argument promotion'
 @@ over a LUA_INTEGER.
 @@ over a LUA_INTEGER.
 @@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
 @@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
@@ -671,6 +660,34 @@
 #define lua_getlocaledecpoint()		(localeconv()->decimal_point[0])
 #define lua_getlocaledecpoint()		(localeconv()->decimal_point[0])
 #endif
 #endif
 
 
+
+/*
+** macros to improve jump prediction, used mostly for error handling
+** and debug facilities. (Some macros in the Lua API use these macros.
+** Define LUA_NOBUILTIN if you do not want '__builtin_expect' in your
+** code.)
+*/
+#if !defined(luai_likely)
+
+#if defined(__GNUC__) && !defined(LUA_NOBUILTIN)
+#define luai_likely(x)		(__builtin_expect(((x) != 0), 1))
+#define luai_unlikely(x)	(__builtin_expect(((x) != 0), 0))
+#else
+#define luai_likely(x)		(x)
+#define luai_unlikely(x)	(x)
+#endif
+
+#endif
+
+
+#if defined(LUA_CORE) || defined(LUA_LIB)
+/* shorter names for Lua's own use */
+#define l_likely(x)	luai_likely(x)
+#define l_unlikely(x)	luai_unlikely(x)
+#endif
+
+
+
 /* }================================================================== */
 /* }================================================================== */
 
 
 
 

+ 0 - 6
src/lualib.h

@@ -49,10 +49,4 @@ LUAMOD_API int (luaopen_package) (lua_State *L);
 LUALIB_API void (luaL_openlibs) (lua_State *L);
 LUALIB_API void (luaL_openlibs) (lua_State *L);
 
 
 
 
-
-#if !defined(lua_assert)
-#define lua_assert(x)	((void)0)
-#endif
-
-
 #endif
 #endif

+ 106 - 88
src/lundump.c

@@ -26,7 +26,7 @@
 
 
 
 
 #if !defined(luai_verifycode)
 #if !defined(luai_verifycode)
-#define luai_verifycode(L,b,f)  /* empty */
+#define luai_verifycode(L,f)  /* empty */
 #endif
 #endif
 
 
 
 
@@ -44,21 +44,21 @@ static l_noret error (LoadState *S, const char *why) {
 
 
 
 
 /*
 /*
-** All high-level loads go through LoadVector; you can change it to
+** All high-level loads go through loadVector; you can change it to
 ** adapt to the endianness of the input
 ** adapt to the endianness of the input
 */
 */
-#define LoadVector(S,b,n)	LoadBlock(S,b,(n)*sizeof((b)[0]))
+#define loadVector(S,b,n)	loadBlock(S,b,(n)*sizeof((b)[0]))
 
 
-static void LoadBlock (LoadState *S, void *b, size_t size) {
+static void loadBlock (LoadState *S, void *b, size_t size) {
   if (luaZ_read(S->Z, b, size) != 0)
   if (luaZ_read(S->Z, b, size) != 0)
     error(S, "truncated chunk");
     error(S, "truncated chunk");
 }
 }
 
 
 
 
-#define LoadVar(S,x)		LoadVector(S,&x,1)
+#define loadVar(S,x)		loadVector(S,&x,1)
 
 
 
 
-static lu_byte LoadByte (LoadState *S) {
+static lu_byte loadByte (LoadState *S) {
   int b = zgetc(S->Z);
   int b = zgetc(S->Z);
   if (b == EOZ)
   if (b == EOZ)
     error(S, "truncated chunk");
     error(S, "truncated chunk");
@@ -66,12 +66,12 @@ static lu_byte LoadByte (LoadState *S) {
 }
 }
 
 
 
 
-static size_t LoadUnsigned (LoadState *S, size_t limit) {
+static size_t loadUnsigned (LoadState *S, size_t limit) {
   size_t x = 0;
   size_t x = 0;
   int b;
   int b;
   limit >>= 7;
   limit >>= 7;
   do {
   do {
-    b = LoadByte(S);
+    b = loadByte(S);
     if (x >= limit)
     if (x >= limit)
       error(S, "integer overflow");
       error(S, "integer overflow");
     x = (x << 7) | (b & 0x7f);
     x = (x << 7) | (b & 0x7f);
@@ -80,98 +80,107 @@ static size_t LoadUnsigned (LoadState *S, size_t limit) {
 }
 }
 
 
 
 
-static size_t LoadSize (LoadState *S) {
-  return LoadUnsigned(S, ~(size_t)0);
+static size_t loadSize (LoadState *S) {
+  return loadUnsigned(S, ~(size_t)0);
 }
 }
 
 
 
 
-static int LoadInt (LoadState *S) {
-  return cast_int(LoadUnsigned(S, INT_MAX));
+static int loadInt (LoadState *S) {
+  return cast_int(loadUnsigned(S, INT_MAX));
 }
 }
 
 
 
 
-static lua_Number LoadNumber (LoadState *S) {
+static lua_Number loadNumber (LoadState *S) {
   lua_Number x;
   lua_Number x;
-  LoadVar(S, x);
+  loadVar(S, x);
   return x;
   return x;
 }
 }
 
 
 
 
-static lua_Integer LoadInteger (LoadState *S) {
+static lua_Integer loadInteger (LoadState *S) {
   lua_Integer x;
   lua_Integer x;
-  LoadVar(S, x);
+  loadVar(S, x);
   return x;
   return x;
 }
 }
 
 
 
 
 /*
 /*
-** Load a nullable string
+** Load a nullable string into prototype 'p'.
 */
 */
-static TString *LoadStringN (LoadState *S) {
-  size_t size = LoadSize(S);
-  if (size == 0)
+static TString *loadStringN (LoadState *S, Proto *p) {
+  lua_State *L = S->L;
+  TString *ts;
+  size_t size = loadSize(S);
+  if (size == 0)  /* no string? */
     return NULL;
     return NULL;
   else if (--size <= LUAI_MAXSHORTLEN) {  /* short string? */
   else if (--size <= LUAI_MAXSHORTLEN) {  /* short string? */
     char buff[LUAI_MAXSHORTLEN];
     char buff[LUAI_MAXSHORTLEN];
-    LoadVector(S, buff, size);
-    return luaS_newlstr(S->L, buff, size);
+    loadVector(S, buff, size);  /* load string into buffer */
+    ts = luaS_newlstr(L, buff, size);  /* create string */
   }
   }
   else {  /* long string */
   else {  /* long string */
-    TString *ts = luaS_createlngstrobj(S->L, size);
-    LoadVector(S, getstr(ts), size);  /* load directly in final place */
-    return ts;
+    ts = luaS_createlngstrobj(L, size);  /* create string */
+    setsvalue2s(L, L->top, ts);  /* anchor it ('loadVector' can GC) */
+    luaD_inctop(L);
+    loadVector(S, getstr(ts), size);  /* load directly in final place */
+    L->top--;  /* pop string */
   }
   }
+  luaC_objbarrier(L, p, ts);
+  return ts;
 }
 }
 
 
 
 
 /*
 /*
-** Load a non-nullable string.
+** Load a non-nullable string into prototype 'p'.
 */
 */
-static TString *LoadString (LoadState *S) {
-  TString *st = LoadStringN(S);
+static TString *loadString (LoadState *S, Proto *p) {
+  TString *st = loadStringN(S, p);
   if (st == NULL)
   if (st == NULL)
     error(S, "bad format for constant string");
     error(S, "bad format for constant string");
   return st;
   return st;
 }
 }
 
 
 
 
-static void LoadCode (LoadState *S, Proto *f) {
-  int n = LoadInt(S);
+static void loadCode (LoadState *S, Proto *f) {
+  int n = loadInt(S);
   f->code = luaM_newvectorchecked(S->L, n, Instruction);
   f->code = luaM_newvectorchecked(S->L, n, Instruction);
   f->sizecode = n;
   f->sizecode = n;
-  LoadVector(S, f->code, n);
+  loadVector(S, f->code, n);
 }
 }
 
 
 
 
-static void LoadFunction(LoadState *S, Proto *f, TString *psource);
+static void loadFunction(LoadState *S, Proto *f, TString *psource);
 
 
 
 
-static void LoadConstants (LoadState *S, Proto *f) {
+static void loadConstants (LoadState *S, Proto *f) {
   int i;
   int i;
-  int n = LoadInt(S);
+  int n = loadInt(S);
   f->k = luaM_newvectorchecked(S->L, n, TValue);
   f->k = luaM_newvectorchecked(S->L, n, TValue);
   f->sizek = n;
   f->sizek = n;
   for (i = 0; i < n; i++)
   for (i = 0; i < n; i++)
     setnilvalue(&f->k[i]);
     setnilvalue(&f->k[i]);
   for (i = 0; i < n; i++) {
   for (i = 0; i < n; i++) {
     TValue *o = &f->k[i];
     TValue *o = &f->k[i];
-    int t = LoadByte(S);
+    int t = loadByte(S);
     switch (t) {
     switch (t) {
-      case LUA_TNIL:
+      case LUA_VNIL:
         setnilvalue(o);
         setnilvalue(o);
         break;
         break;
-      case LUA_TBOOLEAN:
-        setbvalue(o, LoadByte(S));
+      case LUA_VFALSE:
+        setbfvalue(o);
         break;
         break;
-      case LUA_TNUMFLT:
-        setfltvalue(o, LoadNumber(S));
+      case LUA_VTRUE:
+        setbtvalue(o);
         break;
         break;
-      case LUA_TNUMINT:
-        setivalue(o, LoadInteger(S));
+      case LUA_VNUMFLT:
+        setfltvalue(o, loadNumber(S));
         break;
         break;
-      case LUA_TSHRSTR:
-      case LUA_TLNGSTR:
-        setsvalue2n(S->L, o, LoadString(S));
+      case LUA_VNUMINT:
+        setivalue(o, loadInteger(S));
+        break;
+      case LUA_VSHRSTR:
+      case LUA_VLNGSTR:
+        setsvalue2n(S->L, o, loadString(S, f));
         break;
         break;
       default: lua_assert(0);
       default: lua_assert(0);
     }
     }
@@ -179,91 +188,99 @@ static void LoadConstants (LoadState *S, Proto *f) {
 }
 }
 
 
 
 
-static void LoadProtos (LoadState *S, Proto *f) {
+static void loadProtos (LoadState *S, Proto *f) {
   int i;
   int i;
-  int n = LoadInt(S);
+  int n = loadInt(S);
   f->p = luaM_newvectorchecked(S->L, n, Proto *);
   f->p = luaM_newvectorchecked(S->L, n, Proto *);
   f->sizep = n;
   f->sizep = n;
   for (i = 0; i < n; i++)
   for (i = 0; i < n; i++)
     f->p[i] = NULL;
     f->p[i] = NULL;
   for (i = 0; i < n; i++) {
   for (i = 0; i < n; i++) {
     f->p[i] = luaF_newproto(S->L);
     f->p[i] = luaF_newproto(S->L);
-    LoadFunction(S, f->p[i], f->source);
+    luaC_objbarrier(S->L, f, f->p[i]);
+    loadFunction(S, f->p[i], f->source);
   }
   }
 }
 }
 
 
 
 
-static void LoadUpvalues (LoadState *S, Proto *f) {
+/*
+** Load the upvalues for a function. The names must be filled first,
+** because the filling of the other fields can raise read errors and
+** the creation of the error message can call an emergency collection;
+** in that case all prototypes must be consistent for the GC.
+*/
+static void loadUpvalues (LoadState *S, Proto *f) {
   int i, n;
   int i, n;
-  n = LoadInt(S);
+  n = loadInt(S);
   f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
   f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
   f->sizeupvalues = n;
   f->sizeupvalues = n;
-  for (i = 0; i < n; i++) {
+  for (i = 0; i < n; i++)  /* make array valid for GC */
     f->upvalues[i].name = NULL;
     f->upvalues[i].name = NULL;
-    f->upvalues[i].instack = LoadByte(S);
-    f->upvalues[i].idx = LoadByte(S);
-    f->upvalues[i].kind = LoadByte(S);
+  for (i = 0; i < n; i++) {  /* following calls can raise errors */
+    f->upvalues[i].instack = loadByte(S);
+    f->upvalues[i].idx = loadByte(S);
+    f->upvalues[i].kind = loadByte(S);
   }
   }
 }
 }
 
 
 
 
-static void LoadDebug (LoadState *S, Proto *f) {
+static void loadDebug (LoadState *S, Proto *f) {
   int i, n;
   int i, n;
-  n = LoadInt(S);
+  n = loadInt(S);
   f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte);
   f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte);
   f->sizelineinfo = n;
   f->sizelineinfo = n;
-  LoadVector(S, f->lineinfo, n);
-  n = LoadInt(S);
+  loadVector(S, f->lineinfo, n);
+  n = loadInt(S);
   f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo);
   f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo);
   f->sizeabslineinfo = n;
   f->sizeabslineinfo = n;
   for (i = 0; i < n; i++) {
   for (i = 0; i < n; i++) {
-    f->abslineinfo[i].pc = LoadInt(S);
-    f->abslineinfo[i].line = LoadInt(S);
+    f->abslineinfo[i].pc = loadInt(S);
+    f->abslineinfo[i].line = loadInt(S);
   }
   }
-  n = LoadInt(S);
+  n = loadInt(S);
   f->locvars = luaM_newvectorchecked(S->L, n, LocVar);
   f->locvars = luaM_newvectorchecked(S->L, n, LocVar);
   f->sizelocvars = n;
   f->sizelocvars = n;
   for (i = 0; i < n; i++)
   for (i = 0; i < n; i++)
     f->locvars[i].varname = NULL;
     f->locvars[i].varname = NULL;
   for (i = 0; i < n; i++) {
   for (i = 0; i < n; i++) {
-    f->locvars[i].varname = LoadStringN(S);
-    f->locvars[i].startpc = LoadInt(S);
-    f->locvars[i].endpc = LoadInt(S);
+    f->locvars[i].varname = loadStringN(S, f);
+    f->locvars[i].startpc = loadInt(S);
+    f->locvars[i].endpc = loadInt(S);
   }
   }
-  n = LoadInt(S);
+  n = loadInt(S);
   for (i = 0; i < n; i++)
   for (i = 0; i < n; i++)
-    f->upvalues[i].name = LoadStringN(S);
+    f->upvalues[i].name = loadStringN(S, f);
 }
 }
 
 
 
 
-static void LoadFunction (LoadState *S, Proto *f, TString *psource) {
-  f->source = LoadStringN(S);
+static void loadFunction (LoadState *S, Proto *f, TString *psource) {
+  f->source = loadStringN(S, f);
   if (f->source == NULL)  /* no source in dump? */
   if (f->source == NULL)  /* no source in dump? */
     f->source = psource;  /* reuse parent's source */
     f->source = psource;  /* reuse parent's source */
-  f->linedefined = LoadInt(S);
-  f->lastlinedefined = LoadInt(S);
-  f->numparams = LoadByte(S);
-  f->is_vararg = LoadByte(S);
-  f->maxstacksize = LoadByte(S);
-  LoadCode(S, f);
-  LoadConstants(S, f);
-  LoadUpvalues(S, f);
-  LoadProtos(S, f);
-  LoadDebug(S, f);
+  f->linedefined = loadInt(S);
+  f->lastlinedefined = loadInt(S);
+  f->numparams = loadByte(S);
+  f->is_vararg = loadByte(S);
+  f->maxstacksize = loadByte(S);
+  loadCode(S, f);
+  loadConstants(S, f);
+  loadUpvalues(S, f);
+  loadProtos(S, f);
+  loadDebug(S, f);
 }
 }
 
 
 
 
 static void checkliteral (LoadState *S, const char *s, const char *msg) {
 static void checkliteral (LoadState *S, const char *s, const char *msg) {
   char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
   char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
   size_t len = strlen(s);
   size_t len = strlen(s);
-  LoadVector(S, buff, len);
+  loadVector(S, buff, len);
   if (memcmp(s, buff, len) != 0)
   if (memcmp(s, buff, len) != 0)
     error(S, msg);
     error(S, msg);
 }
 }
 
 
 
 
 static void fchecksize (LoadState *S, size_t size, const char *tname) {
 static void fchecksize (LoadState *S, size_t size, const char *tname) {
-  if (LoadByte(S) != size)
+  if (loadByte(S) != size)
     error(S, luaO_pushfstring(S->L, "%s size mismatch", tname));
     error(S, luaO_pushfstring(S->L, "%s size mismatch", tname));
 }
 }
 
 
@@ -273,23 +290,23 @@ static void fchecksize (LoadState *S, size_t size, const char *tname) {
 static void checkHeader (LoadState *S) {
 static void checkHeader (LoadState *S) {
   /* skip 1st char (already read and checked) */
   /* skip 1st char (already read and checked) */
   checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk");
   checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk");
-  if (LoadInt(S) != LUAC_VERSION)
+  if (loadByte(S) != LUAC_VERSION)
     error(S, "version mismatch");
     error(S, "version mismatch");
-  if (LoadByte(S) != LUAC_FORMAT)
+  if (loadByte(S) != LUAC_FORMAT)
     error(S, "format mismatch");
     error(S, "format mismatch");
   checkliteral(S, LUAC_DATA, "corrupted chunk");
   checkliteral(S, LUAC_DATA, "corrupted chunk");
   checksize(S, Instruction);
   checksize(S, Instruction);
   checksize(S, lua_Integer);
   checksize(S, lua_Integer);
   checksize(S, lua_Number);
   checksize(S, lua_Number);
-  if (LoadInteger(S) != LUAC_INT)
+  if (loadInteger(S) != LUAC_INT)
     error(S, "integer format mismatch");
     error(S, "integer format mismatch");
-  if (LoadNumber(S) != LUAC_NUM)
+  if (loadNumber(S) != LUAC_NUM)
     error(S, "float format mismatch");
     error(S, "float format mismatch");
 }
 }
 
 
 
 
 /*
 /*
-** load precompiled chunk
+** Load precompiled chunk.
 */
 */
 LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
 LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
   LoadState S;
   LoadState S;
@@ -303,13 +320,14 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
   S.L = L;
   S.L = L;
   S.Z = Z;
   S.Z = Z;
   checkHeader(&S);
   checkHeader(&S);
-  cl = luaF_newLclosure(L, LoadByte(&S));
+  cl = luaF_newLclosure(L, loadByte(&S));
   setclLvalue2s(L, L->top, cl);
   setclLvalue2s(L, L->top, cl);
   luaD_inctop(L);
   luaD_inctop(L);
   cl->p = luaF_newproto(L);
   cl->p = luaF_newproto(L);
-  LoadFunction(&S, cl->p, NULL);
+  luaC_objbarrier(L, cl, cl->p);
+  loadFunction(&S, cl->p, NULL);
   lua_assert(cl->nupvalues == cl->p->sizeupvalues);
   lua_assert(cl->nupvalues == cl->p->sizeupvalues);
-  luai_verifycode(L, buff, cl->p);
+  luai_verifycode(L, cl->p);
   return cl;
   return cl;
 }
 }
 
 

+ 6 - 1
src/lundump.h

@@ -18,7 +18,12 @@
 #define LUAC_INT	0x5678
 #define LUAC_INT	0x5678
 #define LUAC_NUM	cast_num(370.5)
 #define LUAC_NUM	cast_num(370.5)
 
 
-#define LUAC_VERSION	LUA_VERSION_NUM
+/*
+** Encode major-minor version in one byte, one nibble for each
+*/
+#define MYINT(s)	(s[0]-'0')  /* assume one-digit numerals */
+#define LUAC_VERSION	(MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR))
+
 #define LUAC_FORMAT	0	/* this is the official format */
 #define LUAC_FORMAT	0	/* this is the official format */
 
 
 /* load one chunk; from lundump.c */
 /* load one chunk; from lundump.c */

+ 6 - 6
src/lutf8lib.c

@@ -29,7 +29,7 @@
 ** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
 ** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
 */
 */
 #if (UINT_MAX >> 30) >= 1
 #if (UINT_MAX >> 30) >= 1
-typedef	unsigned int utfint;
+typedef unsigned int utfint;
 #else
 #else
 typedef unsigned long utfint;
 typedef unsigned long utfint;
 #endif
 #endif
@@ -97,9 +97,9 @@ static int utflen (lua_State *L) {
   lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len);
   lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len);
   int lax = lua_toboolean(L, 4);
   int lax = lua_toboolean(L, 4);
   luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2,
   luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2,
-                   "initial position out of string");
+                   "initial position out of bounds");
   luaL_argcheck(L, --posj < (lua_Integer)len, 3,
   luaL_argcheck(L, --posj < (lua_Integer)len, 3,
-                   "final position out of string");
+                   "final position out of bounds");
   while (posi <= posj) {
   while (posi <= posj) {
     const char *s1 = utf8_decode(s + posi, NULL, !lax);
     const char *s1 = utf8_decode(s + posi, NULL, !lax);
     if (s1 == NULL) {  /* conversion error? */
     if (s1 == NULL) {  /* conversion error? */
@@ -127,8 +127,8 @@ static int codepoint (lua_State *L) {
   int lax = lua_toboolean(L, 4);
   int lax = lua_toboolean(L, 4);
   int n;
   int n;
   const char *se;
   const char *se;
-  luaL_argcheck(L, posi >= 1, 2, "out of range");
-  luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range");
+  luaL_argcheck(L, posi >= 1, 2, "out of bounds");
+  luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of bounds");
   if (posi > pose) return 0;  /* empty interval; return no values */
   if (posi > pose) return 0;  /* empty interval; return no values */
   if (pose - posi >= INT_MAX)  /* (lua_Integer -> int) overflow? */
   if (pose - posi >= INT_MAX)  /* (lua_Integer -> int) overflow? */
     return luaL_error(L, "string slice too long");
     return luaL_error(L, "string slice too long");
@@ -187,7 +187,7 @@ static int byteoffset (lua_State *L) {
   lua_Integer posi = (n >= 0) ? 1 : len + 1;
   lua_Integer posi = (n >= 0) ? 1 : len + 1;
   posi = u_posrelat(luaL_optinteger(L, 3, posi), len);
   posi = u_posrelat(luaL_optinteger(L, 3, posi), len);
   luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3,
   luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3,
-                   "position out of range");
+                   "position out of bounds");
   if (n == 0) {
   if (n == 0) {
     /* find beginning of current byte sequence */
     /* find beginning of current byte sequence */
     while (posi > 0 && iscont(s + posi)) posi--;
     while (posi > 0 && iscont(s + posi)) posi--;

+ 289 - 242
src/lvm.c

@@ -55,7 +55,7 @@
 */
 */
 
 
 /* number of bits in the mantissa of a float */
 /* number of bits in the mantissa of a float */
-#define NBM		(l_mathlim(MANT_DIG))
+#define NBM		(l_floatatt(MANT_DIG))
 
 
 /*
 /*
 ** Check whether some integers may not fit in a float, testing whether
 ** Check whether some integers may not fit in a float, testing whether
@@ -80,6 +80,21 @@
 #endif
 #endif
 
 
 
 
+/*
+** Try to convert a value from string to a number value.
+** If the value is not a string or is a string not representing
+** a valid numeral (or if coercions from strings to numbers
+** are disabled via macro 'cvt2num'), do not modify 'result'
+** and return 0.
+*/
+static int l_strton (const TValue *obj, TValue *result) {
+  lua_assert(obj != result);
+  if (!cvt2num(obj))  /* is object not a string? */
+    return 0;
+  else
+    return (luaO_str2num(svalue(obj), result) == vslen(obj) + 1);
+}
+
 
 
 /*
 /*
 ** Try to convert a value to a float. The float case is already handled
 ** Try to convert a value to a float. The float case is already handled
@@ -91,8 +106,7 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) {
     *n = cast_num(ivalue(obj));
     *n = cast_num(ivalue(obj));
     return 1;
     return 1;
   }
   }
-  else if (cvt2num(obj) &&  /* string coercible to number? */
-            luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
+  else if (l_strton(obj, &v)) {  /* string coercible to number? */
     *n = nvalue(&v);  /* convert result of 'luaO_str2num' to a float */
     *n = nvalue(&v);  /* convert result of 'luaO_str2num' to a float */
     return 1;
     return 1;
   }
   }
@@ -102,16 +116,13 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) {
 
 
 
 
 /*
 /*
-** try to convert a float to an integer, rounding according to 'mode':
-** mode == 0: accepts only integral values
-** mode == 1: takes the floor of the number
-** mode == 2: takes the ceil of the number
+** try to convert a float to an integer, rounding according to 'mode'.
 */
 */
-int luaV_flttointeger (lua_Number n, lua_Integer *p, int mode) {
+int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode) {
   lua_Number f = l_floor(n);
   lua_Number f = l_floor(n);
   if (n != f) {  /* not an integral value? */
   if (n != f) {  /* not an integral value? */
-    if (mode == 0) return 0;  /* fails if mode demands integral value */
-    else if (mode > 1)  /* needs ceil? */
+    if (mode == F2Ieq) return 0;  /* fails if mode demands integral value */
+    else if (mode == F2Iceil)  /* needs ceil? */
       f += 1;  /* convert floor to ceil (remember: n != f) */
       f += 1;  /* convert floor to ceil (remember: n != f) */
   }
   }
   return lua_numbertointeger(f, p);
   return lua_numbertointeger(f, p);
@@ -123,7 +134,7 @@ int luaV_flttointeger (lua_Number n, lua_Integer *p, int mode) {
 ** without string coercion.
 ** without string coercion.
 ** ("Fast track" handled by macro 'tointegerns'.)
 ** ("Fast track" handled by macro 'tointegerns'.)
 */
 */
-int luaV_tointegerns (const TValue *obj, lua_Integer *p, int mode) {
+int luaV_tointegerns (const TValue *obj, lua_Integer *p, F2Imod mode) {
   if (ttisfloat(obj))
   if (ttisfloat(obj))
     return luaV_flttointeger(fltvalue(obj), p, mode);
     return luaV_flttointeger(fltvalue(obj), p, mode);
   else if (ttisinteger(obj)) {
   else if (ttisinteger(obj)) {
@@ -138,33 +149,33 @@ int luaV_tointegerns (const TValue *obj, lua_Integer *p, int mode) {
 /*
 /*
 ** try to convert a value to an integer.
 ** try to convert a value to an integer.
 */
 */
-int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
+int luaV_tointeger (const TValue *obj, lua_Integer *p, F2Imod mode) {
   TValue v;
   TValue v;
-  if (cvt2num(obj) && luaO_str2num(svalue(obj), &v) == vslen(obj) + 1)
-    obj = &v;  /* change string to its corresponding number */
+  if (l_strton(obj, &v))  /* does 'obj' point to a numerical string? */
+    obj = &v;  /* change it to point to its corresponding number */
   return luaV_tointegerns(obj, p, mode);
   return luaV_tointegerns(obj, p, mode);
 }
 }
 
 
 
 
 /*
 /*
 ** Try to convert a 'for' limit to an integer, preserving the semantics
 ** Try to convert a 'for' limit to an integer, preserving the semantics
-** of the loop.  (The following explanation assumes a positive step;
-** it is valid for negative steps mutatis mutandis.)
-** Return true if the loop must not run.
+** of the loop. Return true if the loop must not run; otherwise, '*p'
+** gets the integer limit.
+** (The following explanation assumes a positive step; it is valid for
+** negative steps mutatis mutandis.)
 ** If the limit is an integer or can be converted to an integer,
 ** If the limit is an integer or can be converted to an integer,
 ** rounding down, that is the limit.
 ** rounding down, that is the limit.
 ** Otherwise, check whether the limit can be converted to a float. If
 ** Otherwise, check whether the limit can be converted to a float. If
 ** the float is too large, clip it to LUA_MAXINTEGER.  If the float
 ** the float is too large, clip it to LUA_MAXINTEGER.  If the float
 ** is too negative, the loop should not run, because any initial
 ** is too negative, the loop should not run, because any initial
-** integer value is greater than such limit; so, it returns true to
-** signal that.
-** (For this latter case, no integer limit would be correct; even a
-** limit of LUA_MININTEGER would run the loop once for an initial
-** value equal to LUA_MININTEGER.)
+** integer value is greater than such limit; so, the function returns
+** true to signal that. (For this latter case, no integer limit would be
+** correct; even a limit of LUA_MININTEGER would run the loop once for
+** an initial value equal to LUA_MININTEGER.)
 */
 */
 static int forlimit (lua_State *L, lua_Integer init, const TValue *lim,
 static int forlimit (lua_State *L, lua_Integer init, const TValue *lim,
                                    lua_Integer *p, lua_Integer step) {
                                    lua_Integer *p, lua_Integer step) {
-  if (!luaV_tointeger(lim, p, (step < 0 ? 2 : 1))) {
+  if (!luaV_tointeger(lim, p, (step < 0 ? F2Iceil : F2Ifloor))) {
     /* not coercible to in integer */
     /* not coercible to in integer */
     lua_Number flim;  /* try to convert to float */
     lua_Number flim;  /* try to convert to float */
     if (!tonumber(lim, &flim)) /* cannot convert to float? */
     if (!tonumber(lim, &flim)) /* cannot convert to float? */
@@ -183,6 +194,91 @@ static int forlimit (lua_State *L, lua_Integer init, const TValue *lim,
 }
 }
 
 
 
 
+/*
+** Prepare a numerical for loop (opcode OP_FORPREP).
+** Return true to skip the loop. Otherwise,
+** after preparation, stack will be as follows:
+**   ra : internal index (safe copy of the control variable)
+**   ra + 1 : loop counter (integer loops) or limit (float loops)
+**   ra + 2 : step
+**   ra + 3 : control variable
+*/
+static int forprep (lua_State *L, StkId ra) {
+  TValue *pinit = s2v(ra);
+  TValue *plimit = s2v(ra + 1);
+  TValue *pstep = s2v(ra + 2);
+  if (ttisinteger(pinit) && ttisinteger(pstep)) { /* integer loop? */
+    lua_Integer init = ivalue(pinit);
+    lua_Integer step = ivalue(pstep);
+    lua_Integer limit;
+    if (step == 0)
+      luaG_runerror(L, "'for' step is zero");
+    setivalue(s2v(ra + 3), init);  /* control variable */
+    if (forlimit(L, init, plimit, &limit, step))
+      return 1;  /* skip the loop */
+    else {  /* prepare loop counter */
+      lua_Unsigned count;
+      if (step > 0) {  /* ascending loop? */
+        count = l_castS2U(limit) - l_castS2U(init);
+        if (step != 1)  /* avoid division in the too common case */
+          count /= l_castS2U(step);
+      }
+      else {  /* step < 0; descending loop */
+        count = l_castS2U(init) - l_castS2U(limit);
+        /* 'step+1' avoids negating 'mininteger' */
+        count /= l_castS2U(-(step + 1)) + 1u;
+      }
+      /* store the counter in place of the limit (which won't be
+         needed anymore) */
+      setivalue(plimit, l_castU2S(count));
+    }
+  }
+  else {  /* try making all values floats */
+    lua_Number init; lua_Number limit; lua_Number step;
+    if (l_unlikely(!tonumber(plimit, &limit)))
+      luaG_forerror(L, plimit, "limit");
+    if (l_unlikely(!tonumber(pstep, &step)))
+      luaG_forerror(L, pstep, "step");
+    if (l_unlikely(!tonumber(pinit, &init)))
+      luaG_forerror(L, pinit, "initial value");
+    if (step == 0)
+      luaG_runerror(L, "'for' step is zero");
+    if (luai_numlt(0, step) ? luai_numlt(limit, init)
+                            : luai_numlt(init, limit))
+      return 1;  /* skip the loop */
+    else {
+      /* make sure internal values are all floats */
+      setfltvalue(plimit, limit);
+      setfltvalue(pstep, step);
+      setfltvalue(s2v(ra), init);  /* internal index */
+      setfltvalue(s2v(ra + 3), init);  /* control variable */
+    }
+  }
+  return 0;
+}
+
+
+/*
+** Execute a step of a float numerical for loop, returning
+** true iff the loop must continue. (The integer case is
+** written online with opcode OP_FORLOOP, for performance.)
+*/
+static int floatforloop (StkId ra) {
+  lua_Number step = fltvalue(s2v(ra + 2));
+  lua_Number limit = fltvalue(s2v(ra + 1));
+  lua_Number idx = fltvalue(s2v(ra));  /* internal index */
+  idx = luai_numadd(L, idx, step);  /* increment index */
+  if (luai_numlt(0, step) ? luai_numle(idx, limit)
+                          : luai_numle(limit, idx)) {
+    chgfltvalue(s2v(ra), idx);  /* update internal index */
+    setfltvalue(s2v(ra + 3), idx);  /* and control variable */
+    return 1;  /* jump back */
+  }
+  else
+    return 0;  /* finish the loop */
+}
+
+
 /*
 /*
 ** Finish the table access 'val = t[key]'.
 ** Finish the table access 'val = t[key]'.
 ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to
 ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to
@@ -196,7 +292,7 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
     if (slot == NULL) {  /* 't' is not a table? */
     if (slot == NULL) {  /* 't' is not a table? */
       lua_assert(!ttistable(t));
       lua_assert(!ttistable(t));
       tm = luaT_gettmbyobj(L, t, TM_INDEX);
       tm = luaT_gettmbyobj(L, t, TM_INDEX);
-      if (unlikely(notm(tm)))
+      if (l_unlikely(notm(tm)))
         luaG_typeerror(L, t, "index");  /* no metamethod */
         luaG_typeerror(L, t, "index");  /* no metamethod */
       /* else will try the metamethod */
       /* else will try the metamethod */
     }
     }
@@ -241,10 +337,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
       lua_assert(isempty(slot));  /* slot must be empty */
       lua_assert(isempty(slot));  /* slot must be empty */
       tm = fasttm(L, h->metatable, TM_NEWINDEX);  /* get metamethod */
       tm = fasttm(L, h->metatable, TM_NEWINDEX);  /* get metamethod */
       if (tm == NULL) {  /* no metamethod? */
       if (tm == NULL) {  /* no metamethod? */
-        if (isabstkey(slot))  /* no previous entry? */
-          slot = luaH_newkey(L, h, key);  /* create one */
-        /* no metamethod and (now) there is an entry with given key */
-        setobj2t(L, cast(TValue *, slot), val);  /* set its new value */
+        luaH_finishset(L, h, key, slot, val);  /* set new value */
         invalidateTMcache(h);
         invalidateTMcache(h);
         luaC_barrierback(L, obj2gco(h), val);
         luaC_barrierback(L, obj2gco(h), val);
         return;
         return;
@@ -253,7 +346,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
     }
     }
     else {  /* not a table; check metamethod */
     else {  /* not a table; check metamethod */
       tm = luaT_gettmbyobj(L, t, TM_NEWINDEX);
       tm = luaT_gettmbyobj(L, t, TM_NEWINDEX);
-      if (unlikely(notm(tm)))
+      if (l_unlikely(notm(tm)))
         luaG_typeerror(L, t, "index");
         luaG_typeerror(L, t, "index");
     }
     }
     /* try the metamethod */
     /* try the metamethod */
@@ -318,7 +411,7 @@ static int LTintfloat (lua_Integer i, lua_Number f) {
     return luai_numlt(cast_num(i), f);  /* compare them as floats */
     return luai_numlt(cast_num(i), f);  /* compare them as floats */
   else {  /* i < f <=> i < ceil(f) */
   else {  /* i < f <=> i < ceil(f) */
     lua_Integer fi;
     lua_Integer fi;
-    if (luaV_flttointeger(f, &fi, 2))  /* fi = ceil(f) */
+    if (luaV_flttointeger(f, &fi, F2Iceil))  /* fi = ceil(f) */
       return i < fi;   /* compare them as integers */
       return i < fi;   /* compare them as integers */
     else  /* 'f' is either greater or less than all integers */
     else  /* 'f' is either greater or less than all integers */
       return f > 0;  /* greater? */
       return f > 0;  /* greater? */
@@ -335,7 +428,7 @@ static int LEintfloat (lua_Integer i, lua_Number f) {
     return luai_numle(cast_num(i), f);  /* compare them as floats */
     return luai_numle(cast_num(i), f);  /* compare them as floats */
   else {  /* i <= f <=> i <= floor(f) */
   else {  /* i <= f <=> i <= floor(f) */
     lua_Integer fi;
     lua_Integer fi;
-    if (luaV_flttointeger(f, &fi, 1))  /* fi = floor(f) */
+    if (luaV_flttointeger(f, &fi, F2Ifloor))  /* fi = floor(f) */
       return i <= fi;   /* compare them as integers */
       return i <= fi;   /* compare them as integers */
     else  /* 'f' is either greater or less than all integers */
     else  /* 'f' is either greater or less than all integers */
       return f > 0;  /* greater? */
       return f > 0;  /* greater? */
@@ -352,7 +445,7 @@ static int LTfloatint (lua_Number f, lua_Integer i) {
     return luai_numlt(f, cast_num(i));  /* compare them as floats */
     return luai_numlt(f, cast_num(i));  /* compare them as floats */
   else {  /* f < i <=> floor(f) < i */
   else {  /* f < i <=> floor(f) < i */
     lua_Integer fi;
     lua_Integer fi;
-    if (luaV_flttointeger(f, &fi, 1))  /* fi = floor(f) */
+    if (luaV_flttointeger(f, &fi, F2Ifloor))  /* fi = floor(f) */
       return fi < i;   /* compare them as integers */
       return fi < i;   /* compare them as integers */
     else  /* 'f' is either greater or less than all integers */
     else  /* 'f' is either greater or less than all integers */
       return f < 0;  /* less? */
       return f < 0;  /* less? */
@@ -369,7 +462,7 @@ static int LEfloatint (lua_Number f, lua_Integer i) {
     return luai_numle(f, cast_num(i));  /* compare them as floats */
     return luai_numle(f, cast_num(i));  /* compare them as floats */
   else {  /* f <= i <=> ceil(f) <= i */
   else {  /* f <= i <=> ceil(f) <= i */
     lua_Integer fi;
     lua_Integer fi;
-    if (luaV_flttointeger(f, &fi, 2))  /* fi = ceil(f) */
+    if (luaV_flttointeger(f, &fi, F2Iceil))  /* fi = ceil(f) */
       return fi <= i;   /* compare them as integers */
       return fi <= i;   /* compare them as integers */
     else  /* 'f' is either greater or less than all integers */
     else  /* 'f' is either greater or less than all integers */
       return f < 0;  /* less? */
       return f < 0;  /* less? */
@@ -445,11 +538,6 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
 
 
 /*
 /*
 ** return 'l <= r' for non-numbers.
 ** return 'l <= r' for non-numbers.
-** If it needs a metamethod and there is no '__le', try '__lt', based
-** on l <= r iff !(r < l) (assuming a total order). If the metamethod
-** yields during this substitution, the continuation has to know about
-** it (to negate the result of r<l); bit CIST_LEQ in the call status
-** keeps that information.
 */
 */
 static int lessequalothers (lua_State *L, const TValue *l, const TValue *r) {
 static int lessequalothers (lua_State *L, const TValue *l, const TValue *r) {
   lua_assert(!ttisnumber(l) || !ttisnumber(r));
   lua_assert(!ttisnumber(l) || !ttisnumber(r));
@@ -480,21 +568,25 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
     if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER)
     if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER)
       return 0;  /* only numbers can be equal with different variants */
       return 0;  /* only numbers can be equal with different variants */
     else {  /* two numbers with different variants */
     else {  /* two numbers with different variants */
-      lua_Integer i1, i2;  /* compare them as integers */
-      return (tointegerns(t1, &i1) && tointegerns(t2, &i2) && i1 == i2);
+      /* One of them is an integer. If the other does not have an
+         integer value, they cannot be equal; otherwise, compare their
+         integer values. */
+      lua_Integer i1, i2;
+      return (luaV_tointegerns(t1, &i1, F2Ieq) &&
+              luaV_tointegerns(t2, &i2, F2Ieq) &&
+              i1 == i2);
     }
     }
   }
   }
   /* values have same type and same variant */
   /* values have same type and same variant */
   switch (ttypetag(t1)) {
   switch (ttypetag(t1)) {
-    case LUA_TNIL: return 1;
-    case LUA_TNUMINT: return (ivalue(t1) == ivalue(t2));
-    case LUA_TNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2));
-    case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2);  /* true must be 1! */
-    case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
-    case LUA_TLCF: return fvalue(t1) == fvalue(t2);
-    case LUA_TSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2));
-    case LUA_TLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2));
-    case LUA_TUSERDATA: {
+    case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE: return 1;
+    case LUA_VNUMINT: return (ivalue(t1) == ivalue(t2));
+    case LUA_VNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2));
+    case LUA_VLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
+    case LUA_VLCF: return fvalue(t1) == fvalue(t2);
+    case LUA_VSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2));
+    case LUA_VLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2));
+    case LUA_VUSERDATA: {
       if (uvalue(t1) == uvalue(t2)) return 1;
       if (uvalue(t1) == uvalue(t2)) return 1;
       else if (L == NULL) return 0;
       else if (L == NULL) return 0;
       tm = fasttm(L, uvalue(t1)->metatable, TM_EQ);
       tm = fasttm(L, uvalue(t1)->metatable, TM_EQ);
@@ -502,7 +594,7 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
         tm = fasttm(L, uvalue(t2)->metatable, TM_EQ);
         tm = fasttm(L, uvalue(t2)->metatable, TM_EQ);
       break;  /* will try TM */
       break;  /* will try TM */
     }
     }
-    case LUA_TTABLE: {
+    case LUA_VTABLE: {
       if (hvalue(t1) == hvalue(t2)) return 1;
       if (hvalue(t1) == hvalue(t2)) return 1;
       else if (L == NULL) return 0;
       else if (L == NULL) return 0;
       tm = fasttm(L, hvalue(t1)->metatable, TM_EQ);
       tm = fasttm(L, hvalue(t1)->metatable, TM_EQ);
@@ -544,7 +636,8 @@ static void copy2buff (StkId top, int n, char *buff) {
 ** from 'L->top - total' up to 'L->top - 1'.
 ** from 'L->top - total' up to 'L->top - 1'.
 */
 */
 void luaV_concat (lua_State *L, int total) {
 void luaV_concat (lua_State *L, int total) {
-  lua_assert(total >= 2);
+  if (total == 1)
+    return;  /* "all" values already concatenated */
   do {
   do {
     StkId top = L->top;
     StkId top = L->top;
     int n = 2;  /* number of elements handled in this pass (at least 2) */
     int n = 2;  /* number of elements handled in this pass (at least 2) */
@@ -563,7 +656,7 @@ void luaV_concat (lua_State *L, int total) {
       /* collect total length and number of strings */
       /* collect total length and number of strings */
       for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
       for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
         size_t l = vslen(s2v(top - n - 1));
         size_t l = vslen(s2v(top - n - 1));
-        if (unlikely(l >= (MAX_SIZE/sizeof(char)) - tl))
+        if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl))
           luaG_runerror(L, "string length overflow");
           luaG_runerror(L, "string length overflow");
         tl += l;
         tl += l;
       }
       }
@@ -590,24 +683,24 @@ void luaV_concat (lua_State *L, int total) {
 void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
 void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
   const TValue *tm;
   const TValue *tm;
   switch (ttypetag(rb)) {
   switch (ttypetag(rb)) {
-    case LUA_TTABLE: {
+    case LUA_VTABLE: {
       Table *h = hvalue(rb);
       Table *h = hvalue(rb);
       tm = fasttm(L, h->metatable, TM_LEN);
       tm = fasttm(L, h->metatable, TM_LEN);
       if (tm) break;  /* metamethod? break switch to call it */
       if (tm) break;  /* metamethod? break switch to call it */
       setivalue(s2v(ra), luaH_getn(h));  /* else primitive len */
       setivalue(s2v(ra), luaH_getn(h));  /* else primitive len */
       return;
       return;
     }
     }
-    case LUA_TSHRSTR: {
+    case LUA_VSHRSTR: {
       setivalue(s2v(ra), tsvalue(rb)->shrlen);
       setivalue(s2v(ra), tsvalue(rb)->shrlen);
       return;
       return;
     }
     }
-    case LUA_TLNGSTR: {
+    case LUA_VLNGSTR: {
       setivalue(s2v(ra), tsvalue(rb)->u.lnglen);
       setivalue(s2v(ra), tsvalue(rb)->u.lnglen);
       return;
       return;
     }
     }
     default: {  /* try metamethod */
     default: {  /* try metamethod */
       tm = luaT_gettmbyobj(L, rb, TM_LEN);
       tm = luaT_gettmbyobj(L, rb, TM_LEN);
-      if (unlikely(notm(tm)))  /* no metamethod? */
+      if (l_unlikely(notm(tm)))  /* no metamethod? */
         luaG_typeerror(L, rb, "get length of");
         luaG_typeerror(L, rb, "get length of");
       break;
       break;
     }
     }
@@ -623,7 +716,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
 ** otherwise 'floor(q) == trunc(q) - 1'.
 ** otherwise 'floor(q) == trunc(q) - 1'.
 */
 */
 lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) {
 lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) {
-  if (unlikely(l_castS2U(n) + 1u <= 1u)) {  /* special cases: -1 or 0 */
+  if (l_unlikely(l_castS2U(n) + 1u <= 1u)) {  /* special cases: -1 or 0 */
     if (n == 0)
     if (n == 0)
       luaG_runerror(L, "attempt to divide by zero");
       luaG_runerror(L, "attempt to divide by zero");
     return intop(-, 0, m);   /* n==-1; avoid overflow with 0x80000...//-1 */
     return intop(-, 0, m);   /* n==-1; avoid overflow with 0x80000...//-1 */
@@ -643,7 +736,7 @@ lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) {
 ** about luaV_idiv.)
 ** about luaV_idiv.)
 */
 */
 lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) {
 lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) {
-  if (unlikely(l_castS2U(n) + 1u <= 1u)) {  /* special cases: -1 or 0 */
+  if (l_unlikely(l_castS2U(n) + 1u <= 1u)) {  /* special cases: -1 or 0 */
     if (n == 0)
     if (n == 0)
       luaG_runerror(L, "attempt to perform 'n%%0'");
       luaG_runerror(L, "attempt to perform 'n%%0'");
     return 0;   /* m % -1 == 0; avoid overflow with 0x80000...%-1 */
     return 0;   /* m % -1 == 0; avoid overflow with 0x80000...%-1 */
@@ -750,10 +843,12 @@ void luaV_finishOp (lua_State *L) {
       int a = GETARG_A(inst);      /* first element to concatenate */
       int a = GETARG_A(inst);      /* first element to concatenate */
       int total = cast_int(top - 1 - (base + a));  /* yet to concatenate */
       int total = cast_int(top - 1 - (base + a));  /* yet to concatenate */
       setobjs2s(L, top - 2, top);  /* put TM result in proper position */
       setobjs2s(L, top - 2, top);  /* put TM result in proper position */
-      if (total > 1) {  /* are there elements to concat? */
-        L->top = top - 1;  /* top is one after last element (at top-2) */
-        luaV_concat(L, total);  /* concat them (may yield again) */
-      }
+      L->top = top - 1;  /* top is one after last element (at top-2) */
+      luaV_concat(L, total);  /* concat them (may yield again) */
+      break;
+    }
+    case OP_CLOSE:  case OP_RETURN: {  /* yielded closing variables */
+      ci->u.l.savedpc--;  /* repeat instruction to close other vars. */
       break;
       break;
     }
     }
     default: {
     default: {
@@ -788,39 +883,22 @@ void luaV_finishOp (lua_State *L) {
 #define l_gei(a,b)	(a >= b)
 #define l_gei(a,b)	(a >= b)
 
 
 
 
-/*
-** Auxiliary macro for arithmetic operations over floats and others
-** with immediate operand. 'fop' is the float operation; 'tm' is the
-** corresponding metamethod; 'flip' is true if operands were flipped.
-*/
-#define op_arithfI_aux(L,v1,imm,fop,tm,flip) {  \
-  lua_Number nb;  \
-  if (tonumberns(v1, nb)) {  \
-    lua_Number fimm = cast_num(imm);  \
-    pc++; setfltvalue(s2v(ra), fop(L, nb, fimm));  \
-  }}
-
-
-/*
-** Arithmetic operations over floats and others with immediate operand.
-*/
-#define op_arithfI(L,fop,tm) {  \
-  TValue *v1 = vRB(i);  \
-  int imm = GETARG_sC(i);  \
-  op_arithfI_aux(L, v1, imm, fop, tm, 0); }
-
 /*
 /*
 ** Arithmetic operations with immediate operands. 'iop' is the integer
 ** Arithmetic operations with immediate operands. 'iop' is the integer
-** operation.
+** operation, 'fop' is the float operation.
 */
 */
-#define op_arithI(L,iop,fop,tm,flip) {  \
+#define op_arithI(L,iop,fop) {  \
   TValue *v1 = vRB(i);  \
   TValue *v1 = vRB(i);  \
   int imm = GETARG_sC(i);  \
   int imm = GETARG_sC(i);  \
   if (ttisinteger(v1)) {  \
   if (ttisinteger(v1)) {  \
     lua_Integer iv1 = ivalue(v1);  \
     lua_Integer iv1 = ivalue(v1);  \
     pc++; setivalue(s2v(ra), iop(L, iv1, imm));  \
     pc++; setivalue(s2v(ra), iop(L, iv1, imm));  \
   }  \
   }  \
-  else op_arithfI_aux(L, v1, imm, fop, tm, flip); }
+  else if (ttisfloat(v1)) {  \
+    lua_Number nb = fltvalue(v1);  \
+    lua_Number fimm = cast_num(imm);  \
+    pc++; setfltvalue(s2v(ra), fop(L, nb, fimm)); \
+  }}
 
 
 
 
 /*
 /*
@@ -844,11 +922,18 @@ void luaV_finishOp (lua_State *L) {
 
 
 
 
 /*
 /*
-** Arithmetic operations with register operands.
+** Arithmetic operations with K operands for floats.
 */
 */
-#define op_arith(L,iop,fop) {  \
+#define op_arithfK(L,fop) {  \
   TValue *v1 = vRB(i);  \
   TValue *v1 = vRB(i);  \
-  TValue *v2 = vRC(i);  \
+  TValue *v2 = KC(i); lua_assert(ttisnumber(v2));  \
+  op_arithf_aux(L, v1, v2, fop); }
+
+
+/*
+** Arithmetic operations over integers and floats.
+*/
+#define op_arith_aux(L,v1,v2,iop,fop) {  \
   if (ttisinteger(v1) && ttisinteger(v2)) {  \
   if (ttisinteger(v1) && ttisinteger(v2)) {  \
     lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2);  \
     lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2);  \
     pc++; setivalue(s2v(ra), iop(L, i1, i2));  \
     pc++; setivalue(s2v(ra), iop(L, i1, i2));  \
@@ -857,32 +942,21 @@ void luaV_finishOp (lua_State *L) {
 
 
 
 
 /*
 /*
-** Arithmetic operations with K operands.
+** Arithmetic operations with register operands.
 */
 */
-#define op_arithK(L,iop,fop,flip) {  \
+#define op_arith(L,iop,fop) {  \
   TValue *v1 = vRB(i);  \
   TValue *v1 = vRB(i);  \
-  TValue *v2 = KC(i);  \
-  if (ttisinteger(v1) && ttisinteger(v2)) {  \
-    lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2);  \
-    pc++; setivalue(s2v(ra), iop(L, i1, i2));  \
-  }  \
-  else { \
-    lua_Number n1; lua_Number n2;  \
-    if (tonumberns(v1, n1) && tonumberns(v2, n2)) {  \
-      pc++; setfltvalue(s2v(ra), fop(L, n1, n2));  \
-    }}}
+  TValue *v2 = vRC(i);  \
+  op_arith_aux(L, v1, v2, iop, fop); }
 
 
 
 
 /*
 /*
-** Arithmetic operations with K operands for floats.
+** Arithmetic operations with K operands.
 */
 */
-#define op_arithfK(L,fop) {  \
+#define op_arithK(L,iop,fop) {  \
   TValue *v1 = vRB(i);  \
   TValue *v1 = vRB(i);  \
-  TValue *v2 = KC(i);  \
-  lua_Number n1; lua_Number n2;  \
-  if (tonumberns(v1, n1) && tonumberns(v2, n2)) {  \
-    pc++; setfltvalue(s2v(ra), fop(L, n1, n2));  \
-  }}
+  TValue *v2 = KC(i); lua_assert(ttisnumber(v2));  \
+  op_arith_aux(L, v1, v2, iop, fop); }
 
 
 
 
 /*
 /*
@@ -911,9 +985,11 @@ void luaV_finishOp (lua_State *L) {
 
 
 
 
 /*
 /*
-** Order operations with register operands.
+** Order operations with register operands. 'opn' actually works
+** for all numbers, but the fast track improves performance for
+** integers.
 */
 */
-#define op_order(L,opi,opf,other) {  \
+#define op_order(L,opi,opn,other) {  \
         int cond;  \
         int cond;  \
         TValue *rb = vRB(i);  \
         TValue *rb = vRB(i);  \
         if (ttisinteger(s2v(ra)) && ttisinteger(rb)) {  \
         if (ttisinteger(s2v(ra)) && ttisinteger(rb)) {  \
@@ -922,14 +998,15 @@ void luaV_finishOp (lua_State *L) {
           cond = opi(ia, ib);  \
           cond = opi(ia, ib);  \
         }  \
         }  \
         else if (ttisnumber(s2v(ra)) && ttisnumber(rb))  \
         else if (ttisnumber(s2v(ra)) && ttisnumber(rb))  \
-          cond = opf(s2v(ra), rb);  \
+          cond = opn(s2v(ra), rb);  \
         else  \
         else  \
           Protect(cond = other(L, s2v(ra), rb));  \
           Protect(cond = other(L, s2v(ra), rb));  \
         docondjump(); }
         docondjump(); }
 
 
 
 
 /*
 /*
-** Order operations with immediate operand.
+** Order operations with immediate operand. (Immediate operand is
+** always small enough to have an exact representation as a float.)
 */
 */
 #define op_orderI(L,opi,opf,inv,tm) {  \
 #define op_orderI(L,opi,opf,inv,tm) {  \
         int cond;  \
         int cond;  \
@@ -977,7 +1054,8 @@ void luaV_finishOp (lua_State *L) {
 #define updatebase(ci)	(base = ci->func + 1)
 #define updatebase(ci)	(base = ci->func + 1)
 
 
 
 
-#define updatestack(ci) { if (trap) { updatebase(ci); ra = RA(i); } }
+#define updatestack(ci)  \
+	{ if (l_unlikely(trap)) { updatebase(ci); ra = RA(i); } }
 
 
 
 
 /*
 /*
@@ -1021,25 +1099,21 @@ void luaV_finishOp (lua_State *L) {
 #define ProtectNT(exp)  (savepc(L), (exp), updatetrap(ci))
 #define ProtectNT(exp)  (savepc(L), (exp), updatetrap(ci))
 
 
 /*
 /*
-** Protect code that will finish the loop (returns) or can only raise
-** errors. (That is, it will not return to the interpreter main loop
-** after changing the stack or hooks.)
+** Protect code that can only raise errors. (That is, it cannnot change
+** the stack or hooks.)
 */
 */
 #define halfProtect(exp)  (savestate(L,ci), (exp))
 #define halfProtect(exp)  (savestate(L,ci), (exp))
 
 
-/* idem, but without changing the stack */
-#define halfProtectNT(exp)  (savepc(L), (exp))
-
-
+/* 'c' is the limit of live values in the stack */
 #define checkGC(L,c)  \
 #define checkGC(L,c)  \
-	{ luaC_condGC(L, L->top = (c),  /* limit of live values */ \
+	{ luaC_condGC(L, (savepc(L), L->top = (c)), \
                          updatetrap(ci)); \
                          updatetrap(ci)); \
            luai_threadyield(L); }
            luai_threadyield(L); }
 
 
 
 
 /* fetch an instruction and prepare its execution */
 /* fetch an instruction and prepare its execution */
 #define vmfetch()	{ \
 #define vmfetch()	{ \
-  if (trap) {  /* stack reallocation or hooks? */ \
+  if (l_unlikely(trap)) {  /* stack reallocation or hooks? */ \
     trap = luaG_traceexec(L, pc);  /* handle hooks */ \
     trap = luaG_traceexec(L, pc);  /* handle hooks */ \
     updatebase(ci);  /* correct stack */ \
     updatebase(ci);  /* correct stack */ \
   } \
   } \
@@ -1061,17 +1135,20 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
 #if LUA_USE_JUMPTABLE
 #if LUA_USE_JUMPTABLE
 #include "ljumptab.h"
 #include "ljumptab.h"
 #endif
 #endif
- tailcall:
+ startfunc:
   trap = L->hookmask;
   trap = L->hookmask;
+ returning:  /* trap already set */
   cl = clLvalue(s2v(ci->func));
   cl = clLvalue(s2v(ci->func));
   k = cl->p->k;
   k = cl->p->k;
   pc = ci->u.l.savedpc;
   pc = ci->u.l.savedpc;
-  if (trap) {
-    if (cl->p->is_vararg)
-      trap = 0;  /* hooks will start after VARARGPREP instruction */
-    else if (pc == cl->p->code)  /* first instruction (not resuming)? */
-      luaD_hookcall(L, ci);
-    ci->u.l.trap = 1;  /* there may be other hooks */
+  if (l_unlikely(trap)) {
+    if (pc == cl->p->code) {  /* first instruction (not resuming)? */
+      if (cl->p->is_vararg)
+        trap = 0;  /* hooks will start after VARARGPREP instruction */
+      else  /* check 'call' hook */
+        luaD_hookcall(L, ci);
+    }
+    ci->u.l.trap = 1;  /* assume trap is on, for now */
   }
   }
   base = ci->func + 1;
   base = ci->func + 1;
   /* main loop of interpreter */
   /* main loop of interpreter */
@@ -1079,10 +1156,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
     Instruction i;  /* instruction being executed */
     Instruction i;  /* instruction being executed */
     StkId ra;  /* instruction's A register */
     StkId ra;  /* instruction's A register */
     vmfetch();
     vmfetch();
+// low-level line tracing for debugging Lua
+// printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
     lua_assert(base == ci->func + 1);
     lua_assert(base == ci->func + 1);
-    lua_assert(base <= L->top && L->top < L->stack + L->stacksize);
+    lua_assert(base <= L->top && L->top < L->stack_last);
     /* invalidate top for instructions not expecting it */
     /* invalidate top for instructions not expecting it */
-    lua_assert(isIT(i) || (L->top = base));
+    lua_assert(isIT(i) || (cast_void(L->top = base), 1));
     vmdispatch (GET_OPCODE(i)) {
     vmdispatch (GET_OPCODE(i)) {
       vmcase(OP_MOVE) {
       vmcase(OP_MOVE) {
         setobjs2s(L, ra, RB(i));
         setobjs2s(L, ra, RB(i));
@@ -1109,9 +1188,17 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         setobj2s(L, ra, rb);
         setobj2s(L, ra, rb);
         vmbreak;
         vmbreak;
       }
       }
-      vmcase(OP_LOADBOOL) {
-        setbvalue(s2v(ra), GETARG_B(i));
-        if (GETARG_C(i)) pc++;  /* skip next instruction (if C) */
+      vmcase(OP_LOADFALSE) {
+        setbfvalue(s2v(ra));
+        vmbreak;
+      }
+      vmcase(OP_LFALSESKIP) {
+        setbfvalue(s2v(ra));
+        pc++;  /* skip next instruction */
+        vmbreak;
+      }
+      vmcase(OP_LOADTRUE) {
+        setbtvalue(s2v(ra));
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_LOADNIL) {
       vmcase(OP_LOADNIL) {
@@ -1243,8 +1330,9 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         Table *t;
         Table *t;
         if (b > 0)
         if (b > 0)
           b = 1 << (b - 1);  /* size is 2^(b - 1) */
           b = 1 << (b - 1);  /* size is 2^(b - 1) */
-        if (TESTARG_k(i))
-          c += GETARG_Ax(*pc) * (MAXARG_C + 1);
+        lua_assert((!TESTARG_k(i)) == (GETARG_Ax(*pc) == 0));
+        if (TESTARG_k(i))  /* non-zero extra argument? */
+          c += GETARG_Ax(*pc) * (MAXARG_C + 1);  /* add it to size */
         pc++;  /* skip extra argument */
         pc++;  /* skip extra argument */
         L->top = ra + 1;  /* correct top in case of emergency GC */
         L->top = ra + 1;  /* correct top in case of emergency GC */
         t = luaH_new(L);  /* memory allocation */
         t = luaH_new(L);  /* memory allocation */
@@ -1268,23 +1356,23 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_ADDI) {
       vmcase(OP_ADDI) {
-        op_arithI(L, l_addi, luai_numadd, TM_ADD, GETARG_k(i));
+        op_arithI(L, l_addi, luai_numadd);
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_ADDK) {
       vmcase(OP_ADDK) {
-        op_arithK(L, l_addi, luai_numadd, GETARG_k(i));
+        op_arithK(L, l_addi, luai_numadd);
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_SUBK) {
       vmcase(OP_SUBK) {
-        op_arithK(L, l_subi, luai_numsub, 0);
+        op_arithK(L, l_subi, luai_numsub);
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_MULK) {
       vmcase(OP_MULK) {
-        op_arithK(L, l_muli, luai_nummul, GETARG_k(i));
+        op_arithK(L, l_muli, luai_nummul);
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_MODK) {
       vmcase(OP_MODK) {
-        op_arithK(L, luaV_mod, luaV_modf, 0);
+        op_arithK(L, luaV_mod, luaV_modf);
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_POWK) {
       vmcase(OP_POWK) {
@@ -1296,7 +1384,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_IDIVK) {
       vmcase(OP_IDIVK) {
-        op_arithK(L, luaV_idiv, luai_numidiv, 0);
+        op_arithK(L, luaV_idiv, luai_numidiv);
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_BANDK) {
       vmcase(OP_BANDK) {
@@ -1430,8 +1518,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
       }
       }
       vmcase(OP_NOT) {
       vmcase(OP_NOT) {
         TValue *rb = vRB(i);
         TValue *rb = vRB(i);
-        int nrb = l_isfalse(rb);  /* next assignment may change this value */
-        setbvalue(s2v(ra), nrb);
+        if (l_isfalse(rb))
+          setbtvalue(s2v(ra));
+        else
+          setbfvalue(s2v(ra));
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_LEN) {
       vmcase(OP_LEN) {
@@ -1446,7 +1536,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_CLOSE) {
       vmcase(OP_CLOSE) {
-        Protect(luaF_close(L, ra, LUA_OK));
+        Protect(luaF_close(L, ra, LUA_OK, 1));
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_TBC) {
       vmcase(OP_TBC) {
@@ -1476,7 +1566,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
       vmcase(OP_EQK) {
       vmcase(OP_EQK) {
         TValue *rb = KB(i);
         TValue *rb = KB(i);
         /* basic types do not use '__eq'; we can use raw equality */
         /* basic types do not use '__eq'; we can use raw equality */
-        int cond = luaV_equalobj(NULL, s2v(ra), rb);
+        int cond = luaV_rawequalobj(s2v(ra), rb);
         docondjump();
         docondjump();
         vmbreak;
         vmbreak;
       }
       }
@@ -1524,49 +1614,54 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_CALL) {
       vmcase(OP_CALL) {
+        CallInfo *newci;
         int b = GETARG_B(i);
         int b = GETARG_B(i);
         int nresults = GETARG_C(i) - 1;
         int nresults = GETARG_C(i) - 1;
         if (b != 0)  /* fixed number of arguments? */
         if (b != 0)  /* fixed number of arguments? */
           L->top = ra + b;  /* top signals number of arguments */
           L->top = ra + b;  /* top signals number of arguments */
         /* else previous instruction set top */
         /* else previous instruction set top */
-        ProtectNT(luaD_call(L, ra, nresults));
+        savepc(L);  /* in case of errors */
+        if ((newci = luaD_precall(L, ra, nresults)) == NULL)
+          updatetrap(ci);  /* C call; nothing else to be done */
+        else {  /* Lua call: run function in this same C frame */
+          ci = newci;
+          ci->callstatus = 0;  /* call re-uses 'luaV_execute' */
+          goto startfunc;
+        }
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_TAILCALL) {
       vmcase(OP_TAILCALL) {
         int b = GETARG_B(i);  /* number of arguments + 1 (function) */
         int b = GETARG_B(i);  /* number of arguments + 1 (function) */
         int nparams1 = GETARG_C(i);
         int nparams1 = GETARG_C(i);
-        /* delat is virtual 'func' - real 'func' (vararg functions) */
+        /* delta is virtual 'func' - real 'func' (vararg functions) */
         int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
         int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
         if (b != 0)
         if (b != 0)
           L->top = ra + b;
           L->top = ra + b;
         else  /* previous instruction set top */
         else  /* previous instruction set top */
           b = cast_int(L->top - ra);
           b = cast_int(L->top - ra);
-        savepc(ci);  /* some calls here can raise errors */
+        savepc(ci);  /* several calls here can raise errors */
         if (TESTARG_k(i)) {
         if (TESTARG_k(i)) {
-          /* close upvalues from current call; the compiler ensures
-             that there are no to-be-closed variables here, so this
-             call cannot change the stack */
-          luaF_close(L, base, NOCLOSINGMETH);
+          luaF_closeupval(L, base);  /* close upvalues from current call */
+          lua_assert(L->tbclist < base);  /* no pending tbc variables */
           lua_assert(base == ci->func + 1);
           lua_assert(base == ci->func + 1);
         }
         }
-        if (!ttisfunction(s2v(ra))) {  /* not a function? */
+        while (!ttisfunction(s2v(ra))) {  /* not a function? */
           luaD_tryfuncTM(L, ra);  /* try '__call' metamethod */
           luaD_tryfuncTM(L, ra);  /* try '__call' metamethod */
           b++;  /* there is now one extra argument */
           b++;  /* there is now one extra argument */
+          checkstackGCp(L, 1, ra);
         }
         }
         if (!ttisLclosure(s2v(ra))) {  /* C function? */
         if (!ttisLclosure(s2v(ra))) {  /* C function? */
-          luaD_call(L, ra, LUA_MULTRET);  /* call it */
+          luaD_precall(L, ra, LUA_MULTRET);  /* call it */
           updatetrap(ci);
           updatetrap(ci);
           updatestack(ci);  /* stack may have been relocated */
           updatestack(ci);  /* stack may have been relocated */
-          ci->func -= delta;
-          luaD_poscall(L, ci, cast_int(L->top - ra));
-          return;
+          ci->func -= delta;  /* restore 'func' (if vararg) */
+          luaD_poscall(L, ci, cast_int(L->top - ra));  /* finish caller */
+          updatetrap(ci);  /* 'luaD_poscall' can change hooks */
+          goto ret;  /* caller returns after the tail call */
         }
         }
-        else {  /* Lua tail call */
-          ci->func -= delta;
-          luaD_pretailcall(L, ci, ra, b);  /* prepare call frame */
-          goto tailcall;
-        }
-        vmbreak;
+        ci->func -= delta;  /* restore 'func' (if vararg) */
+        luaD_pretailcall(L, ci, ra, b);  /* prepare call frame */
+        goto startfunc;  /* execute the callee */
       }
       }
       vmcase(OP_RETURN) {
       vmcase(OP_RETURN) {
         int n = GETARG_B(i) - 1;  /* number of results */
         int n = GETARG_B(i) - 1;  /* number of results */
@@ -1577,7 +1672,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         if (TESTARG_k(i)) {  /* may there be open upvalues? */
         if (TESTARG_k(i)) {  /* may there be open upvalues? */
           if (L->top < ci->top)
           if (L->top < ci->top)
             L->top = ci->top;
             L->top = ci->top;
-          luaF_close(L, base, LUA_OK);
+          luaF_close(L, base, CLOSEKTOP, 1);
           updatetrap(ci);
           updatetrap(ci);
           updatestack(ci);
           updatestack(ci);
         }
         }
@@ -1585,26 +1680,31 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
           ci->func -= ci->u.l.nextraargs + nparams1;
           ci->func -= ci->u.l.nextraargs + nparams1;
         L->top = ra + n;  /* set call for 'luaD_poscall' */
         L->top = ra + n;  /* set call for 'luaD_poscall' */
         luaD_poscall(L, ci, n);
         luaD_poscall(L, ci, n);
-        return;
+        updatetrap(ci);  /* 'luaD_poscall' can change hooks */
+        goto ret;
       }
       }
       vmcase(OP_RETURN0) {
       vmcase(OP_RETURN0) {
-        if (L->hookmask) {
+        if (l_unlikely(L->hookmask)) {
           L->top = ra;
           L->top = ra;
-          halfProtectNT(luaD_poscall(L, ci, 0));  /* no hurry... */
+          savepc(ci);
+          luaD_poscall(L, ci, 0);  /* no hurry... */
+          trap = 1;
         }
         }
         else {  /* do the 'poscall' here */
         else {  /* do the 'poscall' here */
-          int nres = ci->nresults;
+          int nres;
           L->ci = ci->previous;  /* back to caller */
           L->ci = ci->previous;  /* back to caller */
           L->top = base - 1;
           L->top = base - 1;
-          while (nres-- > 0)
+          for (nres = ci->nresults; l_unlikely(nres > 0); nres--)
             setnilvalue(s2v(L->top++));  /* all results are nil */
             setnilvalue(s2v(L->top++));  /* all results are nil */
         }
         }
-        return;
+        goto ret;
       }
       }
       vmcase(OP_RETURN1) {
       vmcase(OP_RETURN1) {
-        if (L->hookmask) {
+        if (l_unlikely(L->hookmask)) {
           L->top = ra + 1;
           L->top = ra + 1;
-          halfProtectNT(luaD_poscall(L, ci, 1));  /* no hurry... */
+          savepc(ci);
+          luaD_poscall(L, ci, 1);  /* no hurry... */
+          trap = 1;
         }
         }
         else {  /* do the 'poscall' here */
         else {  /* do the 'poscall' here */
           int nres = ci->nresults;
           int nres = ci->nresults;
@@ -1614,11 +1714,17 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
           else {
           else {
             setobjs2s(L, base - 1, ra);  /* at least this result */
             setobjs2s(L, base - 1, ra);  /* at least this result */
             L->top = base;
             L->top = base;
-            while (--nres > 0)  /* complete missing results */
-              setnilvalue(s2v(L->top++));
+            for (; l_unlikely(nres > 1); nres--)
+              setnilvalue(s2v(L->top++));  /* complete missing results */
           }
           }
         }
         }
-        return;
+       ret:  /* return from a Lua function */
+        if (ci->callstatus & CIST_FRESH)
+          return;  /* end this frame */
+        else {
+          ci = ci->previous;
+          goto returning;  /* continue running caller in this frame */
+        }
       }
       }
       vmcase(OP_FORLOOP) {
       vmcase(OP_FORLOOP) {
         if (ttisinteger(s2v(ra + 2))) {  /* integer loop? */
         if (ttisinteger(s2v(ra + 2))) {  /* integer loop? */
@@ -1633,73 +1739,15 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
             pc -= GETARG_Bx(i);  /* jump back */
             pc -= GETARG_Bx(i);  /* jump back */
           }
           }
         }
         }
-        else {  /* floating loop */
-          lua_Number step = fltvalue(s2v(ra + 2));
-          lua_Number limit = fltvalue(s2v(ra + 1));
-          lua_Number idx = fltvalue(s2v(ra));
-          idx = luai_numadd(L, idx, step);  /* increment index */
-          if (luai_numlt(0, step) ? luai_numle(idx, limit)
-                                  : luai_numle(limit, idx)) {
-            chgfltvalue(s2v(ra), idx);  /* update internal index */
-            setfltvalue(s2v(ra + 3), idx);  /* and control variable */
-            pc -= GETARG_Bx(i);  /* jump back */
-          }
-        }
+        else if (floatforloop(ra))  /* float loop */
+          pc -= GETARG_Bx(i);  /* jump back */
         updatetrap(ci);  /* allows a signal to break the loop */
         updatetrap(ci);  /* allows a signal to break the loop */
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_FORPREP) {
       vmcase(OP_FORPREP) {
-        TValue *pinit = s2v(ra);
-        TValue *plimit = s2v(ra + 1);
-        TValue *pstep = s2v(ra + 2);
         savestate(L, ci);  /* in case of errors */
         savestate(L, ci);  /* in case of errors */
-        if (ttisinteger(pinit) && ttisinteger(pstep)) { /* integer loop? */
-          lua_Integer init = ivalue(pinit);
-          lua_Integer step = ivalue(pstep);
-          lua_Integer limit;
-          if (step == 0)
-            luaG_runerror(L, "'for' step is zero");
-          setivalue(s2v(ra + 3), init);  /* control variable */
-          if (forlimit(L, init, plimit, &limit, step))
-            pc += GETARG_Bx(i) + 1;  /* skip the loop */
-          else {  /* prepare loop counter */
-            lua_Unsigned count;
-            if (step > 0) {  /* ascending loop? */
-              count = l_castS2U(limit) - l_castS2U(init);
-              if (step != 1)  /* avoid division in the too common case */
-                count /= l_castS2U(step);
-            }
-            else {  /* step < 0; descending loop */
-              count = l_castS2U(init) - l_castS2U(limit);
-              /* 'step+1' avoids negating 'mininteger' */
-              count /= l_castS2U(-(step + 1)) + 1u;
-            }
-            /* store the counter in place of the limit (which won't be
-               needed anymore */
-            setivalue(plimit, l_castU2S(count));
-          }
-        }
-        else {  /* try making all values floats */
-          lua_Number init; lua_Number limit; lua_Number step;
-          if (unlikely(!tonumber(plimit, &limit)))
-            luaG_forerror(L, plimit, "limit");
-          if (unlikely(!tonumber(pstep, &step)))
-            luaG_forerror(L, pstep, "step");
-          if (unlikely(!tonumber(pinit, &init)))
-            luaG_forerror(L, pinit, "initial value");
-          if (step == 0)
-            luaG_runerror(L, "'for' step is zero");
-          if (luai_numlt(0, step) ? luai_numlt(limit, init)
-                                   : luai_numlt(init, limit))
-            pc += GETARG_Bx(i) + 1;  /* skip the loop */
-          else {
-            /* make sure internal values are all float */
-            setfltvalue(plimit, limit);
-            setfltvalue(pstep, step);
-            setfltvalue(s2v(ra), init);  /* internal index */
-            setfltvalue(s2v(ra + 3), init);  /* control variable */
-          }
-        }
+        if (forprep(L, ra))
+          pc += GETARG_Bx(i) + 1;  /* skip the loop */
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_TFORPREP) {
       vmcase(OP_TFORPREP) {
@@ -1769,11 +1817,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_VARARGPREP) {
       vmcase(OP_VARARGPREP) {
-        luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p);
-        updatetrap(ci);
-        if (trap) {
+        ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p));
+        if (l_unlikely(trap)) {  /* previous "Protect" updated trap */
           luaD_hookcall(L, ci);
           luaD_hookcall(L, ci);
-          L->oldpc = pc + 1;  /* next opcode will be seen as a "new" line */
+          L->oldpc = 1;  /* next opcode will be seen as a "new" line */
         }
         }
         updatebase(ci);  /* function has new base after adjustment */
         updatebase(ci);  /* function has new base after adjustment */
         vmbreak;
         vmbreak;

+ 19 - 6
src/lvm.h

@@ -33,10 +33,20 @@
 ** integral values)
 ** integral values)
 */
 */
 #if !defined(LUA_FLOORN2I)
 #if !defined(LUA_FLOORN2I)
-#define LUA_FLOORN2I		0
+#define LUA_FLOORN2I		F2Ieq
 #endif
 #endif
 
 
 
 
+/*
+** Rounding modes for float->integer coercion
+ */
+typedef enum {
+  F2Ieq,     /* no rounding; accepts only integral values */
+  F2Ifloor,  /* takes the floor of the number */
+  F2Iceil    /* takes the ceil of the number */
+} F2Imod;
+
+
 /* convert an object to a float (including string coercion) */
 /* convert an object to a float (including string coercion) */
 #define tonumber(o,n) \
 #define tonumber(o,n) \
 	(ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))
 	(ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))
@@ -50,12 +60,14 @@
 
 
 /* convert an object to an integer (including string coercion) */
 /* convert an object to an integer (including string coercion) */
 #define tointeger(o,i) \
 #define tointeger(o,i) \
-  (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))
+  (l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \
+                          : luaV_tointeger(o,i,LUA_FLOORN2I))
 
 
 
 
 /* convert an object to an integer (without string coercion) */
 /* convert an object to an integer (without string coercion) */
 #define tointegerns(o,i) \
 #define tointegerns(o,i) \
-  (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointegerns(o,i,LUA_FLOORN2I))
+  (l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \
+                          : luaV_tointegerns(o,i,LUA_FLOORN2I))
 
 
 
 
 #define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
 #define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
@@ -104,9 +116,10 @@ LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
 LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
 LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
 LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
 LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
 LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
 LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
-LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode);
-LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p, int mode);
-LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, int mode);
+LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, F2Imod mode);
+LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p,
+                                F2Imod mode);
+LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode);
 LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
 LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
                                StkId val, const TValue *slot);
                                StkId val, const TValue *slot);
 LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
 LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно