Explorar el Código

Upstream Lua 5.4.6

Hugo Musso Gualandi hace 1 año
padre
commit
89128a4c24
Se han modificado 48 ficheros con 1955 adiciones y 1320 borrados
  1. 10 18
      Makefile
  2. 25 14
      doc/contents.html
  3. 72 29
      doc/lua.1
  4. 341 184
      doc/manual.html
  5. 17 19
      doc/readme.html
  6. 7 26
      src/Makefile
  7. 148 140
      src/lapi.c
  8. 10 7
      src/lapi.h
  9. 32 25
      src/lauxlib.c
  10. 9 1
      src/lauxlib.h
  11. 25 4
      src/lbaselib.c
  12. 114 57
      src/lcode.c
  13. 4 4
      src/lcorolib.c
  14. 116 69
      src/ldebug.c
  15. 1 1
      src/ldebug.h
  16. 204 143
      src/ldo.c
  17. 14 5
      src/ldo.h
  18. 6 2
      src/ldump.c
  19. 27 28
      src/lfunc.c
  20. 3 3
      src/lfunc.h
  21. 66 55
      src/lgc.c
  22. 21 8
      src/lgc.h
  23. 3 3
      src/llex.c
  24. 32 5
      src/llimits.h
  25. 7 7
      src/lmathlib.c
  26. 41 27
      src/lmem.c
  27. 7 2
      src/loadlib.c
  28. 29 19
      src/lobject.c
  29. 19 11
      src/lobject.h
  30. 18 5
      src/lopcodes.h
  31. 17 19
      src/loslib.c
  32. 32 21
      src/lparser.c
  33. 41 35
      src/lstate.c
  34. 18 13
      src/lstate.h
  35. 94 37
      src/lstrlib.c
  36. 33 24
      src/ltable.c
  37. 0 1
      src/ltable.h
  38. 4 3
      src/ltablib.c
  39. 19 19
      src/ltm.c
  40. 3 2
      src/ltm.h
  41. 48 28
      src/lua.c
  42. 16 11
      src/lua.h
  43. 5 18
      src/luac.c
  44. 15 8
      src/luaconf.h
  45. 5 3
      src/lundump.c
  46. 19 17
      src/lutf8lib.c
  47. 153 140
      src/lvm.c
  48. 5 0
      src/lvm.h

+ 10 - 18
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
 
 
 # Where to install. The installation starts in the src and doc directories,
 # Where to install. The installation starts in the src and doc directories,
 # so take care if INSTALL_TOP is not an absolute path. See the local target.
 # so take care if INSTALL_TOP is not an absolute path. See the local target.
@@ -36,7 +36,7 @@ RM= rm -f
 # == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
 # == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
 
 
 # Convenience platforms targets.
 # Convenience platforms targets.
-PLATS= aix bsd c89 freebsd generic guess linux linux-readline macosx mingw posix solaris
+PLATS= guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
 
 
 # What to install.
 # What to install.
 TO_BIN= lua luac
 TO_BIN= lua luac
@@ -46,16 +46,13 @@ TO_MAN= lua.1 luac.1
 
 
 # Lua version and release.
 # Lua version and release.
 V= 5.4
 V= 5.4
-R= $V.0
+R= $V.6
 
 
 # Targets start here.
 # Targets start here.
 all:	$(PLAT)
 all:	$(PLAT)
 
 
-$(PLATS) clean:
-	cd src && $(MAKE) $@
-
-test:	dummy
-	src/lua -v
+$(PLATS) help test clean:
+	@cd src && $(MAKE) $@
 
 
 install: dummy
 install: dummy
 	cd src && $(MKDIR) $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD)
 	cd src && $(MKDIR) $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD)
@@ -73,15 +70,10 @@ uninstall:
 local:
 local:
 	$(MAKE) install INSTALL_TOP=../install
 	$(MAKE) install INSTALL_TOP=../install
 
 
-none:
-	@echo "Please do 'make PLATFORM' where PLATFORM is one of these:"
-	@echo "   $(PLATS)"
-	@echo "See doc/readme.html for complete instructions."
-
-# make may get confused with test/ and install/
+# make may get confused with install/ if it does not support .PHONY.
 dummy:
 dummy:
 
 
-# echo config parameters
+# Echo config parameters.
 echo:
 echo:
 	@cd src && $(MAKE) -s echo
 	@cd src && $(MAKE) -s echo
 	@echo "PLAT= $(PLAT)"
 	@echo "PLAT= $(PLAT)"
@@ -101,14 +93,14 @@ echo:
 	@echo "INSTALL_EXEC= $(INSTALL_EXEC)"
 	@echo "INSTALL_EXEC= $(INSTALL_EXEC)"
 	@echo "INSTALL_DATA= $(INSTALL_DATA)"
 	@echo "INSTALL_DATA= $(INSTALL_DATA)"
 
 
-# echo pkg-config data
+# Echo pkg-config data.
 pc:
 pc:
 	@echo "version=$R"
 	@echo "version=$R"
 	@echo "prefix=$(INSTALL_TOP)"
 	@echo "prefix=$(INSTALL_TOP)"
 	@echo "libdir=$(INSTALL_LIB)"
 	@echo "libdir=$(INSTALL_LIB)"
 	@echo "includedir=$(INSTALL_INC)"
 	@echo "includedir=$(INSTALL_INC)"
 
 
-# list targets that do not create files (but not all makes understand .PHONY)
-.PHONY: all $(PLATS) clean test install uninstall local none dummy echo pc
+# Targets that do not create files (not all makes understand .PHONY).
+.PHONY: all $(PLATS) help test clean install uninstall local dummy echo pc
 
 
 # (end of Makefile)
 # (end of Makefile)

+ 25 - 14
doc/contents.html

@@ -32,7 +32,7 @@ For a complete introduction to Lua programming, see the book
 
 
 <P>
 <P>
 <SMALL>
 <SMALL>
-Copyright &copy; 2019 Lua.org, PUC-Rio.
+Copyright &copy; 2020&ndash;2023 Lua.org, PUC-Rio.
 Freely available under the terms of the
 Freely available under the terms of the
 <A HREF="http://www.lua.org/license.html">Lua license</A>.
 <A HREF="http://www.lua.org/license.html">Lua license</A>.
 </SMALL>
 </SMALL>
@@ -85,6 +85,8 @@ Freely available under the terms of the
 <LI><A HREF="manual.html#3.4.9">3.4.9 &ndash; Table Constructors</A>
 <LI><A HREF="manual.html#3.4.9">3.4.9 &ndash; Table Constructors</A>
 <LI><A HREF="manual.html#3.4.10">3.4.10 &ndash; Function Calls</A>
 <LI><A HREF="manual.html#3.4.10">3.4.10 &ndash; Function Calls</A>
 <LI><A HREF="manual.html#3.4.11">3.4.11 &ndash; Function Definitions</A>
 <LI><A HREF="manual.html#3.4.11">3.4.11 &ndash; Function Definitions</A>
+<LI><A HREF="manual.html#3.4.12">3.4.12 &ndash; Lists of expressions, multiple results, and adjustment<A>
+
 </UL>
 </UL>
 <LI><A HREF="manual.html#3.5">3.5 &ndash; Visibility Rules</A>
 <LI><A HREF="manual.html#3.5">3.5 &ndash; Visibility Rules</A>
 </UL>
 </UL>
@@ -92,14 +94,20 @@ Freely available under the terms of the
 <LI><A HREF="manual.html#4">4 &ndash; The Application Program Interface</A>
 <LI><A HREF="manual.html#4">4 &ndash; The Application Program Interface</A>
 <UL>
 <UL>
 <LI><A HREF="manual.html#4.1">4.1 &ndash; The Stack</A>
 <LI><A HREF="manual.html#4.1">4.1 &ndash; The Stack</A>
-<LI><A HREF="manual.html#4.2">4.2 &ndash; Stack Size</A>
-<LI><A HREF="manual.html#4.3">4.3 &ndash; Valid and Acceptable Indices</A>
-<LI><A HREF="manual.html#4.4">4.4 &ndash; C Closures</A>
-<LI><A HREF="manual.html#4.5">4.5 &ndash; Registry</A>
-<LI><A HREF="manual.html#4.6">4.6 &ndash; Error Handling in C</A>
-<LI><A HREF="manual.html#4.7">4.7 &ndash; Handling Yields in C</A>
-<LI><A HREF="manual.html#4.8">4.8 &ndash; Functions and Types</A>
-<LI><A HREF="manual.html#4.9">4.9 &ndash; The Debug Interface</A>
+<UL>
+<LI><A HREF="manual.html#4.1.1">4.1.1 &ndash; Stack Size</A>
+<LI><A HREF="manual.html#4.1.2">4.1.2 &ndash; Valid and Acceptable Indices</A>
+<LI><A HREF="manual.html#4.1.3">4.1.3 &ndash; Pointers to strings</A>
+</UL>
+<LI><A HREF="manual.html#4.2">4.2 &ndash; C Closures</A>
+<LI><A HREF="manual.html#4.3">4.3 &ndash; Registry</A>
+<LI><A HREF="manual.html#4.4">4.4 &ndash; Error Handling in C</A>
+<UL>
+<LI><A HREF="manual.html#4.4.1">4.4.1 &ndash; Status Codes</A>
+</UL>
+<LI><A HREF="manual.html#4.5">4.5 &ndash; Handling Yields in C</A>
+<LI><A HREF="manual.html#4.6">4.6 &ndash; Functions and Types</A>
+<LI><A HREF="manual.html#4.7">4.7 &ndash; The Debug Interface</A>
 </UL>
 </UL>
 <P>
 <P>
 <LI><A HREF="manual.html#5">5 &ndash; The Auxiliary Library</A>
 <LI><A HREF="manual.html#5">5 &ndash; The Auxiliary Library</A>
@@ -192,7 +200,6 @@ Freely available under the terms of the
 <A HREF="manual.html#pdf-debug.getregistry">debug.getregistry</A><BR>
 <A HREF="manual.html#pdf-debug.getregistry">debug.getregistry</A><BR>
 <A HREF="manual.html#pdf-debug.getupvalue">debug.getupvalue</A><BR>
 <A HREF="manual.html#pdf-debug.getupvalue">debug.getupvalue</A><BR>
 <A HREF="manual.html#pdf-debug.getuservalue">debug.getuservalue</A><BR>
 <A HREF="manual.html#pdf-debug.getuservalue">debug.getuservalue</A><BR>
-<A HREF="manual.html#pdf-debug.setcstacklimit">debug.setcstacklimit</A><BR>
 <A HREF="manual.html#pdf-debug.sethook">debug.sethook</A><BR>
 <A HREF="manual.html#pdf-debug.sethook">debug.sethook</A><BR>
 <A HREF="manual.html#pdf-debug.setlocal">debug.setlocal</A><BR>
 <A HREF="manual.html#pdf-debug.setlocal">debug.setlocal</A><BR>
 <A HREF="manual.html#pdf-debug.setmetatable">debug.setmetatable</A><BR>
 <A HREF="manual.html#pdf-debug.setmetatable">debug.setmetatable</A><BR>
@@ -391,6 +398,7 @@ Freely available under the terms of the
 <A HREF="manual.html#lua_callk">lua_callk</A><BR>
 <A HREF="manual.html#lua_callk">lua_callk</A><BR>
 <A HREF="manual.html#lua_checkstack">lua_checkstack</A><BR>
 <A HREF="manual.html#lua_checkstack">lua_checkstack</A><BR>
 <A HREF="manual.html#lua_close">lua_close</A><BR>
 <A HREF="manual.html#lua_close">lua_close</A><BR>
+<A HREF="manual.html#lua_closeslot">lua_closeslot</A><BR>
 <A HREF="manual.html#lua_compare">lua_compare</A><BR>
 <A HREF="manual.html#lua_compare">lua_compare</A><BR>
 <A HREF="manual.html#lua_concat">lua_concat</A><BR>
 <A HREF="manual.html#lua_concat">lua_concat</A><BR>
 <A HREF="manual.html#lua_copy">lua_copy</A><BR>
 <A HREF="manual.html#lua_copy">lua_copy</A><BR>
@@ -470,7 +478,6 @@ Freely available under the terms of the
 <A HREF="manual.html#lua_resume">lua_resume</A><BR>
 <A HREF="manual.html#lua_resume">lua_resume</A><BR>
 <A HREF="manual.html#lua_rotate">lua_rotate</A><BR>
 <A HREF="manual.html#lua_rotate">lua_rotate</A><BR>
 <A HREF="manual.html#lua_setallocf">lua_setallocf</A><BR>
 <A HREF="manual.html#lua_setallocf">lua_setallocf</A><BR>
-<A HREF="manual.html#lua_setcstacklimit">lua_setcstacklimit</A><BR>
 <A HREF="manual.html#lua_setfield">lua_setfield</A><BR>
 <A HREF="manual.html#lua_setfield">lua_setfield</A><BR>
 <A HREF="manual.html#lua_setglobal">lua_setglobal</A><BR>
 <A HREF="manual.html#lua_setglobal">lua_setglobal</A><BR>
 <A HREF="manual.html#lua_sethook">lua_sethook</A><BR>
 <A HREF="manual.html#lua_sethook">lua_sethook</A><BR>
@@ -529,6 +536,7 @@ Freely available under the terms of the
 <A HREF="manual.html#luaL_buffinit">luaL_buffinit</A><BR>
 <A HREF="manual.html#luaL_buffinit">luaL_buffinit</A><BR>
 <A HREF="manual.html#luaL_buffinitsize">luaL_buffinitsize</A><BR>
 <A HREF="manual.html#luaL_buffinitsize">luaL_buffinitsize</A><BR>
 <A HREF="manual.html#luaL_bufflen">luaL_bufflen</A><BR>
 <A HREF="manual.html#luaL_bufflen">luaL_bufflen</A><BR>
+<A HREF="manual.html#luaL_buffsub">luaL_buffsub</A><BR>
 <A HREF="manual.html#luaL_callmeta">luaL_callmeta</A><BR>
 <A HREF="manual.html#luaL_callmeta">luaL_callmeta</A><BR>
 <A HREF="manual.html#luaL_checkany">luaL_checkany</A><BR>
 <A HREF="manual.html#luaL_checkany">luaL_checkany</A><BR>
 <A HREF="manual.html#luaL_checkinteger">luaL_checkinteger</A><BR>
 <A HREF="manual.html#luaL_checkinteger">luaL_checkinteger</A><BR>
@@ -567,6 +575,7 @@ Freely available under the terms of the
 <A HREF="manual.html#luaL_optstring">luaL_optstring</A><BR>
 <A HREF="manual.html#luaL_optstring">luaL_optstring</A><BR>
 <A HREF="manual.html#luaL_prepbuffer">luaL_prepbuffer</A><BR>
 <A HREF="manual.html#luaL_prepbuffer">luaL_prepbuffer</A><BR>
 <A HREF="manual.html#luaL_prepbuffsize">luaL_prepbuffsize</A><BR>
 <A HREF="manual.html#luaL_prepbuffsize">luaL_prepbuffsize</A><BR>
+<A HREF="manual.html#luaL_pushfail">luaL_pushfail</A><BR>
 <A HREF="manual.html#luaL_pushresult">luaL_pushresult</A><BR>
 <A HREF="manual.html#luaL_pushresult">luaL_pushresult</A><BR>
 <A HREF="manual.html#luaL_pushresultsize">luaL_pushresultsize</A><BR>
 <A HREF="manual.html#luaL_pushresultsize">luaL_pushresultsize</A><BR>
 <A HREF="manual.html#luaL_ref">luaL_ref</A><BR>
 <A HREF="manual.html#luaL_ref">luaL_ref</A><BR>
@@ -606,7 +615,7 @@ Freely available under the terms of the
 <A HREF="manual.html#pdf-LUA_HOOKLINE">LUA_HOOKLINE</A><BR>
 <A HREF="manual.html#pdf-LUA_HOOKLINE">LUA_HOOKLINE</A><BR>
 <A HREF="manual.html#pdf-LUA_HOOKRET">LUA_HOOKRET</A><BR>
 <A HREF="manual.html#pdf-LUA_HOOKRET">LUA_HOOKRET</A><BR>
 <A HREF="manual.html#pdf-LUA_HOOKTAILCALL">LUA_HOOKTAILCALL</A><BR>
 <A HREF="manual.html#pdf-LUA_HOOKTAILCALL">LUA_HOOKTAILCALL</A><BR>
-<A HREF="manual.html#pdf-LUAL_BUFFERSIZE">LUAL_BUFFERSIZE</A><BR>
+<A HREF="manual.html#pdf-LUA_LOADED_TABLE">LUA_LOADED_TABLE</A><BR>
 <A HREF="manual.html#pdf-LUA_MASKCALL">LUA_MASKCALL</A><BR>
 <A HREF="manual.html#pdf-LUA_MASKCALL">LUA_MASKCALL</A><BR>
 <A HREF="manual.html#pdf-LUA_MASKCOUNT">LUA_MASKCOUNT</A><BR>
 <A HREF="manual.html#pdf-LUA_MASKCOUNT">LUA_MASKCOUNT</A><BR>
 <A HREF="manual.html#pdf-LUA_MASKLINE">LUA_MASKLINE</A><BR>
 <A HREF="manual.html#pdf-LUA_MASKLINE">LUA_MASKLINE</A><BR>
@@ -634,6 +643,7 @@ Freely available under the terms of the
 <A HREF="manual.html#pdf-LUA_OPSHR">LUA_OPSHR</A><BR>
 <A HREF="manual.html#pdf-LUA_OPSHR">LUA_OPSHR</A><BR>
 <A HREF="manual.html#pdf-LUA_OPSUB">LUA_OPSUB</A><BR>
 <A HREF="manual.html#pdf-LUA_OPSUB">LUA_OPSUB</A><BR>
 <A HREF="manual.html#pdf-LUA_OPUNM">LUA_OPUNM</A><BR>
 <A HREF="manual.html#pdf-LUA_OPUNM">LUA_OPUNM</A><BR>
+<A HREF="manual.html#pdf-LUA_PRELOAD_TABLE">LUA_PRELOAD_TABLE</A><BR>
 <A HREF="manual.html#pdf-LUA_REFNIL">LUA_REFNIL</A><BR>
 <A HREF="manual.html#pdf-LUA_REFNIL">LUA_REFNIL</A><BR>
 <A HREF="manual.html#pdf-LUA_REGISTRYINDEX">LUA_REGISTRYINDEX</A><BR>
 <A HREF="manual.html#pdf-LUA_REGISTRYINDEX">LUA_REGISTRYINDEX</A><BR>
 <A HREF="manual.html#pdf-LUA_RIDX_GLOBALS">LUA_RIDX_GLOBALS</A><BR>
 <A HREF="manual.html#pdf-LUA_RIDX_GLOBALS">LUA_RIDX_GLOBALS</A><BR>
@@ -650,6 +660,7 @@ Freely available under the terms of the
 <A HREF="manual.html#pdf-LUA_TUSERDATA">LUA_TUSERDATA</A><BR>
 <A HREF="manual.html#pdf-LUA_TUSERDATA">LUA_TUSERDATA</A><BR>
 <A HREF="manual.html#pdf-LUA_USE_APICHECK">LUA_USE_APICHECK</A><BR>
 <A HREF="manual.html#pdf-LUA_USE_APICHECK">LUA_USE_APICHECK</A><BR>
 <A HREF="manual.html#pdf-LUA_YIELD">LUA_YIELD</A><BR>
 <A HREF="manual.html#pdf-LUA_YIELD">LUA_YIELD</A><BR>
+<A HREF="manual.html#pdf-LUAL_BUFFERSIZE">LUAL_BUFFERSIZE</A><BR>
 
 
 </TD>
 </TD>
 </TR>
 </TR>
@@ -657,10 +668,10 @@ Freely available under the terms of the
 
 
 <P CLASS="footer">
 <P CLASS="footer">
 Last update:
 Last update:
-Thu Oct  3 17:35:42 UTC 2019
+Sat Apr  1 17:57:05 UTC 2023
 </P>
 </P>
 <!--
 <!--
-Last change: revised for Lua 5.4.0 (beta)
+Last change: revised for Lua 5.4.5
 -->
 -->
 
 
 </BODY>
 </BODY>

+ 72 - 29
doc/lua.1

@@ -1,5 +1,5 @@
-.\" $Id: lua.man,v 1.14 2016/10/17 15:43:50 lhf Exp $
-.TH LUA 1 "$Date: 2016/10/17 15:43:50 $"
+.\" $Id: lua.man,v 1.14 2022/09/23 09:06:36 lhf Exp $
+.TH LUA 1 "$Date: 2022/09/23 09:06:36 $"
 .SH NAME
 .SH NAME
 lua \- Lua interpreter
 lua \- Lua interpreter
 .SH SYNOPSIS
 .SH SYNOPSIS
@@ -25,52 +25,57 @@ the Lua compiler.)
 .B lua
 .B lua
 can be used as a batch interpreter and also interactively.
 can be used as a batch interpreter and also interactively.
 .LP
 .LP
-The given
-.I options
-are handled in order and then
+After handling the
+.IR options ,
 the Lua program in file
 the Lua program in file
 .I script
 .I script
 is loaded and executed.
 is loaded and executed.
-The given
+The
 .I args
 .I args
 are available to
 are available to
 .I script
 .I script
 as strings in a global table named
 as strings in a global table named
-.BR arg .
-If no options or arguments are given,
-then
-.B "\-v \-i"
-is assumed when the standard input is a terminal;
-otherwise,
-.B "\-"
-is assumed.
+.B arg
+and also as arguments to its main function.
+When called without arguments,
+.B lua
+behaves as
+.B "lua \-v \-i"
+if the standard input is a terminal,
+and as
+.B "lua \-"
+otherwise.
 .LP
 .LP
 In interactive mode,
 In interactive mode,
 .B lua
 .B lua
 prompts the user,
 prompts the user,
 reads lines from the standard input,
 reads lines from the standard input,
 and executes them as they are read.
 and executes them as they are read.
-If the line contains an expression or list of expressions,
-then the line is evaluated and the results are printed.
+If the line contains an expression,
+then the line is evaluated and the result is printed.
 If a line does not contain a complete statement,
 If a line does not contain a complete statement,
 then a secondary prompt is displayed and
 then a secondary prompt is displayed and
 lines are read until a complete statement is formed or
 lines are read until a complete statement is formed or
 a syntax error is found.
 a syntax error is found.
 .LP
 .LP
-At the very start,
-before even handling the command line,
+Before handling command line options and scripts,
 .B lua
 .B lua
 checks the contents of the environment variables
 checks the contents of the environment variables
-.B LUA_INIT_5_3
-or
+.B LUA_INIT_5_4
+and
 .BR LUA_INIT ,
 .BR LUA_INIT ,
 in that order.
 in that order.
-If the contents is of the form
+If the contents are of the form
 .RI '@ filename ',
 .RI '@ filename ',
 then
 then
 .I filename
 .I filename
 is executed.
 is executed.
-Otherwise, the string is assumed to be a Lua statement and is executed.
+Otherwise, the contents are assumed to be a Lua statement and is executed.
+When
+.B LUA_INIT_5_4
+is defined,
+.B LUA_INIT
+is ignored.
 .SH OPTIONS
 .SH OPTIONS
 .TP
 .TP
 .BI \-e " stat"
 .BI \-e " stat"
@@ -81,11 +86,17 @@ execute statement
 enter interactive mode after executing
 enter interactive mode after executing
 .IR script .
 .IR script .
 .TP
 .TP
-.BI \-l " name"
-execute the equivalent of
-.IB name =require(' name ')
-before executing
-.IR script .
+.BI \-l " mod"
+require library
+.I mod
+into global
+.IR mod .
+.TP
+.BI \-l " g=mod"
+require library
+.I mod
+into global
+.IR g .
 .TP
 .TP
 .B \-v
 .B \-v
 show version information.
 show version information.
@@ -93,18 +104,50 @@ show version information.
 .B \-E
 .B \-E
 ignore environment variables.
 ignore environment variables.
 .TP
 .TP
+.B \-W
+turn warnings on.
+.TP
 .B \-\-
 .B \-\-
 stop handling options.
 stop handling options.
 .TP
 .TP
 .B \-
 .B \-
 stop handling options and execute the standard input as a file.
 stop handling options and execute the standard input as a file.
+.SH ENVIRONMENT VARIABLES
+The following environment variables affect the execution of
+.BR lua .
+When defined,
+the version-specific variants take priority
+and the version-neutral variants are ignored.
+.TP
+.B LUA_INIT, LUA_INIT_5_4
+Code to be executed before command line options and scripts.
+.TP
+.B LUA_PATH, LUA_PATH_5_4
+Initial value of package.cpath,
+the path used by require to search for Lua loaders.
+.TP
+.B LUA_CPATH, LUA_CPATH_5_4
+Initial value of package.cpath,
+the path used by require to search for C loaders.
+.SH EXIT STATUS
+If a script calls os.exit,
+then
+.B lua
+exits with the given exit status.
+Otherwise,
+.B lua
+exits
+with EXIT_SUCCESS (0 on POSIX systems) if there were no errors
+and
+with EXIT_FAILURE (1 on POSIX systems) if there were errors.
+Errors raised in interactive mode do not cause exits.
+.SH DIAGNOSTICS
+Error messages should be self explanatory.
 .SH "SEE ALSO"
 .SH "SEE ALSO"
 .BR luac (1)
 .BR luac (1)
 .br
 .br
 The documentation at lua.org,
 The documentation at lua.org,
 especially section 7 of the reference manual.
 especially section 7 of the reference manual.
-.SH DIAGNOSTICS
-Error messages should be self explanatory.
 .SH AUTHORS
 .SH AUTHORS
 R. Ierusalimschy,
 R. Ierusalimschy,
 L. H. de Figueiredo,
 L. H. de Figueiredo,

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 341 - 184
doc/manual.html


+ 17 - 19
doc/readme.html

@@ -98,32 +98,28 @@ and
 If you don't have the time or the inclination to compile Lua yourself,
 If you don't have the time or the inclination to compile Lua yourself,
 get a binary from
 get a binary from
 <A HREF="http://lua-users.org/wiki/LuaBinaries">LuaBinaries</A>.
 <A HREF="http://lua-users.org/wiki/LuaBinaries">LuaBinaries</A>.
-Try also
-<A HREF="http://luadist.org/">LuaDist</A>,
-a multi-platform distribution of Lua that includes batteries.
 
 
 <H3>Building Lua</H3>
 <H3>Building Lua</H3>
 <P>
 <P>
-In most Unix-like platforms, simply do "<KBD>make</KBD>" with a suitable target.
+In most common Unix-like platforms, simply do "<KBD>make</KBD>".
 Here are the details.
 Here are the details.
 
 
 <OL>
 <OL>
 <LI>
 <LI>
 Open a terminal window and move to
 Open a terminal window and move to
-the top-level directory, which is named <TT>lua-5.4.0-beta</TT>.
+the top-level directory, which is named <TT>lua-5.4.6</TT>.
 The <TT>Makefile</TT> there controls both the build process and the installation process.
 The <TT>Makefile</TT> there controls both the build process and the installation process.
 <P>
 <P>
 <LI>
 <LI>
-  Do "<KBD>make</KBD>" and see if your platform is listed.
+  Do "<KBD>make</KBD>". The <TT>Makefile</TT> will guess your platform and build Lua for it.
+<P>
+<LI>
+  If the guess failed, do "<KBD>make help</KBD>" and see if your platform is listed.
   The platforms currently supported are:
   The platforms currently supported are:
 <P>
 <P>
 <P CLASS="display">
 <P CLASS="display">
-   aix bsd c89 freebsd generic guess linux linux-readline macosx mingw posix solaris
+   guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
 </P>
 </P>
-<P>
-  If your platform is a common Unix-like platform,
-  just do "<KBD>make guess</KBD>".
-  The <TT>Makefile</TT> will guess your platform and build Lua for it.
 <P>
 <P>
   If your platform is listed, just do "<KBD>make xxx</KBD>", where xxx
   If your platform is listed, just do "<KBD>make xxx</KBD>", where xxx
   is your platform name.
   is your platform name.
@@ -143,11 +139,12 @@ and liblua.a (the library).
   after building Lua. This will run the interpreter and print its version.
   after building Lua. This will run the interpreter and print its version.
 </OL>
 </OL>
 <P>
 <P>
-If you're running Linux and get compilation errors when building for <TT>linux-readline</TT>,
+If you're running Linux, try "<KBD>make linux-readline</KBD>" to build the interactive Lua interpreter with handy line-editing and history capabilities.
+If you get compilation errors,
 make sure you have installed the <TT>readline</TT> development package
 make sure you have installed the <TT>readline</TT> development package
 (which is probably named <TT>libreadline-dev</TT> or <TT>readline-devel</TT>).
 (which is probably named <TT>libreadline-dev</TT> or <TT>readline-devel</TT>).
 If you get link errors after that,
 If you get link errors after that,
-then try "<KBD>make linux MYLIBS=-ltermcap</KBD>".
+then try "<KBD>make linux-readline MYLIBS=-ltermcap</KBD>".
 
 
 <H3>Installing Lua</H3>
 <H3>Installing Lua</H3>
 <P>
 <P>
@@ -157,11 +154,12 @@ then try "<KBD>make linux MYLIBS=-ltermcap</KBD>".
   probably need the right permissions to install files, and so may need to do "<KBD>sudo make install</KBD>".
   probably need the right permissions to install files, and so may need to do "<KBD>sudo make install</KBD>".
 
 
 <P>
 <P>
-  To build and install Lua in one step, do "<KBD>make xxx install</KBD>",
-  where xxx is your platform name, including "guess".
+  To build and install Lua in one step, do "<KBD>make all install</KBD>",
+  or "<KBD>make xxx install</KBD>",
+  where xxx is your platform name.
 
 
 <P>
 <P>
-  To install Lua locally, do "<KBD>make local</KBD>".
+  To install Lua locally after building it, do "<KBD>make local</KBD>".
   This will create a directory <TT>install</TT> with subdirectories
   This will create a directory <TT>install</TT> with subdirectories
   <TT>bin</TT>, <TT>include</TT>, <TT>lib</TT>, <TT>man</TT>, <TT>share</TT>,
   <TT>bin</TT>, <TT>include</TT>, <TT>lib</TT>, <TT>man</TT>, <TT>share</TT>,
   and install Lua as listed below.
   and install Lua as listed below.
@@ -302,7 +300,7 @@ For details, see
 <A HREF="http://www.lua.org/license.html">this</A>.
 <A HREF="http://www.lua.org/license.html">this</A>.
 
 
 <BLOCKQUOTE STYLE="padding-bottom: 0em">
 <BLOCKQUOTE STYLE="padding-bottom: 0em">
-Copyright &copy; 1994&ndash;2019 Lua.org, PUC-Rio.
+Copyright &copy; 1994&ndash;2023 Lua.org, PUC-Rio.
 
 
 <P>
 <P>
 Permission is hereby granted, free of charge, to any person obtaining a copy
 Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -329,10 +327,10 @@ THE SOFTWARE.
 
 
 <P CLASS="footer">
 <P CLASS="footer">
 Last update:
 Last update:
-Thu Oct  3 12:42:49 UTC 2019
+Tue May  2 20:08:55 UTC 2023
 </P>
 </P>
 <!--
 <!--
-Last change: revised for Lua 5.4.0 (beta)
+Last change: revised for Lua 5.4.6
 -->
 -->
 
 
 </BODY>
 </BODY>

+ 7 - 26
src/Makefile

@@ -30,7 +30,7 @@ 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= guess aix bsd c89 freebsd generic linux linux-readline macosx mingw posix solaris
+PLATS= guess aix bsd c89 freebsd generic ios 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
@@ -43,14 +43,8 @@ LUA_O=	lua.o
 LUAC_T=	luac
 LUAC_T=	luac
 LUAC_O=	luac.o
 LUAC_O=	luac.o
 
 
-AOT_T=	luaot
-AOT_O=	luaot.o
-
-AOT2_T=	luaot-trampoline
-AOT2_O=	luaot-trampoline.o
-
-ALL_O= $(BASE_O) $(LUA_O) $(LUAC_O) $(AOT_O) $(AOT2_O)
-ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) $(AOT_T) $(AOT2_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.
@@ -72,12 +66,6 @@ $(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)
 
 
-$(AOT_T): $(AOT_O) $(LUA_A)
-	$(CC) -o $@ $(LDFLAGS) $(AOT_O) $(LUA_A) $(LIBS)
-
-$(AOT2_T): $(AOT2_O) $(LUA_A)
-	$(CC) -o $@ $(LDFLAGS) $(AOT2_O) $(LUA_A) $(LIBS)
-
 test:
 test:
 	./$(LUA_T) -v
 	./$(LUA_T) -v
 
 
@@ -91,7 +79,7 @@ echo:
 	@echo "PLAT= $(PLAT)"
 	@echo "PLAT= $(PLAT)"
 	@echo "CC= $(CC)"
 	@echo "CC= $(CC)"
 	@echo "CFLAGS= $(CFLAGS)"
 	@echo "CFLAGS= $(CFLAGS)"
-	@echo "LDFLAGS= $(SYSLDFLAGS)"
+	@echo "LDFLAGS= $(LDFLAGS)"
 	@echo "LIBS= $(LIBS)"
 	@echo "LIBS= $(LIBS)"
 	@echo "AR= $(AR)"
 	@echo "AR= $(AR)"
 	@echo "RANLIB= $(RANLIB)"
 	@echo "RANLIB= $(RANLIB)"
@@ -129,6 +117,9 @@ FreeBSD NetBSD OpenBSD freebsd:
 
 
 generic: $(ALL)
 generic: $(ALL)
 
 
+ios:
+	$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_IOS"
+
 Linux linux:	linux-noreadline
 Linux linux:	linux-noreadline
 
 
 linux-noreadline:
 linux-noreadline:
@@ -165,16 +156,6 @@ lparser.o:
 lcode.o:
 lcode.o:
 	$(CC) $(CFLAGS) $(CMCFLAGS) -c lcode.c
 	$(CC) $(CFLAGS) $(CMCFLAGS) -c lcode.c
 
 
-# LuaAOT has extra if-defs
-
-luaot.o: luaot.c luaot_gotos.c \
- lua.h lauxlib.h ldebug.h lobject.h lopcodes.h lopnames.h lstate.h lundump.h
-	$(CC) $(CFLAGS) -c $< -o $@ -DLUAOT_USE_GOTOS
-
-luaot-trampoline.o: luaot.c luaot_switches.c \
- lua.h lauxlib.h ldebug.h lobject.h lopcodes.h lopnames.h lstate.h lundump.h
-	$(CC) $(CFLAGS) -c $< -o $@ -DLUAOT_USE_SWITCHES
-
 # DO NOT DELETE
 # DO NOT DELETE
 
 
 lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
 lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \

+ 148 - 140
src/lapi.c

@@ -53,45 +53,57 @@ const char lua_ident[] =
 #define isupvalue(i)		((i) < LUA_REGISTRYINDEX)
 #define isupvalue(i)		((i) < LUA_REGISTRYINDEX)
 
 
 
 
+/*
+** Convert an acceptable index to a pointer to its respective value.
+** Non-valid indices return the special nil value 'G(L)->nilvalue'.
+*/
 static TValue *index2value (lua_State *L, int idx) {
 static TValue *index2value (lua_State *L, int idx) {
   CallInfo *ci = L->ci;
   CallInfo *ci = L->ci;
   if (idx > 0) {
   if (idx > 0) {
-    StkId o = ci->func + idx;
-    api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index");
-    if (o >= L->top) return &G(L)->nilvalue;
+    StkId o = ci->func.p + idx;
+    api_check(L, idx <= ci->top.p - (ci->func.p + 1), "unacceptable index");
+    if (o >= L->top.p) return &G(L)->nilvalue;
     else return s2v(o);
     else return s2v(o);
   }
   }
   else if (!ispseudo(idx)) {  /* negative index */
   else if (!ispseudo(idx)) {  /* negative index */
-    api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
-    return s2v(L->top + idx);
+    api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
+                 "invalid index");
+    return s2v(L->top.p + idx);
   }
   }
   else if (idx == LUA_REGISTRYINDEX)
   else if (idx == LUA_REGISTRYINDEX)
     return &G(L)->l_registry;
     return &G(L)->l_registry;
   else {  /* upvalues */
   else {  /* upvalues */
     idx = LUA_REGISTRYINDEX - idx;
     idx = LUA_REGISTRYINDEX - idx;
     api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
     api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
-    if (ttislcf(s2v(ci->func)))  /* light C function? */
-      return &G(L)->nilvalue;  /* it has no upvalues */
-    else {
-      CClosure *func = clCvalue(s2v(ci->func));
+    if (ttisCclosure(s2v(ci->func.p))) {  /* C closure? */
+      CClosure *func = clCvalue(s2v(ci->func.p));
       return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
       return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
                                       : &G(L)->nilvalue;
                                       : &G(L)->nilvalue;
     }
     }
+    else {  /* light C function or Lua function (through a hook)?) */
+      api_check(L, ttislcf(s2v(ci->func.p)), "caller not a C function");
+      return &G(L)->nilvalue;  /* no upvalues */
+    }
   }
   }
 }
 }
 
 
 
 
-static StkId index2stack (lua_State *L, int idx) {
+
+/*
+** Convert a valid actual index (not a pseudo-index) to its address.
+*/
+l_sinline StkId index2stack (lua_State *L, int idx) {
   CallInfo *ci = L->ci;
   CallInfo *ci = L->ci;
   if (idx > 0) {
   if (idx > 0) {
-    StkId o = ci->func + idx;
-    api_check(L, o < L->top, "unacceptable index");
+    StkId o = ci->func.p + idx;
+    api_check(L, o < L->top.p, "invalid index");
     return o;
     return o;
   }
   }
   else {    /* non-positive index */
   else {    /* non-positive index */
-    api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
+    api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
+                 "invalid index");
     api_check(L, !ispseudo(idx), "invalid index");
     api_check(L, !ispseudo(idx), "invalid index");
-    return L->top + idx;
+    return L->top.p + idx;
   }
   }
 }
 }
 
 
@@ -102,17 +114,12 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
   lua_lock(L);
   lua_lock(L);
   ci = L->ci;
   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.p - L->top.p > n)  /* stack large enough? */
     res = 1;  /* yes; check is OK */
     res = 1;  /* yes; check is OK */
-  else {  /* no; need to grow stack */
-    int inuse = cast_int(L->top - L->stack) + EXTRA_STACK;
-    if (inuse > LUAI_MAXSTACK - n)  /* can grow without overflow? */
-      res = 0;  /* no */
-    else  /* try to grow stack */
-      res = luaD_growstack(L, n, 0);
-  }
-  if (res && ci->top < L->top + n)
-    ci->top = L->top + n;  /* adjust frame top */
+  else  /* need to grow stack */
+    res = luaD_growstack(L, n, 0);
+  if (res && ci->top.p < L->top.p + n)
+    ci->top.p = L->top.p + n;  /* adjust frame top */
   lua_unlock(L);
   lua_unlock(L);
   return res;
   return res;
 }
 }
@@ -124,11 +131,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
   lua_lock(to);
   lua_lock(to);
   api_checknelems(from, n);
   api_checknelems(from, n);
   api_check(from, G(from) == G(to), "moving among independent states");
   api_check(from, G(from) == G(to), "moving among independent states");
-  api_check(from, to->ci->top - to->top >= n, "stack overflow");
-  from->top -= n;
+  api_check(from, to->ci->top.p - to->top.p >= n, "stack overflow");
+  from->top.p -= n;
   for (i = 0; i < n; i++) {
   for (i = 0; i < n; i++) {
-    setobjs2s(to, to->top, from->top + i);
-    to->top++;  /* stack already checked by previous 'api_check' */
+    setobjs2s(to, to->top.p, from->top.p + i);
+    to->top.p++;  /* stack already checked by previous 'api_check' */
   }
   }
   lua_unlock(to);
   lua_unlock(to);
 }
 }
@@ -162,12 +169,12 @@ LUA_API lua_Number lua_version (lua_State *L) {
 LUA_API int lua_absindex (lua_State *L, int idx) {
 LUA_API int lua_absindex (lua_State *L, int idx) {
   return (idx > 0 || ispseudo(idx))
   return (idx > 0 || ispseudo(idx))
          ? idx
          ? idx
-         : cast_int(L->top - L->ci->func) + idx;
+         : cast_int(L->top.p - L->ci->func.p) + idx;
 }
 }
 
 
 
 
 LUA_API int lua_gettop (lua_State *L) {
 LUA_API int lua_gettop (lua_State *L) {
-  return cast_int(L->top - (L->ci->func + 1));
+  return cast_int(L->top.p - (L->ci->func.p + 1));
 }
 }
 
 
 
 
@@ -177,24 +184,24 @@ LUA_API void lua_settop (lua_State *L, int idx) {
   ptrdiff_t diff;  /* difference for new top */
   ptrdiff_t diff;  /* difference for new top */
   lua_lock(L);
   lua_lock(L);
   ci = L->ci;
   ci = L->ci;
-  func = ci->func;
+  func = ci->func.p;
   if (idx >= 0) {
   if (idx >= 0) {
-    api_check(L, idx <= ci->top - (func + 1), "new top too large");
-    diff = ((func + 1) + idx) - L->top;
+    api_check(L, idx <= ci->top.p - (func + 1), "new top too large");
+    diff = ((func + 1) + idx) - L->top.p;
     for (; diff > 0; diff--)
     for (; diff > 0; diff--)
-      setnilvalue(s2v(L->top++));  /* clear new slots */
+      setnilvalue(s2v(L->top.p++));  /* clear new slots */
   }
   }
   else {
   else {
-    api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
+    api_check(L, -(idx+1) <= (L->top.p - (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) */
   }
   }
-  api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot");
-  newtop = L->top + diff;
-  if (diff < 0 && L->tbclist >= newtop) {
+  api_check(L, L->tbclist.p < L->top.p, "previous pop of an unclosed slot");
+  newtop = L->top.p + diff;
+  if (diff < 0 && L->tbclist.p >= newtop) {
     lua_assert(hastocloseCfunc(ci->nresults));
     lua_assert(hastocloseCfunc(ci->nresults));
-    luaF_close(L, newtop, CLOSEKTOP, 0);
+    newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
   }
   }
-  L->top = newtop;  /* correct top only after closing any upvalue */
+  L->top.p = newtop;  /* correct top only after closing any upvalue */
   lua_unlock(L);
   lua_unlock(L);
 }
 }
 
 
@@ -203,10 +210,9 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
   StkId level;
   StkId level;
   lua_lock(L);
   lua_lock(L);
   level = index2stack(L, idx);
   level = index2stack(L, idx);
-  api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level,
+  api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level,
      "no variable to close at given level");
      "no variable to close at given level");
-  luaF_close(L, level, CLOSEKTOP, 0);
-  level = index2stack(L, idx);  /* stack may be moved */
+  level = luaF_close(L, level, CLOSEKTOP, 0);
   setnilvalue(s2v(level));
   setnilvalue(s2v(level));
   lua_unlock(L);
   lua_unlock(L);
 }
 }
@@ -218,7 +224,7 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
 ** Note that we move(copy) only the value inside the stack.
 ** Note that we move(copy) only the value inside the stack.
 ** (We do not move additional fields that may exist.)
 ** (We do not move additional fields that may exist.)
 */
 */
-static void reverse (lua_State *L, StkId from, StkId to) {
+l_sinline void reverse (lua_State *L, StkId from, StkId to) {
   for (; from < to; from++, to--) {
   for (; from < to; from++, to--) {
     TValue temp;
     TValue temp;
     setobj(L, &temp, s2v(from));
     setobj(L, &temp, s2v(from));
@@ -235,7 +241,7 @@ static void reverse (lua_State *L, StkId from, StkId to) {
 LUA_API void lua_rotate (lua_State *L, int idx, int n) {
 LUA_API void lua_rotate (lua_State *L, int idx, int n) {
   StkId p, t, m;
   StkId p, t, m;
   lua_lock(L);
   lua_lock(L);
-  t = L->top - 1;  /* end of stack segment being rotated */
+  t = L->top.p - 1;  /* end of stack segment being rotated */
   p = index2stack(L, idx);  /* start of segment */
   p = index2stack(L, idx);  /* start of segment */
   api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
   api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
   m = (n >= 0 ? t - n : p - n - 1);  /* end of prefix */
   m = (n >= 0 ? t - n : p - n - 1);  /* end of prefix */
@@ -254,7 +260,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int 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.p)), fr);
   /* LUA_REGISTRYINDEX does not need gc barrier
   /* LUA_REGISTRYINDEX does not need gc barrier
      (collector revisits it before finishing collection) */
      (collector revisits it before finishing collection) */
   lua_unlock(L);
   lua_unlock(L);
@@ -263,7 +269,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
 
 
 LUA_API void lua_pushvalue (lua_State *L, int idx) {
 LUA_API void lua_pushvalue (lua_State *L, int idx) {
   lua_lock(L);
   lua_lock(L);
-  setobj2s(L, L->top, index2value(L, idx));
+  setobj2s(L, L->top.p, index2value(L, idx));
   api_incr_top(L);
   api_incr_top(L);
   lua_unlock(L);
   lua_unlock(L);
 }
 }
@@ -332,12 +338,12 @@ LUA_API void lua_arith (lua_State *L, int op) {
     api_checknelems(L, 2);  /* all other operations expect two operands */
     api_checknelems(L, 2);  /* all other operations expect two operands */
   else {  /* for unary operations, add fake 2nd operand */
   else {  /* for unary operations, add fake 2nd operand */
     api_checknelems(L, 1);
     api_checknelems(L, 1);
-    setobjs2s(L, L->top, L->top - 1);
+    setobjs2s(L, L->top.p, L->top.p - 1);
     api_incr_top(L);
     api_incr_top(L);
   }
   }
   /* first operand at top - 2, second at top - 1; result go to top - 2 */
   /* first operand at top - 2, second at top - 1; result go to top - 2 */
-  luaO_arith(L, op, s2v(L->top - 2), s2v(L->top - 1), L->top - 2);
-  L->top--;  /* remove second operand */
+  luaO_arith(L, op, s2v(L->top.p - 2), s2v(L->top.p - 1), L->top.p - 2);
+  L->top.p--;  /* remove second operand */
   lua_unlock(L);
   lua_unlock(L);
 }
 }
 
 
@@ -363,7 +369,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
 
 
 
 
 LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
 LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
-  size_t sz = luaO_str2num(s, s2v(L->top));
+  size_t sz = luaO_str2num(s, s2v(L->top.p));
   if (sz != 0)
   if (sz != 0)
     api_incr_top(L);
     api_incr_top(L);
   return sz;
   return sz;
@@ -438,7 +444,7 @@ LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) {
 }
 }
 
 
 
 
-static void *touserdata (const TValue *o) {
+l_sinline void *touserdata (const TValue *o) {
   switch (ttype(o)) {
   switch (ttype(o)) {
     case LUA_TUSERDATA: return getudatamem(uvalue(o));
     case LUA_TUSERDATA: return getudatamem(uvalue(o));
     case LUA_TLIGHTUSERDATA: return pvalue(o);
     case LUA_TLIGHTUSERDATA: return pvalue(o);
@@ -490,7 +496,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
 
 
 LUA_API void lua_pushnil (lua_State *L) {
 LUA_API void lua_pushnil (lua_State *L) {
   lua_lock(L);
   lua_lock(L);
-  setnilvalue(s2v(L->top));
+  setnilvalue(s2v(L->top.p));
   api_incr_top(L);
   api_incr_top(L);
   lua_unlock(L);
   lua_unlock(L);
 }
 }
@@ -498,7 +504,7 @@ LUA_API void lua_pushnil (lua_State *L) {
 
 
 LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
 LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
   lua_lock(L);
   lua_lock(L);
-  setfltvalue(s2v(L->top), n);
+  setfltvalue(s2v(L->top.p), n);
   api_incr_top(L);
   api_incr_top(L);
   lua_unlock(L);
   lua_unlock(L);
 }
 }
@@ -506,7 +512,7 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
 
 
 LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
 LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
   lua_lock(L);
   lua_lock(L);
-  setivalue(s2v(L->top), n);
+  setivalue(s2v(L->top.p), n);
   api_incr_top(L);
   api_incr_top(L);
   lua_unlock(L);
   lua_unlock(L);
 }
 }
@@ -521,7 +527,7 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
   TString *ts;
   TString *ts;
   lua_lock(L);
   lua_lock(L);
   ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
   ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
-  setsvalue2s(L, L->top, ts);
+  setsvalue2s(L, L->top.p, ts);
   api_incr_top(L);
   api_incr_top(L);
   luaC_checkGC(L);
   luaC_checkGC(L);
   lua_unlock(L);
   lua_unlock(L);
@@ -532,11 +538,11 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
 LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
 LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
   lua_lock(L);
   lua_lock(L);
   if (s == NULL)
   if (s == NULL)
-    setnilvalue(s2v(L->top));
+    setnilvalue(s2v(L->top.p));
   else {
   else {
     TString *ts;
     TString *ts;
     ts = luaS_new(L, s);
     ts = luaS_new(L, s);
-    setsvalue2s(L, L->top, ts);
+    setsvalue2s(L, L->top.p, ts);
     s = getstr(ts);  /* internal copy's address */
     s = getstr(ts);  /* internal copy's address */
   }
   }
   api_incr_top(L);
   api_incr_top(L);
@@ -573,7 +579,7 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
 LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
 LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
   lua_lock(L);
   lua_lock(L);
   if (n == 0) {
   if (n == 0) {
-    setfvalue(s2v(L->top), fn);
+    setfvalue(s2v(L->top.p), fn);
     api_incr_top(L);
     api_incr_top(L);
   }
   }
   else {
   else {
@@ -582,13 +588,13 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
     api_check(L, n <= MAXUPVAL, "upvalue index too large");
     api_check(L, n <= MAXUPVAL, "upvalue index too large");
     cl = luaF_newCclosure(L, n);
     cl = luaF_newCclosure(L, n);
     cl->f = fn;
     cl->f = fn;
-    L->top -= n;
+    L->top.p -= n;
     while (n--) {
     while (n--) {
-      setobj2n(L, &cl->upvalue[n], s2v(L->top + n));
+      setobj2n(L, &cl->upvalue[n], s2v(L->top.p + n));
       /* does not need barrier because closure is white */
       /* does not need barrier because closure is white */
       lua_assert(iswhite(cl));
       lua_assert(iswhite(cl));
     }
     }
-    setclCvalue(L, s2v(L->top), cl);
+    setclCvalue(L, s2v(L->top.p), cl);
     api_incr_top(L);
     api_incr_top(L);
     luaC_checkGC(L);
     luaC_checkGC(L);
   }
   }
@@ -599,9 +605,9 @@ 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);
   if (b)
   if (b)
-    setbtvalue(s2v(L->top));
+    setbtvalue(s2v(L->top.p));
   else
   else
-    setbfvalue(s2v(L->top));
+    setbfvalue(s2v(L->top.p));
   api_incr_top(L);
   api_incr_top(L);
   lua_unlock(L);
   lua_unlock(L);
 }
 }
@@ -609,7 +615,7 @@ LUA_API void lua_pushboolean (lua_State *L, int b) {
 
 
 LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
 LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
   lua_lock(L);
   lua_lock(L);
-  setpvalue(s2v(L->top), p);
+  setpvalue(s2v(L->top.p), p);
   api_incr_top(L);
   api_incr_top(L);
   lua_unlock(L);
   lua_unlock(L);
 }
 }
@@ -617,7 +623,7 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
 
 
 LUA_API int lua_pushthread (lua_State *L) {
 LUA_API int lua_pushthread (lua_State *L) {
   lua_lock(L);
   lua_lock(L);
-  setthvalue(L, s2v(L->top), L);
+  setthvalue(L, s2v(L->top.p), L);
   api_incr_top(L);
   api_incr_top(L);
   lua_unlock(L);
   lua_unlock(L);
   return (G(L)->mainthread == L);
   return (G(L)->mainthread == L);
@@ -630,20 +636,20 @@ LUA_API int lua_pushthread (lua_State *L) {
 */
 */
 
 
 
 
-static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
+l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
   const TValue *slot;
   const TValue *slot;
   TString *str = luaS_new(L, k);
   TString *str = luaS_new(L, k);
   if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
   if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
-    setobj2s(L, L->top, slot);
+    setobj2s(L, L->top.p, slot);
     api_incr_top(L);
     api_incr_top(L);
   }
   }
   else {
   else {
-    setsvalue2s(L, L->top, str);
+    setsvalue2s(L, L->top.p, str);
     api_incr_top(L);
     api_incr_top(L);
-    luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
+    luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
   }
   }
   lua_unlock(L);
   lua_unlock(L);
-  return ttype(s2v(L->top - 1));
+  return ttype(s2v(L->top.p - 1));
 }
 }
 
 
 
 
@@ -670,13 +676,13 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
   TValue *t;
   TValue *t;
   lua_lock(L);
   lua_lock(L);
   t = index2value(L, idx);
   t = index2value(L, idx);
-  if (luaV_fastget(L, t, s2v(L->top - 1), slot, luaH_get)) {
-    setobj2s(L, L->top - 1, slot);
+  if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) {
+    setobj2s(L, L->top.p - 1, slot);
   }
   }
   else
   else
-    luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
+    luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
   lua_unlock(L);
   lua_unlock(L);
-  return ttype(s2v(L->top - 1));
+  return ttype(s2v(L->top.p - 1));
 }
 }
 
 
 
 
@@ -692,27 +698,27 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
   lua_lock(L);
   lua_lock(L);
   t = index2value(L, idx);
   t = index2value(L, idx);
   if (luaV_fastgeti(L, t, n, slot)) {
   if (luaV_fastgeti(L, t, n, slot)) {
-    setobj2s(L, L->top, slot);
+    setobj2s(L, L->top.p, slot);
   }
   }
   else {
   else {
     TValue aux;
     TValue aux;
     setivalue(&aux, n);
     setivalue(&aux, n);
-    luaV_finishget(L, t, &aux, L->top, slot);
+    luaV_finishget(L, t, &aux, L->top.p, slot);
   }
   }
   api_incr_top(L);
   api_incr_top(L);
   lua_unlock(L);
   lua_unlock(L);
-  return ttype(s2v(L->top - 1));
+  return ttype(s2v(L->top.p - 1));
 }
 }
 
 
 
 
-static int finishrawget (lua_State *L, const TValue *val) {
+l_sinline int finishrawget (lua_State *L, const TValue *val) {
   if (isempty(val))  /* avoid copying empty items to the stack */
   if (isempty(val))  /* avoid copying empty items to the stack */
-    setnilvalue(s2v(L->top));
+    setnilvalue(s2v(L->top.p));
   else
   else
-    setobj2s(L, L->top, val);
+    setobj2s(L, L->top.p, val);
   api_incr_top(L);
   api_incr_top(L);
   lua_unlock(L);
   lua_unlock(L);
-  return ttype(s2v(L->top - 1));
+  return ttype(s2v(L->top.p - 1));
 }
 }
 
 
 
 
@@ -729,8 +735,8 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
   lua_lock(L);
   lua_lock(L);
   api_checknelems(L, 1);
   api_checknelems(L, 1);
   t = gettable(L, idx);
   t = gettable(L, idx);
-  val = luaH_get(t, s2v(L->top - 1));
-  L->top--;  /* remove key */
+  val = luaH_get(t, s2v(L->top.p - 1));
+  L->top.p--;  /* remove key */
   return finishrawget(L, val);
   return finishrawget(L, val);
 }
 }
 
 
@@ -757,7 +763,7 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
   Table *t;
   Table *t;
   lua_lock(L);
   lua_lock(L);
   t = luaH_new(L);
   t = luaH_new(L);
-  sethvalue2s(L, L->top, t);
+  sethvalue2s(L, L->top.p, t);
   api_incr_top(L);
   api_incr_top(L);
   if (narray > 0 || nrec > 0)
   if (narray > 0 || nrec > 0)
     luaH_resize(L, t, narray, nrec);
     luaH_resize(L, t, narray, nrec);
@@ -784,7 +790,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
       break;
       break;
   }
   }
   if (mt != NULL) {
   if (mt != NULL) {
-    sethvalue2s(L, L->top, mt);
+    sethvalue2s(L, L->top.p, mt);
     api_incr_top(L);
     api_incr_top(L);
     res = 1;
     res = 1;
   }
   }
@@ -800,12 +806,12 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
   o = index2value(L, idx);
   o = index2value(L, idx);
   api_check(L, ttisfulluserdata(o), "full userdata expected");
   api_check(L, ttisfulluserdata(o), "full userdata expected");
   if (n <= 0 || n > uvalue(o)->nuvalue) {
   if (n <= 0 || n > uvalue(o)->nuvalue) {
-    setnilvalue(s2v(L->top));
+    setnilvalue(s2v(L->top.p));
     t = LUA_TNONE;
     t = LUA_TNONE;
   }
   }
   else {
   else {
-    setobj2s(L, L->top, &uvalue(o)->uv[n - 1].uv);
-    t = ttype(s2v(L->top));
+    setobj2s(L, L->top.p, &uvalue(o)->uv[n - 1].uv);
+    t = ttype(s2v(L->top.p));
   }
   }
   api_incr_top(L);
   api_incr_top(L);
   lua_unlock(L);
   lua_unlock(L);
@@ -825,14 +831,14 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
   TString *str = luaS_new(L, k);
   TString *str = luaS_new(L, k);
   api_checknelems(L, 1);
   api_checknelems(L, 1);
   if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
   if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
-    luaV_finishfastset(L, t, slot, s2v(L->top - 1));
-    L->top--;  /* pop value */
+    luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
+    L->top.p--;  /* pop value */
   }
   }
   else {
   else {
-    setsvalue2s(L, L->top, str);  /* push 'str' (to make it a TValue) */
+    setsvalue2s(L, L->top.p, str);  /* push 'str' (to make it a TValue) */
     api_incr_top(L);
     api_incr_top(L);
-    luaV_finishset(L, t, s2v(L->top - 1), s2v(L->top - 2), slot);
-    L->top -= 2;  /* pop value and key */
+    luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), slot);
+    L->top.p -= 2;  /* pop value and key */
   }
   }
   lua_unlock(L);  /* lock done by caller */
   lua_unlock(L);  /* lock done by caller */
 }
 }
@@ -852,12 +858,12 @@ LUA_API void lua_settable (lua_State *L, int idx) {
   lua_lock(L);
   lua_lock(L);
   api_checknelems(L, 2);
   api_checknelems(L, 2);
   t = index2value(L, idx);
   t = index2value(L, idx);
-  if (luaV_fastget(L, t, s2v(L->top - 2), slot, luaH_get)) {
-    luaV_finishfastset(L, t, slot, s2v(L->top - 1));
+  if (luaV_fastget(L, t, s2v(L->top.p - 2), slot, luaH_get)) {
+    luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
   }
   }
   else
   else
-    luaV_finishset(L, t, s2v(L->top - 2), s2v(L->top - 1), slot);
-  L->top -= 2;  /* pop index and value */
+    luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), slot);
+  L->top.p -= 2;  /* pop index and value */
   lua_unlock(L);
   lua_unlock(L);
 }
 }
 
 
@@ -875,14 +881,14 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
   api_checknelems(L, 1);
   api_checknelems(L, 1);
   t = index2value(L, idx);
   t = index2value(L, idx);
   if (luaV_fastgeti(L, t, n, slot)) {
   if (luaV_fastgeti(L, t, n, slot)) {
-    luaV_finishfastset(L, t, slot, s2v(L->top - 1));
+    luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
   }
   }
   else {
   else {
     TValue aux;
     TValue aux;
     setivalue(&aux, n);
     setivalue(&aux, n);
-    luaV_finishset(L, t, &aux, s2v(L->top - 1), slot);
+    luaV_finishset(L, t, &aux, s2v(L->top.p - 1), slot);
   }
   }
-  L->top--;  /* pop value */
+  L->top.p--;  /* pop value */
   lua_unlock(L);
   lua_unlock(L);
 }
 }
 
 
@@ -892,16 +898,16 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
   lua_lock(L);
   lua_lock(L);
   api_checknelems(L, n);
   api_checknelems(L, n);
   t = gettable(L, idx);
   t = gettable(L, idx);
-  luaH_set(L, t, key, s2v(L->top - 1));
+  luaH_set(L, t, key, s2v(L->top.p - 1));
   invalidateTMcache(t);
   invalidateTMcache(t);
-  luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
-  L->top -= n;
+  luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
+  L->top.p -= n;
   lua_unlock(L);
   lua_unlock(L);
 }
 }
 
 
 
 
 LUA_API void lua_rawset (lua_State *L, int idx) {
 LUA_API void lua_rawset (lua_State *L, int idx) {
-  aux_rawset(L, idx, s2v(L->top - 2), 2);
+  aux_rawset(L, idx, s2v(L->top.p - 2), 2);
 }
 }
 
 
 
 
@@ -917,9 +923,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
   lua_lock(L);
   lua_lock(L);
   api_checknelems(L, 1);
   api_checknelems(L, 1);
   t = gettable(L, idx);
   t = gettable(L, idx);
-  luaH_setint(L, t, n, s2v(L->top - 1));
-  luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
-  L->top--;
+  luaH_setint(L, t, n, s2v(L->top.p - 1));
+  luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
+  L->top.p--;
   lua_unlock(L);
   lua_unlock(L);
 }
 }
 
 
@@ -930,11 +936,11 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
   lua_lock(L);
   lua_lock(L);
   api_checknelems(L, 1);
   api_checknelems(L, 1);
   obj = index2value(L, objindex);
   obj = index2value(L, objindex);
-  if (ttisnil(s2v(L->top - 1)))
+  if (ttisnil(s2v(L->top.p - 1)))
     mt = NULL;
     mt = NULL;
   else {
   else {
-    api_check(L, ttistable(s2v(L->top - 1)), "table expected");
-    mt = hvalue(s2v(L->top - 1));
+    api_check(L, ttistable(s2v(L->top.p - 1)), "table expected");
+    mt = hvalue(s2v(L->top.p - 1));
   }
   }
   switch (ttype(obj)) {
   switch (ttype(obj)) {
     case LUA_TTABLE: {
     case LUA_TTABLE: {
@@ -958,7 +964,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
       break;
       break;
     }
     }
   }
   }
-  L->top--;
+  L->top.p--;
   lua_unlock(L);
   lua_unlock(L);
   return 1;
   return 1;
 }
 }
@@ -974,11 +980,11 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
   if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue)))
   if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue)))
     res = 0;  /* 'n' not in [1, uvalue(o)->nuvalue] */
     res = 0;  /* 'n' not in [1, uvalue(o)->nuvalue] */
   else {
   else {
-    setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top - 1));
-    luaC_barrierback(L, gcvalue(o), s2v(L->top - 1));
+    setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top.p - 1));
+    luaC_barrierback(L, gcvalue(o), s2v(L->top.p - 1));
     res = 1;
     res = 1;
   }
   }
-  L->top--;
+  L->top.p--;
   lua_unlock(L);
   lua_unlock(L);
   return res;
   return res;
 }
 }
@@ -990,7 +996,8 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
 
 
 
 
 #define checkresults(L,na,nr) \
 #define checkresults(L,na,nr) \
-     api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
+     api_check(L, (nr) == LUA_MULTRET \
+               || (L->ci->top.p - L->top.p >= (nr) - (na)), \
 	"results from function overflow current stack size")
 	"results from function overflow current stack size")
 
 
 
 
@@ -1003,7 +1010,7 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
   api_checknelems(L, nargs+1);
   api_checknelems(L, nargs+1);
   api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
   api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
   checkresults(L, nargs, nresults);
   checkresults(L, nargs, nresults);
-  func = L->top - (nargs+1);
+  func = L->top.p - (nargs+1);
   if (k != NULL && yieldable(L)) {  /* need to prepare continuation? */
   if (k != NULL && yieldable(L)) {  /* need to prepare continuation? */
     L->ci->u.c.k = k;  /* save continuation */
     L->ci->u.c.k = k;  /* save continuation */
     L->ci->u.c.ctx = ctx;  /* save context */
     L->ci->u.c.ctx = ctx;  /* save context */
@@ -1051,7 +1058,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
     api_check(L, ttisfunction(s2v(o)), "error handler must be a function");
     api_check(L, ttisfunction(s2v(o)), "error handler must be a function");
     func = savestack(L, o);
     func = savestack(L, o);
   }
   }
-  c.func = L->top - (nargs+1);  /* function to be called */
+  c.func = L->top.p - (nargs+1);  /* function to be called */
   if (k == NULL || !yieldable(L)) {  /* no continuation or no yieldable? */
   if (k == NULL || !yieldable(L)) {  /* no continuation or no yieldable? */
     c.nresults = nresults;  /* do a 'conventional' protected call */
     c.nresults = nresults;  /* do a 'conventional' protected call */
     status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
     status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
@@ -1086,12 +1093,12 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
   luaZ_init(L, &z, reader, data);
   luaZ_init(L, &z, reader, data);
   status = luaD_protectedparser(L, &z, chunkname, mode);
   status = luaD_protectedparser(L, &z, chunkname, mode);
   if (status == LUA_OK) {  /* no errors? */
   if (status == LUA_OK) {  /* no errors? */
-    LClosure *f = clLvalue(s2v(L->top - 1));  /* get newly created function */
+    LClosure *f = clLvalue(s2v(L->top.p - 1));  /* get new 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 */
       const TValue *gt = getGtable(L);
       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.p, gt);
       luaC_barrier(L, f->upvals[0], gt);
       luaC_barrier(L, f->upvals[0], gt);
     }
     }
   }
   }
@@ -1105,7 +1112,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
   TValue *o;
   TValue *o;
   lua_lock(L);
   lua_lock(L);
   api_checknelems(L, 1);
   api_checknelems(L, 1);
-  o = s2v(L->top - 1);
+  o = s2v(L->top.p - 1);
   if (isLfunction(o))
   if (isLfunction(o))
     status = luaU_dump(L, getproto(o), writer, data, strip);
     status = luaU_dump(L, getproto(o), writer, data, strip);
   else
   else
@@ -1126,18 +1133,19 @@ 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;
+  global_State *g = G(L);
+  if (g->gcstp & GCSTPGC)  /* internal stop? */
+    return -1;  /* all options are invalid when stopped */
   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: {
-      g->gcrunning = 0;
+      g->gcstp = GCSTPUSR;  /* stopped by the user */
       break;
       break;
     }
     }
     case LUA_GCRESTART: {
     case LUA_GCRESTART: {
       luaE_setdebt(g, 0);
       luaE_setdebt(g, 0);
-      g->gcrunning = 1;
+      g->gcstp = 0;  /* (GCSTPGC must be already zero here) */
       break;
       break;
     }
     }
     case LUA_GCCOLLECT: {
     case LUA_GCCOLLECT: {
@@ -1156,8 +1164,8 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
     case LUA_GCSTEP: {
     case LUA_GCSTEP: {
       int data = va_arg(argp, int);
       int data = va_arg(argp, int);
       l_mem debt = 1;  /* =1 to signal that it did an actual step */
       l_mem debt = 1;  /* =1 to signal that it did an actual step */
-      lu_byte oldrunning = g->gcrunning;
-      g->gcrunning = 1;  /* allow GC to run */
+      lu_byte oldstp = g->gcstp;
+      g->gcstp = 0;  /* allow GC to run (GCSTPGC must be zero here) */
       if (data == 0) {
       if (data == 0) {
         luaE_setdebt(g, 0);  /* do a basic step */
         luaE_setdebt(g, 0);  /* do a basic step */
         luaC_step(L);
         luaC_step(L);
@@ -1167,7 +1175,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
         luaE_setdebt(g, debt);
         luaE_setdebt(g, debt);
         luaC_checkGC(L);
         luaC_checkGC(L);
       }
       }
-      g->gcrunning = oldrunning;  /* restore previous state */
+      g->gcstp = oldstp;  /* restore previous state */
       if (debt > 0 && g->gcstate == GCSpause)  /* end of cycle? */
       if (debt > 0 && g->gcstate == GCSpause)  /* end of cycle? */
         res = 1;  /* signal it */
         res = 1;  /* signal it */
       break;
       break;
@@ -1185,7 +1193,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
       break;
       break;
     }
     }
     case LUA_GCISRUNNING: {
     case LUA_GCISRUNNING: {
-      res = g->gcrunning;
+      res = gcrunning(g);
       break;
       break;
     }
     }
     case LUA_GCGEN: {
     case LUA_GCGEN: {
@@ -1230,7 +1238,7 @@ 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;
   TValue *errobj;
   lua_lock(L);
   lua_lock(L);
-  errobj = s2v(L->top - 1);
+  errobj = s2v(L->top.p - 1);
   api_checknelems(L, 1);
   api_checknelems(L, 1);
   /* error object is the memory error message? */
   /* error object is the memory error message? */
   if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
   if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
@@ -1248,12 +1256,12 @@ LUA_API int lua_next (lua_State *L, int idx) {
   lua_lock(L);
   lua_lock(L);
   api_checknelems(L, 1);
   api_checknelems(L, 1);
   t = gettable(L, idx);
   t = gettable(L, idx);
-  more = luaH_next(L, t, L->top - 1);
+  more = luaH_next(L, t, L->top.p - 1);
   if (more) {
   if (more) {
     api_incr_top(L);
     api_incr_top(L);
   }
   }
   else  /* no more elements */
   else  /* no more elements */
-    L->top -= 1;  /* remove key */
+    L->top.p -= 1;  /* remove key */
   lua_unlock(L);
   lua_unlock(L);
   return more;
   return more;
 }
 }
@@ -1265,7 +1273,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->tbclist < o, "given index below or equal a marked one");
+  api_check(L, L->tbclist.p < 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 */
@@ -1280,7 +1288,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
   if (n > 0)
   if (n > 0)
     luaV_concat(L, n);
     luaV_concat(L, n);
   else {  /* nothing to concatenate */
   else {  /* nothing to concatenate */
-    setsvalue2s(L, L->top, luaS_newlstr(L, "", 0));  /* push empty string */
+    setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0));  /* push empty string */
     api_incr_top(L);
     api_incr_top(L);
   }
   }
   luaC_checkGC(L);
   luaC_checkGC(L);
@@ -1292,7 +1300,7 @@ LUA_API void lua_len (lua_State *L, int idx) {
   TValue *t;
   TValue *t;
   lua_lock(L);
   lua_lock(L);
   t = index2value(L, idx);
   t = index2value(L, idx);
-  luaV_objlen(L, L->top, t);
+  luaV_objlen(L, L->top.p, t);
   api_incr_top(L);
   api_incr_top(L);
   lua_unlock(L);
   lua_unlock(L);
 }
 }
@@ -1337,7 +1345,7 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
   lua_lock(L);
   lua_lock(L);
   api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value");
   api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value");
   u = luaS_newudata(L, size, nuvalue);
   u = luaS_newudata(L, size, nuvalue);
-  setuvalue(L, s2v(L->top), u);
+  setuvalue(L, s2v(L->top.p), u);
   api_incr_top(L);
   api_incr_top(L);
   luaC_checkGC(L);
   luaC_checkGC(L);
   lua_unlock(L);
   lua_unlock(L);
@@ -1363,7 +1371,7 @@ static const char *aux_upvalue (TValue *fi, int n, TValue **val,
       Proto *p = f->p;
       Proto *p = f->p;
       if (!(cast_uint(n) - 1u  < cast_uint(p->sizeupvalues)))
       if (!(cast_uint(n) - 1u  < cast_uint(p->sizeupvalues)))
         return NULL;  /* 'n' not in [1, p->sizeupvalues] */
         return NULL;  /* 'n' not in [1, p->sizeupvalues] */
-      *val = f->upvals[n-1]->v;
+      *val = f->upvals[n-1]->v.p;
       if (owner) *owner = obj2gco(f->upvals[n - 1]);
       if (owner) *owner = obj2gco(f->upvals[n - 1]);
       name = p->upvalues[n-1].name;
       name = p->upvalues[n-1].name;
       return (name == NULL) ? "(no name)" : getstr(name);
       return (name == NULL) ? "(no name)" : getstr(name);
@@ -1379,7 +1387,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
   lua_lock(L);
   lua_lock(L);
   name = aux_upvalue(index2value(L, funcindex), n, &val, NULL);
   name = aux_upvalue(index2value(L, funcindex), n, &val, NULL);
   if (name) {
   if (name) {
-    setobj2s(L, L->top, val);
+    setobj2s(L, L->top.p, val);
     api_incr_top(L);
     api_incr_top(L);
   }
   }
   lua_unlock(L);
   lua_unlock(L);
@@ -1397,8 +1405,8 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
   api_checknelems(L, 1);
   api_checknelems(L, 1);
   name = aux_upvalue(fi, n, &val, &owner);
   name = aux_upvalue(fi, n, &val, &owner);
   if (name) {
   if (name) {
-    L->top--;
-    setobj(L, val, s2v(L->top));
+    L->top.p--;
+    setobj(L, val, s2v(L->top.p));
     luaC_barrier(L, owner, val);
     luaC_barrier(L, owner, val);
   }
   }
   lua_unlock(L);
   lua_unlock(L);

+ 10 - 7
src/lapi.h

@@ -12,23 +12,26 @@
 #include "lstate.h"
 #include "lstate.h"
 
 
 
 
-/* Increments 'L->top', checking for stack overflows */
-#define api_incr_top(L)   {L->top++; api_check(L, L->top <= L->ci->top, \
-				"stack overflow");}
+/* Increments 'L->top.p', checking for stack overflows */
+#define api_incr_top(L)	{L->top.p++; \
+			 api_check(L, L->top.p <= L->ci->top.p, \
+					"stack overflow");}
 
 
 
 
 /*
 /*
 ** 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 accommodate 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.p').
 */
 */
 #define adjustresults(L,nres) \
 #define adjustresults(L,nres) \
-    { if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
+    { if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
+	L->ci->top.p = L->top.p; }
 
 
 
 
 /* Ensure the stack has at least 'n' elements */
 /* Ensure the stack has at least 'n' elements */
-#define api_checknelems(L,n)	api_check(L, (n) < (L->top - L->ci->func), \
-				  "not enough elements in the stack")
+#define api_checknelems(L,n) \
+	api_check(L, (n) < (L->top.p - L->ci->func.p), \
+			  "not enough elements in the stack")
 
 
 
 
 /*
 /*

+ 32 - 25
src/lauxlib.c

@@ -526,13 +526,14 @@ static void newbox (lua_State *L) {
 
 
 /*
 /*
 ** Compute new size for buffer 'B', enough to accommodate extra 'sz'
 ** Compute new size for buffer 'B', enough to accommodate extra 'sz'
-** bytes.
+** bytes. (The test for "not big enough" also gets the case when the
+** computation of 'newsize' overflows.)
 */
 */
 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) * 3;  /* buffer size * 1.5 */
   if (l_unlikely(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)  /* not big enough? */
     newsize = B->n + sz;
     newsize = B->n + sz;
   return newsize;
   return newsize;
 }
 }
@@ -611,7 +612,7 @@ LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
 ** box (if existent) is not on the top of the stack. So, instead of
 ** box (if existent) is not on the top of the stack. So, instead of
 ** calling 'luaL_addlstring', it replicates the code using -2 as the
 ** calling 'luaL_addlstring', it replicates the code using -2 as the
 ** last argument to 'prepbuffsize', signaling that the box is (or will
 ** last argument to 'prepbuffsize', signaling that the box is (or will
-** be) bellow the string being added to the buffer. (Box creation can
+** be) below the string being added to the buffer. (Box creation can
 ** trigger an emergency GC, so we should not remove the string from the
 ** trigger an emergency GC, so we should not remove the string from the
 ** stack before we have the space guaranteed.)
 ** stack before we have the space guaranteed.)
 */
 */
@@ -739,17 +740,18 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
 }
 }
 
 
 
 
-static int skipBOM (LoadF *lf) {
-  const char *p = "\xEF\xBB\xBF";  /* UTF-8 BOM mark */
-  int c;
-  lf->n = 0;
-  do {
-    c = getc(lf->f);
-    if (c == EOF || c != *(const unsigned char *)p++) return c;
-    lf->buff[lf->n++] = c;  /* to be read by the parser */
-  } while (*p != '\0');
-  lf->n = 0;  /* prefix matched; discard it */
-  return getc(lf->f);  /* return next character */
+/*
+** Skip an optional BOM at the start of a stream. If there is an
+** incomplete BOM (the first character is correct but the rest is
+** not), returns the first character anyway to force an error
+** (as no chunk can start with 0xEF).
+*/
+static int skipBOM (FILE *f) {
+  int c = getc(f);  /* read first character */
+  if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF)  /* correct BOM? */
+    return getc(f);  /* ignore BOM and return next char */
+  else  /* no (valid) BOM */
+    return c;  /* return first character */
 }
 }
 
 
 
 
@@ -760,13 +762,13 @@ static int skipBOM (LoadF *lf) {
 ** first "valid" character of the file (after the optional BOM and
 ** first "valid" character of the file (after the optional BOM and
 ** a first-line comment).
 ** a first-line comment).
 */
 */
-static int skipcomment (LoadF *lf, int *cp) {
-  int c = *cp = skipBOM(lf);
+static int skipcomment (FILE *f, int *cp) {
+  int c = *cp = skipBOM(f);
   if (c == '#') {  /* first line is a comment (Unix exec. file)? */
   if (c == '#') {  /* first line is a comment (Unix exec. file)? */
     do {  /* skip first line */
     do {  /* skip first line */
-      c = getc(lf->f);
+      c = getc(f);
     } while (c != EOF && c != '\n');
     } while (c != EOF && c != '\n');
-    *cp = getc(lf->f);  /* skip end-of-line, if present */
+    *cp = getc(f);  /* next character after comment, if present */
     return 1;  /* there was a comment */
     return 1;  /* there was a comment */
   }
   }
   else return 0;  /* no comment */
   else return 0;  /* no comment */
@@ -788,12 +790,16 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
     lf.f = fopen(filename, "r");
     lf.f = fopen(filename, "r");
     if (lf.f == NULL) return errfile(L, "open", fnameindex);
     if (lf.f == NULL) return errfile(L, "open", fnameindex);
   }
   }
-  if (skipcomment(&lf, &c))  /* read initial portion */
-    lf.buff[lf.n++] = '\n';  /* add line to correct line numbers */
-  if (c == LUA_SIGNATURE[0] && filename) {  /* binary file? */
-    lf.f = freopen(filename, "rb", lf.f);  /* reopen in binary mode */
-    if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
-    skipcomment(&lf, &c);  /* re-read initial portion */
+  lf.n = 0;
+  if (skipcomment(lf.f, &c))  /* read initial portion */
+    lf.buff[lf.n++] = '\n';  /* add newline to correct line numbers */
+  if (c == LUA_SIGNATURE[0]) {  /* binary file? */
+    lf.n = 0;  /* remove possible newline */
+    if (filename) {  /* "real" file? */
+      lf.f = freopen(filename, "rb", lf.f);  /* reopen in binary mode */
+      if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
+      skipcomment(lf.f, &c);  /* re-read initial portion */
+    }
   }
   }
   if (c != EOF)
   if (c != EOF)
     lf.buff[lf.n++] = c;  /* 'c' is the first character of the stream */
     lf.buff[lf.n++] = c;  /* 'c' is the first character of the stream */
@@ -881,6 +887,7 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
 
 
 
 
 LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
 LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
+  idx = lua_absindex(L,idx);
   if (luaL_callmeta(L, idx, "__tostring")) {  /* metafield? */
   if (luaL_callmeta(L, idx, "__tostring")) {  /* metafield? */
     if (!lua_isstring(L, -1))
     if (!lua_isstring(L, -1))
       luaL_error(L, "'__tostring' must return a string");
       luaL_error(L, "'__tostring' must return a string");

+ 9 - 1
src/lauxlib.h

@@ -102,7 +102,7 @@ LUALIB_API lua_State *(luaL_newstate) (void);
 
 
 LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
 LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
 
 
-LUALIB_API void luaL_addgsub (luaL_Buffer *b, const char *s,
+LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s,
                                      const char *p, const char *r);
                                      const char *p, const char *r);
 LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s,
 LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s,
                                     const char *p, const char *r);
                                     const char *p, const char *r);
@@ -154,6 +154,14 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
 #define luaL_loadbuffer(L,s,sz,n)	luaL_loadbufferx(L,s,sz,n,NULL)
 #define luaL_loadbuffer(L,s,sz,n)	luaL_loadbufferx(L,s,sz,n,NULL)
 
 
 
 
+/*
+** Perform arithmetic operations on lua_Integer values with wrap-around
+** semantics, as the Lua core does.
+*/
+#define luaL_intop(op,v1,v2)  \
+	((lua_Integer)((lua_Unsigned)(v1) op (lua_Unsigned)(v2)))
+
+
 /* push the value used to represent failure/error */
 /* push the value used to represent failure/error */
 #define luaL_pushfail(L)	lua_pushnil(L)
 #define luaL_pushfail(L)	lua_pushnil(L)
 
 

+ 25 - 4
src/lbaselib.c

@@ -182,12 +182,20 @@ 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");
+  if (oldmode == -1)
+    luaL_pushfail(L);  /* invalid call to 'lua_gc' */
+  else
+    lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
+                                             : "generational");
   return 1;
   return 1;
 }
 }
 
 
 
 
+/*
+** check whether call to 'lua_gc' was valid (not inside a finalizer)
+*/
+#define checkvalres(res) { if (res == -1) break; }
+
 static int luaB_collectgarbage (lua_State *L) {
 static int luaB_collectgarbage (lua_State *L) {
   static const char *const opts[] = {"stop", "restart", "collect",
   static const char *const opts[] = {"stop", "restart", "collect",
     "count", "step", "setpause", "setstepmul",
     "count", "step", "setpause", "setstepmul",
@@ -200,12 +208,14 @@ static int luaB_collectgarbage (lua_State *L) {
     case LUA_GCCOUNT: {
     case LUA_GCCOUNT: {
       int k = lua_gc(L, o);
       int k = lua_gc(L, o);
       int b = lua_gc(L, LUA_GCCOUNTB);
       int b = lua_gc(L, LUA_GCCOUNTB);
+      checkvalres(k);
       lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024));
       lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024));
       return 1;
       return 1;
     }
     }
     case LUA_GCSTEP: {
     case LUA_GCSTEP: {
       int step = (int)luaL_optinteger(L, 2, 0);
       int step = (int)luaL_optinteger(L, 2, 0);
       int res = lua_gc(L, o, step);
       int res = lua_gc(L, o, step);
+      checkvalres(res);
       lua_pushboolean(L, res);
       lua_pushboolean(L, res);
       return 1;
       return 1;
     }
     }
@@ -213,11 +223,13 @@ static int luaB_collectgarbage (lua_State *L) {
     case LUA_GCSETSTEPMUL: {
     case LUA_GCSETSTEPMUL: {
       int p = (int)luaL_optinteger(L, 2, 0);
       int p = (int)luaL_optinteger(L, 2, 0);
       int previous = lua_gc(L, o, p);
       int previous = lua_gc(L, o, p);
+      checkvalres(previous);
       lua_pushinteger(L, previous);
       lua_pushinteger(L, previous);
       return 1;
       return 1;
     }
     }
     case LUA_GCISRUNNING: {
     case LUA_GCISRUNNING: {
       int res = lua_gc(L, o);
       int res = lua_gc(L, o);
+      checkvalres(res);
       lua_pushboolean(L, res);
       lua_pushboolean(L, res);
       return 1;
       return 1;
     }
     }
@@ -234,10 +246,13 @@ static int luaB_collectgarbage (lua_State *L) {
     }
     }
     default: {
     default: {
       int res = lua_gc(L, o);
       int res = lua_gc(L, o);
+      checkvalres(res);
       lua_pushinteger(L, res);
       lua_pushinteger(L, res);
       return 1;
       return 1;
     }
     }
   }
   }
+  luaL_pushfail(L);  /* invalid call (inside a finalizer) */
+  return 1;
 }
 }
 
 
 
 
@@ -261,6 +276,11 @@ static int luaB_next (lua_State *L) {
 }
 }
 
 
 
 
+static int pairscont (lua_State *L, int status, lua_KContext k) {
+  (void)L; (void)status; (void)k;  /* unused */
+  return 3;
+}
+
 static int luaB_pairs (lua_State *L) {
 static int luaB_pairs (lua_State *L) {
   luaL_checkany(L, 1);
   luaL_checkany(L, 1);
   if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) {  /* no metamethod? */
   if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) {  /* no metamethod? */
@@ -270,7 +290,7 @@ static int luaB_pairs (lua_State *L) {
   }
   }
   else {
   else {
     lua_pushvalue(L, 1);  /* argument 'self' to metamethod */
     lua_pushvalue(L, 1);  /* argument 'self' to metamethod */
-    lua_call(L, 1, 3);  /* get 3 values from metamethod */
+    lua_callk(L, 1, 3, 0, pairscont);  /* get 3 values from metamethod */
   }
   }
   return 3;
   return 3;
 }
 }
@@ -280,7 +300,8 @@ static int luaB_pairs (lua_State *L) {
 ** Traversal function for 'ipairs'
 ** Traversal function for 'ipairs'
 */
 */
 static int ipairsaux (lua_State *L) {
 static int ipairsaux (lua_State *L) {
-  lua_Integer i = luaL_checkinteger(L, 2) + 1;
+  lua_Integer i = luaL_checkinteger(L, 2);
+  i = luaL_intop(+, i, 1);
   lua_pushinteger(L, i);
   lua_pushinteger(L, i);
   return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
   return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
 }
 }

+ 114 - 57
src/lcode.c

@@ -10,6 +10,7 @@
 #include "lprefix.h"
 #include "lprefix.h"
 
 
 
 
+#include <float.h>
 #include <limits.h>
 #include <limits.h>
 #include <math.h>
 #include <math.h>
 #include <stdlib.h>
 #include <stdlib.h>
@@ -580,24 +581,41 @@ static int stringK (FuncState *fs, TString *s) {
 
 
 /*
 /*
 ** Add an integer to list of constants and return its index.
 ** Add an integer to list of constants and return its index.
-** Integers use userdata as keys to avoid collision with floats with
-** same value; conversion to 'void*' is used only for hashing, so there
-** are no "precision" problems.
 */
 */
 static int luaK_intK (FuncState *fs, lua_Integer n) {
 static int luaK_intK (FuncState *fs, lua_Integer n) {
-  TValue k, o;
-  setpvalue(&k, cast_voidp(cast_sizet(n)));
+  TValue o;
   setivalue(&o, n);
   setivalue(&o, n);
-  return addk(fs, &k, &o);
+  return addk(fs, &o, &o);  /* use integer itself as key */
 }
 }
 
 
 /*
 /*
-** Add a float to list of constants and return its index.
+** Add a float to list of constants and return its index. Floats
+** with integral values need a different key, to avoid collision
+** with actual integers. To that, we add to the number its smaller
+** power-of-two fraction that is still significant in its scale.
+** For doubles, that would be 1/2^52.
+** (This method is not bulletproof: there may be another float
+** with that value, and for floats larger than 2^53 the result is
+** still an integer. At worst, this only wastes an entry with
+** a duplicate.)
 */
 */
 static int luaK_numberK (FuncState *fs, lua_Number r) {
 static int luaK_numberK (FuncState *fs, lua_Number r) {
   TValue o;
   TValue o;
+  lua_Integer ik;
   setfltvalue(&o, r);
   setfltvalue(&o, r);
-  return addk(fs, &o, &o);  /* use number itself as key */
+  if (!luaV_flttointeger(r, &ik, F2Ieq))  /* not an integral value? */
+    return addk(fs, &o, &o);  /* use number itself as key */
+  else {  /* must build an alternative key */
+    const int nbm = l_floatatt(MANT_DIG);
+    const lua_Number q = l_mathop(ldexp)(l_mathop(1.0), -nbm + 1);
+    const lua_Number k = (ik == 0) ? q : r + r*q;  /* new key */
+    TValue kv;
+    setfltvalue(&kv, k);
+    /* result is not an integral value, unless value is too large */
+    lua_assert(!luaV_flttointeger(k, &ik, F2Ieq) ||
+                l_mathop(fabs)(r) >= l_mathop(1e6));
+    return addk(fs, &kv, &o);
+  }
 }
 }
 
 
 
 
@@ -1333,6 +1351,35 @@ static int constfolding (FuncState *fs, int op, expdesc *e1,
 }
 }
 
 
 
 
+/*
+** Convert a BinOpr to an OpCode  (ORDER OPR - ORDER OP)
+*/
+l_sinline OpCode binopr2op (BinOpr opr, BinOpr baser, OpCode base) {
+  lua_assert(baser <= opr &&
+            ((baser == OPR_ADD && opr <= OPR_SHR) ||
+             (baser == OPR_LT && opr <= OPR_LE)));
+  return cast(OpCode, (cast_int(opr) - cast_int(baser)) + cast_int(base));
+}
+
+
+/*
+** Convert a UnOpr to an OpCode  (ORDER OPR - ORDER OP)
+*/
+l_sinline OpCode unopr2op (UnOpr opr) {
+  return cast(OpCode, (cast_int(opr) - cast_int(OPR_MINUS)) +
+                                       cast_int(OP_UNM));
+}
+
+
+/*
+** Convert a BinOpr to a tag method  (ORDER OPR - ORDER TM)
+*/
+l_sinline TMS binopr2TM (BinOpr opr) {
+  lua_assert(OPR_ADD <= opr && opr <= OPR_SHR);
+  return cast(TMS, (cast_int(opr) - cast_int(OPR_ADD)) + cast_int(TM_ADD));
+}
+
+
 /*
 /*
 ** Emit code for unary expressions that "produce values"
 ** Emit code for unary expressions that "produce values"
 ** (everything but 'not').
 ** (everything but 'not').
@@ -1371,12 +1418,15 @@ static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2,
 ** Emit code for binary expressions that "produce values" over
 ** Emit code for binary expressions that "produce values" over
 ** two registers.
 ** two registers.
 */
 */
-static void codebinexpval (FuncState *fs, OpCode op,
+static void codebinexpval (FuncState *fs, BinOpr opr,
                            expdesc *e1, expdesc *e2, int line) {
                            expdesc *e1, expdesc *e2, int line) {
-  int v2 = luaK_exp2anyreg(fs, e2);  /* both operands are in registers */
+  OpCode op = binopr2op(opr, OPR_ADD, OP_ADD);
+  int v2 = luaK_exp2anyreg(fs, e2);  /* make sure 'e2' is in a register */
+  /* 'e1' must be already in a register or it is a constant */
+  lua_assert((VNIL <= e1->k && e1->k <= VKSTR) ||
+             e1->k == VNONRELOC || e1->k == VRELOC);
   lua_assert(OP_ADD <= op && op <= OP_SHR);
   lua_assert(OP_ADD <= op && op <= OP_SHR);
-  finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN,
-                  cast(TMS, (op - OP_ADD) + TM_ADD));
+  finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, binopr2TM(opr));
 }
 }
 
 
 
 
@@ -1392,6 +1442,18 @@ static void codebini (FuncState *fs, OpCode op,
 }
 }
 
 
 
 
+/*
+** Code binary operators with K operand.
+*/
+static void codebinK (FuncState *fs, BinOpr opr,
+                      expdesc *e1, expdesc *e2, int flip, int line) {
+  TMS event = binopr2TM(opr);
+  int v2 = e2->u.info;  /* K index */
+  OpCode op = binopr2op(opr, OPR_ADD, OP_ADDK);
+  finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
+}
+
+
 /* Try to code a binary operator negating its second operand.
 /* Try to code a binary operator negating its second operand.
 ** For the metamethod, 2nd operand must keep its original value.
 ** For the metamethod, 2nd operand must keep its original value.
 */
 */
@@ -1419,24 +1481,27 @@ static void swapexps (expdesc *e1, expdesc *e2) {
 }
 }
 
 
 
 
+/*
+** Code binary operators with no constant operand.
+*/
+static void codebinNoK (FuncState *fs, BinOpr opr,
+                        expdesc *e1, expdesc *e2, int flip, int line) {
+  if (flip)
+    swapexps(e1, e2);  /* back to original order */
+  codebinexpval(fs, opr, e1, e2, line);  /* use standard operators */
+}
+
+
 /*
 /*
 ** Code arithmetic operators ('+', '-', ...). If second operand is a
 ** Code arithmetic operators ('+', '-', ...). If second operand is a
 ** constant in the proper range, use variant opcodes with K operands.
 ** constant in the proper range, use variant opcodes with K operands.
 */
 */
 static void codearith (FuncState *fs, BinOpr opr,
 static void codearith (FuncState *fs, BinOpr opr,
                        expdesc *e1, expdesc *e2, int flip, int line) {
                        expdesc *e1, expdesc *e2, int flip, int line) {
-  TMS event = cast(TMS, opr + TM_ADD);
-  if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) {  /* K operand? */
-    int v2 = e2->u.info;  /* K index */
-    OpCode op = cast(OpCode, opr + OP_ADDK);
-    finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
-  }
-  else {  /* 'e2' is neither an immediate nor a K operand */
-    OpCode op = cast(OpCode, opr + OP_ADD);
-    if (flip)
-      swapexps(e1, e2);  /* back to original order */
-    codebinexpval(fs, op, e1, e2, line);  /* use standard operators */
-  }
+  if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2))  /* K operand? */
+    codebinK(fs, opr, e1, e2, flip, line);
+  else  /* 'e2' is neither an immediate nor a K operand */
+    codebinNoK(fs, opr, e1, e2, flip, line);
 }
 }
 
 
 
 
@@ -1453,35 +1518,27 @@ static void codecommutative (FuncState *fs, BinOpr op,
     flip = 1;
     flip = 1;
   }
   }
   if (op == OPR_ADD && isSCint(e2))  /* immediate operand? */
   if (op == OPR_ADD && isSCint(e2))  /* immediate operand? */
-    codebini(fs, cast(OpCode, OP_ADDI), e1, e2, flip, line, TM_ADD);
+    codebini(fs, OP_ADDI, e1, e2, flip, line, TM_ADD);
   else
   else
     codearith(fs, op, e1, e2, flip, line);
     codearith(fs, op, e1, e2, flip, line);
 }
 }
 
 
 
 
 /*
 /*
-** Code bitwise operations; they are all associative, so the function
+** Code bitwise operations; they are all commutative, so the function
 ** tries to put an integer constant as the 2nd operand (a K operand).
 ** tries to put an integer constant as the 2nd operand (a K operand).
 */
 */
 static void codebitwise (FuncState *fs, BinOpr opr,
 static void codebitwise (FuncState *fs, BinOpr opr,
                          expdesc *e1, expdesc *e2, int line) {
                          expdesc *e1, expdesc *e2, int line) {
   int flip = 0;
   int flip = 0;
-  int v2;
-  OpCode op;
-  if (e1->k == VKINT && luaK_exp2RK(fs, e1)) {
+  if (e1->k == VKINT) {
     swapexps(e1, e2);  /* 'e2' will be the constant operand */
     swapexps(e1, e2);  /* 'e2' will be the constant operand */
     flip = 1;
     flip = 1;
   }
   }
-  else if (!(e2->k == VKINT && luaK_exp2RK(fs, e2))) {  /* no constants? */
-    op = cast(OpCode, opr + OP_ADD);
-    codebinexpval(fs, op, e1, e2, line);  /* all-register opcodes */
-    return;
-  }
-  v2 = e2->u.info;  /* index in K array */
-  op = cast(OpCode, opr + OP_ADDK);
-  lua_assert(ttisinteger(&fs->f->k[v2]));
-  finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK,
-                  cast(TMS, opr + TM_ADD));
+  if (e2->k == VKINT && luaK_exp2K(fs, e2))  /* K operand? */
+    codebinK(fs, opr, e1, e2, flip, line);
+  else  /* no constants */
+    codebinNoK(fs, opr, e1, e2, flip, line);
 }
 }
 
 
 
 
@@ -1489,25 +1546,27 @@ static void codebitwise (FuncState *fs, BinOpr opr,
 ** Emit code for order comparisons. When using an immediate operand,
 ** Emit code for order comparisons. When using an immediate operand,
 ** 'isfloat' tells whether the original value was a float.
 ** 'isfloat' tells whether the original value was a float.
 */
 */
-static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
+static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
   int r1, r2;
   int r1, r2;
   int im;
   int im;
   int isfloat = 0;
   int isfloat = 0;
+  OpCode op;
   if (isSCnumber(e2, &im, &isfloat)) {
   if (isSCnumber(e2, &im, &isfloat)) {
     /* use immediate operand */
     /* use immediate operand */
     r1 = luaK_exp2anyreg(fs, e1);
     r1 = luaK_exp2anyreg(fs, e1);
     r2 = im;
     r2 = im;
-    op = cast(OpCode, (op - OP_LT) + OP_LTI);
+    op = binopr2op(opr, OPR_LT, OP_LTI);
   }
   }
   else if (isSCnumber(e1, &im, &isfloat)) {
   else if (isSCnumber(e1, &im, &isfloat)) {
     /* transform (A < B) to (B > A) and (A <= B) to (B >= A) */
     /* transform (A < B) to (B > A) and (A <= B) to (B >= A) */
     r1 = luaK_exp2anyreg(fs, e2);
     r1 = luaK_exp2anyreg(fs, e2);
     r2 = im;
     r2 = im;
-    op = (op == OP_LT) ? OP_GTI : OP_GEI;
+    op = binopr2op(opr, OPR_LT, OP_GTI);
   }
   }
   else {  /* regular case, compare two registers */
   else {  /* regular case, compare two registers */
     r1 = luaK_exp2anyreg(fs, e1);
     r1 = luaK_exp2anyreg(fs, e1);
     r2 = luaK_exp2anyreg(fs, e2);
     r2 = luaK_exp2anyreg(fs, e2);
+    op = binopr2op(opr, OPR_LT, OP_LT);
   }
   }
   freeexps(fs, e1, e2);
   freeexps(fs, e1, e2);
   e1->u.info = condjump(fs, op, r1, r2, isfloat, 1);
   e1->u.info = condjump(fs, op, r1, r2, isfloat, 1);
@@ -1533,7 +1592,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
     op = OP_EQI;
     op = OP_EQI;
     r2 = im;  /* immediate operand */
     r2 = im;  /* immediate operand */
   }
   }
-  else if (luaK_exp2RK(fs, e2)) {  /* 1st expression is constant? */
+  else if (luaK_exp2RK(fs, e2)) {  /* 2nd expression is constant? */
     op = OP_EQK;
     op = OP_EQK;
     r2 = e2->u.info;  /* constant index */
     r2 = e2->u.info;  /* constant index */
   }
   }
@@ -1550,16 +1609,16 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
 /*
 /*
 ** Apply prefix operation 'op' to expression 'e'.
 ** Apply prefix operation 'op' to expression 'e'.
 */
 */
-void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
+void luaK_prefix (FuncState *fs, UnOpr opr, expdesc *e, int line) {
   static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
   static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
   luaK_dischargevars(fs, e);
   luaK_dischargevars(fs, e);
-  switch (op) {
+  switch (opr) {
     case OPR_MINUS: case OPR_BNOT:  /* use 'ef' as fake 2nd operand */
     case OPR_MINUS: case OPR_BNOT:  /* use 'ef' as fake 2nd operand */
-      if (constfolding(fs, op + LUA_OPUNM, e, &ef))
+      if (constfolding(fs, opr + LUA_OPUNM, e, &ef))
         break;
         break;
       /* else */ /* FALLTHROUGH */
       /* else */ /* FALLTHROUGH */
     case OPR_LEN:
     case OPR_LEN:
-      codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);
+      codeunexpval(fs, unopr2op(opr), e, line);
       break;
       break;
     case OPR_NOT: codenot(fs, e); break;
     case OPR_NOT: codenot(fs, e); break;
     default: lua_assert(0);
     default: lua_assert(0);
@@ -1593,7 +1652,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
     case OPR_SHL: case OPR_SHR: {
     case OPR_SHL: case OPR_SHR: {
       if (!tonumeral(v, NULL))
       if (!tonumeral(v, NULL))
         luaK_exp2anyreg(fs, v);
         luaK_exp2anyreg(fs, v);
-      /* else keep numeral, which may be folded with 2nd operand */
+      /* else keep numeral, which may be folded or used as an immediate
+         operand */
       break;
       break;
     }
     }
     case OPR_EQ: case OPR_NE: {
     case OPR_EQ: case OPR_NE: {
@@ -1688,30 +1748,27 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
         /* coded as (r1 >> -I) */;
         /* coded as (r1 >> -I) */;
       }
       }
       else  /* regular case (two registers) */
       else  /* regular case (two registers) */
-       codebinexpval(fs, OP_SHL, e1, e2, line);
+       codebinexpval(fs, opr, e1, e2, line);
       break;
       break;
     }
     }
     case OPR_SHR: {
     case OPR_SHR: {
       if (isSCint(e2))
       if (isSCint(e2))
         codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR);  /* r1 >> I */
         codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR);  /* r1 >> I */
       else  /* regular case (two registers) */
       else  /* regular case (two registers) */
-        codebinexpval(fs, OP_SHR, e1, e2, line);
+        codebinexpval(fs, opr, e1, e2, line);
       break;
       break;
     }
     }
     case OPR_EQ: case OPR_NE: {
     case OPR_EQ: case OPR_NE: {
       codeeq(fs, opr, e1, e2);
       codeeq(fs, opr, e1, e2);
       break;
       break;
     }
     }
-    case OPR_LT: case OPR_LE: {
-      OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
-      codeorder(fs, op, e1, e2);
-      break;
-    }
     case OPR_GT: case OPR_GE: {
     case OPR_GT: case OPR_GE: {
       /* '(a > b)' <=> '(b < a)';  '(a >= b)' <=> '(b <= a)' */
       /* '(a > b)' <=> '(b < a)';  '(a >= b)' <=> '(b <= a)' */
-      OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
       swapexps(e1, e2);
       swapexps(e1, e2);
-      codeorder(fs, op, e1, e2);
+      opr = cast(BinOpr, (opr - OPR_GT) + OPR_LT);
+    }  /* FALLTHROUGH */
+    case OPR_LT: case OPR_LE: {
+      codeorder(fs, opr, e1, e2);
       break;
       break;
     }
     }
     default: lua_assert(0);
     default: lua_assert(0);

+ 4 - 4
src/lcorolib.c

@@ -76,9 +76,9 @@ static int luaB_auxwrap (lua_State *L) {
   if (l_unlikely(r < 0)) {  /* error? */
   if (l_unlikely(r < 0)) {  /* error? */
     int stat = lua_status(co);
     int stat = lua_status(co);
     if (stat != LUA_OK && stat != LUA_YIELD) {  /* error in the coroutine? */
     if (stat != LUA_OK && stat != LUA_YIELD) {  /* error in the coroutine? */
-      stat = lua_resetthread(co);  /* close its tbc variables */
+      stat = lua_closethread(co, L);  /* close its tbc variables */
       lua_assert(stat != LUA_OK);
       lua_assert(stat != LUA_OK);
-      lua_xmove(co, L, 1);  /* copy error message */
+      lua_xmove(co, L, 1);  /* move error message to the caller */
     }
     }
     if (stat != LUA_ERRMEM &&  /* not a memory error and ... */
     if (stat != LUA_ERRMEM &&  /* not a memory error and ... */
         lua_type(L, -1) == LUA_TSTRING) {  /* ... error object is a string? */
         lua_type(L, -1) == LUA_TSTRING) {  /* ... error object is a string? */
@@ -172,14 +172,14 @@ static int luaB_close (lua_State *L) {
   int status = auxstatus(L, co);
   int status = auxstatus(L, co);
   switch (status) {
   switch (status) {
     case COS_DEAD: case COS_YIELD: {
     case COS_DEAD: case COS_YIELD: {
-      status = lua_resetthread(co);
+      status = lua_closethread(co, L);
       if (status == LUA_OK) {
       if (status == LUA_OK) {
         lua_pushboolean(L, 1);
         lua_pushboolean(L, 1);
         return 1;
         return 1;
       }
       }
       else {
       else {
         lua_pushboolean(L, 0);
         lua_pushboolean(L, 0);
-        lua_xmove(co, L, 1);  /* copy error message */
+        lua_xmove(co, L, 1);  /* move error message */
         return 2;
         return 2;
       }
       }
     }
     }

+ 116 - 69
src/ldebug.c

@@ -34,8 +34,8 @@
 #define noLuaClosure(f)		((f) == NULL || (f)->c.tt == LUA_VCCL)
 #define noLuaClosure(f)		((f) == NULL || (f)->c.tt == LUA_VCCL)
 
 
 
 
-static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
-                                    const char **name);
+static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
+                                                   const char **name);
 
 
 
 
 static int currentpc (CallInfo *ci) {
 static int currentpc (CallInfo *ci) {
@@ -64,7 +64,7 @@ static int getbaseline (const Proto *f, int pc, int *basepc) {
   }
   }
   else {
   else {
     int i = cast_uint(pc) / MAXIWTHABS - 1;  /* get an estimate */
     int i = cast_uint(pc) / MAXIWTHABS - 1;  /* get an estimate */
-    /* estimate must be a lower bond of the correct base */
+    /* estimate must be a lower bound of the correct base */
     lua_assert(i < 0 ||
     lua_assert(i < 0 ||
               (i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
               (i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
     while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc)
     while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc)
@@ -182,10 +182,10 @@ 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))->p->is_vararg) {
     int nextra = ci->u.l.nextraargs;
     int nextra = ci->u.l.nextraargs;
     if (n >= -nextra) {  /* 'n' is negative */
     if (n >= -nextra) {  /* 'n' is negative */
-      *pos = ci->func - nextra - (n + 1);
+      *pos = ci->func.p - nextra - (n + 1);
       return "(vararg)";  /* generic name for any vararg */
       return "(vararg)";  /* generic name for any vararg */
     }
     }
   }
   }
@@ -194,7 +194,7 @@ static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
 
 
 
 
 const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
 const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
-  StkId base = ci->func + 1;
+  StkId base = ci->func.p + 1;
   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? */
@@ -203,7 +203,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
       name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
       name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
   }
   }
   if (name == NULL) {  /* no 'standard' name? */
   if (name == NULL) {  /* no 'standard' name? */
-    StkId limit = (ci == L->ci) ? L->top : ci->next->func;
+    StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
     if (limit - base >= n && n > 0) {  /* is 'n' inside 'ci' stack? */
     if (limit - base >= n && n > 0) {  /* is 'n' inside 'ci' stack? */
       /* generic name for any valid slot */
       /* generic name for any valid slot */
       name = isLua(ci) ? "(temporary)" : "(C temporary)";
       name = isLua(ci) ? "(temporary)" : "(C temporary)";
@@ -221,16 +221,16 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
   const char *name;
   const char *name;
   lua_lock(L);
   lua_lock(L);
   if (ar == NULL) {  /* information about non-active function? */
   if (ar == NULL) {  /* information about non-active function? */
-    if (!isLfunction(s2v(L->top - 1)))  /* not a Lua function? */
+    if (!isLfunction(s2v(L->top.p - 1)))  /* not a Lua function? */
       name = NULL;
       name = NULL;
     else  /* consider live variables at function start (parameters) */
     else  /* consider live variables at function start (parameters) */
-      name = luaF_getlocalname(clLvalue(s2v(L->top - 1))->p, n, 0);
+      name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
   }
   }
   else {  /* active function; get information through 'ar' */
   else {  /* active function; get information through 'ar' */
     StkId pos = NULL;  /* to avoid warnings */
     StkId pos = NULL;  /* to avoid warnings */
     name = luaG_findlocal(L, ar->i_ci, n, &pos);
     name = luaG_findlocal(L, ar->i_ci, n, &pos);
     if (name) {
     if (name) {
-      setobjs2s(L, L->top, pos);
+      setobjs2s(L, L->top.p, pos);
       api_incr_top(L);
       api_incr_top(L);
     }
     }
   }
   }
@@ -245,8 +245,8 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
   lua_lock(L);
   lua_lock(L);
   name = luaG_findlocal(L, ar->i_ci, n, &pos);
   name = luaG_findlocal(L, ar->i_ci, n, &pos);
   if (name) {
   if (name) {
-    setobjs2s(L, pos, L->top - 1);
-    L->top--;  /* pop value */
+    setobjs2s(L, pos, L->top.p - 1);
+    L->top.p--;  /* pop value */
   }
   }
   lua_unlock(L);
   lua_unlock(L);
   return name;
   return name;
@@ -289,7 +289,7 @@ static int nextline (const Proto *p, int currentline, int pc) {
 
 
 static void collectvalidlines (lua_State *L, Closure *f) {
 static void collectvalidlines (lua_State *L, Closure *f) {
   if (noLuaClosure(f)) {
   if (noLuaClosure(f)) {
-    setnilvalue(s2v(L->top));
+    setnilvalue(s2v(L->top.p));
     api_incr_top(L);
     api_incr_top(L);
   }
   }
   else {
   else {
@@ -298,10 +298,17 @@ static void collectvalidlines (lua_State *L, Closure *f) {
     const Proto *p = f->l.p;
     const Proto *p = f->l.p;
     int currentline = p->linedefined;
     int currentline = p->linedefined;
     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.p, t);  /* push it on stack */
     api_incr_top(L);
     api_incr_top(L);
     setbtvalue(&v);  /* boolean 'true' to be the value of all indices */
     setbtvalue(&v);  /* boolean 'true' to be the value of all indices */
-    for (i = 0; i < p->sizelineinfo; i++) {  /* for all instructions */
+    if (!p->is_vararg)  /* regular function? */
+      i = 0;  /* consider all instructions */
+    else {  /* vararg function */
+      lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
+      currentline = nextline(p, currentline, 0);
+      i = 1;  /* skip first instruction (OP_VARARGPREP) */
+    }
+    for (; i < p->sizelineinfo; i++) {  /* for each instruction */
       currentline = nextline(p, currentline, i);  /* get its line */
       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 */
     }
     }
@@ -310,15 +317,9 @@ static void collectvalidlines (lua_State *L, Closure *f) {
 
 
 
 
 static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
 static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
-  if (ci == NULL)  /* no 'ci'? */
-    return NULL;  /* no info */
-  else if (ci->callstatus & CIST_FIN) {  /* is this a finalizer? */
-    *name = "__gc";
-    return "metamethod";  /* report it as such */
-  }
-  /* calling function is a known Lua function? */
-  else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
-    return funcnamefromcode(L, ci->previous, name);
+  /* calling function is a known function? */
+  if (ci != NULL && !(ci->callstatus & CIST_TAIL))
+    return funcnamefromcall(L, ci->previous, name);
   else return NULL;  /* no way to find a name */
   else return NULL;  /* no way to find a name */
 }
 }
 
 
@@ -387,20 +388,20 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
   lua_lock(L);
   lua_lock(L);
   if (*what == '>') {
   if (*what == '>') {
     ci = NULL;
     ci = NULL;
-    func = s2v(L->top - 1);
+    func = s2v(L->top.p - 1);
     api_check(L, ttisfunction(func), "function expected");
     api_check(L, ttisfunction(func), "function expected");
     what++;  /* skip the '>' */
     what++;  /* skip the '>' */
-    L->top--;  /* pop function */
+    L->top.p--;  /* pop function */
   }
   }
   else {
   else {
     ci = ar->i_ci;
     ci = ar->i_ci;
-    func = s2v(ci->func);
+    func = s2v(ci->func.p);
     lua_assert(ttisfunction(func));
     lua_assert(ttisfunction(func));
   }
   }
   cl = ttisclosure(func) ? clvalue(func) : NULL;
   cl = ttisclosure(func) ? clvalue(func) : NULL;
   status = auxgetinfo(L, what, ar, cl, ci);
   status = auxgetinfo(L, what, ar, cl, ci);
   if (strchr(what, 'f')) {
   if (strchr(what, 'f')) {
-    setobj2s(L, L->top, func);
+    setobj2s(L, L->top.p, func);
     api_incr_top(L);
     api_incr_top(L);
   }
   }
   if (strchr(what, 'L'))
   if (strchr(what, 'L'))
@@ -590,16 +591,10 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
 ** Returns what the name is (e.g., "for iterator", "method",
 ** Returns what the name is (e.g., "for iterator", "method",
 ** "metamethod") and sets '*name' to point to the name.
 ** "metamethod") and sets '*name' to point to the name.
 */
 */
-static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
-                                     const char **name) {
+static const char *funcnamefromcode (lua_State *L, const Proto *p,
+                                     int pc, const char **name) {
   TMS tm = (TMS)0;  /* (initial value avoids warnings) */
   TMS tm = (TMS)0;  /* (initial value avoids warnings) */
-  const Proto *p = ci_func(ci)->p;  /* calling function */
-  int pc = currentpc(ci);  /* calling instruction index */
   Instruction i = p->code[pc];  /* calling instruction */
   Instruction i = p->code[pc];  /* calling instruction */
-  if (ci->callstatus & CIST_HOOKED) {  /* was it called inside a hook? */
-    *name = "?";
-    return "hook";
-  }
   switch (GET_OPCODE(i)) {
   switch (GET_OPCODE(i)) {
     case OP_CALL:
     case OP_CALL:
     case OP_TAILCALL:
     case OP_TAILCALL:
@@ -636,23 +631,44 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
   return "metamethod";
   return "metamethod";
 }
 }
 
 
+
+/*
+** Try to find a name for a function based on how it was called.
+*/
+static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
+                                                   const char **name) {
+  if (ci->callstatus & CIST_HOOKED) {  /* was it called inside a hook? */
+    *name = "?";
+    return "hook";
+  }
+  else if (ci->callstatus & CIST_FIN) {  /* was it called as a finalizer? */
+    *name = "__gc";
+    return "metamethod";  /* report it as such */
+  }
+  else if (isLua(ci))
+    return funcnamefromcode(L, ci_func(ci)->p, currentpc(ci), name);
+  else
+    return NULL;
+}
+
 /* }====================================================== */
 /* }====================================================== */
 
 
 
 
 
 
 /*
 /*
-** 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).
+** Check whether pointer 'o' points to some value in the stack frame of
+** the current function and, if so, returns its index.  Because 'o' may
+** not point to a value in this stack, we cannot compare it with the
+** region boundaries (undefined behavior in ISO C).
 */
 */
-static int isinstack (CallInfo *ci, const TValue *o) {
-  StkId pos;
-  for (pos = ci->func + 1; pos < ci->top; pos++) {
-    if (o == s2v(pos))
-      return 1;
+static int instack (CallInfo *ci, const TValue *o) {
+  int pos;
+  StkId base = ci->func.p + 1;
+  for (pos = 0; base + pos < ci->top.p; pos++) {
+    if (o == s2v(base + pos))
+      return pos;
   }
   }
-  return 0;  /* not found */
+  return -1;  /* not found */
 }
 }
 
 
 
 
@@ -666,7 +682,7 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
   LClosure *c = ci_func(ci);
   LClosure *c = ci_func(ci);
   int i;
   int i;
   for (i = 0; i < c->nupvalues; i++) {
   for (i = 0; i < c->nupvalues; i++) {
-    if (c->upvals[i]->v == o) {
+    if (c->upvals[i]->v.p == o) {
       *name = upvalname(c->p, i);
       *name = upvalname(c->p, i);
       return "upvalue";
       return "upvalue";
     }
     }
@@ -675,36 +691,64 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
 }
 }
 
 
 
 
+static const char *formatvarinfo (lua_State *L, const char *kind,
+                                                const char *name) {
+  if (kind == NULL)
+    return "";  /* no information */
+  else
+    return luaO_pushfstring(L, " (%s '%s')", kind, name);
+}
+
+/*
+** Build a string with a "description" for the value 'o', such as
+** "variable 'x'" or "upvalue 'y'".
+*/
 static const char *varinfo (lua_State *L, const TValue *o) {
 static const char *varinfo (lua_State *L, const TValue *o) {
-  const char *name = NULL;  /* to avoid warnings */
   CallInfo *ci = L->ci;
   CallInfo *ci = L->ci;
+  const char *name = NULL;  /* to avoid warnings */
   const char *kind = NULL;
   const char *kind = NULL;
   if (isLua(ci)) {
   if (isLua(ci)) {
     kind = getupvalname(ci, o, &name);  /* check whether 'o' is an upvalue */
     kind = getupvalname(ci, o, &name);  /* check whether 'o' is an upvalue */
-    if (!kind && isinstack(ci, o))  /* no? try a register */
-      kind = getobjname(ci_func(ci)->p, currentpc(ci),
-                        cast_int(cast(StkId, o) - (ci->func + 1)), &name);
+    if (!kind) {  /* not an upvalue? */
+      int reg = instack(ci, o);  /* try a register */
+      if (reg >= 0)  /* is 'o' a register? */
+        kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name);
+    }
   }
   }
-  return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : "";
+  return formatvarinfo(L, kind, name);
 }
 }
 
 
 
 
-l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
+/*
+** Raise a type error
+*/
+static l_noret typeerror (lua_State *L, const TValue *o, const char *op,
+                          const char *extra) {
   const char *t = luaT_objtypename(L, o);
   const char *t = luaT_objtypename(L, o);
-  luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o));
+  luaG_runerror(L, "attempt to %s a %s value%s", op, t, extra);
 }
 }
 
 
 
 
+/*
+** Raise a type error with "standard" information about the faulty
+** object 'o' (using 'varinfo').
+*/
+l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
+  typeerror(L, o, op, varinfo(L, o));
+}
+
+
+/*
+** Raise an error for calling a non-callable object. Try to find a name
+** for the object based on how it was called ('funcnamefromcall'); if it
+** cannot get a name there, try 'varinfo'.
+*/
 l_noret luaG_callerror (lua_State *L, const TValue *o) {
 l_noret luaG_callerror (lua_State *L, const TValue *o) {
   CallInfo *ci = L->ci;
   CallInfo *ci = L->ci;
   const char *name = NULL;  /* to avoid warnings */
   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");
+  const char *kind = funcnamefromcall(L, ci, &name);
+  const char *extra = kind ? formatvarinfo(L, kind, name) : varinfo(L, o);
+  typeerror(L, o, "call", extra);
 }
 }
 
 
 
 
@@ -766,10 +810,10 @@ l_noret luaG_errormsg (lua_State *L) {
   if (L->errfunc != 0) {  /* is there an error handling function? */
   if (L->errfunc != 0) {  /* is there an error handling function? */
     StkId errfunc = restorestack(L, L->errfunc);
     StkId errfunc = restorestack(L, L->errfunc);
     lua_assert(ttisfunction(s2v(errfunc)));
     lua_assert(ttisfunction(s2v(errfunc)));
-    setobjs2s(L, L->top, L->top - 1);  /* move argument */
-    setobjs2s(L, L->top - 1, errfunc);  /* push function */
-    L->top++;  /* assume EXTRA_STACK */
-    luaD_callnoyield(L, L->top - 2, 1);  /* call it */
+    setobjs2s(L, L->top.p, L->top.p - 1);  /* move argument */
+    setobjs2s(L, L->top.p - 1, errfunc);  /* push function */
+    L->top.p++;  /* assume EXTRA_STACK */
+    luaD_callnoyield(L, L->top.p - 2, 1);  /* call it */
   }
   }
   luaD_throw(L, LUA_ERRRUN);
   luaD_throw(L, LUA_ERRRUN);
 }
 }
@@ -783,8 +827,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
   va_start(argp, fmt);
   va_start(argp, 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, getcurrentline(ci));
     luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
+    setobjs2s(L, L->top.p - 2, L->top.p - 1);  /* remove 'msg' */
+    L->top.p--;
+  }
   luaG_errormsg(L);
   luaG_errormsg(L);
 }
 }
 
 
@@ -801,7 +848,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
   if (p->lineinfo == NULL)  /* no debug information? */
   if (p->lineinfo == NULL)  /* no debug information? */
     return 0;
     return 0;
   if (newpc - oldpc < MAXIWTHABS / 2) {  /* not too far apart? */
   if (newpc - oldpc < MAXIWTHABS / 2) {  /* not too far apart? */
-    int delta = 0;  /* line diference */
+    int delta = 0;  /* line difference */
     int pc = oldpc;
     int pc = oldpc;
     for (;;) {
     for (;;) {
       int lineinfo = p->lineinfo[++pc];
       int lineinfo = p->lineinfo[++pc];
@@ -828,7 +875,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
 ** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
 ** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
 ** at most causes an extra call to a line hook.)
 ** at most causes an extra call to a line hook.)
 ** This function is not "Protected" when called, so it should correct
 ** This function is not "Protected" when called, so it should correct
-** 'L->top' before calling anything that can run the GC.
+** 'L->top.p' 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;
@@ -851,7 +898,7 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
     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)))  /* top not being used? */
   if (!isIT(*(ci->u.l.savedpc - 1)))  /* top not being used? */
-    L->top = ci->top;  /* correct top */
+    L->top.p = ci->top.p;  /* 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) {

+ 1 - 1
src/ldebug.h

@@ -15,7 +15,7 @@
 
 
 
 
 /* Active Lua function (given call info) */
 /* Active Lua function (given call info) */
-#define ci_func(ci)		(clLvalue(s2v((ci)->func)))
+#define ci_func(ci)		(clLvalue(s2v((ci)->func.p)))
 
 
 
 
 #define resethookcount(L)	(L->hookcount = L->basehookcount)
 #define resethookcount(L)	(L->hookcount = L->basehookcount)

+ 204 - 143
src/ldo.c

@@ -104,11 +104,11 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
     }
     }
     default: {
     default: {
       lua_assert(errorstatus(errcode));  /* real error */
       lua_assert(errorstatus(errcode));  /* real error */
-      setobjs2s(L, oldtop, L->top - 1);  /* error message on current top */
+      setobjs2s(L, oldtop, L->top.p - 1);  /* error message on current top */
       break;
       break;
     }
     }
   }
   }
-  L->top = oldtop + 1;
+  L->top.p = oldtop + 1;
 }
 }
 
 
 
 
@@ -121,7 +121,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
     global_State *g = G(L);
     global_State *g = G(L);
     errcode = luaE_resetthread(L, errcode);  /* close all upvalues */
     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.p++, L->top.p - 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 */
@@ -157,16 +157,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
 ** Stack reallocation
 ** Stack reallocation
 ** ===================================================================
 ** ===================================================================
 */
 */
-static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
+
+
+/*
+** Change all pointers to the stack into offsets.
+*/
+static void relstack (lua_State *L) {
+  CallInfo *ci;
+  UpVal *up;
+  L->top.offset = savestack(L, L->top.p);
+  L->tbclist.offset = savestack(L, L->tbclist.p);
+  for (up = L->openupval; up != NULL; up = up->u.open.next)
+    up->v.offset = savestack(L, uplevel(up));
+  for (ci = L->ci; ci != NULL; ci = ci->previous) {
+    ci->top.offset = savestack(L, ci->top.p);
+    ci->func.offset = savestack(L, ci->func.p);
+  }
+}
+
+
+/*
+** Change back all offsets into pointers.
+*/
+static void correctstack (lua_State *L) {
   CallInfo *ci;
   CallInfo *ci;
   UpVal *up;
   UpVal *up;
-  L->top = (L->top - oldstack) + newstack;
-  L->tbclist = (L->tbclist - oldstack) + newstack;
+  L->top.p = restorestack(L, L->top.offset);
+  L->tbclist.p = restorestack(L, L->tbclist.offset);
   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.p = s2v(restorestack(L, up->v.offset));
   for (ci = L->ci; ci != NULL; ci = ci->previous) {
   for (ci = L->ci; ci != NULL; ci = ci->previous) {
-    ci->top = (ci->top - oldstack) + newstack;
-    ci->func = (ci->func - oldstack) + newstack;
+    ci->top.p = restorestack(L, ci->top.offset);
+    ci->func.p = restorestack(L, ci->func.offset);
     if (isLua(ci))
     if (isLua(ci))
       ci->u.l.trap = 1;  /* signal to update 'trap' in 'luaV_execute' */
       ci->u.l.trap = 1;  /* signal to update 'trap' in 'luaV_execute' */
   }
   }
@@ -176,44 +198,45 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
 /* some space for error handling */
 /* some space for error handling */
 #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.)
+** Reallocate the stack to a new size, correcting all pointers into it.
+** In ISO C, any pointer use after the pointer has been deallocated is
+** undefined behavior. So, before the reallocation, all pointers are
+** changed to offsets, and after the reallocation they are changed back
+** to pointers. As during the reallocation the pointers are invalid, the
+** reallocation cannot run emergency collections.
+**
 ** In case of allocation error, raise an error or return false according
 ** In case of allocation error, raise an error or return false according
 ** to 'raiseerror'.
 ** to 'raiseerror'.
 */
 */
 int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
 int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
   int oldsize = stacksize(L);
   int oldsize = stacksize(L);
   int i;
   int i;
-  StkId newstack = luaM_reallocvector(L, NULL, 0,
-                                      newsize + EXTRA_STACK, StackValue);
+  StkId newstack;
+  int oldgcstop = G(L)->gcstopem;
   lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
   lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
+  relstack(L);  /* change pointers to offsets */
+  G(L)->gcstopem = 1;  /* stop emergency collection */
+  newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
+                                   newsize + EXTRA_STACK, StackValue);
+  G(L)->gcstopem = oldgcstop;  /* restore emergency collection */
   if (l_unlikely(newstack == NULL)) {  /* reallocation failed? */
   if (l_unlikely(newstack == NULL)) {  /* reallocation failed? */
+    correctstack(L);  /* change offsets back to pointers */
     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 */
   }
   }
-  /* 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++)
+  L->stack.p = newstack;
+  correctstack(L);  /* change offsets back to pointers */
+  L->stack_last.p = L->stack.p + newsize;
+  for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
     setnilvalue(s2v(newstack + i)); /* erase new segment */
     setnilvalue(s2v(newstack + i)); /* erase new segment */
-  correctstack(L, L->stack, newstack);
-  luaM_freearray(L, L->stack, oldsize + EXTRA_STACK);
-  L->stack = newstack;
-  L->stack_last = L->stack + newsize;
   return 1;
   return 1;
 }
 }
 
 
 
 
 /*
 /*
-** Try to grow the stack by at least 'n' elements. when 'raiseerror'
+** Try to grow the stack by at least 'n' elements. When '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) {
@@ -227,35 +250,38 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) {
       luaD_throw(L, LUA_ERRERR);  /* error inside message handler */
       luaD_throw(L, LUA_ERRERR);  /* error inside message handler */
     return 0;  /* if not 'raiseerror', just signal it */
     return 0;  /* if not 'raiseerror', just signal it */
   }
   }
-  else {
+  else if (n < LUAI_MAXSTACK) {  /* avoids arithmetic overflows */
     int newsize = 2 * size;  /* tentative new size */
     int newsize = 2 * size;  /* tentative new size */
-    int needed = cast_int(L->top - L->stack) + n;
+    int needed = cast_int(L->top.p - L->stack.p) + 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 (l_likely(newsize <= LUAI_MAXSTACK))
     if (l_likely(newsize <= LUAI_MAXSTACK))
       return luaD_reallocstack(L, newsize, raiseerror);
       return luaD_reallocstack(L, newsize, raiseerror);
-    else {  /* stack overflow */
-      /* add extra size to be able to handle the error message */
-      luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
-      if (raiseerror)
-        luaG_runerror(L, "stack overflow");
-      return 0;
-    }
   }
   }
+  /* else stack overflow */
+  /* add extra size to be able to handle the error message */
+  luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
+  if (raiseerror)
+    luaG_runerror(L, "stack overflow");
+  return 0;
 }
 }
 
 
 
 
+/*
+** Compute how much of the stack is being used, by computing the
+** maximum top of all call frames in the stack and the current top.
+*/
 static int stackinuse (lua_State *L) {
 static int stackinuse (lua_State *L) {
   CallInfo *ci;
   CallInfo *ci;
   int res;
   int res;
-  StkId lim = L->top;
+  StkId lim = L->top.p;
   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.p) lim = ci->top.p;
   }
   }
-  lua_assert(lim <= L->stack_last);
-  res = cast_int(lim - L->stack) + 1;  /* part of stack in use */
+  lua_assert(lim <= L->stack_last.p + EXTRA_STACK);
+  res = cast_int(lim - L->stack.p) + 1;  /* part of stack in use */
   if (res < LUA_MINSTACK)
   if (res < LUA_MINSTACK)
     res = LUA_MINSTACK;  /* ensure a minimum size */
     res = LUA_MINSTACK;  /* ensure a minimum size */
   return res;
   return res;
@@ -273,17 +299,13 @@ static int stackinuse (lua_State *L) {
 */
 */
 void luaD_shrinkstack (lua_State *L) {
 void luaD_shrinkstack (lua_State *L) {
   int inuse = stackinuse(L);
   int inuse = stackinuse(L);
-  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;
-  }
+  int max = (inuse > LUAI_MAXSTACK / 3) ? LUAI_MAXSTACK : inuse * 3;
   /* if thread is currently not handling a stack overflow and its
   /* if thread is currently not handling a stack overflow and its
      size is larger than maximum "reasonable" size, shrink it */
      size is larger than maximum "reasonable" size, shrink it */
-  if (inuse <= LUAI_MAXSTACK && stacksize(L) > max)
+  if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) {
+    int nsize = (inuse > LUAI_MAXSTACK / 2) ? LUAI_MAXSTACK : inuse * 2;
     luaD_reallocstack(L, nsize, 0);  /* ok if that fails */
     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 */
@@ -292,7 +314,7 @@ void luaD_shrinkstack (lua_State *L) {
 
 
 void luaD_inctop (lua_State *L) {
 void luaD_inctop (lua_State *L) {
   luaD_checkstack(L, 1);
   luaD_checkstack(L, 1);
-  L->top++;
+  L->top.p++;
 }
 }
 
 
 /* }================================================================== */
 /* }================================================================== */
@@ -309,8 +331,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);  /* preserve original 'top' */
-    ptrdiff_t ci_top = savestack(L, ci->top);  /* idem for 'ci->top' */
+    ptrdiff_t top = savestack(L, L->top.p);  /* preserve original 'top' */
+    ptrdiff_t ci_top = savestack(L, ci->top.p);  /* idem for 'ci->top' */
     lua_Debug ar;
     lua_Debug ar;
     ar.event = event;
     ar.event = event;
     ar.currentline = line;
     ar.currentline = line;
@@ -320,11 +342,11 @@ 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 */
+    if (isLua(ci) && L->top.p < ci->top.p)
+      L->top.p = ci->top.p;  /* protect entire activation register */
     luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
     luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
-    if (ci->top < L->top + LUA_MINSTACK)
-      ci->top = L->top + LUA_MINSTACK;
+    if (ci->top.p < L->top.p + LUA_MINSTACK)
+      ci->top.p = L->top.p + 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;
     lua_unlock(L);
     lua_unlock(L);
@@ -332,8 +354,8 @@ void luaD_hook (lua_State *L, int event, int line,
     lua_lock(L);
     lua_lock(L);
     lua_assert(!L->allowhook);
     lua_assert(!L->allowhook);
     L->allowhook = 1;
     L->allowhook = 1;
-    ci->top = restorestack(L, ci_top);
-    L->top = restorestack(L, top);
+    ci->top.p = restorestack(L, ci_top);
+    L->top.p = restorestack(L, top);
     ci->callstatus &= ~mask;
     ci->callstatus &= ~mask;
   }
   }
 }
 }
@@ -364,7 +386,7 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) {
 */
 */
 static void rethook (lua_State *L, CallInfo *ci, int nres) {
 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 */
+    StkId firstres = L->top.p - nres;  /* index of first result */
     int delta = 0;  /* correction for vararg functions */
     int delta = 0;  /* correction for vararg functions */
     int ftransfer;
     int ftransfer;
     if (isLua(ci)) {
     if (isLua(ci)) {
@@ -372,10 +394,10 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
       if (p->is_vararg)
       if (p->is_vararg)
         delta = ci->u.l.nextraargs + p->numparams + 1;
         delta = ci->u.l.nextraargs + p->numparams + 1;
     }
     }
-    ci->func += delta;  /* if vararg, back to virtual 'func' */
-    ftransfer = cast(unsigned short, firstres - ci->func);
+    ci->func.p += delta;  /* if vararg, back to virtual 'func' */
+    ftransfer = cast(unsigned short, firstres - ci->func.p);
     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.p -= delta;
   }
   }
   if (isLua(ci = ci->previous))
   if (isLua(ci = ci->previous))
     L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p);  /* set 'oldpc' */
     L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p);  /* set 'oldpc' */
@@ -387,15 +409,18 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
 ** stack, below original 'func', so that 'luaD_precall' 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) {
-  const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL);
+StkId luaD_tryfuncTM (lua_State *L, StkId func) {
+  const TValue *tm;
   StkId p;
   StkId p;
+  checkstackGCp(L, 1, func);  /* space for metamethod */
+  tm = luaT_gettmbyobj(L, s2v(func), TM_CALL);  /* (after previous GC) */
   if (l_unlikely(ttisnil(tm)))
   if (l_unlikely(ttisnil(tm)))
     luaG_callerror(L, s2v(func));  /* nothing to call */
     luaG_callerror(L, s2v(func));  /* nothing to call */
-  for (p = L->top; p > func; p--)  /* open space for metamethod */
+  for (p = L->top.p; 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.p++;  /* stack space pre-allocated by the caller */
   setobj2s(L, func, tm);  /* metamethod is the new function to be called */
   setobj2s(L, func, tm);  /* metamethod is the new function to be called */
+  return func;
 }
 }
 
 
 
 
@@ -405,33 +430,34 @@ void luaD_tryfuncTM (lua_State *L, StkId func) {
 ** expressions, multiple results for tail calls/single parameters)
 ** expressions, multiple results for tail calls/single parameters)
 ** separated.
 ** separated.
 */
 */
-static void moveresults (lua_State *L, StkId res, int nres, int wanted) {
+l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
   StkId firstresult;
   StkId firstresult;
   int i;
   int i;
   switch (wanted) {  /* handle typical cases separately */
   switch (wanted) {  /* handle typical cases separately */
     case 0:  /* no values needed */
     case 0:  /* no values needed */
-      L->top = res;
+      L->top.p = res;
       return;
       return;
     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  /* at least one result */
       else  /* at least one result */
-        setobjs2s(L, res, L->top - nres);  /* move it to proper place */
-      L->top = res + 1;
+        setobjs2s(L, res, L->top.p - nres);  /* move it to proper place */
+      L->top.p = 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:  /* two/more results and/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);
         L->ci->callstatus |= CIST_CLSRET;  /* in case of yields */
         L->ci->callstatus |= CIST_CLSRET;  /* in case of yields */
         L->ci->u2.nres = nres;
         L->ci->u2.nres = nres;
-        luaF_close(L, res, CLOSEKTOP, 1);
+        res = luaF_close(L, res, CLOSEKTOP, 1);
         L->ci->callstatus &= ~CIST_CLSRET;
         L->ci->callstatus &= ~CIST_CLSRET;
-        if (L->hookmask)  /* if needed, call hook after '__close's */
+        if (L->hookmask) {  /* if needed, call hook after '__close's */
+          ptrdiff_t savedres = savestack(L, res);
           rethook(L, L->ci, nres);
           rethook(L, L->ci, nres);
-        res = restorestack(L, savedres);  /* close and hook can move stack */
+          res = restorestack(L, savedres);  /* hook can move stack */
+        }
         wanted = decodeNresults(wanted);
         wanted = decodeNresults(wanted);
         if (wanted == LUA_MULTRET)
         if (wanted == LUA_MULTRET)
           wanted = nres;  /* we want all results */
           wanted = nres;  /* we want all results */
@@ -439,14 +465,14 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) {
       break;
       break;
   }
   }
   /* generic case */
   /* generic case */
-  firstresult = L->top - nres;  /* index of first result */
+  firstresult = L->top.p - nres;  /* index of first result */
   if (nres > wanted)  /* extra results? */
   if (nres > wanted)  /* extra results? */
     nres = wanted;  /* don't need them */
     nres = wanted;  /* don't need them */
   for (i = 0; i < nres; i++)  /* move all results to correct place */
   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));
-  L->top = res + wanted;  /* top points after the last result */
+  L->top.p = res + wanted;  /* top points after the last result */
 }
 }
 
 
 
 
@@ -461,7 +487,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
   if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
   if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
     rethook(L, ci, nres);
     rethook(L, ci, nres);
   /* move results to proper place */
   /* move results to proper place */
-  moveresults(L, ci->func, nres, wanted);
+  moveresults(L, ci->func.p, nres, wanted);
   /* function cannot be in any of these cases when returning */
   /* function cannot be in any of these cases when returning */
   lua_assert(!(ci->callstatus &
   lua_assert(!(ci->callstatus &
         (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
         (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
@@ -473,27 +499,81 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
 #define next_ci(L)  (L->ci->next ? L->ci->next : luaE_extendCI(L))
 #define next_ci(L)  (L->ci->next ? L->ci->next : luaE_extendCI(L))
 
 
 
 
+l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,
+                                                int mask, StkId top) {
+  CallInfo *ci = L->ci = next_ci(L);  /* new frame */
+  ci->func.p = func;
+  ci->nresults = nret;
+  ci->callstatus = mask;
+  ci->top.p = top;
+  return ci;
+}
+
+
+/*
+** precall for C functions
+*/
+l_sinline int precallC (lua_State *L, StkId func, int nresults,
+                                            lua_CFunction f) {
+  int n;  /* number of returns */
+  CallInfo *ci;
+  checkstackGCp(L, LUA_MINSTACK, func);  /* ensure minimum stack size */
+  L->ci = ci = prepCallInfo(L, func, nresults, CIST_C,
+                               L->top.p + LUA_MINSTACK);
+  lua_assert(ci->top.p <= L->stack_last.p);
+  if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
+    int narg = cast_int(L->top.p - func) - 1;
+    luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
+  }
+  lua_unlock(L);
+  n = (*f)(L);  /* do the actual call */
+  lua_lock(L);
+  api_checknelems(L, n);
+  luaD_poscall(L, ci, n);
+  return n;
+}
+
+
 /*
 /*
 ** Prepare a function for a tail call, building its call info on top
 ** Prepare a function for a tail call, building its call info on top
 ** of the current call info. 'narg1' is the number of arguments plus 1
 ** of the current call info. 'narg1' is the number of arguments plus 1
-** (so that it includes the function itself).
+** (so that it includes the function itself). Return the number of
+** results, if it was a C function, or -1 for a Lua function.
 */
 */
-void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
-  Proto *p = clLvalue(s2v(func))->p;
-  int fsize = p->maxstacksize;  /* frame size */
-  int nfixparams = p->numparams;
-  int i;
-  for (i = 0; i < narg1; i++)  /* move down function and arguments */
-    setobjs2s(L, ci->func + i, func + i);
-  checkstackGC(L, fsize);
-  func = ci->func;  /* moved-down function */
-  for (; narg1 <= nfixparams; narg1++)
-    setnilvalue(s2v(func + narg1));  /* complete missing arguments */
-  ci->top = func + 1 + fsize;  /* top for new function */
-  lua_assert(ci->top <= L->stack_last);
-  ci->u.l.savedpc = p->code;  /* starting point */
-  ci->callstatus |= CIST_TAIL;
-  L->top = func + narg1;  /* set top */
+int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
+                                    int narg1, int delta) {
+ retry:
+  switch (ttypetag(s2v(func))) {
+    case LUA_VCCL:  /* C closure */
+      return precallC(L, func, LUA_MULTRET, clCvalue(s2v(func))->f);
+    case LUA_VLCF:  /* light C function */
+      return precallC(L, func, LUA_MULTRET, fvalue(s2v(func)));
+    case LUA_VLCL: {  /* Lua function */
+      Proto *p = clLvalue(s2v(func))->p;
+      int fsize = p->maxstacksize;  /* frame size */
+      int nfixparams = p->numparams;
+      int i;
+      checkstackGCp(L, fsize - delta, func);
+      ci->func.p -= delta;  /* restore 'func' (if vararg) */
+      for (i = 0; i < narg1; i++)  /* move down function and arguments */
+        setobjs2s(L, ci->func.p + i, func + i);
+      func = ci->func.p;  /* moved-down function */
+      for (; narg1 <= nfixparams; narg1++)
+        setnilvalue(s2v(func + narg1));  /* complete missing arguments */
+      ci->top.p = func + 1 + fsize;  /* top for new function */
+      lua_assert(ci->top.p <= L->stack_last.p);
+      ci->u.l.savedpc = p->code;  /* starting point */
+      ci->callstatus |= CIST_TAIL;
+      L->top.p = func + narg1;  /* set top */
+      return -1;
+    }
+    default: {  /* not a function */
+      func = luaD_tryfuncTM(L, func);  /* try to get '__call' metamethod */
+      /* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */
+      narg1++;
+      goto retry;  /* try again */
+    }
+  }
 }
 }
 
 
 
 
@@ -506,56 +586,31 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
 ** original function position.
 ** original function position.
 */
 */
 CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
 CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
-  lua_CFunction f;
  retry:
  retry:
   switch (ttypetag(s2v(func))) {
   switch (ttypetag(s2v(func))) {
     case LUA_VCCL:  /* C closure */
     case LUA_VCCL:  /* C closure */
-      f = clCvalue(s2v(func))->f;
-      goto Cfunc;
+      precallC(L, func, nresults, clCvalue(s2v(func))->f);
+      return NULL;
     case LUA_VLCF:  /* light C function */
     case LUA_VLCF:  /* light C function */
-      f = fvalue(s2v(func));
-     Cfunc: {
-      int n;  /* number of returns */
-      CallInfo *ci;
-      checkstackGCp(L, LUA_MINSTACK, func);  /* ensure minimum stack size */
-      L->ci = ci = next_ci(L);
-      ci->nresults = nresults;
-      ci->callstatus = CIST_C;
-      ci->top = L->top + LUA_MINSTACK;
-      ci->func = func;
-      lua_assert(ci->top <= L->stack_last);
-      if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
-        int narg = cast_int(L->top - func) - 1;
-        luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
-      }
-      lua_unlock(L);
-      n = (*f)(L);  /* do the actual call */
-      lua_lock(L);
-      api_checknelems(L, n);
-      luaD_poscall(L, ci, n);
+      precallC(L, func, nresults, fvalue(s2v(func)));
       return NULL;
       return NULL;
-    }
     case LUA_VLCL: {  /* 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.p - 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 */
       checkstackGCp(L, fsize, func);
       checkstackGCp(L, fsize, func);
-      L->ci = ci = next_ci(L);
-      ci->nresults = nresults;
+      L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize);
       ci->u.l.savedpc = p->code;  /* starting point */
       ci->u.l.savedpc = p->code;  /* starting point */
-      ci->top = func + 1 + fsize;
-      ci->func = func;
-      L->ci = ci;
       for (; narg < nfixparams; narg++)
       for (; narg < nfixparams; narg++)
-        setnilvalue(s2v(L->top++));  /* complete missing arguments */
-      lua_assert(ci->top <= L->stack_last);
+        setnilvalue(s2v(L->top.p++));  /* complete missing arguments */
+      lua_assert(ci->top.p <= L->stack_last.p);
       return ci;
       return ci;
     }
     }
     default: {  /* not a function */
     default: {  /* not a function */
-      checkstackGCp(L, 1, func);  /* space for metamethod */
-      luaD_tryfuncTM(L, func);  /* try to get '__call' metamethod */
+      func = luaD_tryfuncTM(L, func);  /* try to get '__call' metamethod */
+      /* return luaD_precall(L, func, nresults); */
       goto retry;  /* try again with metamethod */
       goto retry;  /* try again with metamethod */
     }
     }
   }
   }
@@ -566,12 +621,17 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
 ** Call a function (C or Lua) through C. 'inc' can be 1 (increment
 ** 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
 ** number of recursive invocations in the C stack) or nyci (the same
 ** plus increment number of non-yieldable calls).
 ** plus increment number of non-yieldable calls).
+** This function can be called with some use of EXTRA_STACK, so it should
+** check the stack before doing anything else. 'luaD_precall' already
+** does that.
 */
 */
-static void ccall (lua_State *L, StkId func, int nResults, int inc) {
+l_sinline void ccall (lua_State *L, StkId func, int nResults, l_uint32 inc) {
   CallInfo *ci;
   CallInfo *ci;
   L->nCcalls += inc;
   L->nCcalls += inc;
-  if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
+  if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) {
+    checkstackp(L, 0, func);  /* free any use of EXTRA_STACK */
     luaE_checkcstack(L);
     luaE_checkcstack(L);
+  }
   if ((ci = luaD_precall(L, func, nResults)) != NULL) {  /* Lua function? */
   if ((ci = luaD_precall(L, func, nResults)) != NULL) {  /* Lua function? */
     ci->callstatus = CIST_FRESH;  /* mark that it is a "fresh" execute */
     ci->callstatus = CIST_FRESH;  /* mark that it is a "fresh" execute */
     luaV_execute(L, ci);  /* call it */
     luaV_execute(L, ci);  /* call it */
@@ -619,8 +679,7 @@ static int finishpcallk (lua_State *L,  CallInfo *ci) {
   else {  /* error */
   else {  /* error */
     StkId func = restorestack(L, ci->u2.funcidx);
     StkId func = restorestack(L, ci->u2.funcidx);
     L->allowhook = getoah(ci->callstatus);  /* restore 'allowhook' */
     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 */
+    func = luaF_close(L, func, status, 1);  /* can yield or raise an error */
     luaD_seterrorobj(L, status, func);
     luaD_seterrorobj(L, status, func);
     luaD_shrinkstack(L);   /* restore stack size in case of overflow */
     luaD_shrinkstack(L);   /* restore stack size in case of overflow */
     setcistrecst(ci, LUA_OK);  /* clear original status */
     setcistrecst(ci, LUA_OK);  /* clear original status */
@@ -708,8 +767,8 @@ static CallInfo *findpcall (lua_State *L) {
 ** coroutine error handler and should not kill the coroutine.)
 ** coroutine error handler and should not kill the coroutine.)
 */
 */
 static int resume_error (lua_State *L, const char *msg, int narg) {
 static int resume_error (lua_State *L, const char *msg, int narg) {
-  L->top -= narg;  /* remove args from the stack */
-  setsvalue2s(L, L->top, luaS_new(L, msg));  /* push error message */
+  L->top.p -= narg;  /* remove args from the stack */
+  setsvalue2s(L, L->top.p, luaS_new(L, msg));  /* push error message */
   api_incr_top(L);
   api_incr_top(L);
   lua_unlock(L);
   lua_unlock(L);
   return LUA_ERRRUN;
   return LUA_ERRRUN;
@@ -725,16 +784,15 @@ static int resume_error (lua_State *L, const char *msg, int narg) {
 */
 */
 static void resume (lua_State *L, void *ud) {
 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.p - n;  /* first argument */
   CallInfo *ci = L->ci;
   CallInfo *ci = L->ci;
   if (L->status == LUA_OK)  /* starting a coroutine? */
   if (L->status == LUA_OK)  /* starting a coroutine? */
-    ccall(L, firstArg - 1, LUA_MULTRET, 1);  /* just call its body */
+    ccall(L, firstArg - 1, LUA_MULTRET, 0);  /* 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) */
-    luaE_incCstack(L);  /* control the C stack */
     if (isLua(ci)) {  /* yielded inside a hook? */
     if (isLua(ci)) {  /* yielded inside a hook? */
-      L->top = firstArg;  /* discard arguments */
+      L->top.p = 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 */
@@ -777,12 +835,15 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
   if (L->status == LUA_OK) {  /* may be starting a coroutine */
   if (L->status == LUA_OK) {  /* may be starting a coroutine */
     if (L->ci != &L->base_ci)  /* not in base level? */
     if (L->ci != &L->base_ci)  /* not in base level? */
       return resume_error(L, "cannot resume non-suspended coroutine", nargs);
       return resume_error(L, "cannot resume non-suspended coroutine", nargs);
-    else if (L->top - (L->ci->func + 1) == nargs)  /* no function? */
+    else if (L->top.p - (L->ci->func.p + 1) == nargs)  /* no function? */
       return resume_error(L, "cannot resume dead coroutine", nargs);
       return resume_error(L, "cannot resume dead coroutine", 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);
   L->nCcalls = (from) ? getCcalls(from) : 0;
   L->nCcalls = (from) ? getCcalls(from) : 0;
+  if (getCcalls(L) >= LUAI_MAXCCALLS)
+    return resume_error(L, "C stack overflow", nargs);
+  L->nCcalls++;
   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);
@@ -792,11 +853,11 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
     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' */
-    luaD_seterrorobj(L, status, L->top);  /* push error message */
-    L->ci->top = L->top;
+    luaD_seterrorobj(L, status, L->top.p);  /* push error message */
+    L->ci->top.p = L->top.p;
   }
   }
   *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield
   *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield
-                                    : cast_int(L->top - (L->ci->func + 1));
+                                    : cast_int(L->top.p - (L->ci->func.p + 1));
   lua_unlock(L);
   lua_unlock(L);
   return status;
   return status;
 }
 }
@@ -951,7 +1012,7 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
   p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
   p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
   p.dyd.label.arr = NULL; p.dyd.label.size = 0;
   p.dyd.label.arr = NULL; p.dyd.label.size = 0;
   luaZ_initbuffer(L, &p.buff);
   luaZ_initbuffer(L, &p.buff);
-  status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
+  status = luaD_pcall(L, f_parser, &p, savestack(L, L->top.p), L->errfunc);
   luaZ_freebuffer(L, &p.buff);
   luaZ_freebuffer(L, &p.buff);
   luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
   luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
   luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);
   luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);

+ 14 - 5
src/ldo.h

@@ -8,6 +8,7 @@
 #define ldo_h
 #define ldo_h
 
 
 
 
+#include "llimits.h"
 #include "lobject.h"
 #include "lobject.h"
 #include "lstate.h"
 #include "lstate.h"
 #include "lzio.h"
 #include "lzio.h"
@@ -23,7 +24,7 @@
 ** at every check.
 ** at every check.
 */
 */
 #define luaD_checkstackaux(L,n,pre,pos)  \
 #define luaD_checkstackaux(L,n,pre,pos)  \
-	if (l_unlikely(L->stack_last - L->top <= (n))) \
+	if (l_unlikely(L->stack_last.p - L->top.p <= (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); }
 
 
@@ -32,11 +33,18 @@
 
 
 
 
 
 
-#define savestack(L,p)		((char *)(p) - (char *)L->stack)
-#define restorestack(L,n)	((StkId)((char *)L->stack + (n)))
+#define savestack(L,pt)		(cast_charp(pt) - cast_charp(L->stack.p))
+#define restorestack(L,n)	cast(StkId, cast_charp(L->stack.p) + (n))
 
 
 
 
 /* macro to check stack size, preserving 'p' */
 /* macro to check stack size, preserving 'p' */
+#define checkstackp(L,n,p)  \
+  luaD_checkstackaux(L, n, \
+    ptrdiff_t t__ = savestack(L, p),  /* save 'p' */ \
+    p = restorestack(L, t__))  /* 'pos' part: restore 'p' */
+
+
+/* macro to check stack size and GC, preserving 'p' */
 #define checkstackGCp(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' */ \
@@ -58,11 +66,12 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
 LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
 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 int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
+                                              int narg1, int delta);
 LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
 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 StkId luaD_tryfuncTM (lua_State *L, StkId func);
 LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status);
 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);

+ 6 - 2
src/ldump.c

@@ -10,6 +10,7 @@
 #include "lprefix.h"
 #include "lprefix.h"
 
 
 
 
+#include <limits.h>
 #include <stddef.h>
 #include <stddef.h>
 
 
 #include "lua.h"
 #include "lua.h"
@@ -55,8 +56,11 @@ static void dumpByte (DumpState *D, int y) {
 }
 }
 
 
 
 
-/* dumpInt Buff Size */
-#define DIBS    ((sizeof(size_t) * 8 / 7) + 1)
+/*
+** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6"
+** rounds up the division.)
+*/
+#define DIBS    ((sizeof(size_t) * CHAR_BIT + 6) / 7)
 
 
 static void dumpSize (DumpState *D, size_t x) {
 static void dumpSize (DumpState *D, size_t x) {
   lu_byte buff[DIBS];
   lu_byte buff[DIBS];

+ 27 - 28
src/lfunc.c

@@ -50,8 +50,8 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
   for (i = 0; i < cl->nupvalues; i++) {
   for (i = 0; i < cl->nupvalues; i++) {
     GCObject *o = luaC_newobj(L, LUA_VUPVAL, 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 */
-    setnilvalue(uv->v);
+    uv->v.p = &uv->u.value;  /* make it closed */
+    setnilvalue(uv->v.p);
     cl->upvals[i] = uv;
     cl->upvals[i] = uv;
     luaC_objbarrier(L, cl, uv);
     luaC_objbarrier(L, cl, uv);
   }
   }
@@ -62,12 +62,11 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
 ** Create a new upvalue at the given level, and link it to the list of
 ** Create a new upvalue at the given level, and link it to the list of
 ** 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, StkId level, UpVal **prev) {
   GCObject *o = luaC_newobj(L, LUA_VUPVAL, 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->tbc = tbc;
+  uv->v.p = s2v(level);  /* current value lives in the stack */
   uv->u.open.next = next;  /* link it to list of open upvalues */
   uv->u.open.next = next;  /* link it to list of open upvalues */
   uv->u.open.previous = prev;
   uv->u.open.previous = prev;
   if (next)
   if (next)
@@ -96,7 +95,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
     pp = &p->u.open.next;
     pp = &p->u.open.next;
   }
   }
   /* not found: create a new upvalue after 'pp' */
   /* not found: create a new upvalue after 'pp' */
-  return newupval(L, 0, level, pp);
+  return newupval(L, level, pp);
 }
 }
 
 
 
 
@@ -106,12 +105,12 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
 ** (This function assumes EXTRA_STACK.)
 ** (This function assumes EXTRA_STACK.)
 */
 */
 static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
 static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
-  StkId top = L->top;
+  StkId top = L->top.p;
   const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
   const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
   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.p = top + 3;  /* add function and arguments */
   if (yy)
   if (yy)
     luaD_call(L, top, 0);
     luaD_call(L, top, 0);
   else
   else
@@ -126,7 +125,7 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
 static void checkclosemth (lua_State *L, StkId level) {
 static void checkclosemth (lua_State *L, StkId level) {
   const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
   const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
   if (ttisnil(tm)) {  /* no metamethod? */
   if (ttisnil(tm)) {  /* no metamethod? */
-    int idx = cast_int(level - L->ci->func);  /* variable index */
+    int idx = cast_int(level - L->ci->func.p);  /* variable index */
     const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
     const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
     if (vname == NULL) vname = "?";
     if (vname == NULL) vname = "?";
     luaG_runerror(L, "variable '%s' got a non-closable value", vname);
     luaG_runerror(L, "variable '%s' got a non-closable value", vname);
@@ -160,23 +159,23 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
 ** is used.)
 ** is used.)
 */
 */
 #define MAXDELTA  \
 #define MAXDELTA  \
-	((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1)
+	((256ul << ((sizeof(L->stack.p->tbclist.delta) - 1) * 8)) - 1)
 
 
 
 
 /*
 /*
 ** Insert a variable in the list of to-be-closed variables.
 ** 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) {
-  lua_assert(level > L->tbclist);
+  lua_assert(level > L->tbclist.p);
   if (l_isfalse(s2v(level)))
   if (l_isfalse(s2v(level)))
     return;  /* false doesn't need to be closed */
     return;  /* false doesn't need to be closed */
   checkclosemth(L, level);  /* value must have a close method */
   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;
+  while (cast_uint(level - L->tbclist.p) > MAXDELTA) {
+    L->tbclist.p += MAXDELTA;  /* create a dummy node at maximum delta */
+    L->tbclist.p->tbclist.delta = 0;
   }
   }
-  level->tbclist.delta = cast(unsigned short, level - L->tbclist);
-  L->tbclist = level;
+  level->tbclist.delta = cast(unsigned short, level - L->tbclist.p);
+  L->tbclist.p = level;
 }
 }
 
 
 
 
@@ -196,10 +195,10 @@ void luaF_closeupval (lua_State *L, StkId level) {
   StkId upl;  /* stack index pointed by 'uv' */
   StkId upl;  /* stack index pointed by 'uv' */
   while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
   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.p);
     luaF_unlinkupval(uv);  /* remove upvalue from 'openupval' list */
     luaF_unlinkupval(uv);  /* remove upvalue from 'openupval' list */
-    setobj(L, slot, uv->v);  /* move value to upvalue slot */
-    uv->v = slot;  /* now current value lives here */
+    setobj(L, slot, uv->v.p);  /* move value to upvalue slot */
+    uv->v.p = slot;  /* now current value lives here */
     if (!iswhite(uv)) {  /* neither white nor dead? */
     if (!iswhite(uv)) {  /* neither white nor dead? */
       nw2black(uv);  /* closed upvalues cannot be gray */
       nw2black(uv);  /* closed upvalues cannot be gray */
       luaC_barrier(L, uv, slot);
       luaC_barrier(L, uv, slot);
@@ -209,31 +208,32 @@ void luaF_closeupval (lua_State *L, StkId level) {
 
 
 
 
 /*
 /*
-** Remove firt element from the tbclist plus its dummy nodes.
+** Remove first element from the tbclist plus its dummy nodes.
 */
 */
 static void poptbclist (lua_State *L) {
 static void poptbclist (lua_State *L) {
-  StkId tbc = L->tbclist;
+  StkId tbc = L->tbclist.p;
   lua_assert(tbc->tbclist.delta > 0);  /* first element cannot be dummy */
   lua_assert(tbc->tbclist.delta > 0);  /* first element cannot be dummy */
   tbc -= tbc->tbclist.delta;
   tbc -= tbc->tbclist.delta;
-  while (tbc > L->stack && tbc->tbclist.delta == 0)
+  while (tbc > L->stack.p && tbc->tbclist.delta == 0)
     tbc -= MAXDELTA;  /* remove dummy nodes */
     tbc -= MAXDELTA;  /* remove dummy nodes */
-  L->tbclist = tbc;
+  L->tbclist.p = tbc;
 }
 }
 
 
 
 
 /*
 /*
 ** Close all upvalues and to-be-closed variables up to the given stack
 ** Close all upvalues and to-be-closed variables up to the given stack
-** level.
+** level. Return restored 'level'.
 */
 */
-void luaF_close (lua_State *L, StkId level, int status, int yy) {
+StkId luaF_close (lua_State *L, StkId level, int status, int yy) {
   ptrdiff_t levelrel = savestack(L, level);
   ptrdiff_t levelrel = savestack(L, level);
   luaF_closeupval(L, level);  /* first, close the upvalues */
   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 */
+  while (L->tbclist.p >= level) {  /* traverse tbc's down to that level */
+    StkId tbc = L->tbclist.p;  /* get variable index */
     poptbclist(L);  /* remove it from list */
     poptbclist(L);  /* remove it from list */
     prepcallclosemth(L, tbc, status, yy);  /* close variable */
     prepcallclosemth(L, tbc, status, yy);  /* close variable */
     level = restorestack(L, levelrel);
     level = restorestack(L, levelrel);
   }
   }
+  return level;
 }
 }
 
 
 
 
@@ -260,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;
 }
 }
 
 

+ 3 - 3
src/lfunc.h

@@ -29,10 +29,10 @@
 #define MAXUPVAL	255
 #define MAXUPVAL	255
 
 
 
 
-#define upisopen(up)	((up)->v != &(up)->u.value)
+#define upisopen(up)	((up)->v.p != &(up)->u.value)
 
 
 
 
-#define uplevel(up)	check_exp(upisopen(up), cast(StkId, (up)->v))
+#define uplevel(up)	check_exp(upisopen(up), cast(StkId, (up)->v.p))
 
 
 
 
 /*
 /*
@@ -54,7 +54,7 @@ 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 void luaF_closeupval (lua_State *L, StkId level);
 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 StkId 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,

+ 66 - 55
src/lgc.c

@@ -252,12 +252,13 @@ void luaC_fix (lua_State *L, GCObject *o) {
 
 
 
 
 /*
 /*
-** create a new collectable object (with given type and size) and link
-** it to 'allgc' list.
+** create a new collectable object (with given type, size, and offset)
+** and link it to 'allgc' list.
 */
 */
-GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
+GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
   global_State *g = G(L);
   global_State *g = G(L);
-  GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz));
+  char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
+  GCObject *o = cast(GCObject *, p + offset);
   o->marked = luaC_white(g);
   o->marked = luaC_white(g);
   o->tt = tt;
   o->tt = tt;
   o->next = g->allgc;
   o->next = g->allgc;
@@ -265,6 +266,11 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
   return o;
   return o;
 }
 }
 
 
+
+GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
+  return luaC_newobjdt(L, tt, sz, 0);
+}
+
 /* }====================================================== */
 /* }====================================================== */
 
 
 
 
@@ -301,7 +307,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
         set2gray(uv);  /* open upvalues are kept gray */
         set2gray(uv);  /* open upvalues are kept gray */
       else
       else
         set2black(uv);  /* closed upvalues are visited here */
         set2black(uv);  /* closed upvalues are visited here */
-      markvalue(g, uv->v);  /* mark its content */
+      markvalue(g, uv->v.p);  /* mark its content */
       break;
       break;
     }
     }
     case LUA_VUSERDATA: {
     case LUA_VUSERDATA: {
@@ -376,7 +382,7 @@ static int remarkupvals (global_State *g) {
         work++;
         work++;
         if (!iswhite(uv)) {  /* upvalue already visited? */
         if (!iswhite(uv)) {  /* upvalue already visited? */
           lua_assert(upisopen(uv) && isgray(uv));
           lua_assert(upisopen(uv) && isgray(uv));
-          markvalue(g, uv->v);  /* mark its value */
+          markvalue(g, uv->v.p);  /* mark its value */
         }
         }
       }
       }
     }
     }
@@ -620,19 +626,19 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
 */
 */
 static int traversethread (global_State *g, lua_State *th) {
 static int traversethread (global_State *g, lua_State *th) {
   UpVal *uv;
   UpVal *uv;
-  StkId o = th->stack;
+  StkId o = th->stack.p;
   if (isold(th) || g->gcstate == GCSpropagate)
   if (isold(th) || g->gcstate == GCSpropagate)
     linkgclist(th, g->grayagain);  /* insert into 'grayagain' list */
     linkgclist(th, g->grayagain);  /* insert into 'grayagain' list */
   if (o == NULL)
   if (o == NULL)
     return 1;  /* stack not completely built yet */
     return 1;  /* stack not completely built yet */
   lua_assert(g->gcstate == GCSatomic ||
   lua_assert(g->gcstate == GCSatomic ||
              th->openupval == NULL || isintwups(th));
              th->openupval == NULL || isintwups(th));
-  for (; o < th->top; o++)  /* mark live elements in the stack */
+  for (; o < th->top.p; o++)  /* mark live elements in the stack */
     markvalue(g, s2v(o));
     markvalue(g, s2v(o));
   for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
   for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
     markobject(g, uv);  /* open upvalues cannot be collected */
     markobject(g, uv);  /* open upvalues cannot be collected */
   if (g->gcstate == GCSatomic) {  /* final traversal? */
   if (g->gcstate == GCSatomic) {  /* final traversal? */
-    for (; o < th->stack_last + EXTRA_STACK; o++)
+    for (; o < th->stack_last.p + EXTRA_STACK; o++)
       setnilvalue(s2v(o));  /* clear dead stack slice */
       setnilvalue(s2v(o));  /* clear dead stack slice */
     /* 'remarkupvals' may have removed thread from 'twups' list */
     /* 'remarkupvals' may have removed thread from 'twups' list */
     if (!isintwups(th) && th->openupval != NULL) {
     if (!isintwups(th) && th->openupval != NULL) {
@@ -892,7 +898,7 @@ static GCObject *udata2finalize (global_State *g) {
 
 
 static void dothecall (lua_State *L, void *ud) {
 static void dothecall (lua_State *L, void *ud) {
   UNUSED(ud);
   UNUSED(ud);
-  luaD_callnoyield(L, L->top - 2, 0);
+  luaD_callnoyield(L, L->top.p - 2, 0);
 }
 }
 
 
 
 
@@ -906,19 +912,19 @@ static void GCTM (lua_State *L) {
   if (!notm(tm)) {  /* is there a finalizer? */
   if (!notm(tm)) {  /* is there a finalizer? */
     int status;
     int status;
     lu_byte oldah = L->allowhook;
     lu_byte oldah = L->allowhook;
-    int running  = g->gcrunning;
+    int oldgcstp  = g->gcstp;
+    g->gcstp |= GCSTPGC;  /* avoid GC steps */
     L->allowhook = 0;  /* stop debug hooks during GC metamethod */
     L->allowhook = 0;  /* stop debug hooks during GC metamethod */
-    g->gcrunning = 0;  /* avoid GC steps */
-    setobj2s(L, L->top++, tm);  /* push finalizer... */
-    setobj2s(L, L->top++, &v);  /* ... and its argument */
+    setobj2s(L, L->top.p++, tm);  /* push finalizer... */
+    setobj2s(L, L->top.p++, &v);  /* ... and its argument */
     L->ci->callstatus |= CIST_FIN;  /* will run a finalizer */
     L->ci->callstatus |= CIST_FIN;  /* will run a finalizer */
-    status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
+    status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0);
     L->ci->callstatus &= ~CIST_FIN;  /* not running a finalizer anymore */
     L->ci->callstatus &= ~CIST_FIN;  /* not running a finalizer anymore */
     L->allowhook = oldah;  /* restore hooks */
     L->allowhook = oldah;  /* restore hooks */
-    g->gcrunning = running;  /* restore state */
+    g->gcstp = oldgcstp;  /* restore state */
     if (l_unlikely(status != LUA_OK)) {  /* error while running __gc? */
     if (l_unlikely(status != LUA_OK)) {  /* error while running __gc? */
-      luaE_warnerror(L, "__gc metamethod");
-      L->top--;  /* pops error object */
+      luaE_warnerror(L, "__gc");
+      L->top.p--;  /* pops error object */
     }
     }
   }
   }
 }
 }
@@ -1011,7 +1017,8 @@ static void correctpointers (global_State *g, GCObject *o) {
 void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
 void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
   global_State *g = G(L);
   global_State *g = G(L);
   if (tofinalize(o) ||                 /* obj. is already marked... */
   if (tofinalize(o) ||                 /* obj. is already marked... */
-      gfasttm(g, mt, TM_GC) == NULL)   /* or has no finalizer? */
+      gfasttm(g, mt, TM_GC) == NULL ||    /* or has no finalizer... */
+      (g->gcstp & GCSTPCLS))                   /* or closing state? */
     return;  /* nothing to be done */
     return;  /* nothing to be done */
   else {  /* move 'o' to 'finobj' list */
   else {  /* move 'o' to 'finobj' list */
     GCObject **p;
     GCObject **p;
@@ -1040,7 +1047,25 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
 ** =======================================================
 ** =======================================================
 */
 */
 
 
-static void setpause (global_State *g);
+
+/*
+** Set the "time" to wait before starting a new GC cycle; cycle will
+** start when memory use hits the threshold of ('estimate' * pause /
+** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
+** because Lua cannot even start with less than PAUSEADJ bytes).
+*/
+static void setpause (global_State *g) {
+  l_mem threshold, debt;
+  int pause = getgcparam(g->gcpause);
+  l_mem estimate = g->GCestimate / PAUSEADJ;  /* adjust 'estimate' */
+  lua_assert(estimate > 0);
+  threshold = (pause < MAX_LMEM / estimate)  /* overflow? */
+            ? estimate * pause  /* no overflow */
+            : MAX_LMEM;  /* overflow; truncate to maximum */
+  debt = gettotalbytes(g) - threshold;
+  if (debt > 0) debt = 0;
+  luaE_setdebt(g, debt);
+}
 
 
 
 
 /*
 /*
@@ -1284,6 +1309,15 @@ static void atomic2gen (lua_State *L, global_State *g) {
 }
 }
 
 
 
 
+/*
+** Set debt for the next minor collection, which will happen when
+** memory grows 'genminormul'%.
+*/
+static void setminordebt (global_State *g) {
+  luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
+}
+
+
 /*
 /*
 ** Enter generational mode. Must go until the end of an atomic cycle
 ** Enter generational mode. Must go until the end of an atomic cycle
 ** to ensure that all objects are correctly marked and weak tables
 ** to ensure that all objects are correctly marked and weak tables
@@ -1296,6 +1330,7 @@ static lu_mem entergen (lua_State *L, global_State *g) {
   luaC_runtilstate(L, bitmask(GCSpropagate));  /* start new cycle */
   luaC_runtilstate(L, bitmask(GCSpropagate));  /* start new cycle */
   numobjs = atomic(L);  /* propagates all and then do the atomic stuff */
   numobjs = atomic(L);  /* propagates all and then do the atomic stuff */
   atomic2gen(L, g);
   atomic2gen(L, g);
+  setminordebt(g);  /* set debt assuming next cycle will be minor */
   return numobjs;
   return numobjs;
 }
 }
 
 
@@ -1341,15 +1376,6 @@ static lu_mem fullgen (lua_State *L, global_State *g) {
 }
 }
 
 
 
 
-/*
-** Set debt for the next minor collection, which will happen when
-** memory grows 'genminormul'%.
-*/
-static void setminordebt (global_State *g) {
-  luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
-}
-
-
 /*
 /*
 ** Does a major collection after last collection was a "bad collection".
 ** Does a major collection after last collection was a "bad collection".
 **
 **
@@ -1421,8 +1447,8 @@ static void genstep (lua_State *L, global_State *g) {
       lu_mem numobjs = fullgen(L, g);  /* do a major collection */
       lu_mem numobjs = fullgen(L, g);  /* do a major collection */
       if (gettotalbytes(g) < majorbase + (majorinc / 2)) {
       if (gettotalbytes(g) < majorbase + (majorinc / 2)) {
         /* collected at least half of memory growth since last major
         /* collected at least half of memory growth since last major
-           collection; keep doing minor collections */
-        setminordebt(g);
+           collection; keep doing minor collections. */
+        lua_assert(g->lastatomic == 0);
       }
       }
       else {  /* bad collection */
       else {  /* bad collection */
         g->lastatomic = numobjs;  /* signal that last collection was bad */
         g->lastatomic = numobjs;  /* signal that last collection was bad */
@@ -1448,26 +1474,6 @@ static void genstep (lua_State *L, global_State *g) {
 */
 */
 
 
 
 
-/*
-** Set the "time" to wait before starting a new GC cycle; cycle will
-** start when memory use hits the threshold of ('estimate' * pause /
-** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
-** because Lua cannot even start with less than PAUSEADJ bytes).
-*/
-static void setpause (global_State *g) {
-  l_mem threshold, debt;
-  int pause = getgcparam(g->gcpause);
-  l_mem estimate = g->GCestimate / PAUSEADJ;  /* adjust 'estimate' */
-  lua_assert(estimate > 0);
-  threshold = (pause < MAX_LMEM / estimate)  /* overflow? */
-            ? estimate * pause  /* no overflow */
-            : MAX_LMEM;  /* overflow; truncate to maximum */
-  debt = gettotalbytes(g) - threshold;
-  if (debt > 0) debt = 0;
-  luaE_setdebt(g, debt);
-}
-
-
 /*
 /*
 ** Enter first sweep phase.
 ** Enter first sweep phase.
 ** The call to 'sweeptolive' makes the pointer point to an object
 ** The call to 'sweeptolive' makes the pointer point to an object
@@ -1502,12 +1508,13 @@ static void deletelist (lua_State *L, GCObject *p, GCObject *limit) {
 */
 */
 void luaC_freeallobjects (lua_State *L) {
 void luaC_freeallobjects (lua_State *L) {
   global_State *g = G(L);
   global_State *g = G(L);
+  g->gcstp = GCSTPCLS;  /* no extra finalizers after here */
   luaC_changemode(L, KGC_INC);
   luaC_changemode(L, KGC_INC);
   separatetobefnz(g, 1);  /* separate all objects with finalizers */
   separatetobefnz(g, 1);  /* separate all objects with finalizers */
   lua_assert(g->finobj == NULL);
   lua_assert(g->finobj == NULL);
   callallpendingfinalizers(L);
   callallpendingfinalizers(L);
   deletelist(L, g->allgc, obj2gco(g->mainthread));
   deletelist(L, g->allgc, obj2gco(g->mainthread));
-  deletelist(L, g->finobj, NULL);
+  lua_assert(g->finobj == NULL);  /* no new finalizers */
   deletelist(L, g->fixedgc, NULL);  /* collect fixed objects */
   deletelist(L, g->fixedgc, NULL);  /* collect fixed objects */
   lua_assert(g->strt.nuse == 0);
   lua_assert(g->strt.nuse == 0);
 }
 }
@@ -1647,6 +1654,7 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
 }
 }
 
 
 
 
+
 /*
 /*
 ** Performs a basic incremental step. The debt and step size are
 ** Performs a basic incremental step. The debt and step size are
 ** converted from bytes to "units of work"; then the function loops
 ** converted from bytes to "units of work"; then the function loops
@@ -1673,12 +1681,15 @@ static void incstep (lua_State *L, global_State *g) {
 }
 }
 
 
 /*
 /*
-** performs a basic GC step if collector is running
+** Performs a basic GC step if collector is running. (If collector is
+** not running, set a reasonable debt to avoid it being called at
+** every single check.)
 */
 */
 void luaC_step (lua_State *L) {
 void luaC_step (lua_State *L) {
   global_State *g = G(L);
   global_State *g = G(L);
-  lua_assert(!g->gcemergency);
-  if (g->gcrunning) {  /* running? */
+  if (!gcrunning(g))  /* not running? */
+    luaE_setdebt(g, -2000);
+  else {
     if(isdecGCmodegen(g))
     if(isdecGCmodegen(g))
       genstep(L, g);
       genstep(L, g);
     else
     else

+ 21 - 8
src/lgc.h

@@ -148,6 +148,16 @@
 */
 */
 #define isdecGCmodegen(g)	(g->gckind == KGC_GEN || g->lastatomic != 0)
 #define isdecGCmodegen(g)	(g->gckind == KGC_GEN || g->lastatomic != 0)
 
 
+
+/*
+** Control when GC is running:
+*/
+#define GCSTPUSR	1  /* bit true when GC stopped by user */
+#define GCSTPGC		2  /* bit true when GC stopped by itself */
+#define GCSTPCLS	4  /* bit true when closing Lua state */
+#define gcrunning(g)	((g)->gcstp == 0)
+
+
 /*
 /*
 ** Does one step of collection when debt becomes positive. 'pre'/'pos'
 ** Does one step of collection when debt becomes positive. 'pre'/'pos'
 ** allows some adjustments to be done only when needed. macro
 ** allows some adjustments to be done only when needed. macro
@@ -162,24 +172,27 @@
 #define luaC_checkGC(L)		luaC_condGC(L,(void)0,(void)0)
 #define luaC_checkGC(L)		luaC_condGC(L,(void)0,(void)0)
 
 
 
 
-#define luaC_barrier(L,p,v) (  \
-	(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ?  \
-	luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
-
-#define luaC_barrierback(L,p,v) (  \
-	(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
-	luaC_barrierback_(L,p) : cast_void(0))
-
 #define luaC_objbarrier(L,p,o) (  \
 #define luaC_objbarrier(L,p,o) (  \
 	(isblack(p) && iswhite(o)) ? \
 	(isblack(p) && iswhite(o)) ? \
 	luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
 	luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
 
 
+#define luaC_barrier(L,p,v) (  \
+	iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0))
+
+#define luaC_objbarrierback(L,p,o) (  \
+	(isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0))
+
+#define luaC_barrierback(L,p,v) (  \
+	iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0))
+
 LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
 LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
 LUAI_FUNC void luaC_freeallobjects (lua_State *L);
 LUAI_FUNC void luaC_freeallobjects (lua_State *L);
 LUAI_FUNC void luaC_step (lua_State *L);
 LUAI_FUNC void luaC_step (lua_State *L);
 LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
 LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
 LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
 LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
 LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
 LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
+LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz,
+                                                 size_t offset);
 LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
 LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
 LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
 LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
 LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
 LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);

+ 3 - 3
src/llex.c

@@ -128,7 +128,7 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
 ** ensuring there is only one copy of each unique string.  The table
 ** 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
 ** 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 irrelevant. We use the string itself as the value only because it
-** is a TValue readly available. Later, the code generation can change
+** is a TValue readily available. Later, the code generation can change
 ** this value.
 ** this value.
 */
 */
 TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
 TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
@@ -138,12 +138,12 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
   if (!ttisnil(o))  /* string already present? */
   if (!ttisnil(o))  /* string already present? */
     ts = keystrval(nodefromval(o));  /* get saved copy */
     ts = keystrval(nodefromval(o));  /* get saved copy */
   else {  /* not in use yet */
   else {  /* not in use yet */
-    TValue *stv = s2v(L->top++);  /* reserve stack space for string */
+    TValue *stv = s2v(L->top.p++);  /* reserve stack space for string */
     setsvalue(L, stv, ts);  /* temporarily anchor the string */
     setsvalue(L, stv, ts);  /* temporarily anchor the string */
     luaH_finishset(L, ls->h, stv, o, stv);  /* t[string] = 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 */
     /* 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 */
+    L->top.p--;  /* remove string from stack */
   }
   }
   return ts;
   return ts;
 }
 }

+ 32 - 5
src/llimits.h

@@ -71,11 +71,24 @@ typedef signed char ls_byte;
 
 
 
 
 /*
 /*
-** conversion of pointer to unsigned integer:
-** this is for hashing only; there is no problem if the integer
-** cannot hold the whole pointer value
+** conversion of pointer to unsigned integer: this is for hashing only;
+** there is no problem if the integer cannot hold the whole pointer
+** value. (In strict ISO C this may cause undefined behavior, but no
+** actual machine seems to bother.)
 */
 */
-#define point2uint(p)	((unsigned int)((size_t)(p) & UINT_MAX))
+#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
+    __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+#if defined(UINTPTR_MAX)  /* even in C99 this type is optional */
+#define L_P2I	uintptr_t
+#else  /* no 'intptr'? */
+#define L_P2I	uintmax_t  /* use the largest available integer */
+#endif
+#else  /* C89 option */
+#define L_P2I	size_t
+#endif
+
+#define point2uint(p)	((unsigned int)((L_P2I)(p) & UINT_MAX))
 
 
 
 
 
 
@@ -165,6 +178,20 @@ typedef LUAI_UACINT l_uacInt;
 #endif
 #endif
 
 
 
 
+/*
+** Inline functions
+*/
+#if !defined(LUA_USE_C89)
+#define l_inline	inline
+#elif defined(__GNUC__)
+#define l_inline	__inline__
+#else
+#define l_inline	/* empty */
+#endif
+
+#define l_sinline	static l_inline
+
+
 /*
 /*
 ** type for virtual-machine instructions;
 ** type for virtual-machine instructions;
 ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
 ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
@@ -347,7 +374,7 @@ typedef l_uint32 Instruction;
 #define condchangemem(L,pre,pos)	((void)0)
 #define condchangemem(L,pre,pos)	((void)0)
 #else
 #else
 #define condchangemem(L,pre,pos)  \
 #define condchangemem(L,pre,pos)  \
-	{ if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } }
+	{ if (gcrunning(G(L))) { pre; luaC_fullgc(L, 0); pos; } }
 #endif
 #endif
 
 
 #endif
 #endif

+ 7 - 7
src/lmathlib.c

@@ -267,7 +267,7 @@ static int math_type (lua_State *L) {
 
 
 /* try to find an integer type with at least 64 bits */
 /* try to find an integer type with at least 64 bits */
 
 
-#if (ULONG_MAX >> 31 >> 31) >= 3
+#if ((ULONG_MAX >> 31) >> 31) >= 3
 
 
 /* 'long' has at least 64 bits */
 /* 'long' has at least 64 bits */
 #define Rand64		unsigned long
 #define Rand64		unsigned long
@@ -277,9 +277,9 @@ static int math_type (lua_State *L) {
 /* there is a 'long long' type (which must have at least 64 bits) */
 /* there is a 'long long' type (which must have at least 64 bits) */
 #define Rand64		unsigned long long
 #define Rand64		unsigned long long
 
 
-#elif (LUA_MAXUNSIGNED >> 31 >> 31) >= 3
+#elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
 
 
-/* 'lua_Integer' has at least 64 bits */
+/* 'lua_Unsigned' has at least 64 bits */
 #define Rand64		lua_Unsigned
 #define Rand64		lua_Unsigned
 
 
 #endif
 #endif
@@ -475,7 +475,7 @@ static lua_Number I2d (Rand64 x) {
 
 
 /* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
 /* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
 #define scaleFIG  \
 #define scaleFIG  \
-	((lua_Number)1.0 / (UONE << 30) / 8.0 / (UONE << (FIGS - 33)))
+    (l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33)))
 
 
 /*
 /*
 ** use FIGS - 32 bits from lower half, throwing out the other
 ** use FIGS - 32 bits from lower half, throwing out the other
@@ -486,7 +486,7 @@ static lua_Number I2d (Rand64 x) {
 /*
 /*
 ** higher 32 bits go after those (FIGS - 32) bits: shiftHI = 2^(FIGS - 32)
 ** higher 32 bits go after those (FIGS - 32) bits: shiftHI = 2^(FIGS - 32)
 */
 */
-#define shiftHI		((lua_Number)(UONE << (FIGS - 33)) * 2.0)
+#define shiftHI		((lua_Number)(UONE << (FIGS - 33)) * l_mathop(2.0))
 
 
 
 
 static lua_Number I2d (Rand64 x) {
 static lua_Number I2d (Rand64 x) {
@@ -500,12 +500,12 @@ static lua_Number I2d (Rand64 x) {
 
 
 /* convert a 'Rand64' to a 'lua_Unsigned' */
 /* convert a 'Rand64' to a 'lua_Unsigned' */
 static lua_Unsigned I2UInt (Rand64 x) {
 static lua_Unsigned I2UInt (Rand64 x) {
-  return ((lua_Unsigned)trim32(x.h) << 31 << 1) | (lua_Unsigned)trim32(x.l);
+  return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l);
 }
 }
 
 
 /* convert a 'lua_Unsigned' to a 'Rand64' */
 /* convert a 'lua_Unsigned' to a 'Rand64' */
 static Rand64 Int2I (lua_Unsigned n) {
 static Rand64 Int2I (lua_Unsigned n) {
-  return packI((lu_int32)(n >> 31 >> 1), (lu_int32)n);
+  return packI((lu_int32)((n >> 31) >> 1), (lu_int32)n);
 }
 }
 
 
 #endif  /* } */
 #endif  /* } */

+ 41 - 27
src/lmem.c

@@ -22,25 +22,6 @@
 #include "lstate.h"
 #include "lstate.h"
 
 
 
 
-#if defined(EMERGENCYGCTESTS)
-/*
-** 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) {
-  if (completestate(g) && ns > 0)  /* frees never fail */
-    return NULL;  /* fail */
-  else  /* normal allocation */
-    return (*g->frealloc)(g->ud, block, os, ns);
-}
-#else
-#define firsttry(g,block,os,ns)    ((*g->frealloc)(g->ud, block, os, ns))
-#endif
-
-
-
-
 
 
 /*
 /*
 ** About the realloc function:
 ** About the realloc function:
@@ -60,6 +41,43 @@ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
 */
 */
 
 
 
 
+/*
+** Macro to call the allocation function.
+*/
+#define callfrealloc(g,block,os,ns)    ((*g->frealloc)(g->ud, block, os, ns))
+
+
+/*
+** When an allocation fails, it will try again after an emergency
+** collection, except when it cannot run a collection.  The GC should
+** not be called while the 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.
+*/
+#define cantryagain(g)	(completestate(g) && !g->gcstopem)
+
+
+
+
+#if defined(EMERGENCYGCTESTS)
+/*
+** First allocation will fail except when freeing a block (frees never
+** fail) and when it cannot try again; 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) {
+  if (ns > 0 && cantryagain(g))
+    return NULL;  /* fail */
+  else  /* normal allocation */
+    return callfrealloc(g, block, os, ns);
+}
+#else
+#define firsttry(g,block,os,ns)    callfrealloc(g, block, os, ns)
+#endif
+
+
+
 
 
 
 
 /*
 /*
@@ -132,7 +150,7 @@ l_noret luaM_toobig (lua_State *L) {
 void luaM_free_ (lua_State *L, void *block, size_t osize) {
 void luaM_free_ (lua_State *L, void *block, size_t osize) {
   global_State *g = G(L);
   global_State *g = G(L);
   lua_assert((osize == 0) == (block == NULL));
   lua_assert((osize == 0) == (block == NULL));
-  (*g->frealloc)(g->ud, block, osize, 0);
+  callfrealloc(g, block, osize, 0);
   g->GCdebt -= osize;
   g->GCdebt -= osize;
 }
 }
 
 
@@ -140,19 +158,15 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
 /*
 /*
 ** In case of allocation fail, this function will do an emergency
 ** In case of allocation fail, this function will do an emergency
 ** collection to free some memory and then try the allocation again.
 ** 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 (completestate(g) && !g->gcstopem) {
+  if (cantryagain(g)) {
     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 callfrealloc(g, block, osize, nsize);  /* try again */
   }
   }
-  else return NULL;  /* cannot free any memory without a full state */
+  else return NULL;  /* cannot run an emergency collection */
 }
 }
 
 
 
 

+ 7 - 2
src/loadlib.c

@@ -708,8 +708,13 @@ static const luaL_Reg ll_funcs[] = {
 
 
 
 
 static void createsearcherstable (lua_State *L) {
 static void createsearcherstable (lua_State *L) {
-  static const lua_CFunction searchers[] =
-    {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
+  static const lua_CFunction searchers[] = {
+    searcher_preload,
+    searcher_Lua,
+    searcher_C,
+    searcher_Croot,
+    NULL
+  };
   int i;
   int i;
   /* create 'searchers' table */
   /* create 'searchers' table */
   lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
   lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);

+ 29 - 19
src/lobject.c

@@ -62,7 +62,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
     case LUA_OPBOR: return intop(|, v1, v2);
     case LUA_OPBOR: return intop(|, v1, v2);
     case LUA_OPBXOR: return intop(^, v1, v2);
     case LUA_OPBXOR: return intop(^, v1, v2);
     case LUA_OPSHL: return luaV_shiftl(v1, v2);
     case LUA_OPSHL: return luaV_shiftl(v1, v2);
-    case LUA_OPSHR: return luaV_shiftl(v1, -v2);
+    case LUA_OPSHR: return luaV_shiftr(v1, v2);
     case LUA_OPUNM: return intop(-, 0, v1);
     case LUA_OPUNM: return intop(-, 0, v1);
     case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
     case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
     default: lua_assert(0); return 0;
     default: lua_assert(0); return 0;
@@ -164,7 +164,7 @@ static int isneg (const char **s) {
 */
 */
 static lua_Number lua_strx2number (const char *s, char **endptr) {
 static lua_Number lua_strx2number (const char *s, char **endptr) {
   int dot = lua_getlocaledecpoint();
   int dot = lua_getlocaledecpoint();
-  lua_Number r = 0.0;  /* result (accumulator) */
+  lua_Number r = l_mathop(0.0);  /* result (accumulator) */
   int sigdig = 0;  /* number of significant digits */
   int sigdig = 0;  /* number of significant digits */
   int nosigdig = 0;  /* number of non-significant digits */
   int nosigdig = 0;  /* number of non-significant digits */
   int e = 0;  /* exponent correction */
   int e = 0;  /* exponent correction */
@@ -174,7 +174,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
   while (lisspace(cast_uchar(*s))) s++;  /* skip initial spaces */
   while (lisspace(cast_uchar(*s))) s++;  /* skip initial spaces */
   neg = isneg(&s);  /* check sign */
   neg = isneg(&s);  /* check sign */
   if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')))  /* check '0x' */
   if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')))  /* check '0x' */
-    return 0.0;  /* invalid format (no '0x') */
+    return l_mathop(0.0);  /* invalid format (no '0x') */
   for (s += 2; ; s++) {  /* skip '0x' and read numeral */
   for (s += 2; ; s++) {  /* skip '0x' and read numeral */
     if (*s == dot) {
     if (*s == dot) {
       if (hasdot) break;  /* second dot? stop loop */
       if (hasdot) break;  /* second dot? stop loop */
@@ -184,14 +184,14 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
       if (sigdig == 0 && *s == '0')  /* non-significant digit (zero)? */
       if (sigdig == 0 && *s == '0')  /* non-significant digit (zero)? */
         nosigdig++;
         nosigdig++;
       else if (++sigdig <= MAXSIGDIG)  /* can read it without overflow? */
       else if (++sigdig <= MAXSIGDIG)  /* can read it without overflow? */
-          r = (r * cast_num(16.0)) + luaO_hexavalue(*s);
+          r = (r * l_mathop(16.0)) + luaO_hexavalue(*s);
       else e++; /* too many digits; ignore, but still count for exponent */
       else e++; /* too many digits; ignore, but still count for exponent */
       if (hasdot) e--;  /* decimal digit? correct exponent */
       if (hasdot) e--;  /* decimal digit? correct exponent */
     }
     }
     else break;  /* neither a dot nor a digit */
     else break;  /* neither a dot nor a digit */
   }
   }
   if (nosigdig + sigdig == 0)  /* no digits? */
   if (nosigdig + sigdig == 0)  /* no digits? */
-    return 0.0;  /* invalid format */
+    return l_mathop(0.0);  /* invalid format */
   *endptr = cast_charp(s);  /* valid up to here */
   *endptr = cast_charp(s);  /* valid up to here */
   e *= 4;  /* each digit multiplies/divides value by 2^4 */
   e *= 4;  /* each digit multiplies/divides value by 2^4 */
   if (*s == 'p' || *s == 'P') {  /* exponent part? */
   if (*s == 'p' || *s == 'P') {  /* exponent part? */
@@ -200,7 +200,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
     s++;  /* skip 'p' */
     s++;  /* skip 'p' */
     neg1 = isneg(&s);  /* sign */
     neg1 = isneg(&s);  /* sign */
     if (!lisdigit(cast_uchar(*s)))
     if (!lisdigit(cast_uchar(*s)))
-      return 0.0;  /* invalid; must have at least one digit */
+      return l_mathop(0.0);  /* invalid; must have at least one digit */
     while (lisdigit(cast_uchar(*s)))  /* read exponent */
     while (lisdigit(cast_uchar(*s)))  /* read exponent */
       exp1 = exp1 * 10 + *(s++) - '0';
       exp1 = exp1 * 10 + *(s++) - '0';
     if (neg1) exp1 = -exp1;
     if (neg1) exp1 = -exp1;
@@ -386,29 +386,39 @@ void luaO_tostring (lua_State *L, TValue *obj) {
 ** ===================================================================
 ** ===================================================================
 */
 */
 
 
-/* size for buffer space used by 'luaO_pushvfstring' */
-#define BUFVFS		200
+/*
+** Size for buffer space used by 'luaO_pushvfstring'. It should be
+** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages,
+** so that 'luaG_addinfo' can work directly on the buffer.
+*/
+#define BUFVFS		(LUA_IDSIZE + MAXNUMBER2STR + 95)
 
 
 /* buffer used by 'luaO_pushvfstring' */
 /* buffer used by 'luaO_pushvfstring' */
 typedef struct BuffFS {
 typedef struct BuffFS {
   lua_State *L;
   lua_State *L;
-  int pushed;  /* number of string pieces already on the stack */
+  int pushed;  /* true if there is a part of the result on the stack */
   int blen;  /* length of partial string in 'space' */
   int blen;  /* length of partial string in 'space' */
   char space[BUFVFS];  /* holds last part of the result */
   char space[BUFVFS];  /* holds last part of the result */
 } BuffFS;
 } BuffFS;
 
 
 
 
 /*
 /*
-** Push given string to the stack, as part of the buffer, and
-** join the partial strings in the stack into one.
+** Push given string to the stack, as part of the result, and
+** join it to previous partial result if there is one.
+** It may call 'luaV_concat' while using one slot from EXTRA_STACK.
+** This call cannot invoke metamethods, as both operands must be
+** strings. It can, however, raise an error if the result is too
+** long. In that case, 'luaV_concat' frees the extra slot before
+** raising the error.
 */
 */
-static void pushstr (BuffFS *buff, const char *str, size_t l) {
+static void pushstr (BuffFS *buff, const char *str, size_t lstr) {
   lua_State *L = buff->L;
   lua_State *L = buff->L;
-  setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
-  L->top++;  /* may use one extra slot */
-  buff->pushed++;
-  luaV_concat(L, buff->pushed);  /* join partial results into one */
-  buff->pushed = 1;
+  setsvalue2s(L, L->top.p, luaS_newlstr(L, str, lstr));
+  L->top.p++;  /* may use one slot from EXTRA_STACK */
+  if (!buff->pushed)  /* no previous string on the stack? */
+    buff->pushed = 1;  /* now there is one */
+  else  /* join previous string with new one */
+    luaV_concat(L, 2);
 }
 }
 
 
 
 
@@ -454,7 +464,7 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
 
 
 
 
 /*
 /*
-** Add a number to the buffer.
+** Add a numeral to the buffer.
 */
 */
 static void addnum2buff (BuffFS *buff, TValue *num) {
 static void addnum2buff (BuffFS *buff, TValue *num) {
   char *numbuff = getbuff(buff, MAXNUMBER2STR);
   char *numbuff = getbuff(buff, MAXNUMBER2STR);
@@ -532,7 +542,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 */
   lua_assert(buff.pushed == 1);
   lua_assert(buff.pushed == 1);
-  return svalue(s2v(L->top - 1));
+  return svalue(s2v(L->top.p - 1));
 }
 }
 
 
 
 

+ 19 - 11
src/lobject.h

@@ -52,6 +52,8 @@ typedef union Value {
   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 */
+  /* not used, but may avoid warnings for uninitialized value */
+  lu_byte ub;
 } Value;
 } Value;
 
 
 
 
@@ -68,7 +70,7 @@ typedef struct TValue {
 
 
 
 
 #define val_(o)		((o)->value_)
 #define val_(o)		((o)->value_)
-#define valraw(o)	(&val_(o))
+#define valraw(o)	(val_(o))
 
 
 
 
 /* raw type tag of a TValue */
 /* raw type tag of a TValue */
@@ -112,7 +114,7 @@ typedef struct TValue {
 #define settt_(o,t)	((o)->tt_=(t))
 #define settt_(o,t)	((o)->tt_=(t))
 
 
 
 
-/* main macro to copy values (from 'obj1' to 'obj2') */
+/* main macro to copy values (from 'obj2' to 'obj1') */
 #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_; settt_(io1, io2->tt_); \
           io1->value_ = io2->value_; settt_(io1, io2->tt_); \
@@ -155,6 +157,17 @@ typedef union StackValue {
 /* index to stack elements */
 /* index to stack elements */
 typedef StackValue *StkId;
 typedef StackValue *StkId;
 
 
+
+/*
+** When reallocating the stack, change all pointers to the stack into
+** proper offsets.
+*/
+typedef union {
+  StkId p;  /* actual pointer */
+  ptrdiff_t offset;  /* used while the stack is being reallocated */
+} StkIdRel;
+
+
 /* convert a 'StackValue' to a 'TValue' */
 /* convert a 'StackValue' to a 'TValue' */
 #define s2v(o)	(&(o)->val)
 #define s2v(o)	(&(o)->val)
 
 
@@ -533,12 +546,6 @@ typedef struct AbsLineInfo {
   int line;
   int line;
 } AbsLineInfo;
 } AbsLineInfo;
 
 
-
-/*
-** AOT implementation
-*/
-typedef struct CallInfo *(*AotCompiledFunction) (lua_State *L, struct CallInfo *ci);
-
 /*
 /*
 ** Function Prototypes
 ** Function Prototypes
 */
 */
@@ -565,7 +572,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;
 
 
 /* }================================================================== */
 /* }================================================================== */
@@ -622,8 +628,10 @@ typedef struct Proto {
 */
 */
 typedef struct UpVal {
 typedef struct UpVal {
   CommonHeader;
   CommonHeader;
-  lu_byte tbc;  /* true if it represents a to-be-closed variable */
-  TValue *v;  /* points to stack or to its own value */
+  union {
+    TValue *p;  /* points to stack or to its own value */
+    ptrdiff_t offset;  /* used while the stack is being reallocated */
+  } v;
   union {
   union {
     struct {  /* (when open) */
     struct {  /* (when open) */
       struct UpVal *next;  /* linked list */
       struct UpVal *next;  /* linked list */

+ 18 - 5
src/lopcodes.h

@@ -21,7 +21,7 @@ iABC          C(8)     |      B(8)     |k|     A(8)      |   Op(7)     |
 iABx                Bx(17)               |     A(8)      |   Op(7)     |
 iABx                Bx(17)               |     A(8)      |   Op(7)     |
 iAsBx              sBx (signed)(17)      |     A(8)      |   Op(7)     |
 iAsBx              sBx (signed)(17)      |     A(8)      |   Op(7)     |
 iAx                           Ax(25)                     |   Op(7)     |
 iAx                           Ax(25)                     |   Op(7)     |
-isJ                           sJ(25)                     |   Op(7)     |
+isJ                           sJ (signed)(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
@@ -190,7 +190,8 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ};  /* basic instruction formats */
 
 
 
 
 /*
 /*
-** grep "ORDER OP" if you change these enums
+** Grep "ORDER OP" if you change these enums. Opcodes marked with a (*)
+** has extra descriptions in the notes after the enumeration.
 */
 */
 
 
 typedef enum {
 typedef enum {
@@ -203,7 +204,7 @@ OP_LOADF,/*	A sBx	R[A] := (lua_Number)sBx				*/
 OP_LOADK,/*	A Bx	R[A] := K[Bx]					*/
 OP_LOADK,/*	A Bx	R[A] := K[Bx]					*/
 OP_LOADKX,/*	A	R[A] := K[extra arg]				*/
 OP_LOADKX,/*	A	R[A] := K[extra arg]				*/
 OP_LOADFALSE,/*	A	R[A] := false					*/
 OP_LOADFALSE,/*	A	R[A] := false					*/
-OP_LFALSESKIP,/*A	R[A] := false; pc++				*/
+OP_LFALSESKIP,/*A	R[A] := false; pc++	(*)			*/
 OP_LOADTRUE,/*	A	R[A] := true					*/
 OP_LOADTRUE,/*	A	R[A] := true					*/
 OP_LOADNIL,/*	A B	R[A], R[A+1], ..., R[A+B] := nil		*/
 OP_LOADNIL,/*	A B	R[A], R[A+1], ..., R[A+B] := nil		*/
 OP_GETUPVAL,/*	A B	R[A] := UpValue[B]				*/
 OP_GETUPVAL,/*	A B	R[A] := UpValue[B]				*/
@@ -254,7 +255,7 @@ OP_BXOR,/*	A B C	R[A] := R[B] ~ R[C]				*/
 OP_SHL,/*	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_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_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_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_MMBINK,/*	A B C k		call C metamethod over R[A] and K[B]	*/
 
 
@@ -280,7 +281,7 @@ 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_GEI,/*	A sB k	if ((R[A] >= sB) ~= k) then pc++		*/
 
 
 OP_TEST,/*	A k	if (not R[A] == k) then pc++			*/
 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_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_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_TAILCALL,/*	A B C k	return R[A](R[A+1], ... ,R[A+B-1])		*/
@@ -315,6 +316,18 @@ OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
 
 
 /*===========================================================================
 /*===========================================================================
   Notes:
   Notes:
+
+  (*) Opcode OP_LFALSESKIP is used to convert a condition to a boolean
+  value, in a code equivalent to (not cond ? false : true).  (It
+  produces false and skips the next instruction producing true.)
+
+  (*) Opcodes OP_MMBIN and variants follow each arithmetic and
+  bitwise opcode. If the operation succeeds, it skips this next
+  opcode. Otherwise, this opcode calls the corresponding metamethod.
+
+  (*) Opcode OP_TESTSET is used in short-circuit expressions that need
+  both to jump and to produce a value, such as (a = b or c).
+
   (*) In OP_CALL, if (B == 0) then B = top - A. If (C == 0), then
   (*) In OP_CALL, if (B == 0) then B = top - A. If (C == 0), then
   'top' is set to last_result+1, so next open instruction (OP_CALL,
   'top' is set to last_result+1, so next open instruction (OP_CALL,
   OP_RETURN*, OP_SETLIST) may use 'top'.
   OP_RETURN*, OP_SETLIST) may use 'top'.

+ 17 - 19
src/loslib.c

@@ -30,23 +30,14 @@
 */
 */
 #if !defined(LUA_STRFTIMEOPTIONS)	/* { */
 #if !defined(LUA_STRFTIMEOPTIONS)	/* { */
 
 
-/* options for ANSI C 89 (only 1-char options) */
-#define L_STRFTIMEC89		"aAbBcdHIjmMpSUwWxXyYZ%"
-
-/* options for ISO C 99 and POSIX */
-#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
-    "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy"  /* two-char options */
-
-/* options for Windows */
-#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
-    "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y"  /* two-char options */
-
 #if defined(LUA_USE_WINDOWS)
 #if defined(LUA_USE_WINDOWS)
-#define LUA_STRFTIMEOPTIONS	L_STRFTIMEWIN
-#elif defined(LUA_USE_C89)
-#define LUA_STRFTIMEOPTIONS	L_STRFTIMEC89
+#define LUA_STRFTIMEOPTIONS  "aAbBcdHIjmMpSUwWxXyYzZ%" \
+    "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y"  /* two-char options */
+#elif defined(LUA_USE_C89)  /* ANSI C 89 (only 1-char options) */
+#define LUA_STRFTIMEOPTIONS  "aAbBcdHIjmMpSUwWxXyYZ%"
 #else  /* C99 specification */
 #else  /* C99 specification */
-#define LUA_STRFTIMEOPTIONS	L_STRFTIMEC99
+#define LUA_STRFTIMEOPTIONS  "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
+    "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy"  /* two-char options */
 #endif
 #endif
 
 
 #endif					/* } */
 #endif					/* } */
@@ -138,12 +129,21 @@
 /* }================================================================== */
 /* }================================================================== */
 
 
 
 
+#if !defined(l_system)
+#if defined(LUA_USE_IOS)
+/* Despite claiming to be ISO C, iOS does not implement 'system'. */
+#define l_system(cmd) ((cmd) == NULL ? 0 : -1)
+#else
+#define l_system(cmd)	system(cmd)  /* default definition */
+#endif
+#endif
+
 
 
 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;
   int stat;
   errno = 0;
   errno = 0;
-  stat = system(cmd);
+  stat = l_system(cmd);
   if (cmd != NULL)
   if (cmd != NULL)
     return luaL_execresult(L, stat);
     return luaL_execresult(L, stat);
   else {
   else {
@@ -260,9 +260,7 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
     res = d;
     res = d;
   }
   }
   else {
   else {
-    /* unsigned avoids overflow when lua_Integer has 32 bits */
-    if (!(res >= 0 ? (lua_Unsigned)res <= (lua_Unsigned)INT_MAX + delta
-                   : (lua_Integer)INT_MIN + delta <= res))
+    if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res))
       return luaL_error(L, "field '%s' is out-of-bound", key);
       return luaL_error(L, "field '%s' is out-of-bound", key);
     res -= delta;
     res -= delta;
   }
   }

+ 32 - 21
src/lparser.c

@@ -416,6 +416,17 @@ static void markupval (FuncState *fs, int level) {
 }
 }
 
 
 
 
+/*
+** Mark that current block has a to-be-closed variable.
+*/
+static void marktobeclosed (FuncState *fs) {
+  BlockCnt *bl = fs->bl;
+  bl->upval = 1;
+  bl->insidetbc = 1;
+  fs->needclose = 1;
+}
+
+
 /*
 /*
 ** Find a variable with the given name 'n'. If it is an upvalue, add
 ** Find a variable with the given name 'n'. If it is an upvalue, add
 ** this upvalue into all intermediate functions. If it is a global, set
 ** this upvalue into all intermediate functions. If it is a global, set
@@ -457,6 +468,7 @@ static void singlevar (LexState *ls, expdesc *var) {
     expdesc key;
     expdesc key;
     singlevaraux(fs, ls->envn, var, 1);  /* get environment variable */
     singlevaraux(fs, ls->envn, var, 1);  /* get environment variable */
     lua_assert(var->k != VVOID);  /* this one must exist */
     lua_assert(var->k != VVOID);  /* this one must exist */
+    luaK_exp2anyregup(fs, var);  /* but could be a constant */
     codestring(&key, varname);  /* key is variable name */
     codestring(&key, varname);  /* key is variable name */
     luaK_indexed(fs, var, &key);  /* env[varname] */
     luaK_indexed(fs, var, &key);  /* env[varname] */
   }
   }
@@ -509,12 +521,12 @@ static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
 
 
 /*
 /*
 ** Solves the goto at index 'g' to given 'label' and removes it
 ** Solves the goto at index 'g' to given 'label' and removes it
-** from the list of pending goto's.
+** from the list of pending gotos.
 ** If it jumps into the scope of some variable, raises an error.
 ** If it jumps into the scope of some variable, raises an error.
 */
 */
 static void solvegoto (LexState *ls, int g, Labeldesc *label) {
 static void solvegoto (LexState *ls, int g, Labeldesc *label) {
   int i;
   int i;
-  Labellist *gl = &ls->dyd->gt;  /* list of goto's */
+  Labellist *gl = &ls->dyd->gt;  /* list of gotos */
   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 (l_unlikely(gt->nactvar < label->nactvar))  /* enter some scope? */
   if (l_unlikely(gt->nactvar < label->nactvar))  /* enter some scope? */
@@ -568,7 +580,7 @@ static int newgotoentry (LexState *ls, TString *name, int line, int pc) {
 /*
 /*
 ** Solves forward jumps. Check whether new label 'lb' matches any
 ** Solves forward jumps. Check whether new label 'lb' matches any
 ** pending gotos in current block and solves them. Return true
 ** pending gotos in current block and solves them. Return true
-** if any of the goto's need to close upvalues.
+** if any of the gotos need to close upvalues.
 */
 */
 static int solvegotos (LexState *ls, Labeldesc *lb) {
 static int solvegotos (LexState *ls, Labeldesc *lb) {
   Labellist *gl = &ls->dyd->gt;
   Labellist *gl = &ls->dyd->gt;
@@ -589,7 +601,7 @@ static int solvegotos (LexState *ls, Labeldesc *lb) {
 /*
 /*
 ** Create a new label with the given 'name' at the given 'line'.
 ** Create a new label with the given 'name' at the given 'line'.
 ** 'last' tells whether label is the last non-op statement in its
 ** 'last' tells whether label is the last non-op statement in its
-** block. Solves all pending goto's to this new label and adds
+** block. Solves all pending gotos to this new label and adds
 ** a close instruction if necessary.
 ** a close instruction if necessary.
 ** Returns true iff it added a close instruction.
 ** Returns true iff it added a close instruction.
 */
 */
@@ -662,19 +674,19 @@ static void leaveblock (FuncState *fs) {
   LexState *ls = fs->ls;
   LexState *ls = fs->ls;
   int hasclose = 0;
   int hasclose = 0;
   int stklevel = reglevel(fs, bl->nactvar);  /* level outside the block */
   int stklevel = reglevel(fs, bl->nactvar);  /* level outside the block */
-  if (bl->isloop)  /* fix pending breaks? */
+  removevars(fs, bl->nactvar);  /* remove block locals */
+  lua_assert(bl->nactvar == fs->nactvar);  /* back to level on entry */
+  if (bl->isloop)  /* has to 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)  /* still need a 'close'? */
     luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0);
     luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0);
-  fs->bl = bl->previous;
-  removevars(fs, bl->nactvar);
-  lua_assert(bl->nactvar == fs->nactvar);
   fs->freereg = stklevel;  /* free registers */
   fs->freereg = stklevel;  /* free registers */
   ls->dyd->label.n = bl->firstlabel;  /* remove local labels */
   ls->dyd->label.n = bl->firstlabel;  /* remove local labels */
-  if (bl->previous)  /* inner block? */
-    movegotosout(fs, bl);  /* update pending gotos to outer block */
+  fs->bl = bl->previous;  /* current block now is previous one */
+  if (bl->previous)  /* was it a nested block? */
+    movegotosout(fs, bl);  /* update pending gotos to enclosing block */
   else {
   else {
-    if (bl->firstgoto < ls->dyd->gt.n)  /* pending gotos in outer block? */
+    if (bl->firstgoto < ls->dyd->gt.n)  /* still pending gotos? */
       undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]);  /* error */
       undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]);  /* error */
   }
   }
 }
 }
@@ -1599,7 +1611,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, fs->nactvar);  /* last control var. must be closed */
+  marktobeclosed(fs);  /* 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);
 }
 }
@@ -1703,11 +1715,9 @@ static int getlocalattribute (LexState *ls) {
 }
 }
 
 
 
 
-static void checktoclose (LexState *ls, int level) {
+static void checktoclose (FuncState *fs, int level) {
   if (level != -1) {  /* is there a to-be-closed variable? */
   if (level != -1) {  /* is there a to-be-closed variable? */
-    FuncState *fs = ls->fs;
-    markupval(fs, level + 1);
-    fs->bl->insidetbc = 1;  /* in the scope of a to-be-closed variable */
+    marktobeclosed(fs);
     luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0);
     luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0);
   }
   }
 }
 }
@@ -1751,7 +1761,7 @@ static void localstat (LexState *ls) {
     adjust_assign(ls, nvars, nexps, &e);
     adjust_assign(ls, nvars, nexps, &e);
     adjustlocalvars(ls, nvars);
     adjustlocalvars(ls, nvars);
   }
   }
-  checktoclose(ls, toclose);
+  checktoclose(fs, toclose);
 }
 }
 
 
 
 
@@ -1776,6 +1786,7 @@ static void funcstat (LexState *ls, int line) {
   luaX_next(ls);  /* skip FUNCTION */
   luaX_next(ls);  /* skip FUNCTION */
   ismethod = funcname(ls, &v);
   ismethod = funcname(ls, &v);
   body(ls, &b, ismethod, line);
   body(ls, &b, ismethod, line);
+  check_readonly(ls, &v);
   luaK_storevar(ls->fs, &v, &b);
   luaK_storevar(ls->fs, &v, &b);
   luaK_fixline(ls->fs, line);  /* definition "happens" in the first line */
   luaK_fixline(ls->fs, line);  /* definition "happens" in the first line */
 }
 }
@@ -1933,10 +1944,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
   LexState lexstate;
   LexState lexstate;
   FuncState funcstate;
   FuncState funcstate;
   LClosure *cl = luaF_newLclosure(L, 1);  /* create main closure */
   LClosure *cl = luaF_newLclosure(L, 1);  /* create main closure */
-  setclLvalue2s(L, L->top, cl);  /* anchor it (to avoid being collected) */
+  setclLvalue2s(L, L->top.p, cl);  /* anchor it (to avoid being collected) */
   luaD_inctop(L);
   luaD_inctop(L);
   lexstate.h = luaH_new(L);  /* create table for scanner */
   lexstate.h = luaH_new(L);  /* create table for scanner */
-  sethvalue2s(L, L->top, lexstate.h);  /* anchor it */
+  sethvalue2s(L, L->top.p, 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);
   luaC_objbarrier(L, cl, cl->p);
@@ -1950,7 +1961,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
   lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
   lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
   /* all scopes should be correctly finished */
   /* all scopes should be correctly finished */
   lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
   lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
-  L->top--;  /* remove scanner's table */
+  L->top.p--;  /* remove scanner's table */
   return cl;  /* closure is on the stack, too */
   return cl;  /* closure is on the stack, too */
 }
 }
 
 

+ 41 - 35
src/lstate.c

@@ -166,7 +166,7 @@ void luaE_checkcstack (lua_State *L) {
   if (getCcalls(L) == LUAI_MAXCCALLS)
   if (getCcalls(L) == LUAI_MAXCCALLS)
     luaG_runerror(L, "C stack overflow");
     luaG_runerror(L, "C stack overflow");
   else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
   else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
-    luaD_throw(L, LUA_ERRERR);  /* error while handing stack error */
+    luaD_throw(L, LUA_ERRERR);  /* error while handling stack error */
 }
 }
 
 
 
 
@@ -180,33 +180,33 @@ LUAI_FUNC void luaE_incCstack (lua_State *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 + EXTRA_STACK, StackValue);
-  L1->tbclist = L1->stack;
+  L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
+  L1->tbclist.p = L1->stack.p;
   for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
   for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
-    setnilvalue(s2v(L1->stack + i));  /* erase new stack */
-  L1->top = L1->stack;
-  L1->stack_last = L1->stack + BASIC_STACK_SIZE;
+    setnilvalue(s2v(L1->stack.p + i));  /* erase new stack */
+  L1->top.p = L1->stack.p;
+  L1->stack_last.p = L1->stack.p + 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;
   ci->callstatus = CIST_C;
   ci->callstatus = CIST_C;
-  ci->func = L1->top;
+  ci->func.p = L1->top.p;
   ci->u.c.k = NULL;
   ci->u.c.k = NULL;
   ci->nresults = 0;
   ci->nresults = 0;
-  setnilvalue(s2v(L1->top));  /* 'function' entry for this 'ci' */
-  L1->top++;
-  ci->top = L1->top + LUA_MINSTACK;
+  setnilvalue(s2v(L1->top.p));  /* 'function' entry for this 'ci' */
+  L1->top.p++;
+  ci->top.p = L1->top.p + LUA_MINSTACK;
   L1->ci = ci;
   L1->ci = ci;
 }
 }
 
 
 
 
 static void freestack (lua_State *L) {
 static void freestack (lua_State *L) {
-  if (L->stack == NULL)
+  if (L->stack.p == NULL)
     return;  /* stack not completely built yet */
     return;  /* stack not completely built yet */
   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, stacksize(L) + EXTRA_STACK);  /* free stack */
+  luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK);  /* free stack */
 }
 }
 
 
 
 
@@ -236,7 +236,7 @@ static void f_luaopen (lua_State *L, void *ud) {
   luaS_init(L);
   luaS_init(L);
   luaT_init(L);
   luaT_init(L);
   luaX_init(L);
   luaX_init(L);
-  g->gcrunning = 1;  /* allow gc */
+  g->gcstp = 0;  /* allow gc */
   setnilvalue(&g->nilvalue);  /* now state is complete */
   setnilvalue(&g->nilvalue);  /* now state is complete */
   luai_userstateopen(L);
   luai_userstateopen(L);
 }
 }
@@ -248,7 +248,7 @@ static void f_luaopen (lua_State *L, void *ud) {
 */
 */
 static void preinit_thread (lua_State *L, global_State *g) {
 static void preinit_thread (lua_State *L, global_State *g) {
   G(L) = g;
   G(L) = g;
-  L->stack = NULL;
+  L->stack.p = NULL;
   L->ci = NULL;
   L->ci = NULL;
   L->nci = 0;
   L->nci = 0;
   L->twups = L;  /* thread has no upvalues */
   L->twups = L;  /* thread has no upvalues */
@@ -269,8 +269,9 @@ static void preinit_thread (lua_State *L, global_State *g) {
 static void close_state (lua_State *L) {
 static void close_state (lua_State *L) {
   global_State *g = G(L);
   global_State *g = G(L);
   if (!completestate(g))  /* closing a partially built state? */
   if (!completestate(g))  /* closing a partially built state? */
-    luaC_freeallobjects(L);  /* jucst collect its objects */
+    luaC_freeallobjects(L);  /* just collect its objects */
   else {  /* closing a fully built state */
   else {  /* closing a fully built state */
+    L->ci = &L->base_ci;  /* unwind CallInfo list */
     luaD_closeprotected(L, 1, LUA_OK);  /* close all upvalues */
     luaD_closeprotected(L, 1, LUA_OK);  /* close all upvalues */
     luaC_freeallobjects(L);  /* collect all objects */
     luaC_freeallobjects(L);  /* collect all objects */
     luai_userstateclose(L);
     luai_userstateclose(L);
@@ -283,20 +284,16 @@ 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;
+  global_State *g = G(L);
+  GCObject *o;
   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->marked = luaC_white(g);
-  L1->tt = LUA_VTHREAD;
-  /* link it on list 'allgc' */
-  L1->next = g->allgc;
-  g->allgc = obj2gco(L1);
+  o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l));
+  L1 = gco2th(o);
   /* anchor it on L stack */
   /* anchor it on L stack */
-  setthvalue2s(L, L->top, L1);
+  setthvalue2s(L, L->top.p, L1);
   api_incr_top(L);
   api_incr_top(L);
   preinit_thread(L1, g);
   preinit_thread(L1, g);
   L1->hookmask = L->hookmask;
   L1->hookmask = L->hookmask;
@@ -315,7 +312,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_closeupval(L1, L1->stack);  /* close all upvalues */
+  luaF_closeupval(L1, L1->stack.p);  /* 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);
@@ -325,32 +322,41 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
 
 
 int luaE_resetthread (lua_State *L, int status) {
 int luaE_resetthread (lua_State *L, int status) {
   CallInfo *ci = L->ci = &L->base_ci;  /* unwind CallInfo list */
   CallInfo *ci = L->ci = &L->base_ci;  /* unwind CallInfo list */
-  setnilvalue(s2v(L->stack));  /* 'function' entry for basic 'ci' */
-  ci->func = L->stack;
+  setnilvalue(s2v(L->stack.p));  /* 'function' entry for basic 'ci' */
+  ci->func.p = L->stack.p;
   ci->callstatus = CIST_C;
   ci->callstatus = CIST_C;
   if (status == LUA_YIELD)
   if (status == LUA_YIELD)
     status = LUA_OK;
     status = LUA_OK;
+  L->status = LUA_OK;  /* so it can run __close metamethods */
   status = luaD_closeprotected(L, 1, status);
   status = luaD_closeprotected(L, 1, status);
   if (status != LUA_OK)  /* errors? */
   if (status != LUA_OK)  /* errors? */
-    luaD_seterrorobj(L, status, L->stack + 1);
+    luaD_seterrorobj(L, status, L->stack.p + 1);
   else
   else
-    L->top = L->stack + 1;
-  ci->top = L->top + LUA_MINSTACK;
-  L->status = cast_byte(status);
-  luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
+    L->top.p = L->stack.p + 1;
+  ci->top.p = L->top.p + LUA_MINSTACK;
+  luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0);
   return status;
   return status;
 }
 }
 
 
 
 
-LUA_API int lua_resetthread (lua_State *L) {
+LUA_API int lua_closethread (lua_State *L, lua_State *from) {
   int status;
   int status;
   lua_lock(L);
   lua_lock(L);
+  L->nCcalls = (from) ? getCcalls(from) : 0;
   status = luaE_resetthread(L, L->status);
   status = luaE_resetthread(L, L->status);
   lua_unlock(L);
   lua_unlock(L);
   return status;
   return status;
 }
 }
 
 
 
 
+/*
+** Deprecated! Use 'lua_closethread' instead.
+*/
+LUA_API int lua_resetthread (lua_State *L) {
+  return lua_closethread(L, NULL);
+}
+
+
 LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
 LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   int i;
   int i;
   lua_State *L;
   lua_State *L;
@@ -372,7 +378,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   g->ud_warn = NULL;
   g->ud_warn = NULL;
   g->mainthread = L;
   g->mainthread = L;
   g->seed = luai_makeseed(L);
   g->seed = luai_makeseed(L);
-  g->gcrunning = 0;  /* no GC while building state */
+  g->gcstp = GCSTPGC;  /* no GC while building state */
   g->strt.size = g->strt.nuse = 0;
   g->strt.size = g->strt.nuse = 0;
   g->strt.hash = NULL;
   g->strt.hash = NULL;
   setnilvalue(&g->l_registry);
   setnilvalue(&g->l_registry);
@@ -425,7 +431,7 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
 ** Generate a warning from an error message
 ** Generate a warning from an error message
 */
 */
 void luaE_warnerror (lua_State *L, const char *where) {
 void luaE_warnerror (lua_State *L, const char *where) {
-  TValue *errobj = s2v(L->top - 1);  /* error object */
+  TValue *errobj = s2v(L->top.p - 1);  /* error object */
   const char *msg = (ttisstring(errobj))
   const char *msg = (ttisstring(errobj))
                   ? svalue(errobj)
                   ? svalue(errobj)
                   : "error object is not a string";
                   : "error object is not a string";

+ 18 - 13
src/lstate.h

@@ -9,6 +9,11 @@
 
 
 #include "lua.h"
 #include "lua.h"
 
 
+
+/* Some header files included here need this definition */
+typedef struct CallInfo CallInfo;
+
+
 #include "lobject.h"
 #include "lobject.h"
 #include "ltm.h"
 #include "ltm.h"
 #include "lzio.h"
 #include "lzio.h"
@@ -139,7 +144,7 @@ struct lua_longjmp;  /* defined in ldo.c */
 
 
 #define BASIC_STACK_SIZE        (2*LUA_MINSTACK)
 #define BASIC_STACK_SIZE        (2*LUA_MINSTACK)
 
 
-#define stacksize(th)	cast_int((th)->stack_last - (th)->stack)
+#define stacksize(th)	cast_int((th)->stack_last.p - (th)->stack.p)
 
 
 
 
 /* kinds of Garbage Collection */
 /* kinds of Garbage Collection */
@@ -165,13 +170,13 @@ typedef struct stringtable {
 ** - field 'nyield' is used only while a function is "doing" an
 ** - field 'nyield' is used only while a function is "doing" an
 ** yield (from the yield until the next resume);
 ** yield (from the yield until the next resume);
 ** - field 'nres' is used only while closing tbc variables when
 ** - field 'nres' is used only while closing tbc variables when
-** returning from a C function;
+** returning from a function;
 ** - field 'transferinfo' is used only during call/returnhooks,
 ** - field 'transferinfo' is used only during call/returnhooks,
 ** before the function starts or after it ends.
 ** before the function starts or after it ends.
 */
 */
-typedef struct CallInfo {
-  StkId func;  /* function index in the stack */
-  StkId	top;  /* top for this function */
+struct CallInfo {
+  StkIdRel func;  /* function index in the stack */
+  StkIdRel	top;  /* top for this function */
   struct CallInfo *previous, *next;  /* dynamic call link */
   struct CallInfo *previous, *next;  /* dynamic call link */
   union {
   union {
     struct {  /* only for Lua functions */
     struct {  /* only for Lua functions */
@@ -196,7 +201,7 @@ typedef struct CallInfo {
   } u2;
   } u2;
   short nresults;  /* expected number of results from this function */
   short nresults;  /* expected number of results from this function */
   unsigned short callstatus;
   unsigned short callstatus;
-} CallInfo;
+};
 
 
 
 
 /*
 /*
@@ -209,7 +214,7 @@ typedef struct CallInfo {
 #define CIST_YPCALL	(1<<4)	/* doing a yieldable protected call */
 #define CIST_YPCALL	(1<<4)	/* doing a yieldable protected call */
 #define CIST_TAIL	(1<<5)	/* call was tail called */
 #define CIST_TAIL	(1<<5)	/* call was tail called */
 #define CIST_HOOKYIELD	(1<<6)	/* last hook called yielded */
 #define CIST_HOOKYIELD	(1<<6)	/* last hook called yielded */
-#define CIST_FIN	(1<<7)	/* call is running a finalizer */
+#define CIST_FIN	(1<<7)	/* function "called" a finalizer */
 #define CIST_TRAN	(1<<8)	/* 'ci' has transfer information */
 #define CIST_TRAN	(1<<8)	/* 'ci' has transfer information */
 #define CIST_CLSRET	(1<<9)  /* function is closing tbc variables */
 #define CIST_CLSRET	(1<<9)  /* function is closing tbc variables */
 /* Bits 10-12 are used for CIST_RECST (see below) */
 /* Bits 10-12 are used for CIST_RECST (see below) */
@@ -263,7 +268,7 @@ typedef struct global_State {
   lu_byte gcstopem;  /* stops emergency collections */
   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 gcstp;  /* control whether GC is running */
   lu_byte gcemergency;  /* true if this is an emergency collection */
   lu_byte gcemergency;  /* true if this is an emergency collection */
   lu_byte gcpause;  /* size of pause between successive GCs */
   lu_byte gcpause;  /* size of pause between successive GCs */
   lu_byte gcstepmul;  /* GC "speed" */
   lu_byte gcstepmul;  /* GC "speed" */
@@ -291,7 +296,7 @@ typedef struct global_State {
   struct lua_State *mainthread;
   struct lua_State *mainthread;
   TString *memerrmsg;  /* message for memory-allocation errors */
   TString *memerrmsg;  /* message for memory-allocation errors */
   TString *tmname[TM_N];  /* array with tag-method names */
   TString *tmname[TM_N];  /* array with tag-method names */
-  struct Table *mt[LUA_NUMTAGS];  /* metatables for basic types */
+  struct Table *mt[LUA_NUMTYPES];  /* metatables for basic types */
   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' */
@@ -306,13 +311,13 @@ struct lua_State {
   lu_byte status;
   lu_byte status;
   lu_byte allowhook;
   lu_byte allowhook;
   unsigned short nci;  /* number of items in 'ci' list */
   unsigned short nci;  /* number of items in 'ci' list */
-  StkId top;  /* first free slot in the stack */
+  StkIdRel 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 */
-  StkId stack_last;  /* end of stack (last element + 1) */
-  StkId stack;  /* stack base */
+  StkIdRel stack_last;  /* end of stack (last element + 1) */
+  StkIdRel 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 */
+  StkIdRel 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 */

+ 94 - 37
src/lstrlib.c

@@ -570,7 +570,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 (l_unlikely(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 to optimize tail recursion */
   if (p != ms->p_end) {  /* end of pattern? */
   if (p != ms->p_end) {  /* end of pattern? */
     switch (*p) {
     switch (*p) {
       case '(': {  /* start capture */
       case '(': {  /* start capture */
@@ -1090,13 +1090,31 @@ static int lua_number2strx (lua_State *L, char *buff, int sz,
 
 
 
 
 /* valid flags in a format specification */
 /* valid flags in a format specification */
-#if !defined(L_FMTFLAGS)
-#define L_FMTFLAGS	"-+ #0"
+#if !defined(L_FMTFLAGSF)
+
+/* valid flags for a, A, e, E, f, F, g, and G conversions */
+#define L_FMTFLAGSF	"-+#0 "
+
+/* valid flags for o, x, and X conversions */
+#define L_FMTFLAGSX	"-#0"
+
+/* valid flags for d and i conversions */
+#define L_FMTFLAGSI	"-+0 "
+
+/* valid flags for u conversions */
+#define L_FMTFLAGSU	"-0"
+
+/* valid flags for c, p, and s conversions */
+#define L_FMTFLAGSC	"-"
+
 #endif
 #endif
 
 
 
 
 /*
 /*
-** maximum size of each format specification (such as "%-099.99d")
+** Maximum size of each format specification (such as "%-099.99d"):
+** Initial '%', flags (up to 5), width (2), period, precision (2),
+** length modifier (8), conversion specifier, and final '\0', plus some
+** extra.
 */
 */
 #define MAX_FORMAT	32
 #define MAX_FORMAT	32
 
 
@@ -1189,25 +1207,53 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
 }
 }
 
 
 
 
-static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
-  const char *p = strfrmt;
-  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)");
-  if (isdigit(uchar(*p))) p++;  /* skip width */
-  if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
-  if (*p == '.') {
-    p++;
-    if (isdigit(uchar(*p))) p++;  /* skip precision */
-    if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
+static const char *get2digits (const char *s) {
+  if (isdigit(uchar(*s))) {
+    s++;
+    if (isdigit(uchar(*s))) s++;  /* (2 digits at most) */
+  }
+  return s;
+}
+
+
+/*
+** Check whether a conversion specification is valid. When called,
+** first character in 'form' must be '%' and last character must
+** be a valid conversion specifier. 'flags' are the accepted flags;
+** 'precision' signals whether to accept a precision.
+*/
+static void checkformat (lua_State *L, const char *form, const char *flags,
+                                       int precision) {
+  const char *spec = form + 1;  /* skip '%' */
+  spec += strspn(spec, flags);  /* skip flags */
+  if (*spec != '0') {  /* a width cannot start with '0' */
+    spec = get2digits(spec);  /* skip width */
+    if (*spec == '.' && precision) {
+      spec++;
+      spec = get2digits(spec);  /* skip precision */
+    }
   }
   }
-  if (isdigit(uchar(*p)))
-    luaL_error(L, "invalid format (width or precision too long)");
+  if (!isalpha(uchar(*spec)))  /* did not go to the end? */
+    luaL_error(L, "invalid conversion specification: '%s'", form);
+}
+
+
+/*
+** Get a conversion specification and copy it to 'form'.
+** Return the address of its last character.
+*/
+static const char *getformat (lua_State *L, const char *strfrmt,
+                                            char *form) {
+  /* spans flags, width, and precision ('0' is included as a flag) */
+  size_t len = strspn(strfrmt, L_FMTFLAGSF "123456789.");
+  len++;  /* adds following character (should be the specifier) */
+  /* still needs space for '%', '\0', plus a length modifier */
+  if (len >= MAX_FORMAT - 10)
+    luaL_error(L, "invalid format (too long)");
   *(form++) = '%';
   *(form++) = '%';
-  memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));
-  form += (p - strfrmt) + 1;
-  *form = '\0';
-  return p;
+  memcpy(form, strfrmt, len * sizeof(char));
+  *(form + len) = '\0';
+  return strfrmt + len - 1;
 }
 }
 
 
 
 
@@ -1230,6 +1276,7 @@ static int str_format (lua_State *L) {
   size_t sfl;
   size_t sfl;
   const char *strfrmt = luaL_checklstring(L, arg, &sfl);
   const char *strfrmt = luaL_checklstring(L, arg, &sfl);
   const char *strfrmt_end = strfrmt+sfl;
   const char *strfrmt_end = strfrmt+sfl;
+  const char *flags;
   luaL_Buffer b;
   luaL_Buffer b;
   luaL_buffinit(L, &b);
   luaL_buffinit(L, &b);
   while (strfrmt < strfrmt_end) {
   while (strfrmt < strfrmt_end) {
@@ -1239,25 +1286,35 @@ static int str_format (lua_State *L) {
       luaL_addchar(&b, *strfrmt++);  /* %% */
       luaL_addchar(&b, *strfrmt++);  /* %% */
     else { /* format item */
     else { /* format item */
       char form[MAX_FORMAT];  /* to store the format ('%...') */
       char form[MAX_FORMAT];  /* to store the format ('%...') */
-      int maxitem = MAX_ITEM;
-      char *buff = luaL_prepbuffsize(&b, maxitem);  /* to put formatted item */
-      int nb = 0;  /* number of bytes in added item */
+      int maxitem = MAX_ITEM;  /* maximum length for the result */
+      char *buff = luaL_prepbuffsize(&b, maxitem);  /* to put result */
+      int nb = 0;  /* number of bytes in result */
       if (++arg > top)
       if (++arg > top)
         return luaL_argerror(L, arg, "no value");
         return luaL_argerror(L, arg, "no value");
-      strfrmt = scanformat(L, strfrmt, form);
+      strfrmt = getformat(L, strfrmt, form);
       switch (*strfrmt++) {
       switch (*strfrmt++) {
         case 'c': {
         case 'c': {
+          checkformat(L, form, L_FMTFLAGSC, 0);
           nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg));
           nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg));
           break;
           break;
         }
         }
         case 'd': case 'i':
         case 'd': case 'i':
-        case 'o': case 'u': case 'x': case 'X': {
+          flags = L_FMTFLAGSI;
+          goto intcase;
+        case 'u':
+          flags = L_FMTFLAGSU;
+          goto intcase;
+        case 'o': case 'x': case 'X':
+          flags = L_FMTFLAGSX;
+         intcase: {
           lua_Integer n = luaL_checkinteger(L, arg);
           lua_Integer n = luaL_checkinteger(L, arg);
+          checkformat(L, form, flags, 1);
           addlenmod(form, LUA_INTEGER_FRMLEN);
           addlenmod(form, LUA_INTEGER_FRMLEN);
           nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n);
           nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n);
           break;
           break;
         }
         }
         case 'a': case 'A':
         case 'a': case 'A':
+          checkformat(L, form, L_FMTFLAGSF, 1);
           addlenmod(form, LUA_NUMBER_FRMLEN);
           addlenmod(form, LUA_NUMBER_FRMLEN);
           nb = lua_number2strx(L, buff, maxitem, form,
           nb = lua_number2strx(L, buff, maxitem, form,
                                   luaL_checknumber(L, arg));
                                   luaL_checknumber(L, arg));
@@ -1268,12 +1325,14 @@ static int str_format (lua_State *L) {
           /* FALLTHROUGH */
           /* FALLTHROUGH */
         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);
+          checkformat(L, form, L_FMTFLAGSF, 1);
           addlenmod(form, LUA_NUMBER_FRMLEN);
           addlenmod(form, LUA_NUMBER_FRMLEN);
           nb = l_sprintf(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);
+          checkformat(L, form, L_FMTFLAGSC, 0);
           if (p == NULL) {  /* avoid calling 'printf' with argument NULL */
           if (p == NULL) {  /* avoid calling 'printf' with argument NULL */
             p = "(null)";  /* result */
             p = "(null)";  /* result */
             form[strlen(form) - 1] = 's';  /* format it as a string */
             form[strlen(form) - 1] = 's';  /* format it as a string */
@@ -1294,7 +1353,8 @@ static int str_format (lua_State *L) {
             luaL_addvalue(&b);  /* keep entire string */
             luaL_addvalue(&b);  /* keep entire string */
           else {
           else {
             luaL_argcheck(L, l == strlen(s), arg, "string contains zeros");
             luaL_argcheck(L, l == strlen(s), arg, "string contains zeros");
-            if (!strchr(form, '.') && l >= 100) {
+            checkformat(L, form, L_FMTFLAGSC, 1);
+            if (strchr(form, '.') == NULL && l >= 100) {
               /* no precision and string is too long to be formatted */
               /* no precision and string is too long to be formatted */
               luaL_addvalue(&b);  /* keep entire string */
               luaL_addvalue(&b);  /* keep entire string */
             }
             }
@@ -1352,15 +1412,6 @@ static const union {
 } nativeendian = {1};
 } nativeendian = {1};
 
 
 
 
-/* dummy structure to get native alignment requirements */
-struct cD {
-  char c;
-  union { double d; void *p; lua_Integer i; lua_Number n; } u;
-};
-
-#define MAXALIGN	(offsetof(struct cD, u))
-
-
 /*
 /*
 ** information to pack/unpack stuff
 ** information to pack/unpack stuff
 */
 */
@@ -1435,6 +1486,8 @@ static void initheader (lua_State *L, Header *h) {
 ** Read and classify next option. 'size' is filled with option's size.
 ** Read and classify next option. 'size' is filled with option's size.
 */
 */
 static KOption getoption (Header *h, const char **fmt, int *size) {
 static KOption getoption (Header *h, const char **fmt, int *size) {
+  /* dummy structure to get native alignment requirements */
+  struct cD { char c; union { LUAI_MAXALIGN; } u; };
   int opt = *((*fmt)++);
   int opt = *((*fmt)++);
   *size = 0;  /* default */
   *size = 0;  /* default */
   switch (opt) {
   switch (opt) {
@@ -1465,7 +1518,11 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
     case '<': h->islittle = 1; break;
     case '<': h->islittle = 1; break;
     case '>': h->islittle = 0; break;
     case '>': h->islittle = 0; break;
     case '=': h->islittle = nativeendian.little; break;
     case '=': h->islittle = nativeendian.little; break;
-    case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break;
+    case '!': {
+      const int maxalign = offsetof(struct cD, u);
+      h->maxalign = getnumlimit(h, fmt, maxalign);
+      break;
+    }
     default: luaL_error(h->L, "invalid format option '%c'", opt);
     default: luaL_error(h->L, "invalid format option '%c'", opt);
   }
   }
   return Knop;
   return Knop;

+ 33 - 24
src/ltable.c

@@ -84,8 +84,6 @@
 #define hashstr(t,str)		hashpow2(t, (str)->hash)
 #define hashstr(t,str)		hashpow2(t, (str)->hash)
 #define hashboolean(t,p)	hashpow2(t, p)
 #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))
 
 
@@ -101,6 +99,20 @@ static const Node dummynode_ = {
 static const TValue absentkey = {ABSTKEYCONSTANT};
 static const TValue absentkey = {ABSTKEYCONSTANT};
 
 
 
 
+/*
+** Hash for integers. To allow a good hash, use the remainder operator
+** ('%'). If integer fits as a non-negative int, compute an int
+** remainder, which is faster. Otherwise, use an unsigned-integer
+** remainder, which uses all bits and ensures a non-negative result.
+*/
+static Node *hashint (const Table *t, lua_Integer i) {
+  lua_Unsigned ui = l_castS2U(i);
+  if (ui <= cast_uint(INT_MAX))
+    return hashmod(t, cast_int(ui));
+  else
+    return hashmod(t, ui);
+}
+
 
 
 /*
 /*
 ** Hash for floating-point numbers.
 ** Hash for floating-point numbers.
@@ -134,26 +146,24 @@ static int l_hashfloat (lua_Number n) {
 
 
 /*
 /*
 ** returns the 'main' position of an element in a table (that is,
 ** returns the 'main' position of an element in a table (that is,
-** the index of its hash value). The key comes broken (tag in 'ktt'
-** and value in 'vkl') so that we can call it on keys inserted into
-** nodes.
+** the index of its hash value).
 */
 */
-static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
-  switch (withvariant(ktt)) {
+static Node *mainpositionTV (const Table *t, const TValue *key) {
+  switch (ttypetag(key)) {
     case LUA_VNUMINT: {
     case LUA_VNUMINT: {
-      lua_Integer key = ivalueraw(*kvl);
-      return hashint(t, key);
+      lua_Integer i = ivalue(key);
+      return hashint(t, i);
     }
     }
     case LUA_VNUMFLT: {
     case LUA_VNUMFLT: {
-      lua_Number n = fltvalueraw(*kvl);
+      lua_Number n = fltvalue(key);
       return hashmod(t, l_hashfloat(n));
       return hashmod(t, l_hashfloat(n));
     }
     }
     case LUA_VSHRSTR: {
     case LUA_VSHRSTR: {
-      TString *ts = tsvalueraw(*kvl);
+      TString *ts = tsvalue(key);
       return hashstr(t, ts);
       return hashstr(t, ts);
     }
     }
     case LUA_VLNGSTR: {
     case LUA_VLNGSTR: {
-      TString *ts = tsvalueraw(*kvl);
+      TString *ts = tsvalue(key);
       return hashpow2(t, luaS_hashlongstr(ts));
       return hashpow2(t, luaS_hashlongstr(ts));
     }
     }
     case LUA_VFALSE:
     case LUA_VFALSE:
@@ -161,26 +171,25 @@ static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
     case LUA_VTRUE:
     case LUA_VTRUE:
       return hashboolean(t, 1);
       return hashboolean(t, 1);
     case LUA_VLIGHTUSERDATA: {
     case LUA_VLIGHTUSERDATA: {
-      void *p = pvalueraw(*kvl);
+      void *p = pvalue(key);
       return hashpointer(t, p);
       return hashpointer(t, p);
     }
     }
     case LUA_VLCF: {
     case LUA_VLCF: {
-      lua_CFunction f = fvalueraw(*kvl);
+      lua_CFunction f = fvalue(key);
       return hashpointer(t, f);
       return hashpointer(t, f);
     }
     }
     default: {
     default: {
-      GCObject *o = gcvalueraw(*kvl);
+      GCObject *o = gcvalue(key);
       return hashpointer(t, o);
       return hashpointer(t, o);
     }
     }
   }
   }
 }
 }
 
 
 
 
-/*
-** Returns the main position of an element given as a 'TValue'
-*/
-static Node *mainpositionTV (const Table *t, const TValue *key) {
-  return mainposition(t, rawtt(key), valraw(key));
+l_sinline Node *mainpositionfromnode (const Table *t, Node *nd) {
+  TValue key;
+  getnodekey(cast(lua_State *, NULL), &key, nd);
+  return mainpositionTV(t, &key);
 }
 }
 
 
 
 
@@ -248,9 +257,11 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t) {
     size |= (size >> 2);
     size |= (size >> 2);
     size |= (size >> 4);
     size |= (size >> 4);
     size |= (size >> 8);
     size |= (size >> 8);
+#if (UINT_MAX >> 14) > 3  /* unsigned int has more than 16 bits */
     size |= (size >> 16);
     size |= (size >> 16);
 #if (UINT_MAX >> 30) > 3
 #if (UINT_MAX >> 30) > 3
     size |= (size >> 32);  /* unsigned int has more than 32 bits */
     size |= (size >> 32);  /* unsigned int has more than 32 bits */
+#endif
 #endif
 #endif
     size++;
     size++;
     lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size);
     lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size);
@@ -479,7 +490,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
       luaG_runerror(L, "table overflow");
       luaG_runerror(L, "table overflow");
     size = twoto(lsize);
     size = twoto(lsize);
     t->node = luaM_newvector(L, size, Node);
     t->node = luaM_newvector(L, size, Node);
-    for (i = 0; i < (int)size; i++) {
+    for (i = 0; i < cast_int(size); i++) {
       Node *n = gnode(t, i);
       Node *n = gnode(t, i);
       gnext(n) = 0;
       gnext(n) = 0;
       setnilkey(n);
       setnilkey(n);
@@ -679,7 +690,7 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
       return;
       return;
     }
     }
     lua_assert(!isdummy(t));
     lua_assert(!isdummy(t));
-    othern = mainposition(t, keytt(mp), &keyval(mp));
+    othern = mainpositionfromnode(t, mp);
     if (othern != mp) {  /* is colliding node out of its main position? */
     if (othern != mp) {  /* is colliding node out of its main position? */
       /* yes; move colliding node into free position */
       /* yes; move colliding node into free position */
       while (othern + gnext(othern) != mp)  /* find previous */
       while (othern + gnext(othern) != mp)  /* find previous */
@@ -966,6 +977,4 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
   return mainpositionTV(t, key);
   return mainpositionTV(t, key);
 }
 }
 
 
-int luaH_isdummy (const Table *t) { return isdummy(t); }
-
 #endif
 #endif

+ 0 - 1
src/ltable.h

@@ -59,7 +59,6 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t);
 
 
 #if defined(LUA_DEBUG)
 #if defined(LUA_DEBUG)
 LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
 LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
-LUAI_FUNC int luaH_isdummy (const Table *t);
 #endif
 #endif
 
 
 
 

+ 4 - 3
src/ltablib.c

@@ -59,8 +59,9 @@ static void checktab (lua_State *L, int arg, int what) {
 
 
 
 
 static int tinsert (lua_State *L) {
 static int tinsert (lua_State *L) {
-  lua_Integer e = aux_getn(L, 1, TAB_RW) + 1;  /* first empty element */
   lua_Integer pos;  /* where to insert new element */
   lua_Integer pos;  /* where to insert new element */
+  lua_Integer e = aux_getn(L, 1, TAB_RW);
+  e = luaL_intop(+, e, 1);  /* first empty element */
   switch (lua_gettop(L)) {
   switch (lua_gettop(L)) {
     case 2: {  /* called with only 2 arguments */
     case 2: {  /* called with only 2 arguments */
       pos = e;  /* insert new element at the end */
       pos = e;  /* insert new element at the end */
@@ -92,7 +93,7 @@ static int tremove (lua_State *L) {
   lua_Integer pos = luaL_optinteger(L, 2, size);
   lua_Integer pos = luaL_optinteger(L, 2, size);
   if (pos != size)  /* validate 'pos' if given */
   if (pos != size)  /* validate 'pos' if given */
     /* check whether 'pos' is in [1, size + 1] */
     /* check whether 'pos' is in [1, size + 1] */
-    luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1,
+    luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2,
                      "position out of bounds");
                      "position out of bounds");
   lua_geti(L, 1, pos);  /* result = t[pos] */
   lua_geti(L, 1, pos);  /* result = t[pos] */
   for ( ; pos < size; pos++) {
   for ( ; pos < size; pos++) {
@@ -147,7 +148,7 @@ static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
   lua_geti(L, 1, i);
   lua_geti(L, 1, i);
   if (l_unlikely(!lua_isstring(L, -1)))
   if (l_unlikely(!lua_isstring(L, -1)))
     luaL_error(L, "invalid value (%s) at index %I in table for 'concat'",
     luaL_error(L, "invalid value (%s) at index %I in table for 'concat'",
-                  luaL_typename(L, -1), i);
+                  luaL_typename(L, -1), (LUAI_UACINT)i);
   luaL_addvalue(b);
   luaL_addvalue(b);
 }
 }
 
 

+ 19 - 19
src/ltm.c

@@ -102,12 +102,12 @@ const char *luaT_objtypename (lua_State *L, const TValue *o) {
 
 
 void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
 void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
                   const TValue *p2, const TValue *p3) {
                   const TValue *p2, const TValue *p3) {
-  StkId func = L->top;
+  StkId func = L->top.p;
   setobj2s(L, func, f);  /* push function (assume EXTRA_STACK) */
   setobj2s(L, func, f);  /* push function (assume EXTRA_STACK) */
   setobj2s(L, func + 1, p1);  /* 1st argument */
   setobj2s(L, func + 1, p1);  /* 1st argument */
   setobj2s(L, func + 2, p2);  /* 2nd argument */
   setobj2s(L, func + 2, p2);  /* 2nd argument */
   setobj2s(L, func + 3, p3);  /* 3rd argument */
   setobj2s(L, func + 3, p3);  /* 3rd argument */
-  L->top = func + 4;
+  L->top.p = func + 4;
   /* metamethod may yield only when called from Lua code */
   /* metamethod may yield only when called from Lua code */
   if (isLuacode(L->ci))
   if (isLuacode(L->ci))
     luaD_call(L, func, 0);
     luaD_call(L, func, 0);
@@ -119,18 +119,18 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
 void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
 void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
                      const TValue *p2, StkId res) {
                      const TValue *p2, StkId res) {
   ptrdiff_t result = savestack(L, res);
   ptrdiff_t result = savestack(L, res);
-  StkId func = L->top;
+  StkId func = L->top.p;
   setobj2s(L, func, f);  /* push function (assume EXTRA_STACK) */
   setobj2s(L, func, f);  /* push function (assume EXTRA_STACK) */
   setobj2s(L, func + 1, p1);  /* 1st argument */
   setobj2s(L, func + 1, p1);  /* 1st argument */
   setobj2s(L, func + 2, p2);  /* 2nd argument */
   setobj2s(L, func + 2, p2);  /* 2nd argument */
-  L->top += 3;
+  L->top.p += 3;
   /* metamethod may yield only when called from Lua code */
   /* metamethod may yield only when called from Lua code */
   if (isLuacode(L->ci))
   if (isLuacode(L->ci))
     luaD_call(L, func, 1);
     luaD_call(L, func, 1);
   else
   else
     luaD_callnoyield(L, func, 1);
     luaD_callnoyield(L, func, 1);
   res = restorestack(L, result);
   res = restorestack(L, result);
-  setobjs2s(L, res, --L->top);  /* move result to its place */
+  setobjs2s(L, res, --L->top.p);  /* move result to its place */
 }
 }
 
 
 
 
@@ -165,7 +165,7 @@ 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.p;
   if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
   if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
                                TM_CONCAT)))
                                TM_CONCAT)))
     luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
     luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
@@ -200,15 +200,15 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
 */
 */
 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 */
-    return !l_isfalse(s2v(L->top));
+  if (callbinTM(L, p1, p2, L->top.p, event))  /* try original event */
+    return !l_isfalse(s2v(L->top.p));
 #if defined(LUA_COMPAT_LT_LE)
 #if defined(LUA_COMPAT_LT_LE)
   else if (event == TM_LE) {
   else if (event == TM_LE) {
       /* try '!(p2 < p1)' for '(p1 <= p2)' */
       /* try '!(p2 < p1)' for '(p1 <= p2)' */
       L->ci->callstatus |= CIST_LEQ;  /* mark it is doing 'lt' for 'le' */
       L->ci->callstatus |= CIST_LEQ;  /* mark it is doing 'lt' for 'le' */
-      if (callbinTM(L, p2, p1, L->top, TM_LT)) {
+      if (callbinTM(L, p2, p1, L->top.p, TM_LT)) {
         L->ci->callstatus ^= CIST_LEQ;  /* clear mark */
         L->ci->callstatus ^= CIST_LEQ;  /* clear mark */
-        return l_isfalse(s2v(L->top));
+        return l_isfalse(s2v(L->top.p));
       }
       }
       /* else error will remove this 'ci'; no need to clear mark */
       /* else error will remove this 'ci'; no need to clear mark */
   }
   }
@@ -238,20 +238,20 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
 void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
 void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
                          const Proto *p) {
                          const Proto *p) {
   int i;
   int i;
-  int actual = cast_int(L->top - ci->func) - 1;  /* number of arguments */
+  int actual = cast_int(L->top.p - ci->func.p) - 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;
   luaD_checkstack(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.p++, ci->func.p);
   /* move fixed parameters to the top of the stack */
   /* move fixed parameters to the top of the stack */
   for (i = 1; i <= nfixparams; i++) {
   for (i = 1; i <= nfixparams; i++) {
-    setobjs2s(L, L->top++, ci->func + i);
-    setnilvalue(s2v(ci->func + i));  /* erase original parameter (for GC) */
+    setobjs2s(L, L->top.p++, ci->func.p + i);
+    setnilvalue(s2v(ci->func.p + i));  /* erase original parameter (for GC) */
   }
   }
-  ci->func += actual + 1;
-  ci->top += actual + 1;
-  lua_assert(L->top <= ci->top && ci->top <= L->stack_last);
+  ci->func.p += actual + 1;
+  ci->top.p += actual + 1;
+  lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
 }
 }
 
 
 
 
@@ -261,10 +261,10 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
   if (wanted < 0) {
   if (wanted < 0) {
     wanted = nextra;  /* get all extra arguments available */
     wanted = nextra;  /* get all extra arguments available */
     checkstackGCp(L, nextra, where);  /* ensure stack space */
     checkstackGCp(L, nextra, where);  /* ensure stack space */
-    L->top = where + nextra;  /* next instruction will need top */
+    L->top.p = where + nextra;  /* next instruction will need top */
   }
   }
   for (i = 0; i < wanted && i < nextra; i++)
   for (i = 0; i < wanted && i < nextra; i++)
-    setobjs2s(L, where + i, ci->func - nextra + i);
+    setobjs2s(L, where + i, ci->func.p - nextra + i);
   for (; i < wanted; i++)   /* complete required results with nil */
   for (; i < wanted; i++)   /* complete required results with nil */
     setnilvalue(s2v(where + i));
     setnilvalue(s2v(where + i));
 }
 }

+ 3 - 2
src/ltm.h

@@ -9,6 +9,7 @@
 
 
 
 
 #include "lobject.h"
 #include "lobject.h"
+#include "lstate.h"
 
 
 
 
 /*
 /*
@@ -95,8 +96,8 @@ LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
                                  int inv, int isfloat, TMS event);
                                  int inv, int isfloat, TMS event);
 
 
 LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
 LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
-                                   struct CallInfo *ci, const Proto *p);
-LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
+                                   CallInfo *ci, const Proto *p);
+LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci,
                                               StkId where, int wanted);
                                               StkId where, int wanted);
 
 
 
 

+ 48 - 28
src/lua.c

@@ -89,14 +89,15 @@ static void print_usage (const char *badoption) {
   lua_writestringerror(
   lua_writestringerror(
   "usage: %s [options] [script [args]]\n"
   "usage: %s [options] [script [args]]\n"
   "Available options are:\n"
   "Available options are:\n"
-  "  -e stat  execute string 'stat'\n"
-  "  -i       enter interactive mode after executing 'script'\n"
-  "  -l name  require library 'name' into global 'name'\n"
-  "  -v       show version information\n"
-  "  -E       ignore environment variables\n"
-  "  -W       turn warnings on\n"
-  "  --       stop handling options\n"
-  "  -        stop handling options and execute stdin\n"
+  "  -e stat   execute string 'stat'\n"
+  "  -i        enter interactive mode after executing 'script'\n"
+  "  -l mod    require library 'mod' into global 'mod'\n"
+  "  -l g=mod  require library 'mod' into global 'g'\n"
+  "  -v        show version information\n"
+  "  -E        ignore environment variables\n"
+  "  -W        turn warnings on\n"
+  "  --        stop handling options\n"
+  "  -         stop handling options and execute stdin\n"
   ,
   ,
   progname);
   progname);
 }
 }
@@ -176,10 +177,11 @@ static void print_version (void) {
 ** to the script (everything after 'script') go to positive indices;
 ** to the script (everything after 'script') go to positive indices;
 ** other arguments (before the script name) go to negative indices.
 ** other arguments (before the script name) go to negative indices.
 ** If there is no script name, assume interpreter's name as base.
 ** If there is no script name, assume interpreter's name as base.
+** (If there is no interpreter's name either, 'script' is -1, so
+** table sizes are zero.)
 */
 */
 static void createargtable (lua_State *L, char **argv, int argc, int script) {
 static void createargtable (lua_State *L, char **argv, int argc, int script) {
   int i, narg;
   int i, narg;
-  if (script == argc) script = 0;  /* no script name? */
   narg = argc - (script + 1);  /* number of positive indices */
   narg = argc - (script + 1);  /* number of positive indices */
   lua_createtable(L, narg, script + 1);
   lua_createtable(L, narg, script + 1);
   for (i = 0; i < argc; i++) {
   for (i = 0; i < argc; i++) {
@@ -207,16 +209,22 @@ static int dostring (lua_State *L, const char *s, const char *name) {
 
 
 
 
 /*
 /*
-** Calls 'require(name)' and stores the result in a global variable
-** with the given name.
+** Receives 'globname[=modname]' and runs 'globname = require(modname)'.
 */
 */
-static int dolibrary (lua_State *L, const char *name) {
+static int dolibrary (lua_State *L, char *globname) {
   int status;
   int status;
+  char *modname = strchr(globname, '=');
+  if (modname == NULL)  /* no explicit name? */
+    modname = globname;  /* module name is equal to global name */
+  else {
+    *modname = '\0';  /* global name ends here */
+    modname++;  /* module name starts after the '=' */
+  }
   lua_getglobal(L, "require");
   lua_getglobal(L, "require");
-  lua_pushstring(L, name);
-  status = docall(L, 1, 1);  /* call 'require(name)' */
+  lua_pushstring(L, modname);
+  status = docall(L, 1, 1);  /* call 'require(modname)' */
   if (status == LUA_OK)
   if (status == LUA_OK)
-    lua_setglobal(L, name);  /* global[name] = require return */
+    lua_setglobal(L, globname);  /* globname = require(modname) */
   return report(L, status);
   return report(L, status);
 }
 }
 
 
@@ -261,14 +269,23 @@ static int handle_script (lua_State *L, char **argv) {
 
 
 /*
 /*
 ** Traverses all arguments from 'argv', returning a mask with those
 ** Traverses all arguments from 'argv', returning a mask with those
-** needed before running any Lua code (or an error code if it finds
-** any invalid argument). 'first' returns the first not-handled argument
-** (either the script name or a bad argument in case of error).
+** needed before running any Lua code or an error code if it finds any
+** invalid argument. In case of error, 'first' is the index of the bad
+** argument.  Otherwise, 'first' is -1 if there is no program name,
+** 0 if there is no script name, or the index of the script name.
 */
 */
 static int collectargs (char **argv, int *first) {
 static int collectargs (char **argv, int *first) {
   int args = 0;
   int args = 0;
   int i;
   int i;
-  for (i = 1; argv[i] != NULL; i++) {
+  if (argv[0] != NULL) {  /* is there a program name? */
+    if (argv[0][0])  /* not empty? */
+      progname = argv[0];  /* save it */
+  }
+  else {  /* no program name */
+    *first = -1;
+    return 0;
+  }
+  for (i = 1; argv[i] != NULL; i++) {  /* handle arguments */
     *first = i;
     *first = i;
     if (argv[i][0] != '-')  /* not an option? */
     if (argv[i][0] != '-')  /* not an option? */
         return args;  /* stop handling options */
         return args;  /* stop handling options */
@@ -309,7 +326,7 @@ static int collectargs (char **argv, int *first) {
         return has_error;
         return has_error;
     }
     }
   }
   }
-  *first = i;  /* no script name */
+  *first = 0;  /* no script name */
   return args;
   return args;
 }
 }
 
 
@@ -327,7 +344,7 @@ static int runargs (lua_State *L, char **argv, int n) {
     switch (option) {
     switch (option) {
       case 'e':  case 'l': {
       case 'e':  case 'l': {
         int status;
         int status;
-        const char *extra = argv[i] + 2;  /* both options need an argument */
+        char *extra = argv[i] + 2;  /* both options need an argument */
         if (*extra == '\0') extra = argv[++i];
         if (*extra == '\0') extra = argv[++i];
         lua_assert(extra != NULL);
         lua_assert(extra != NULL);
         status = (option == 'e')
         status = (option == 'e')
@@ -602,8 +619,8 @@ static int pmain (lua_State *L) {
   char **argv = (char **)lua_touserdata(L, 2);
   char **argv = (char **)lua_touserdata(L, 2);
   int script;
   int script;
   int args = collectargs(argv, &script);
   int args = collectargs(argv, &script);
+  int optlim = (script > 0) ? script : argc; /* first argv not an option */
   luaL_checkversion(L);  /* check that interpreter has correct version */
   luaL_checkversion(L);  /* check that interpreter has correct version */
-  if (argv[0] && argv[0][0]) progname = argv[0];
   if (args == has_error) {  /* bad arg? */
   if (args == has_error) {  /* bad arg? */
     print_usage(argv[script]);  /* 'script' has index of bad arg. */
     print_usage(argv[script]);  /* 'script' has index of bad arg. */
     return 0;
     return 0;
@@ -616,19 +633,21 @@ static int pmain (lua_State *L) {
   }
   }
   luaL_openlibs(L);  /* open standard libraries */
   luaL_openlibs(L);  /* open standard libraries */
   createargtable(L, argv, argc, script);  /* create table 'arg' */
   createargtable(L, argv, argc, script);  /* create table 'arg' */
-  lua_gc(L, LUA_GCGEN, 0, 0);  /* GC in generational mode */
+  lua_gc(L, LUA_GCRESTART);  /* start GC... */
+  lua_gc(L, LUA_GCGEN, 0, 0);  /* ...in generational mode */
   if (!(args & has_E)) {  /* no option '-E'? */
   if (!(args & has_E)) {  /* no option '-E'? */
     if (handle_luainit(L) != LUA_OK)  /* run LUA_INIT */
     if (handle_luainit(L) != LUA_OK)  /* run LUA_INIT */
       return 0;  /* error running LUA_INIT */
       return 0;  /* error running LUA_INIT */
   }
   }
-  if (!runargs(L, argv, script))  /* execute arguments -e and -l */
+  if (!runargs(L, argv, optlim))  /* execute arguments -e and -l */
     return 0;  /* something failed */
     return 0;  /* something failed */
-  if (script < argc &&  /* execute main script (if there is one) */
-      handle_script(L, argv + script) != LUA_OK)
-    return 0;
+  if (script > 0) {  /* execute main script (if there is one) */
+    if (handle_script(L, argv + script) != LUA_OK)
+      return 0;  /* interrupt in case of error */
+  }
   if (args & has_i)  /* -i option? */
   if (args & has_i)  /* -i option? */
     doREPL(L);  /* do read-eval-print loop */
     doREPL(L);  /* do read-eval-print loop */
-  else if (script == argc && !(args & (has_e | has_v))) {  /* no arguments? */
+  else if (script < 1 && !(args & (has_e | has_v))) { /* no active option? */
     if (lua_stdin_is_tty()) {  /* running in interactive mode? */
     if (lua_stdin_is_tty()) {  /* running in interactive mode? */
       print_version();
       print_version();
       doREPL(L);  /* do read-eval-print loop */
       doREPL(L);  /* do read-eval-print loop */
@@ -647,6 +666,7 @@ int main (int argc, char **argv) {
     l_message(argv[0], "cannot create state: not enough memory");
     l_message(argv[0], "cannot create state: not enough memory");
     return EXIT_FAILURE;
     return EXIT_FAILURE;
   }
   }
+  lua_gc(L, LUA_GCSTOP);  /* stop GC while building state */
   lua_pushcfunction(L, &pmain);  /* to call 'pmain' in protected mode */
   lua_pushcfunction(L, &pmain);  /* to call 'pmain' in protected mode */
   lua_pushinteger(L, argc);  /* 1st argument */
   lua_pushinteger(L, argc);  /* 1st argument */
   lua_pushlightuserdata(L, argv); /* 2nd argument */
   lua_pushlightuserdata(L, argv); /* 2nd argument */

+ 16 - 11
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	"3"
+#define LUA_VERSION_RELEASE	"6"
 
 
 #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 + 6)
 
 
 #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-2021 Lua.org, PUC-Rio"
+#define LUA_COPYRIGHT	LUA_RELEASE "  Copyright (C) 1994-2023 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"
 
 
 
 
@@ -131,6 +131,16 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
 typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
 typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
 
 
 
 
+/*
+** Type used by the debug API to collect debug information
+*/
+typedef struct lua_Debug lua_Debug;
+
+
+/*
+** Functions to be called by the debugger in specific events
+*/
+typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
 
 
 
 
 /*
 /*
@@ -153,7 +163,8 @@ extern const char lua_ident[];
 LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
 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);
 LUA_API lua_State *(lua_newthread) (lua_State *L);
 LUA_API lua_State *(lua_newthread) (lua_State *L);
-LUA_API int        (lua_resetthread) (lua_State *L);
+LUA_API int        (lua_closethread) (lua_State *L, lua_State *from);
+LUA_API int        (lua_resetthread) (lua_State *L);  /* Deprecated! */
 
 
 LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
 LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
 
 
@@ -442,12 +453,6 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
 #define LUA_MASKLINE	(1 << LUA_HOOKLINE)
 #define LUA_MASKLINE	(1 << LUA_HOOKLINE)
 #define LUA_MASKCOUNT	(1 << LUA_HOOKCOUNT)
 #define LUA_MASKCOUNT	(1 << LUA_HOOKCOUNT)
 
 
-typedef struct lua_Debug lua_Debug;  /* activation record */
-
-
-/* Functions to be called by the debugger in specific events */
-typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
-
 
 
 LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
 LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
 LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
 LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
@@ -492,7 +497,7 @@ struct lua_Debug {
 
 
 
 
 /******************************************************************************
 /******************************************************************************
-* Copyright (C) 1994-2021 Lua.org, PUC-Rio.
+* Copyright (C) 1994-2023 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

+ 5 - 18
src/luac.c

@@ -121,7 +121,7 @@ static int doargs(int argc, char* argv[])
  return i;
  return i;
 }
 }
 
 
-#define FUNCTION "(function()end)();"
+#define FUNCTION "(function()end)();\n"
 
 
 static const char* reader(lua_State* L, void* ud, size_t* size)
 static const char* reader(lua_State* L, void* ud, size_t* size)
 {
 {
@@ -138,7 +138,7 @@ static const char* reader(lua_State* L, void* ud, size_t* size)
  }
  }
 }
 }
 
 
-#define toproto(L,i) getproto(s2v(L->top+(i)))
+#define toproto(L,i) getproto(s2v(L->top.p+(i)))
 
 
 static const Proto* combine(lua_State* L, int n)
 static const Proto* combine(lua_State* L, int n)
 {
 {
@@ -155,7 +155,6 @@ static const Proto* combine(lua_State* L, int n)
    f->p[i]=toproto(L,i-n-1);
    f->p[i]=toproto(L,i-n-1);
    if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
    if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
   }
   }
-  f->sizelineinfo=0;
   return f;
   return f;
  }
  }
 }
 }
@@ -340,7 +339,6 @@ static void PrintCode(const Proto* f)
  {
  {
   Instruction i=code[pc];
   Instruction i=code[pc];
   OpCode o=GET_OPCODE(i);
   OpCode o=GET_OPCODE(i);
-#if 0
   int a=GETARG_A(i);
   int a=GETARG_A(i);
   int b=GETARG_B(i);
   int b=GETARG_B(i);
   int c=GETARG_C(i);
   int c=GETARG_C(i);
@@ -350,17 +348,6 @@ static void PrintCode(const Proto* f)
   int sc=GETARG_sC(i);
   int sc=GETARG_sC(i);
   int sbx=GETARG_sBx(i);
   int sbx=GETARG_sBx(i);
   int isk=GETARG_k(i);
   int isk=GETARG_k(i);
-#else
-#define a   GETARG_A(i)
-#define b   GETARG_B(i)
-#define c   GETARG_C(i)
-#define ax  GETARG_Ax(i)
-#define bx  GETARG_Bx(i)
-#define sb  GETARG_sB(i)
-#define sc  GETARG_sC(i)
-#define sbx GETARG_sBx(i)
-#define isk GETARG_k(i)
-#endif
   int line=luaG_getfuncline(f,pc);
   int line=luaG_getfuncline(f,pc);
   printf("\t%d\t",pc+1);
   printf("\t%d\t",pc+1);
   if (line>0) printf("[%d]\t",line); else printf("[-]\t");
   if (line>0) printf("[%d]\t",line); else printf("[-]\t");
@@ -612,11 +599,11 @@ static void PrintCode(const Proto* f)
 	if (c==0) printf("all out"); else printf("%d out",c-1);
 	if (c==0) printf("all out"); else printf("%d out",c-1);
 	break;
 	break;
    case OP_TAILCALL:
    case OP_TAILCALL:
-	printf("%d %d %d",a,b,c);
+	printf("%d %d %d%s",a,b,c,ISK);
 	printf(COMMENT "%d in",b-1);
 	printf(COMMENT "%d in",b-1);
 	break;
 	break;
    case OP_RETURN:
    case OP_RETURN:
-	printf("%d %d %d",a,b,c);
+	printf("%d %d %d%s",a,b,c,ISK);
 	printf(COMMENT);
 	printf(COMMENT);
 	if (b==0) printf("all out"); else printf("%d out",b-1);
 	if (b==0) printf("all out"); else printf("%d out",b-1);
 	break;
 	break;
@@ -631,7 +618,7 @@ static void PrintCode(const Proto* f)
 	break;
 	break;
    case OP_FORPREP:
    case OP_FORPREP:
 	printf("%d %d",a,bx);
 	printf("%d %d",a,bx);
-	printf(COMMENT "to %d",pc+bx+2);
+	printf(COMMENT "exit to %d",pc+bx+3);
 	break;
 	break;
    case OP_TFORPREP:
    case OP_TFORPREP:
 	printf("%d %d",a,bx);
 	printf("%d %d",a,bx);

+ 15 - 8
src/luaconf.h

@@ -70,6 +70,12 @@
 #endif
 #endif
 
 
 
 
+#if defined(LUA_USE_IOS)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN
+#endif
+
+
 /*
 /*
 @@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits.
 @@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits.
 */
 */
@@ -305,8 +311,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 */
@@ -481,7 +491,6 @@
 @@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.
 @@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.
 @@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.
 @@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.
 @@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED.
 @@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED.
-@@ LUA_UNSIGNEDBITS is the number of bits in a LUA_UNSIGNED.
 @@ lua_integer2str converts an integer to a string.
 @@ lua_integer2str converts an integer to a string.
 */
 */
 
 
@@ -502,9 +511,6 @@
 #define LUA_UNSIGNED		unsigned LUAI_UACINT
 #define LUA_UNSIGNED		unsigned LUAI_UACINT
 
 
 
 
-#define LUA_UNSIGNEDBITS	(sizeof(LUA_UNSIGNED) * CHAR_BIT)
-
-
 /* now the variable definitions */
 /* now the variable definitions */
 
 
 #if LUA_INT_TYPE == LUA_INT_INT		/* { int */
 #if LUA_INT_TYPE == LUA_INT_INT		/* { int */
@@ -728,7 +734,7 @@
 ** CHANGE it if you need a different limit. This limit is arbitrary;
 ** CHANGE it if you need a different limit. This limit is arbitrary;
 ** its only purpose is to stop Lua from consuming unlimited stack
 ** its only purpose is to stop Lua from consuming unlimited stack
 ** space (and to reserve some numbers for pseudo-indices).
 ** space (and to reserve some numbers for pseudo-indices).
-** (It must fit into max(size_t)/32.)
+** (It must fit into max(size_t)/32 and max(int)/2.)
 */
 */
 #if LUAI_IS32INT
 #if LUAI_IS32INT
 #define LUAI_MAXSTACK		1000000
 #define LUAI_MAXSTACK		1000000
@@ -747,14 +753,15 @@
 
 
 /*
 /*
 @@ LUA_IDSIZE gives the maximum size for the description of the source
 @@ LUA_IDSIZE gives the maximum size for the description of the source
-@@ of a function in debug information.
+** of a function in debug information.
 ** CHANGE it if you want a different size.
 ** CHANGE it if you want a different size.
 */
 */
 #define LUA_IDSIZE	60
 #define LUA_IDSIZE	60
 
 
 
 
 /*
 /*
-@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
+@@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib
+** buffer system.
 */
 */
 #define LUAL_BUFFERSIZE   ((int)(16 * sizeof(void*) * sizeof(lua_Number)))
 #define LUAL_BUFFERSIZE   ((int)(16 * sizeof(void*) * sizeof(lua_Number)))
 
 

+ 5 - 3
src/lundump.c

@@ -120,10 +120,10 @@ static TString *loadStringN (LoadState *S, Proto *p) {
   }
   }
   else {  /* long string */
   else {  /* long string */
     ts = luaS_createlngstrobj(L, size);  /* create string */
     ts = luaS_createlngstrobj(L, size);  /* create string */
-    setsvalue2s(L, L->top, ts);  /* anchor it ('loadVector' can GC) */
+    setsvalue2s(L, L->top.p, ts);  /* anchor it ('loadVector' can GC) */
     luaD_inctop(L);
     luaD_inctop(L);
     loadVector(S, getstr(ts), size);  /* load directly in final place */
     loadVector(S, getstr(ts), size);  /* load directly in final place */
-    L->top--;  /* pop string */
+    L->top.p--;  /* pop string */
   }
   }
   luaC_objbarrier(L, p, ts);
   luaC_objbarrier(L, p, ts);
   return ts;
   return ts;
@@ -248,6 +248,8 @@ static void loadDebug (LoadState *S, Proto *f) {
     f->locvars[i].endpc = loadInt(S);
     f->locvars[i].endpc = loadInt(S);
   }
   }
   n = loadInt(S);
   n = loadInt(S);
+  if (n != 0)  /* does it have debug information? */
+    n = f->sizeupvalues;  /* must be this many */
   for (i = 0; i < n; i++)
   for (i = 0; i < n; i++)
     f->upvalues[i].name = loadStringN(S, f);
     f->upvalues[i].name = loadStringN(S, f);
 }
 }
@@ -321,7 +323,7 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
   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.p, cl);
   luaD_inctop(L);
   luaD_inctop(L);
   cl->p = luaF_newproto(L);
   cl->p = luaF_newproto(L);
   luaC_objbarrier(L, cl, cl->p);
   luaC_objbarrier(L, cl, cl->p);

+ 19 - 17
src/lutf8lib.c

@@ -25,6 +25,9 @@
 
 
 #define MAXUTF		0x7FFFFFFFu
 #define MAXUTF		0x7FFFFFFFu
 
 
+
+#define MSGInvalid	"invalid UTF-8 code"
+
 /*
 /*
 ** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
 ** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
 */
 */
@@ -35,7 +38,8 @@ typedef unsigned long utfint;
 #endif
 #endif
 
 
 
 
-#define iscont(p)	((*(p) & 0xC0) == 0x80)
+#define iscont(c)	(((c) & 0xC0) == 0x80)
+#define iscontp(p)	iscont(*(p))
 
 
 
 
 /* from strlib */
 /* from strlib */
@@ -65,7 +69,7 @@ static const char *utf8_decode (const char *s, utfint *val, int strict) {
     int count = 0;  /* to count number of continuation bytes */
     int count = 0;  /* to count number of continuation bytes */
     for (; c & 0x40; c <<= 1) {  /* while it needs continuation bytes... */
     for (; c & 0x40; c <<= 1) {  /* while it needs continuation bytes... */
       unsigned int cc = (unsigned char)s[++count];  /* read next byte */
       unsigned int cc = (unsigned char)s[++count];  /* read next byte */
-      if ((cc & 0xC0) != 0x80)  /* not a continuation byte? */
+      if (!iscont(cc))  /* not a continuation byte? */
         return NULL;  /* invalid byte sequence */
         return NULL;  /* invalid byte sequence */
       res = (res << 6) | (cc & 0x3F);  /* add lower 6 bits from cont. byte */
       res = (res << 6) | (cc & 0x3F);  /* add lower 6 bits from cont. byte */
     }
     }
@@ -140,7 +144,7 @@ static int codepoint (lua_State *L) {
     utfint code;
     utfint code;
     s = utf8_decode(s, &code, !lax);
     s = utf8_decode(s, &code, !lax);
     if (s == NULL)
     if (s == NULL)
-      return luaL_error(L, "invalid UTF-8 code");
+      return luaL_error(L, MSGInvalid);
     lua_pushinteger(L, code);
     lua_pushinteger(L, code);
     n++;
     n++;
   }
   }
@@ -190,16 +194,16 @@ static int byteoffset (lua_State *L) {
                    "position out of bounds");
                    "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 && iscontp(s + posi)) posi--;
   }
   }
   else {
   else {
-    if (iscont(s + posi))
+    if (iscontp(s + posi))
       return luaL_error(L, "initial position is a continuation byte");
       return luaL_error(L, "initial position is a continuation byte");
     if (n < 0) {
     if (n < 0) {
        while (n < 0 && posi > 0) {  /* move back */
        while (n < 0 && posi > 0) {  /* move back */
          do {  /* find beginning of previous character */
          do {  /* find beginning of previous character */
            posi--;
            posi--;
-         } while (posi > 0 && iscont(s + posi));
+         } while (posi > 0 && iscontp(s + posi));
          n++;
          n++;
        }
        }
      }
      }
@@ -208,7 +212,7 @@ static int byteoffset (lua_State *L) {
        while (n > 0 && posi < (lua_Integer)len) {
        while (n > 0 && posi < (lua_Integer)len) {
          do {  /* find beginning of next character */
          do {  /* find beginning of next character */
            posi++;
            posi++;
-         } while (iscont(s + posi));  /* (cannot pass final '\0') */
+         } while (iscontp(s + posi));  /* (cannot pass final '\0') */
          n--;
          n--;
        }
        }
      }
      }
@@ -224,20 +228,17 @@ static int byteoffset (lua_State *L) {
 static int iter_aux (lua_State *L, int strict) {
 static int iter_aux (lua_State *L, int strict) {
   size_t len;
   size_t len;
   const char *s = luaL_checklstring(L, 1, &len);
   const char *s = luaL_checklstring(L, 1, &len);
-  lua_Integer n = lua_tointeger(L, 2) - 1;
-  if (n < 0)  /* first iteration? */
-    n = 0;  /* start from here */
-  else if (n < (lua_Integer)len) {
-    n++;  /* skip current byte */
-    while (iscont(s + n)) n++;  /* and its continuations */
+  lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
+  if (n < len) {
+    while (iscontp(s + n)) n++;  /* go to next character */
   }
   }
-  if (n >= (lua_Integer)len)
+  if (n >= len)  /* (also handles original 'n' being negative) */
     return 0;  /* no more codepoints */
     return 0;  /* no more codepoints */
   else {
   else {
     utfint code;
     utfint code;
     const char *next = utf8_decode(s + n, &code, strict);
     const char *next = utf8_decode(s + n, &code, strict);
-    if (next == NULL)
-      return luaL_error(L, "invalid UTF-8 code");
+    if (next == NULL || iscontp(next))
+      return luaL_error(L, MSGInvalid);
     lua_pushinteger(L, n + 1);
     lua_pushinteger(L, n + 1);
     lua_pushinteger(L, code);
     lua_pushinteger(L, code);
     return 2;
     return 2;
@@ -256,7 +257,8 @@ static int iter_auxlax (lua_State *L) {
 
 
 static int iter_codes (lua_State *L) {
 static int iter_codes (lua_State *L) {
   int lax = lua_toboolean(L, 2);
   int lax = lua_toboolean(L, 2);
-  luaL_checkstring(L, 1);
+  const char *s = luaL_checkstring(L, 1);
+  luaL_argcheck(L, !iscontp(s), 1, MSGInvalid);
   lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
   lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
   lua_pushvalue(L, 1);
   lua_pushvalue(L, 1);
   lua_pushinteger(L, 0);
   lua_pushinteger(L, 0);

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 153 - 140
src/lvm.c


+ 5 - 0
src/lvm.h

@@ -110,6 +110,11 @@ typedef enum {
       luaC_barrierback(L, gcvalue(t), v); }
       luaC_barrierback(L, gcvalue(t), v); }
 
 
 
 
+/*
+** Shift right is the same as shift left with a negative 'y'
+*/
+#define luaV_shiftr(x,y)	luaV_shiftl(x,intop(-, 0, y))
+
 
 
 
 
 LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
 LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio