Lua diffu-lua-5.4.0-alpha-beta-rc1


README

@@ -1,5 +1,5 @@
 
-This is Lua 5.4.0 (alpha), released on 06 Jun 2019.
+This is Lua 5.4.0 (beta), released on 02 Oct 2019.
 
 For installation instructions, license details, and
 further information about Lua, see doc/readme.html.

doc/contents.html

@@ -192,6 +192,7 @@
 <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.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.setlocal">debug.setlocal</A><BR>
 <A HREF="manual.html#pdf-debug.setmetatable">debug.setmetatable</A><BR>

@@ -437,6 +438,7 @@
 <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_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_setglobal">lua_setglobal</A><BR>
 <A HREF="manual.html#lua_sethook">lua_sethook</A><BR>

@@ -623,10 +625,10 @@
 
 <P CLASS="footer">
 Last update:
-Wed Jun  5 21:27:06 -03 2019
+Mon Sep 30 23:54:47 UTC 2019
 </P>
 <!--
-Last change: revised for Lua 5.4.0 (alpha)
+Last change: revised for Lua 5.4.0 (beta)
 -->
 
 </BODY>

doc/manual.html

@@ -312,7 +312,7 @@
 
 <p>
 When Lua loads a chunk,
-the default value for its <code>_ENV</code> upvalue
+the default value for its <code>_ENV</code> variable
 is the global environment (see <a href="#pdf-load"><code>load</code></a>).
 Therefore, by default,
 free names in Lua code refer to entries in the global environment

@@ -322,7 +322,7 @@
 You can use <a href="#pdf-load"><code>load</code></a> (or <a href="#pdf-loadfile"><code>loadfile</code></a>)
 to load a chunk with a different environment.
 (In C, you have to load the chunk and then change the value
-of its first upvalue.)
+of its first upvalue; see <a href="#lua_setupvalue"><code>lua_setupvalue</code></a>.)
 
 
 

@@ -1493,7 +1493,7 @@
 receive arguments, and return values.
 Moreover, such anonymous function is compiled as in the
 scope of an external local variable called <code>_ENV</code> (see <a href="#2.2">&sect;2.2</a>).
-The resulting function always has <code>_ENV</code> as its only upvalue,
+The resulting function always has <code>_ENV</code> as its only external variable,
 even if it does not use that variable.
 
 

@@ -1713,25 +1713,36 @@
 Their values are called respectively
 the <em>initial value</em>, the <em>limit</em>, and the <em>step</em>.
 If the step is absent, it defaults to&nbsp;1.
-Then the loop body is repeated with the value of the control variable
+
+
+<p>
+If both the initial value and the step are integers,
+the loop is done with integers;
+note that the limit may not be an integer.
+Otherwise, the loop is done with floats.
+(Beware of floating-point accuracy in this case.)
+
+
+<p>
+After that initialization,
+the loop body is repeated with the value of the control variable
 going through an arithmetic progression,
 starting at the initial value,
-with a common difference given by the step,
-until that value passes the limit.
+with a common difference given by the step.
 A negative step makes a decreasing sequence;
 a step equal to zero raises an error.
+The loop continues while the value is less than
+or equal to the limit
+(greater than or equal to for a negative step).
 If the initial value is already greater than the limit
 (or less than, if the step is negative),
 the body is not executed.
 
 
 <p>
-If both the initial value and the step are integers,
-the loop is done with integers;
-in this case, the range of the control variable is clipped
-by the range of integers.
-Otherwise, the loop is done with floats.
-(Beware of floating-point accuracy in this case.)
+For integer loops,
+the control variable never wraps around;
+instead, the loop ends in case of an overflow.
 
 
 <p>

@@ -1827,19 +1838,27 @@
 The declaration can include an initialization:
 
 <pre>
-	stat ::= <b>local</b> namelist [&lsquo;<b>=</b>&rsquo; explist]
-	stat ::=  <b>local</b> &lsquo;<b>&lt;</b>&rsquo; Name &lsquo;<b>&gt;</b>&rsquo; Name &lsquo;<b>=</b>&rsquo; exp </pre><p>
+	stat ::= <b>local</b> attnamelist [&lsquo;<b>=</b>&rsquo; explist]
+	attnamelist ::=  Name attrib {&lsquo;<b>,</b>&rsquo; Name attrib}
+</pre><p>
 If present, an initial assignment has the same semantics
 of a multiple assignment (see <a href="#3.3.3">&sect;3.3.3</a>).
 Otherwise, all variables are initialized with <b>nil</b>.
-The second syntax declares a local with a given attribute,
-which is the name between the angle brackets.
-In this case, there must be an initialization.
+
+
+<p>
+Each variable name may be postfixed by an attribute
+(a name between angle brackets):
+
+<pre>
+	attrib ::= [&lsquo;<b>&lt;</b>&rsquo; Name &lsquo;<b>&gt;</b>&rsquo;]
+</pre><p>
 There are two possible attributes:
 <code>const</code>, which declares a constant variable,
 that is, a variable that cannot be assigned to
 after its initialization;
-and <code>toclose</code>, which declares a to-be-closed variable (see <a href="#3.3.8">&sect;3.3.8</a>).
+and <code>close</code>, which declares a to-be-closed variable (see <a href="#3.3.8">&sect;3.3.8</a>).
+A list of variables can contain at most one to-be-closed variable.
 
 
 <p>

@@ -1857,11 +1876,6 @@
 <h3>3.3.8 &ndash; <a name="3.3.8">To-be-closed Variables</a></h3>
 
 <p>
-A local variable can be declared as a <em>to-be-closed</em> variable,
-using the identifier <code>toclose</code> as its attribute:
-
-<pre>
-	stat ::=  <b>local</b> &lsquo;<b>&lt;</b>&rsquo; <code>toclose</code> &lsquo;<b>&gt;</b>&rsquo; Name &lsquo;<b>=</b>&rsquo; exp </pre><p>
 A to-be-closed variable behaves like a constant local variable,
 except that its value is <em>closed</em> whenever the variable
 goes out of scope, including normal block termination,

@@ -1872,17 +1886,21 @@
 <p>
 Here, to <em>close</em> a value means
 to call its <code>__close</code> metamethod.
-If the value is <b>nil</b>, it is ignored;
-otherwise,
-if it does not have a <code>__close</code> metamethod,
-an error is raised.
 When calling the metamethod,
 the value itself is passed as the first argument
-and the error object (if any) is passed as a second argument;
+and the error object that caused the exit (if any)
+is passed as a second argument;
 if there was no error, the second argument is <b>nil</b>.
 
 
 <p>
+The value assigned to a to-be-closed variable
+must have a <code>__close</code> metamethod
+or be a false value.
+(<b>nil</b> and <b>false</b> are ignored as to-be-closed values.)
+
+
+<p>
 If several to-be-closed variables go out of scope at the same event,
 they are closed in the reverse order that they were declared.
 

@@ -1890,25 +1908,30 @@
 <p>
 If there is any error while running a closing method,
 that error is handled like an error in the regular code
-where the variable was defined;
-in particular,
-the other pending closing methods will still be called.
+where the variable was defined.
+However, Lua may call the method one more time.
+
+
+<p>
 After an error,
-other errors in closing methods
-interrupt the respective method,
+the other pending closing methods will still be called.
+Errors in these methods
+interrupt the respective method and generate a warning,
 but are otherwise ignored;
-the error reported is the original one.
+the error reported is only the original one.
 
 
 <p>
-If a coroutine yields inside a block and is never resumed again,
-the variables visible at that block will never go out of scope,
+If a coroutine yields and is never resumed again,
+some variables may never go out of scope,
 and therefore they will never be closed.
+(These variables are the ones created inside the coroutine
+and in scope at the point where the coroutine yielded.)
 Similarly, if a coroutine ends with an error,
 it does not unwind its stack,
 so it does not close any variable.
 In both cases,
-you should either use finalizers
+you can either use finalizers
 or call <a href="#pdf-coroutine.close"><code>coroutine.close</code></a> to close the variables.
 However, if the coroutine was created
 through <a href="#pdf-coroutine.wrap"><code>coroutine.wrap</code></a>,

@@ -2718,8 +2741,8 @@
 Because of the lexical scoping rules,
 local variables can be freely accessed by functions
 defined inside their scope.
-A local variable used by an inner function is called
-an <em>upvalue</em>, or <em>external local variable</em>,
+A local variable used by an inner function is called an <em>upvalue</em>
+(or <em>external local variable</em>, or simply <em>external variable</em>)
 inside the inner function.
 
 

@@ -2731,9 +2754,9 @@
 <pre>
      a = {}
      local x = 20
-     for i=1,10 do
+     for i = 1, 10 do
        local y = 0
-       a[i] = function () y=y+1; return x+y end
+       a[i] = function () y = y + 1; return x + y end
      end
 </pre><p>
 The loop creates ten closures

@@ -3535,8 +3558,9 @@
 <pre>void lua_close (lua_State *L);</pre>
 
 <p>
-Destroys all objects in the given Lua state
-(calling the corresponding garbage-collection metamethods, if any)
+Close all active to-be-closed variables in the main thread,
+release all objects in the given Lua state
+(calling the corresponding garbage-collection metamethods, if any),
 and frees all dynamic memory used by this state.
 
 

@@ -5097,13 +5121,18 @@
 
 <hr><h3><a name="lua_setmetatable"><code>lua_setmetatable</code></a></h3><p>
 <span class="apii">[-1, +0, &ndash;]</span>
-<pre>void lua_setmetatable (lua_State *L, int index);</pre>
+<pre>int lua_setmetatable (lua_State *L, int index);</pre>
 
 <p>
 Pops a table from the stack and
 sets it as the new metatable for the value at the given index.
 
 
+<p>
+(For historical reasons, this function returns an <code>int</code>,
+which now is always 1.)
+
+
 
 
 

@@ -5274,7 +5303,7 @@
 
 <p>
 This function should not be called for an index
-that is equal to or below an already marked to-be-closed index.
+that is equal to or below an active to-be-closed index.
 
 
 <p>

@@ -5527,6 +5556,10 @@
 to be continued by the message in the next call.
 
 
+<p>
+See <a href="#pdf-warn"><code>warn</code></a> for more details about warnings.
+
+
 
 
 

@@ -5540,6 +5573,10 @@
 continued in another call to this function.
 
 
+<p>
+See <a href="#pdf-warn"><code>warn</code></a> for more details about warnings.
+
+
 
 
 

@@ -6011,11 +6048,7 @@
 
 
 <p>
-For C&nbsp;functions, this function uses the empty string <code>""</code>
-as a name for all upvalues.
-(For Lua functions,
-upvalues are the external local variables that the function uses,
-and that are consequently included in its closure.)
+See <a href="#pdf-debug.getupvalue"><code>debug.getupvalue</code></a> for more information about upvalues.
 
 
 

@@ -6069,6 +6102,24 @@
 
 
 
+<hr><h3><a name="lua_setcstacklimit"><code>lua_setcstacklimit</code></a></h3><p>
+<span class="apii">[-0, +0, &ndash;]</span>
+<pre>int (lua_setcstacklimit) (lua_State *L, unsigned int limit);</pre>
+
+<p>
+Sets a new limit for the C stack.
+This limit controls how deeply nested calls can go in Lua,
+with the intent of avoiding a stack overflow.
+Returns the old limit in case of success,
+or zero in case of error.
+For more details about this function,
+see <a href="#pdf-debug.setcstacklimit"><code>debug.setcstacklimit</code></a>,
+its equivalent in the standard library.
+
+
+
+
+
 <hr><h3><a name="lua_sethook"><code>lua_sethook</code></a></h3><p>
 <span class="apii">[-0, +0, &ndash;]</span>
 <pre>void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);</pre>

@@ -7352,7 +7403,7 @@
 when the handle is closed or collected;
 this function receives the file handle as its sole argument and
 must return either <b>true</b>, in case of success,
-or <b>nil</b> plus an error message, in case of error.
+or a false value plus an error message, in case of error.
 Once Lua calls this field,
 it changes the field value to <code>NULL</code>
 to signal that the handle is closed.

@@ -7511,6 +7562,15 @@
 
 
 <p>
+The notation <b>fail</b> means a return value representing
+some kind of failure or the absence of a better value to return.
+Currently, <b>fail</b> is equal to <b>nil</b>,
+but that may change in future versions.
+The recommendation is to test the success of these functions
+with <code>(not status)</code>, instead of <code>(status == nil)</code>.
+
+
+<p>
 Currently, Lua has the following standard libraries:
 
 <ul>

@@ -7754,8 +7814,8 @@
 
 <p>
 If there are no syntactic errors,
-returns the compiled chunk as a function;
-otherwise, returns <b>nil</b> plus the error message.
+<code>load</code> returns the compiled chunk as a function;
+otherwise, it returns <b>fail</b> plus the error message.
 
 
 <p>

@@ -8012,7 +8072,7 @@
 If the argument is already a number or
 a string convertible to a number,
 then <code>tonumber</code> returns this number;
-otherwise, it returns <b>nil</b>.
+otherwise, it returns <b>fail</b>.
 
 
 <p>

@@ -8030,7 +8090,7 @@
 represents&nbsp;10, '<code>B</code>' represents&nbsp;11, and so forth,
 with '<code>Z</code>' representing 35.
 If the string <code>e</code> is not a valid numeral in the given base,
-the function returns <b>nil</b>.
+the function returns <b>fail</b>.
 
 
 

@@ -8089,6 +8149,18 @@
 of all its arguments (which should be strings).
 
 
+<p>
+By convention,
+a one-piece message starting with '<code>@</code>'
+is intended to be a <em>control message</em>,
+which is a message to the warning system itself.
+In particular, the standard warning function in Lua
+recognizes the control messages "<code>@off</code>",
+to stop the emission of warnings,
+and "<code>@on</code>", to (re)start the emission;
+it ignores unknown control messages.
+
+
 
 
 <p>

@@ -8607,7 +8679,7 @@
 <p>
 Returns the resulting name of the first file that it can
 open in read mode (after closing the file),
-or <b>nil</b> plus an error message if none succeeds.
+or <b>fail</b> plus an error message if none succeeds.
 (This error message lists all file names it tried to open.)
 
 

@@ -8710,7 +8782,7 @@
 <code>pattern</code> (see <a href="#6.4.1">&sect;6.4.1</a>) in the string <code>s</code>.
 If it finds a match, then <code>find</code> returns the indices of&nbsp;<code>s</code>
 where this occurrence starts and ends;
-otherwise, it returns <b>nil</b>.
+otherwise, it returns <b>fail</b>.
 A third, optional numeric argument <code>init</code> specifies
 where to start the search;
 its default value is&nbsp;1 and can be negative.

@@ -8718,7 +8790,6 @@
 turns off the pattern matching facilities,
 so the function does a plain "find substring" operation,
 with no characters in <code>pattern</code> being considered magic.
-Note that if <code>plain</code> is given, then <code>init</code> must be given as well.
 
 
 <p>

@@ -8953,7 +9024,7 @@
 the <code>pattern</code> (see <a href="#6.4.1">&sect;6.4.1</a>) in the string <code>s</code>.
 If it finds one, then <code>match</code> returns
 the captures from the pattern;
-otherwise it returns <b>nil</b>.
+otherwise it returns <b>fail</b>.
 If <code>pattern</code> specifies no captures,
 then the whole match is returned.
 A third, optional numeric argument <code>init</code> specifies

@@ -9277,7 +9348,7 @@
 
 
 <p>
-As a special case, the empty capture <code>()</code> captures
+As a special case, the capture <code>()</code> captures
 the current string position (a number).
 For instance, if we apply the pattern <code>"()aa()"</code> on the
 string <code>"flaaap"</code>, there will be two captures: 3&nbsp;and&nbsp;5.

@@ -9516,7 +9587,7 @@
 that start between positions <code>i</code> and <code>j</code> (both inclusive).
 The default for <code>i</code> is 1 and for <code>j</code> is -1.
 If it finds any invalid byte sequence,
-returns a false value plus the position of the first invalid byte.
+returns <b>fail</b> plus the position of the first invalid byte.
 
 
 

@@ -9536,7 +9607,7 @@
 <code>n</code>-th character from the end of the string.
 If the specified character is neither in the subject
 nor right after its end,
-the function returns <b>nil</b>.
+the function returns <b>fail</b>.
 
 
 <p>

@@ -9972,6 +10043,15 @@
 When called with no arguments,
 Lua generates a seed with
 a weak attempt for randomness.
+
+
+<p>
+This function returns the two seed components
+that were effectively used,
+so that setting them again repeats the sequence.
+
+
+<p>
 To ensure a required level of randomness to the initial state
 (or contrarily, to have a deterministic sequence,
 for instance when debugging a program),

@@ -10018,7 +10098,7 @@
 <p>
 If the value <code>x</code> is convertible to an integer,
 returns that integer.
-Otherwise, returns <b>nil</b>.
+Otherwise, returns <b>fail</b>.
 
 
 

@@ -10030,7 +10110,7 @@
 <p>
 Returns "<code>integer</code>" if <code>x</code> is an integer,
 "<code>float</code>" if it is a float,
-or <b>nil</b> if <code>x</code> is not a number.
+or <b>fail</b> if <code>x</code> is not a number.
 
 
 

@@ -10084,10 +10164,10 @@
 
 <p>
 Unless otherwise stated,
-all I/O functions return <b>nil</b> on failure,
+all I/O functions return <b>fail</b> on failure,
 plus an error message as a second result and
 a system-dependent error code as a third result,
-and some value different from <b>nil</b> on success.
+and some non-false value on success.
 On non-POSIX systems,
 the computation of the error message and error code
 in case of errors

@@ -10144,8 +10224,8 @@
 Opens the given file name in read mode
 and returns an iterator function that
 works like <code>file:lines(&middot;&middot;&middot;)</code> over the opened file.
-When the iterator function detects the end of file,
-it returns no values (to finish the loop) and automatically closes the file.
+When the iterator function fails to read any value,
+it automatically closes the file.
 Besides the iterator function,
 <code>io.lines</code> returns three other values:
 two <b>nil</b> values as placeholders,

@@ -10163,7 +10243,8 @@
 
 
 <p>
-In case of errors this function raises the error,
+In case of errors opening the file,
+this function raises the error,
 instead of returning an error code.
 
 

@@ -10258,7 +10339,7 @@
 Checks whether <code>obj</code> is a valid file handle.
 Returns the string <code>"file"</code> if <code>obj</code> is an open file handle,
 <code>"closed file"</code> if <code>obj</code> is a closed file handle,
-or <b>nil</b> if <code>obj</code> is not a file handle.
+or <b>fail</b> if <code>obj</code> is not a file handle.
 
 
 

@@ -10323,11 +10404,6 @@
 when the loop ends.
 
 
-<p>
-In case of errors this function raises the error,
-instead of returning an error code.
-
-
 
 
 <p>

@@ -10339,7 +10415,7 @@
 according to the given formats, which specify what to read.
 For each format,
 the function returns a string or a number with the characters read,
-or <b>nil</b> if it cannot read data with the specified format.
+or <b>fail</b> if it cannot read data with the specified format.
 (In this latter case,
 the function does not read subsequent formats.)
 When called without arguments,

@@ -10361,31 +10437,32 @@
 if that prefix does not form a valid numeral
 (e.g., an empty string, "<code>0x</code>", or "<code>3.4e-</code>")
 or it is too long (more than 200 characters),
-it is discarded and the format returns <b>nil</b>.
+it is discarded and the format returns <b>fail</b>.
 </li>
 
 <li><b>"<code>a</code>": </b>
 reads the whole file, starting at the current position.
-On end of file, it returns the empty string.
+On end of file, it returns the empty string;
+this format never fails.
 </li>
 
 <li><b>"<code>l</code>": </b>
 reads the next line skipping the end of line,
-returning <b>nil</b> on end of file.
+returning <b>fail</b> on end of file.
 This is the default format.
 </li>
 
 <li><b>"<code>L</code>": </b>
 reads the next line keeping the end-of-line character (if present),
-returning <b>nil</b> on end of file.
+returning <b>fail</b> on end of file.
 </li>
 
 <li><b><em>number</em>: </b>
 reads a string with up to this number of bytes,
-returning <b>nil</b> on end of file.
+returning <b>fail</b> on end of file.
 If <code>number</code> is zero,
 it reads nothing and returns an empty string,
-or <b>nil</b> on end of file.
+or <b>fail</b> on end of file.
 </li>
 
 </ul><p>

@@ -10411,7 +10488,7 @@
 </ul><p>
 In case of success, <code>seek</code> returns the final file position,
 measured in bytes from the beginning of the file.
-If <code>seek</code> fails, it returns <b>nil</b>,
+If <code>seek</code> fails, it returns <b>fail</b>,
 plus a string describing the error.
 
 

@@ -10433,33 +10510,27 @@
 
 
 <p>
-Sets the buffering mode for an output file.
+Sets the buffering mode for a file.
 There are three available modes:
 
 <ul>
+<li><b>"<code>no</code>": </b> no buffering.</li>
+<li><b>"<code>full</code>": </b> full buffering.</li>
+<li><b>"<code>line</code>": </b> line buffering.</li>
+</ul>
 
-<li><b>"<code>no</code>": </b>
-no buffering; the result of any output operation appears immediately.
-</li>
-
-<li><b>"<code>full</code>": </b>
-full buffering; output operation is performed only
-when the buffer is full or when
-you explicitly <code>flush</code> the file (see <a href="#pdf-io.flush"><code>io.flush</code></a>).
-</li>
-
-<li><b>"<code>line</code>": </b>
-line buffering; output is buffered until a newline is output
-or there is any input from some special files
-(such as a terminal device).
-</li>
-
-</ul><p>
+<p>
 For the last two cases,
 <code>size</code> is a hint for the size of the buffer, in bytes.
 The default is an appropriate size.
 
 
+<p>
+The specific behavior of each mode is non portable;
+check the underlying ISO&nbsp;C function <code>setvbuf</code> in your platform for
+more details.
+
+
 
 
 <p>

@@ -10473,7 +10544,6 @@
 
 <p>
 In case of success, this function returns <code>file</code>.
-Otherwise it returns <b>nil</b> plus a string describing the error.
 
 
 

@@ -10538,7 +10608,7 @@
 
 <p>
 If <code>format</code> is absent, it defaults to "<code>%c</code>",
-which gives a reasonable date and time representation
+which gives a human-readable date and time representation
 using the current locale.
 
 

@@ -10573,7 +10643,7 @@
 It passes <code>command</code> to be executed by an operating system shell.
 Its first result is <b>true</b>
 if the command terminated successfully,
-or <b>nil</b> otherwise.
+or <b>fail</b> otherwise.
 After this first result
 the function returns a string plus a number,
 as follows:

@@ -10627,7 +10697,7 @@
 
 <p>
 Returns the value of the process environment variable <code>varname</code>,
-or <b>nil</b> if the variable is not defined.
+or <b>fail</b> if the variable is not defined.
 
 
 

@@ -10639,7 +10709,7 @@
 <p>
 Deletes the file (or empty directory, on POSIX systems)
 with the given name.
-If this function fails, it returns <b>nil</b>,
+If this function fails, it returns <b>fail</b>
 plus a string describing the error and the error code.
 Otherwise, it returns true.
 

@@ -10652,7 +10722,7 @@
 
 <p>
 Renames the file or directory named <code>oldname</code> to <code>newname</code>.
-If this function fails, it returns <b>nil</b>,
+If this function fails, it returns <b>fail</b>,
 plus a string describing the error and the error code.
 Otherwise, it returns true.
 

@@ -10671,7 +10741,7 @@
 <code>"monetary"</code>, <code>"numeric"</code>, or <code>"time"</code>;
 the default category is <code>"all"</code>.
 The function returns the name of the new locale,
-or <b>nil</b> if the request cannot be honored.
+or <b>fail</b> if the request cannot be honored.
 
 
 <p>

@@ -10829,6 +10899,10 @@
 as set by the <a href="#pdf-debug.sethook"><code>debug.sethook</code></a> function.
 
 
+<p>
+Returns <b>fail</b> if there is no active hook.
+
+
 
 
 <p>

@@ -10846,7 +10920,7 @@
 (except for tail calls, which do not count on the stack);
 and so on.
 If <code>f</code> is a number greater than the number of active functions,
-then <code>getinfo</code> returns <b>nil</b>.
+then <code>getinfo</code> returns <b>fail</b>.
 
 
 <p>

@@ -10890,9 +10964,12 @@
 following the order that they are declared in the code,
 counting only the variables that are active
 in the current scope of the function.
+Compile-time constants may not appear in this listing,
+if they were optimized away by the compiler.
 Negative indices refer to vararg arguments;
 -1 is the first vararg argument.
-The function returns <b>nil</b> if there is no variable with the given index,
+The function returns <b>fail</b>
+if there is no variable with the given index,
 and raises an error when called with a level out of range.
 (You can call <a href="#pdf-debug.getinfo"><code>debug.getinfo</code></a> to check whether the level is valid.)
 

@@ -10939,12 +11016,24 @@
 <p>
 This function returns the name and the value of the upvalue
 with index <code>up</code> of the function <code>f</code>.
-The function returns <b>nil</b> if there is no upvalue with the given index.
+The function returns <b>fail</b>
+if there is no upvalue with the given index.
 
 
 <p>
-Variable names starting with '<code>(</code>' (open parenthesis) 
-represent variables with no known names
+(For Lua functions,
+upvalues are the external local variables that the function uses,
+and that are consequently included in its closure.)
+
+
+<p>
+For C&nbsp;functions, this function uses the empty string <code>""</code>
+as a name for all upvalues.
+
+
+<p>
+Variable name '<code>?</code>' (interrogation mark)
+represents variables with no known names
 (variables from chunks saved without debug information).
 
 

@@ -10963,6 +11052,43 @@
 
 
 <p>
+<hr><h3><a name="pdf-debug.setcstacklimit"><code>debug.setcstacklimit (limit)</code></a></h3>
+
+
+<p>
+Sets a new limit for the C stack.
+This limit controls how deeply nested calls can go in Lua,
+with the intent of avoiding a stack overflow.
+A limit too small restricts recursive calls pointlessly;
+a limit too large exposes the interpreter to stack-overflow crashes.
+Unfortunately, there is no way to know a priori
+the maximum safe limit for a platform.
+
+
+<p>
+Each call made from Lua code counts one unit.
+Other operations (e.g., calls made from C to Lua or resuming a coroutine)
+may have a higher cost.
+
+
+<p>
+This function has the following restrictions:
+
+<ul>
+<li>It can only be called from the main coroutine (thread);</li>
+<li>It cannot be called while handling a stack-overflow error;</li>
+<li><code>limit</code> must be less than 40000;</li>
+<li><code>limit</code> cannot be less than the amount of C stack in use.</li>
+</ul><p>
+If a call does not respect some restriction,
+it returns <b>false</b>.
+Otherwise,
+the call returns the old limit.
+
+
+
+
+<p>
 <hr><h3><a name="pdf-debug.sethook"><code>debug.sethook ([thread,] hook, mask [, count])</code></a></h3>
 
 

@@ -11011,7 +11137,7 @@
 <p>
 This function assigns the value <code>value</code> to the local variable
 with index <code>local</code> of the function at level <code>level</code> of the stack.
-The function returns <b>nil</b> if there is no local
+The function returns <b>fail</b> if there is no local
 variable with the given index,
 and raises an error when called with a <code>level</code> out of range.
 (You can call <code>getinfo</code> to check whether the level is valid.)

@@ -11044,11 +11170,15 @@
 <p>
 This function assigns the value <code>value</code> to the upvalue
 with index <code>up</code> of the function <code>f</code>.
-The function returns <b>nil</b> if there is no upvalue
+The function returns <b>fail</b> if there is no upvalue
 with the given index.
 Otherwise, it returns the name of the upvalue.
 
 
+<p>
+See <a href="#pdf-debug.getupvalue"><code>debug.getupvalue</code></a> for more information about upvalues.
+
+
 
 
 <p>

@@ -11063,7 +11193,7 @@
 
 <p>
 Returns <code>udata</code>,
-or <b>nil</b> if the userdata does not have that value.
+or <b>fail</b> if the userdata does not have that value.
 
 
 

@@ -11145,6 +11275,7 @@
 <li><b><code>-i</code>: </b> enters interactive mode after running <em>script</em>;</li>
 <li><b><code>-v</code>: </b> prints version information;</li>
 <li><b><code>-E</code>: </b> ignores environment variables;</li>
+<li><b><code>-W</code>: </b> turn warnings on;</li>
 <li><b><code>--</code>: </b> stops handling options;</li>
 <li><b><code>-</code>: </b> executes <code>stdin</code> as a file and stops handling options.</li>
 </ul><p>

@@ -11176,13 +11307,14 @@
 
 
 <p>
-All options are handled in order, except <code>-i</code> and <code>-E</code>.
+The options <code>-e</code>, <code>-l</code>, and <code>-W</code> are handled in
+the order they appear.
 For instance, an invocation like
 
 <pre>
-     $ lua -e'a=1' -e 'print(a)' script.lua
+     $ lua -e 'a=1' -llib1 script.lua
 </pre><p>
-will first set <code>a</code> to 1, then print the value of <code>a</code>,
+will first set <code>a</code> to 1, then require the library <code>lib1</code>,
 and finally run the file <code>script.lua</code> with no arguments.
 (Here <code>$</code> is the shell prompt. Your prompt may be different.)
 

@@ -11253,7 +11385,8 @@
 the interpreter calls this metamethod to produce the final message.
 Otherwise, the interpreter converts the error object to a string
 and adds a stack traceback to it.
-Warnings are simply printed in the standard error output.
+When warnings are on,
+they are simply printed in the standard error output.
 
 
 <p>

@@ -11503,8 +11636,11 @@
 		 <b>for</b> namelist <b>in</b> explist <b>do</b> block <b>end</b> | 
 		 <b>function</b> funcname funcbody | 
 		 <b>local</b> <b>function</b> Name funcbody | 
-		 <b>local</b> namelist [&lsquo;<b>=</b>&rsquo; explist] | 
-		 <b>local</b> &lsquo;<b>&lt;</b>&rsquo; Name &lsquo;<b>&gt;</b>&rsquo; Name &lsquo;<b>=</b>&rsquo; exp 
+		 <b>local</b> attnamelist [&lsquo;<b>=</b>&rsquo; explist] 
+
+	attnamelist ::=  Name attrib {&lsquo;<b>,</b>&rsquo; Name attrib}
+
+	attrib ::= [&lsquo;<b>&lt;</b>&rsquo; Name &lsquo;<b>&gt;</b>&rsquo;]
 
 	retstat ::= <b>return</b> [explist] [&lsquo;<b>;</b>&rsquo;]
 

@@ -11562,10 +11698,10 @@
 
 <P CLASS="footer">
 Last update:
-Thu Jun  6 15:59:35 -03 2019
+Wed Oct  2 21:30:38 UTC 2019
 </P>
 <!--
-Last change: revised for Lua 5.4.0 (alpha)
+Last change: revised for Lua 5.4.0 (beta)
 -->
 
 </body></html>

doc/readme.html

@@ -110,7 +110,7 @@
 <OL>
 <LI>
 Open a terminal window and move to
-the top-level directory, which is named <TT>lua-5.4.0-alpha</TT>.
+the top-level directory, which is named <TT>lua-5.4.0-beta</TT>.
 The <TT>Makefile</TT> there controls both the build process and the installation process.
 <P>
 <LI>

@@ -329,10 +329,10 @@
 
 <P CLASS="footer">
 Last update:
-Thu Jun  6 10:58:49 -03 2019
+Tue Sep 24 16:42:41 UTC 2019
 </P>
 <!--
-Last change: revised for Lua 5.4.0 (alpha)
+Last change: revised for Lua 5.4.0 (beta)
 -->
 
 </BODY>

src/Makefile

@@ -132,6 +132,17 @@
 # list targets that do not create files (but not all makes understand .PHONY)
 .PHONY: all $(PLATS) default o a clean depend echo none
 
+llex.o:
+	$(CC) $(CFLAGS) -Os -c llex.c
+
+lparser.o:
+	$(CC) $(CFLAGS) -Os -c lparser.c
+
+lcode.o:
+	$(CC) $(CFLAGS) -Os -c lcode.c
+
+	
+
 # DO NOT DELETE
 
 lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \

src/lapi.c

@@ -170,20 +170,23 @@
 
 
 LUA_API void lua_settop (lua_State *L, int idx) {
-  StkId func = L->ci->func;
+  CallInfo *ci = L->ci;
+  StkId func = ci->func;
+  ptrdiff_t diff;  /* difference for new top */
   lua_lock(L);
   if (idx >= 0) {
-    StkId newtop = (func + 1) + idx;
-    api_check(L, idx <= L->stack_last - (func + 1), "new top too large");
-    while (L->top < newtop)
-      setnilvalue(s2v(L->top++));
-    L->top = newtop;
+    api_check(L, idx <= ci->top - (func + 1), "new top too large");
+    diff = ((func + 1) + idx) - L->top;
+    for (; diff > 0; diff--)
+      setnilvalue(s2v(L->top++));  /* clear new slots */
   }
   else {
     api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
-    L->top += idx+1;  /* 'subtract' index (index is negative) */
+    diff = idx + 1;  /* will "subtract" index (as it is negative) */
   }
-  luaF_close(L, L->top, LUA_OK);
+  if (diff < 0 && hastocloseCfunc(ci->nresults))
+    luaF_close(L, L->top + diff, LUA_OK);
+  L->top += diff;  /* correct top only after closing any upvalue */
   lua_unlock(L);
 }
 

src/lapi.h

@@ -11,12 +11,22 @@
 #include "llimits.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");}
 
+
+/*
+** If a call returns too many multiple returns, the callee may not have
+** stack space to accomodate all results. In this case, this macro
+** increases its stack space ('L->ci->top').
+*/
 #define adjustresults(L,nres) \
     { if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
 
+
+/* 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")
 

src/lauxlib.c

@@ -62,7 +62,7 @@
       else if (findfield(L, objidx, level - 1)) {  /* try recursively */
         /* stack: lib_name, lib_table, field_name (top) */
         lua_pushliteral(L, ".");  /* place '.' between the two names */
-        lua_replace(L, -3);  /* (in the slot ocupied by table) */
+        lua_replace(L, -3);  /* (in the slot occupied by table) */
         lua_concat(L, 3);  /* lib_name.field_name */
         return 1;
       }

@@ -249,7 +249,7 @@
     return 1;
   }
   else {
-    lua_pushnil(L);
+    luaL_pushfail(L);
     if (fname)
       lua_pushfstring(L, "%s: %s", fname, strerror(en));
     else

@@ -291,10 +291,10 @@
     if (*what == 'e' && stat == 0)  /* successful termination? */
       lua_pushboolean(L, 1);
     else
-      lua_pushnil(L);
+      luaL_pushfail(L);
     lua_pushstring(L, what);
     lua_pushinteger(L, stat);
-    return 3;  /* return true/nil,what,code */
+    return 3;  /* return true/fail,what,code */
   }
 }
 

@@ -1002,29 +1002,43 @@
 
 
 /*
-** Emit a warning. '*previoustocont' signals whether previous message
-** was to be continued by the current one.
+** Emit a warning. '*warnstate' means:
+** 0 - warning system is off;
+** 1 - ready to start a new message;
+** 2 - previous message is to be continued.
 */
 static void warnf (void *ud, const char *message, int tocont) {
-  int *previoustocont = (int *)ud;
-  if (!*previoustocont)  /* previous message was the last? */
+  int *warnstate = (int *)ud;
+  if (*warnstate != 2 && !tocont && *message == '@') {  /* control message? */
+    if (strcmp(message, "@off") == 0)
+      *warnstate = 0;
+    else if (strcmp(message, "@on") == 0)
+      *warnstate = 1;
+    return;
+  }
+  else if (*warnstate == 0)  /* warnings off? */
+    return;
+  if (*warnstate == 1)  /* previous message was the last? */
     lua_writestringerror("%s", "Lua warning: ");  /* start a new warning */
   lua_writestringerror("%s", message);  /* write message */
-  if (!tocont)  /* is this the last part? */
+  if (tocont)  /* not the last part? */
+    *warnstate = 2;  /* to be continued */
+  else {  /* last part */
     lua_writestringerror("%s", "\n");  /* finish message with end-of-line */
-  *previoustocont = tocont;
+    *warnstate = 1;  /* ready to start a new message */
+  }
 }
 
 
 LUALIB_API lua_State *luaL_newstate (void) {
   lua_State *L = lua_newstate(l_alloc, NULL);
   if (L) {
-    int *previoustocont;  /* space for warning state */
+    int *warnstate;  /* space for warning state */
     lua_atpanic(L, &panic);
-    previoustocont = (int *)lua_newuserdatauv(L, sizeof(int), 0);
+    warnstate = (int *)lua_newuserdatauv(L, sizeof(int), 0);
     luaL_ref(L, LUA_REGISTRYINDEX);  /* make sure it won't be collected */
-    *previoustocont = 0;  /* next message starts a new warning */
-    lua_setwarnf(L, warnf, previoustocont);
+    *warnstate = 0;  /* default is warnings off */
+    lua_setwarnf(L, warnf, warnstate);
   }
   return L;
 }

src/lauxlib.h

@@ -153,6 +153,10 @@
 #define luaL_loadbuffer(L,s,sz,n)	luaL_loadbufferx(L,s,sz,n,NULL)
 
 
+/* push the value used to represent failure/error */
+#define luaL_pushfail(L)	lua_pushnil(L)
+
+
 /*
 ** {======================================================
 ** Generic Buffer manipulation

src/lbaselib.c

@@ -48,9 +48,9 @@
   luaL_checkstring(L, 1);  /* at least one argument */
   for (i = 2; i <= n; i++)
     luaL_checkstring(L, i);  /* make sure all arguments are strings */
-  for (i = 1; i <= n; i++)  /* compose warning */
+  for (i = 1; i < n; i++)  /* compose warning */
     lua_warning(L, lua_tostring(L, i), 1);
-  lua_warning(L, "", 0);  /* close warning */
+  lua_warning(L, lua_tostring(L, n), 0);  /* close warning */
   return 0;
 }
 

@@ -106,7 +106,7 @@
       return 1;
     }  /* else not a number */
   }  /* else not a number */
-  lua_pushnil(L);  /* not a number */
+  luaL_pushfail(L);  /* not a number */
   return 1;
 }
 

@@ -308,9 +308,9 @@
     return 1;
   }
   else {  /* error (message is on top of the stack) */
-    lua_pushnil(L);
+    luaL_pushfail(L);
     lua_insert(L, -2);  /* put before error message */
-    return 2;  /* return nil plus error message */
+    return 2;  /* return fail plus error message */
   }
 }
 

src/lcode.c

@@ -52,7 +52,7 @@
 ** If expression is a numeric constant, fills 'v' with its value
 ** and returns 1. Otherwise, returns 0.
 */
-static int tonumeral(const expdesc *e, TValue *v) {
+static int tonumeral (const expdesc *e, TValue *v) {
   if (hasjumps(e))
     return 0;  /* not a numeral */
   switch (e->k) {

@@ -68,6 +68,42 @@
 
 
 /*
+** Get the constant value from a constant expression
+*/
+static TValue *const2val (FuncState *fs, const expdesc *e) {
+  lua_assert(e->k == VCONST);
+  return &fs->ls->dyd->actvar.arr[e->u.info].k;
+}
+
+
+/*
+** If expression is a constant, fills 'v' with its value
+** and returns 1. Otherwise, returns 0.
+*/
+int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v) {
+  if (hasjumps(e))
+    return 0;  /* not a constant */
+  switch (e->k) {
+    case VFALSE: case VTRUE:
+      setbvalue(v, e->k == VTRUE);
+      return 1;
+    case VNIL:
+      setnilvalue(v);
+      return 1;
+    case VKSTR: {
+      setsvalue(fs->ls->L, v, e->u.strval);
+      return 1;
+    }
+    case VCONST: {
+      setobj(fs->ls->L, v, const2val(fs, e));
+      return 1;
+    }
+    default: return tonumeral(e, v);
+  }
+}
+
+
+/*
 ** Return the previous instruction of the current code. If there
 ** may be a jump target between the current instruction and the
 ** previous one, return an invalid instruction (to avoid wrong

@@ -323,12 +359,12 @@
   Proto *f = fs->f;
   int pc = fs->pc - 1;  /* last instruction coded */
   if (f->lineinfo[pc] != ABSLINEINFO) {  /* relative line info? */
-    fs->previousline -= f->lineinfo[pc];  /* last line saved */
-    fs->iwthabs--;
+    fs->previousline -= f->lineinfo[pc];  /* correct last line saved */
+    fs->iwthabs--;  /* undo previous increment */
   }
   else {  /* absolute line information */
+    lua_assert(f->abslineinfo[fs->nabslineinfo - 1].pc == pc);
     fs->nabslineinfo--;  /* remove it */
-    lua_assert(f->abslineinfo[fs->nabslineinfo].pc = pc);
     fs->iwthabs = MAXIWTHABS + 1;  /* force next line info to be absolute */
   }
 }

@@ -348,7 +384,7 @@
 ** Emit instruction 'i', checking for array sizes and saving also its
 ** line information. Return 'i' position.
 */
-static int luaK_code (FuncState *fs, Instruction i) {
+int luaK_code (FuncState *fs, Instruction i) {
   Proto *f = fs->f;
   /* put new instruction in code array */
   luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction,

@@ -458,7 +494,7 @@
 )
 */
 static void freereg (FuncState *fs, int reg) {
-  if (reg >= fs->nactvar) {
+  if (reg >= luaY_nvarstack(fs)) {
     fs->freereg--;
     lua_assert(reg == fs->freereg);
   }

@@ -537,7 +573,7 @@
 /*
 ** Add a string to list of constants and return its index.
 */
-int luaK_stringK (FuncState *fs, TString *s) {
+static int stringK (FuncState *fs, TString *s) {
   TValue o;
   setsvalue(fs->ls->L, &o, s);
   return addk(fs, &o, &o);  /* use string itself as key */

@@ -590,12 +626,12 @@
 
 
 /*
-** Check whether 'i' can be stored in an 'sC' operand.
-** Equivalent to (0 <= i + OFFSET_sC && i + OFFSET_sC <= MAXARG_C)
-** but without risk of overflows in the addition.
+** Check whether 'i' can be stored in an 'sC' operand. Equivalent to
+** (0 <= int2sC(i) && int2sC(i) <= MAXARG_C) but without risk of
+** overflows in the hidden addition inside 'int2sC'.
 */
 static int fitsC (lua_Integer i) {
-  return (-OFFSET_sC <= i && i <= MAXARG_C - OFFSET_sC);
+  return (l_castS2U(i) + OFFSET_sC <= cast_uint(MAXARG_C));
 }
 
 

@@ -615,14 +651,9 @@
 }
 
 
-static int floatI (lua_Number f, lua_Integer *fi) {
-  return (luaV_flttointeger(f, fi, 0) && fitsBx(*fi));
-}
-
-
 static void luaK_float (FuncState *fs, int reg, lua_Number f) {
   lua_Integer fi;
-  if (floatI(f, &fi))
+  if (luaV_flttointeger(f, &fi, 0) && fitsBx(fi))
     luaK_codeAsBx(fs, OP_LOADF, reg, cast_int(fi));
   else
     luaK_codek(fs, reg, luaK_numberK(fs, f));

@@ -630,6 +661,31 @@
 
 
 /*
+** Convert a constant in 'v' into an expression description 'e'
+*/
+static void const2exp (TValue *v, expdesc *e) {
+  switch (ttypetag(v)) {
+    case LUA_TNUMINT:
+      e->k = VKINT; e->u.ival = ivalue(v);
+      break;
+    case LUA_TNUMFLT:
+      e->k = VKFLT; e->u.nval = fltvalue(v);
+      break;
+    case LUA_TBOOLEAN:
+      e->k = bvalue(v) ? VTRUE : VFALSE;
+      break;
+    case LUA_TNIL:
+      e->k = VNIL;
+      break;
+    case LUA_TSHRSTR:  case LUA_TLNGSTR:
+      e->k = VKSTR; e->u.strval = tsvalue(v);
+      break;
+    default: lua_assert(0);
+  }
+}
+
+
+/*
 ** Fix an expression to return the number of results 'nresults'.
 ** Either 'e' is a multi-ret expression (function call or vararg)
 ** or 'nresults' is LUA_MULTRET (as any expression can satisfy that).

@@ -648,6 +704,16 @@
 
 
 /*
+** Convert a VKSTR to a VK
+*/
+static void str2K (FuncState *fs, expdesc *e) {
+  lua_assert(e->k == VKSTR);
+  e->u.info = stringK(fs, e->u.strval);
+  e->k = VK;
+}
+
+
+/*
 ** Fix an expression to return one result.
 ** If expression is not a multi-ret expression (function call or
 ** vararg), it already returns one result, so nothing needs to be done.

@@ -672,18 +738,22 @@
 
 
 /*
-** Ensure that expression 'e' is not a variable.
+** Ensure that expression 'e' is not a variable (nor a constant).
 ** (Expression still may have jump lists.)
 */
 void luaK_dischargevars (FuncState *fs, expdesc *e) {
   switch (e->k) {
+    case VCONST: {
+      const2exp(const2val(fs, e), e);
+      break;
+    }
     case VLOCAL: {  /* already in a register */
-      e->u.info = e->u.var.idx;
+      e->u.info = e->u.var.sidx;
       e->k = VNONRELOC;  /* becomes a non-relocatable value */
       break;
     }
     case VUPVAL: {  /* move value to some (pending) register */
-      e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.var.idx, 0);
+      e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
       e->k = VRELOC;
       break;
     }

@@ -735,6 +805,9 @@
       luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
       break;
     }
+    case VKSTR: {
+      str2K(fs, e);
+    }  /* FALLTHROUGH */
     case VK: {
       luaK_codek(fs, reg, e->u.info);
       break;

@@ -850,7 +923,7 @@
   if (e->k == VNONRELOC) {  /* expression already has a register? */
     if (!hasjumps(e))  /* no jumps? */
       return e->u.info;  /* result is already in a register */
-    if (e->u.info >= fs->nactvar) {  /* reg. is not a local? */
+    if (e->u.info >= luaY_nvarstack(fs)) {  /* reg. is not a local? */
       exp2reg(fs, e, e->u.info);  /* put final result in it */
       return e->u.info;
     }

@@ -895,6 +968,7 @@
       case VNIL: info = nilK(fs); break;
       case VKINT: info = luaK_intK(fs, e->u.ival); break;
       case VKFLT: info = luaK_numberK(fs, e->u.nval); break;
+      case VKSTR: info = stringK(fs, e->u.strval); break;
       case VK: info = e->u.info; break;
       default: return 0;  /* not a constant */
     }

@@ -939,12 +1013,12 @@
   switch (var->k) {
     case VLOCAL: {
       freeexp(fs, ex);
-      exp2reg(fs, ex, var->u.var.idx);  /* compute 'ex' into proper place */
+      exp2reg(fs, ex, var->u.var.sidx);  /* compute 'ex' into proper place */
       return;
     }
     case VUPVAL: {
       int e = luaK_exp2anyreg(fs, ex);
-      luaK_codeABC(fs, OP_SETUPVAL, e, var->u.var.idx, 0);
+      luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
       break;
     }
     case VINDEXUP: {

@@ -1029,7 +1103,7 @@
       pc = e->u.info;  /* save jump position */
       break;
     }
-    case VK: case VKFLT: case VKINT: case VTRUE: {
+    case VK: case VKFLT: case VKINT: case VKSTR: case VTRUE: {
       pc = NO_JUMP;  /* always true; do nothing */
       break;
     }

@@ -1074,13 +1148,12 @@
 ** Code 'not e', doing constant folding.
 */
 static void codenot (FuncState *fs, expdesc *e) {
-  luaK_dischargevars(fs, e);
   switch (e->k) {
     case VNIL: case VFALSE: {
       e->k = VTRUE;  /* true == not nil == not false */
       break;
     }
-    case VK: case VKFLT: case VKINT: case VTRUE: {
+    case VK: case VKFLT: case VKINT: case VKSTR: case VTRUE: {
       e->k = VFALSE;  /* false == not "x" == not 0.5 == not 1 == not true */
       break;
     }

@@ -1143,15 +1216,16 @@
 ** Check whether expression 'e' is a literal integer or float in
 ** proper range to fit in a register (sB or sC).
 */
-static int isSCnumber (expdesc *e, lua_Integer *i, int *isfloat) {
+static int isSCnumber (expdesc *e, int *pi, int *isfloat) {
+  lua_Integer i;
   if (e->k == VKINT)
-    *i = e->u.ival;
-  else if (!(e->k == VKFLT && floatI(e->u.nval, i)))
-    return 0;  /* not a number */
-  else
+    i = e->u.ival;
+  else if (e->k == VKFLT && luaV_flttointeger(e->u.nval, &i, 0))
     *isfloat = 1;
-  if (!hasjumps(e) && fitsC(*i)) {
-    *i += OFFSET_sC;
+  else
+    return 0;  /* not a number */
+  if (!hasjumps(e) && fitsC(i)) {
+    *pi = int2sC(cast_int(i));
     return 1;
   }
   else

@@ -1166,18 +1240,20 @@
 ** values in registers.
 */
 void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
+  if (k->k == VKSTR)
+    str2K(fs, k);
   lua_assert(!hasjumps(t) &&
              (t->k == VLOCAL || t->k == VNONRELOC || t->k == VUPVAL));
-  if (t->k == VUPVAL && !isKstr(fs, k))  /* upvalue indexed by non string? */
+  if (t->k == VUPVAL && !isKstr(fs, k))  /* upvalue indexed by non 'Kstr'? */
     luaK_exp2anyreg(fs, t);  /* put it in a register */
   if (t->k == VUPVAL) {
-    t->u.ind.t = t->u.var.idx;  /* upvalue index */
+    t->u.ind.t = t->u.info;  /* upvalue index */
     t->u.ind.idx = k->u.info;  /* literal string */
     t->k = VINDEXUP;
   }
   else {
     /* register index of the table */
-    t->u.ind.t = (t->k == VLOCAL) ? t->u.var.idx: t->u.info;
+    t->u.ind.t = (t->k == VLOCAL) ? t->u.var.sidx: t->u.info;
     if (isKstr(fs, k)) {
       t->u.ind.idx = k->u.info;  /* literal string */
       t->k = VINDEXSTR;

@@ -1218,7 +1294,7 @@
 ** (In this case, 'e1' has the final result.)
 */
 static int constfolding (FuncState *fs, int op, expdesc *e1,
-                                                const expdesc *e2) {
+                                        const expdesc *e2) {
   TValue v1, v2, res;
   if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2))
     return 0;  /* non-numeric operands or not safe to fold */

@@ -1257,18 +1333,18 @@
 ** (everything but logical operators 'and'/'or' and comparison
 ** operators).
 ** Expression to produce final result will be encoded in 'e1'.
-** Because 'luaK_exp2anyreg' can free registers, its calls must be
-** in "stack order" (that is, first on 'e2', which may have more
-** recent registers to be released).
 */
 static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2,
-                             OpCode op, int v2, int k, int line) {
+                             OpCode op, int v2, int flip, int line,
+                             OpCode mmop, TMS event) {
   int v1 = luaK_exp2anyreg(fs, e1);
-  int pc = luaK_codeABCk(fs, op, 0, v1, v2, k);
+  int pc = luaK_codeABCk(fs, op, 0, v1, v2, 0);
   freeexps(fs, e1, e2);
   e1->u.info = pc;
   e1->k = VRELOC;  /* all those operations are relocatable */
   luaK_fixline(fs, line);
+  luaK_codeABCk(fs, mmop, v1, v2, event, flip);  /* to call metamethod */
+  luaK_fixline(fs, line);
 }
 
 

@@ -1279,17 +1355,43 @@
 static void codebinexpval (FuncState *fs, OpCode op,
                            expdesc *e1, expdesc *e2, int line) {
   int v2 = luaK_exp2anyreg(fs, e2);  /* both operands are in registers */
-  finishbinexpval(fs, e1, e2, op, v2, 0, line);
+  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));
 }
 
 
 /*
-** Code binary operators ('+', '-', ...) with immediate operands.
+** Code binary operators with immediate operands.
 */
 static void codebini (FuncState *fs, OpCode op,
-                       expdesc *e1, expdesc *e2, int k, int line) {
-  int v2 = cast_int(e2->u.ival) + OFFSET_sC;  /* immediate operand */
-  finishbinexpval(fs, e1, e2, op, v2, k, line);
+                       expdesc *e1, expdesc *e2, int flip, int line,
+                       TMS event) {
+  int v2 = int2sC(cast_int(e2->u.ival));  /* immediate operand */
+  lua_assert(e2->k == VKINT);
+  finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINI, event);
+}
+
+
+/* Try to code a binary operator negating its second operand.
+** For the metamethod, 2nd operand must keep its original value.
+*/
+static int finishbinexpneg (FuncState *fs, expdesc *e1, expdesc *e2,
+                             OpCode op, int line, TMS event) {
+  if (!luaK_isKint(e2))
+    return 0;  /* not an integer constant */
+  else {
+    lua_Integer i2 = e2->u.ival;
+    if (!(fitsC(i2) && fitsC(-i2)))
+      return 0;  /* not in the proper range */
+    else {  /* operating a small integer constant */
+      int v2 = cast_int(i2);
+      finishbinexpval(fs, e1, e2, op, int2sC(-v2), 0, line, OP_MMBINI, event);
+      /* correct metamethod argument */
+      SETARG_B(fs->f->code[fs->pc - 1], int2sC(v2));
+      return 1;  /* successfully coded */
+    }
+  }
 }
 
 

@@ -1300,19 +1402,18 @@
 
 /*
 ** Code arithmetic operators ('+', '-', ...). If second operand is a
-** constant in the proper range, use variant opcodes with immediate
-** operands or K operands.
+** constant in the proper range, use variant opcodes with K operands.
 */
-static void codearith (FuncState *fs, OpCode op,
+static void codearith (FuncState *fs, BinOpr opr,
                        expdesc *e1, expdesc *e2, int flip, int line) {
-  if (isSCint(e2))  /* immediate operand? */
-    codebini(fs, cast(OpCode, op - OP_ADD + OP_ADDI), e1, e2, flip, line);
-  else if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) {  /* K operand? */
+  TMS event = cast(TMS, opr + TM_ADD);
+  if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) {  /* K operand? */
     int v2 = e2->u.info;  /* K index */
-    op = cast(OpCode, op - OP_ADD + OP_ADDK);
-    finishbinexpval(fs, e1, e2, op, v2, flip, line);
+    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 */

@@ -1325,14 +1426,17 @@
 ** numeric constant, change order of operands to try to use an
 ** immediate or K operator.
 */
-static void codecommutative (FuncState *fs, OpCode op,
+static void codecommutative (FuncState *fs, BinOpr op,
                              expdesc *e1, expdesc *e2, int line) {
   int flip = 0;
   if (tonumeral(e1, NULL)) {  /* is first operand a numeric constant? */
     swapexps(e1, e2);  /* change order */
     flip = 1;
   }
-  codearith(fs, op, e1, e2, flip, line);
+  if (op == OPR_ADD && isSCint(e2))  /* immediate operand? */
+    codebini(fs, cast(OpCode, OP_ADDI), e1, e2, flip, line, TM_ADD);
+  else
+    codearith(fs, op, e1, e2, flip, line);
 }
 
 

@@ -1342,41 +1446,23 @@
 */
 static void codebitwise (FuncState *fs, BinOpr opr,
                          expdesc *e1, expdesc *e2, int line) {
-  int inv = 0;
+  int flip = 0;
   int v2;
   OpCode op;
   if (e1->k == VKINT && luaK_exp2RK(fs, e1)) {
     swapexps(e1, e2);  /* 'e2' will be the constant operand */
-    inv = 1;
+    flip = 1;
   }
   else if (!(e2->k == VKINT && luaK_exp2RK(fs, e2))) {  /* no constants? */
-    op = cast(OpCode, opr - OPR_BAND + OP_BAND);
+    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 - OPR_BAND + OP_BANDK);
+  op = cast(OpCode, opr + OP_ADDK);
   lua_assert(ttisinteger(&fs->f->k[v2]));
-  finishbinexpval(fs, e1, e2, op, v2, inv, line);
-}
-
-
-/*
-** Code shift operators. If second operand is constant, use immediate
-** operand (negating it if shift is in the other direction).
-*/
-static void codeshift (FuncState *fs, OpCode op,
-                       expdesc *e1, expdesc *e2, int line) {
-  if (isSCint(e2)) {
-    int changedir = 0;
-    if (op == OP_SHL) {
-      changedir = 1;
-      e2->u.ival = -(e2->u.ival);
-    }
-    codebini(fs, OP_SHRI, e1, e2, changedir, line);
-  }
-  else
-    codebinexpval(fs, op, e1, e2, line);
+  finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK,
+                  cast(TMS, opr + TM_ADD));
 }
 
 

@@ -1386,18 +1472,18 @@
 */
 static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
   int r1, r2;
-  lua_Integer im;
+  int im;
   int isfloat = 0;
   if (isSCnumber(e2, &im, &isfloat)) {
     /* use immediate operand */
     r1 = luaK_exp2anyreg(fs, e1);
-    r2 = cast_int(im);
+    r2 = im;
     op = cast(OpCode, (op - OP_LT) + OP_LTI);
   }
   else if (isSCnumber(e1, &im, &isfloat)) {
     /* transform (A < B) to (B > A) and (A <= B) to (B >= A) */
     r1 = luaK_exp2anyreg(fs, e2);
-    r2 = cast_int(im);
+    r2 = im;
     op = (op == OP_LT) ? OP_GTI : OP_GEI;
   }
   else {  /* regular case, compare two registers */

@@ -1416,7 +1502,7 @@
 */
 static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
   int r1, r2;
-  lua_Integer im;
+  int im;
   int isfloat = 0;  /* not needed here, but kept for symmetry */
   OpCode op;
   if (e1->k != VNONRELOC) {

@@ -1426,7 +1512,7 @@
   r1 = luaK_exp2anyreg(fs, e1);  /* 1nd expression must be in register */
   if (isSCnumber(e2, &im, &isfloat)) {
     op = OP_EQI;
-    r2 = cast_int(im);  /* immediate operand */
+    r2 = im;  /* immediate operand */
   }
   else if (luaK_exp2RK(fs, e2)) {  /* 1st expression is constant? */
     op = OP_EQK;

@@ -1447,11 +1533,12 @@
 */
 void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
   static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
+  luaK_dischargevars(fs, e);
   switch (op) {
     case OPR_MINUS: case OPR_BNOT:  /* use 'ef' as fake 2nd operand */
       if (constfolding(fs, op + LUA_OPUNM, e, &ef))
         break;
-      /* FALLTHROUGH */
+      /* else */ /* FALLTHROUGH */
     case OPR_LEN:
       codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);
       break;

@@ -1466,6 +1553,7 @@
 ** 2nd operand.
 */
 void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
+  luaK_dischargevars(fs, v);
   switch (op) {
     case OPR_AND: {
       luaK_goiftrue(fs, v);  /* go ahead only if 'v' is true */

@@ -1497,8 +1585,7 @@
     }
     case OPR_LT: case OPR_LE:
     case OPR_GT: case OPR_GE: {
-      lua_Integer dummy;
-      int dummy2;
+      int dummy, dummy2;
       if (!isSCnumber(v, &dummy, &dummy2))
         luaK_exp2anyreg(fs, v);
       /* else keep numeral, which may be an immediate operand */

@@ -1535,17 +1622,18 @@
 */
 void luaK_posfix (FuncState *fs, BinOpr opr,
                   expdesc *e1, expdesc *e2, int line) {
+  luaK_dischargevars(fs, e2);
+  if (foldbinop(opr) && constfolding(fs, opr + LUA_OPADD, e1, e2))
+    return;  /* done by folding */
   switch (opr) {
     case OPR_AND: {
-      lua_assert(e1->t == NO_JUMP);  /* list closed by 'luK_infix' */
-      luaK_dischargevars(fs, e2);
+      lua_assert(e1->t == NO_JUMP);  /* list closed by 'luaK_infix' */
       luaK_concat(fs, &e2->f, e1->f);
       *e1 = *e2;
       break;
     }
     case OPR_OR: {
-      lua_assert(e1->f == NO_JUMP);  /* list closed by 'luK_infix' */
-      luaK_dischargevars(fs, e2);
+      lua_assert(e1->f == NO_JUMP);  /* list closed by 'luaK_infix' */
       luaK_concat(fs, &e2->t, e1->t);
       *e1 = *e2;
       break;

@@ -1556,35 +1644,39 @@
       break;
     }
     case OPR_ADD: case OPR_MUL: {
-      if (!constfolding(fs, opr + LUA_OPADD, e1, e2))
-        codecommutative(fs, cast(OpCode, opr + OP_ADD), e1, e2, line);
+      codecommutative(fs, opr, e1, e2, line);
       break;
     }
-    case OPR_SUB: case OPR_DIV:
-    case OPR_IDIV: case OPR_MOD: case OPR_POW: {
-      if (!constfolding(fs, opr + LUA_OPADD, e1, e2))
-        codearith(fs, cast(OpCode, opr + OP_ADD), e1, e2, 0, line);
+    case OPR_SUB: {
+      if (finishbinexpneg(fs, e1, e2, OP_ADDI, line, TM_SUB))
+        break; /* coded as (r1 + -I) */
+      /* ELSE *//* FALLTHROUGH */
+    }
+    case OPR_DIV: case OPR_IDIV: case OPR_MOD: case OPR_POW: {
+      codearith(fs, opr, e1, e2, 0, line);
       break;
     }
     case OPR_BAND: case OPR_BOR: case OPR_BXOR: {
-      if (!constfolding(fs, opr + LUA_OPADD, e1, e2))
-        codebitwise(fs, opr, e1, e2, line);
+      codebitwise(fs, opr, e1, e2, line);
       break;
     }
     case OPR_SHL: {
-      if (!constfolding(fs, LUA_OPSHL, e1, e2)) {
-        if (isSCint(e1)) {
-          swapexps(e1, e2);
-          codebini(fs, OP_SHLI, e1, e2, 1, line);
-        }
-        else
-          codeshift(fs, OP_SHL, e1, e2, line);
+      if (isSCint(e1)) {
+        swapexps(e1, e2);
+        codebini(fs, OP_SHLI, e1, e2, 1, line, TM_SHL);  /* I << r2 */
+      }
+      else if (finishbinexpneg(fs, e1, e2, OP_SHRI, line, TM_SHL)) {
+        /* coded as (r1 >> -I) */;
       }
+      else  /* regular case (two registers) */
+       codebinexpval(fs, OP_SHL, e1, e2, line);
       break;
     }
     case OPR_SHR: {
-      if (!constfolding(fs, LUA_OPSHR, e1, e2))
-        codeshift(fs, OP_SHR, e1, e2, line);
+      if (isSCint(e2))
+        codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR);  /* r1 >> I */
+      else  /* regular case (two registers) */
+        codebinexpval(fs, OP_SHR, e1, e2, line);
       break;
     }
     case OPR_EQ: case OPR_NE: {

@@ -1618,6 +1710,22 @@
 }
 
 
+void luaK_settablesize (FuncState *fs, int pc, int ra, int rc, int rb) {
+  Instruction *inst = &fs->f->code[pc];
+  int extra = 0;
+  int k = 0;
+  if (rb != 0)
+    rb = luaO_ceillog2(rb) + 1;  /* hash size */
+  if (rc > MAXARG_C) {  /* does it need the extra argument? */
+    extra = rc / (MAXARG_C + 1);
+    rc %= (MAXARG_C + 1);
+    k = 1;
+  }
+  *inst = CREATE_ABCk(OP_NEWTABLE, ra, rb, rc, k);
+  *(inst + 1) = CREATE_Ax(OP_EXTRAARG, extra);
+}
+
+
 /*
 ** Emit a SETLIST instruction.
 ** 'base' is register that keeps table;

@@ -1626,17 +1734,17 @@
 ** table (or LUA_MULTRET to add up to stack top).
 */
 void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
-  int c =  (nelems - 1)/LFIELDS_PER_FLUSH + 1;
-  int b = (tostore == LUA_MULTRET) ? 0 : tostore;
   lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH);
-  if (c <= MAXARG_C)
-    luaK_codeABC(fs, OP_SETLIST, base, b, c);
-  else if (c <= MAXARG_Ax) {
-    luaK_codeABC(fs, OP_SETLIST, base, b, 0);
-    codeextraarg(fs, c);
+  if (tostore == LUA_MULTRET)
+    tostore = 0;
+  if (nelems <= MAXARG_C)
+    luaK_codeABC(fs, OP_SETLIST, base, tostore, nelems);
+  else {
+    int extra = nelems / (MAXARG_C + 1);
+    nelems %= (MAXARG_C + 1);
+    luaK_codeABCk(fs, OP_SETLIST, base, tostore, nelems, 1);
+    codeextraarg(fs, extra);
   }
-  else
-    luaX_syntaxerror(fs->ls, "constructor too long");
   fs->freereg = base + 1;  /* free registers with list values */
 }
 

@@ -1675,10 +1783,10 @@
         SET_OPCODE(*pc, OP_RETURN);
       }  /* FALLTHROUGH */
       case OP_RETURN: case OP_TAILCALL: {
-        if (fs->needclose || p->is_vararg) {
-          SETARG_C(*pc, p->is_vararg ? p->numparams + 1 : 0);
-          SETARG_k(*pc, 1);  /* signal that there is extra work */
-        }
+        if (fs->needclose)
+          SETARG_k(*pc, 1);  /* signal that it needs to close */
+        if (p->is_vararg)
+          SETARG_C(*pc, p->numparams + 1);  /* signal that it is vararg */
         break;
       }
       case OP_JMP: {

src/lcode.h

@@ -24,19 +24,27 @@
 ** grep "ORDER OPR" if you change these enums  (ORDER OP)
 */
 typedef enum BinOpr {
+  /* arithmetic operators */
   OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW,
-  OPR_DIV,
-  OPR_IDIV,
+  OPR_DIV, OPR_IDIV,
+  /* bitwise operators */
   OPR_BAND, OPR_BOR, OPR_BXOR,
   OPR_SHL, OPR_SHR,
+  /* string operator */
   OPR_CONCAT,
+  /* comparison operators */
   OPR_EQ, OPR_LT, OPR_LE,
   OPR_NE, OPR_GT, OPR_GE,
+  /* logical operators */
   OPR_AND, OPR_OR,
   OPR_NOBINOPR
 } BinOpr;
 
 
+/* true if operation is foldable (that is, it is arithmetic or bitwise) */
+#define foldbinop(op)	((op) <= OPR_SHR)
+
+
 #define luaK_codeABC(fs,o,a,b,c)	luaK_codeABCk(fs,o,a,b,c,0)
 
 

@@ -51,16 +59,17 @@
 
 #define luaK_jumpto(fs,t)	luaK_patchlist(fs, luaK_jump(fs), t)
 
+LUAI_FUNC int luaK_code (FuncState *fs, Instruction i);
 LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
 LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx);
 LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
                                             int B, int C, int k);
 LUAI_FUNC int luaK_isKint (expdesc *e);
+LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
 LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
 LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
 LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
 LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
-LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s);
 LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n);
 LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
 LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);

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

src/ldblib.c

@@ -21,10 +21,10 @@
 
 
 /*
-** The hook table at registry[&HOOKKEY] maps threads to their current
-** hook function. (We only need the unique address of 'HOOKKEY'.)
+** The hook table at registry[HOOKKEY] maps threads to their current
+** hook function.
 */
-static const int HOOKKEY = 0;
+static const char* HOOKKEY = "_HOOKKEY";
 
 
 /*

@@ -65,7 +65,7 @@
 static int db_getuservalue (lua_State *L) {
   int n = (int)luaL_optinteger(L, 2, 1);
   if (lua_type(L, 1) != LUA_TUSERDATA)
-    lua_pushnil(L);
+    luaL_pushfail(L);
   else if (lua_getiuservalue(L, 1, n) != LUA_TNONE) {
     lua_pushboolean(L, 1);
     return 2;

@@ -80,7 +80,7 @@
   luaL_checkany(L, 2);
   lua_settop(L, 2);
   if (!lua_setiuservalue(L, 1, n))
-    lua_pushnil(L);
+    luaL_pushfail(L);
   return 1;
 }
 

@@ -159,7 +159,7 @@
   }
   else {  /* stack level */
     if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) {
-      lua_pushnil(L);  /* level out of range */
+      luaL_pushfail(L);  /* level out of range */
       return 1;
     }
   }

@@ -223,7 +223,7 @@
       return 2;
     }
     else {
-      lua_pushnil(L);  /* no name (nor value) */
+      luaL_pushfail(L);  /* no name (nor value) */
       return 1;
     }
   }

@@ -314,7 +314,7 @@
 static void hookf (lua_State *L, lua_Debug *ar) {
   static const char *const hooknames[] =
     {"call", "return", "line", "count", "tail call"};
-  lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
+  lua_getfield(L, LUA_REGISTRYINDEX, HOOKKEY);
   lua_pushthread(L);
   if (lua_rawget(L, -2) == LUA_TFUNCTION) {  /* is there a hook function? */
     lua_pushstring(L, hooknames[(int)ar->event]);  /* push event name */

@@ -367,14 +367,12 @@
     count = (int)luaL_optinteger(L, arg + 3, 0);
     func = hookf; mask = makemask(smask, count);
   }
-  if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) {
-    lua_createtable(L, 0, 2);  /* create a hook table */
-    lua_pushvalue(L, -1);
-    lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY);  /* set it in position */
+  if (!luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)) {
+    /* table just created; initialize it */
     lua_pushstring(L, "k");
     lua_setfield(L, -2, "__mode");  /** hooktable.__mode = "k" */
     lua_pushvalue(L, -1);
-    lua_setmetatable(L, -2);  /* setmetatable(hooktable) = hooktable */
+    lua_setmetatable(L, -2);  /* metatable(hooktable) = hooktable */
   }
   checkstack(L, L1, 1);
   lua_pushthread(L1); lua_xmove(L1, L, 1);  /* key (thread) */

@@ -391,12 +389,14 @@
   char buff[5];
   int mask = lua_gethookmask(L1);
   lua_Hook hook = lua_gethook(L1);
-  if (hook == NULL)  /* no hook? */
-    lua_pushnil(L);
+  if (hook == NULL) {  /* no hook? */
+    luaL_pushfail(L);
+    return 1;
+  }
   else if (hook != hookf)  /* external hook? */
     lua_pushliteral(L, "external hook");
   else {  /* hook table must exist */
-    lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
+    lua_getfield(L, LUA_REGISTRYINDEX, HOOKKEY);
     checkstack(L, L1, 1);
     lua_pushthread(L1); lua_xmove(L1, L, 1);
     lua_rawget(L, -2);   /* 1st result = hooktable[L1] */

@@ -437,6 +437,17 @@
 }
 
 
+static int db_setcstacklimit (lua_State *L) {
+  int limit = (int)luaL_checkinteger(L, 1);
+  int res = lua_setcstacklimit(L, limit);
+  if (res == 0)
+    lua_pushboolean(L, 0);
+  else
+    lua_pushinteger(L, res);
+  return 1;
+}
+
+
 static const luaL_Reg dblib[] = {
   {"debug", db_debug},
   {"getuservalue", db_getuservalue},

@@ -454,6 +465,7 @@
   {"setmetatable", db_setmetatable},
   {"setupvalue", db_setupvalue},
   {"traceback", db_traceback},
+  {"setcstacklimit", db_setcstacklimit},
   {NULL, NULL}
 };
 

src/ldebug.c

@@ -465,12 +465,14 @@
 
 
 /*
-** try to find last instruction before 'lastpc' that modified register 'reg'
+** Try to find last instruction before 'lastpc' that modified register 'reg'.
 */
 static int findsetreg (const Proto *p, int lastpc, int reg) {
   int pc;
   int setreg = -1;  /* keep last instruction that changed 'reg' */
   int jmptarget = 0;  /* any code before this address is conditional */
+  if (testMMMode(GET_OPCODE(p->code[lastpc])))
+    lastpc--;  /* previous instruction was not actually executed */
   for (pc = 0; pc < lastpc; pc++) {
     Instruction i = p->code[pc];
     OpCode op = GET_OPCODE(i);

@@ -620,24 +622,8 @@
     case OP_SETTABUP: case OP_SETTABLE: case OP_SETI: case OP_SETFIELD:
       tm = TM_NEWINDEX;
       break;
-    case OP_ADDI: case OP_SUBI: case OP_MULI: case OP_MODI:
-    case OP_POWI: case OP_DIVI: case OP_IDIVI: {
-      int offset = GET_OPCODE(i) - OP_ADDI;  /* ORDER OP */
-      tm = cast(TMS, offset + TM_ADD);  /* ORDER TM */
-      break;
-    }
-    case OP_ADDK: case OP_SUBK: case OP_MULK: case OP_MODK:
-    case OP_POWK: case OP_DIVK: case OP_IDIVK:
-    case OP_BANDK: case OP_BORK: case OP_BXORK: {
-      int offset = GET_OPCODE(i) - OP_ADDK;  /* ORDER OP */
-      tm = cast(TMS, offset + TM_ADD);  /* ORDER TM */
-      break;
-    }
-    case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD:
-    case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND:
-    case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: {
-      int offset = GET_OPCODE(i) - OP_ADD;  /* ORDER OP */
-      tm = cast(TMS, offset + TM_ADD);  /* ORDER TM */
+    case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
+      tm = cast(TMS, GETARG_C(i));
       break;
     }
     case OP_UNM: tm = TM_UNM; break;

@@ -648,8 +634,8 @@
     case OP_LT: case OP_LE: case OP_LTI: case OP_LEI:
       *name = "order";  /* '<=' can call '__lt', etc. */
       return "metamethod";
-    case OP_SHRI: case OP_SHLI:
-      *name = "shift";
+    case OP_CLOSE: case OP_RETURN:
+      *name = "close";
       return "metamethod";
     default:
       return NULL;  /* cannot find a reasonable name */

src/ldo.c

@@ -139,9 +139,9 @@
 
 
 int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
-  l_uint32 oldnCcalls = L->nCcalls - L->nci;
+  global_State *g = G(L);
+  l_uint32 oldnCcalls = g->Cstacklimit - (L->nCcalls + L->nci);
   struct lua_longjmp lj;
-  lua_assert(L->nCcalls >= L->nci);
   lj.status = LUA_OK;
   lj.previous = L->errorJmp;  /* chain new error handler */
   L->errorJmp = &lj;

@@ -149,7 +149,7 @@
     (*f)(L, ud);
   );
   L->errorJmp = lj.previous;  /* restore old error handler */
-  L->nCcalls = oldnCcalls + L->nci;
+  L->nCcalls = g->Cstacklimit - oldnCcalls - L->nci;
   return lj.status;
 }
 

@@ -348,18 +348,18 @@
 
 
 /*
-** Check whether __call metafield of 'func' is a function. If so, put
-** it in stack below original 'func' so that 'luaD_call' can call
-** it. Raise an error if __call metafield is not a function.
+** Check whether 'func' has a '__call' metafield. If so, put it in the
+** stack, below original 'func', so that 'luaD_call' can call it. Raise
+** 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 p;
-  if (unlikely(!ttisfunction(tm)))
-    luaG_typeerror(L, s2v(func), "call");
-  for (p = L->top; p > func; p--)
+  if (unlikely(ttisnil(tm)))
+    luaG_typeerror(L, s2v(func), "call");  /* nothing to call */
+  for (p = L->top; p > func; p--)  /* open space for metamethod */
     setobjs2s(L, p, p-1);
-  L->top++;  /* assume EXTRA_STACK */
+  L->top++;  /* stack space pre-allocated by the caller */
   setobj2s(L, func, tm);  /* metamethod is the new function to be called */
 }
 

@@ -457,13 +457,13 @@
 */
 void luaD_call (lua_State *L, StkId func, int nresults) {
   lua_CFunction f;
-  TValue *funcv = s2v(func);
-  switch (ttypetag(funcv)) {
+ retry:
+  switch (ttypetag(s2v(func))) {
     case LUA_TCCL:  /* C closure */
-      f = clCvalue(funcv)->f;
+      f = clCvalue(s2v(func))->f;
       goto Cfunc;
     case LUA_TLCF:  /* light C function */
-      f = fvalue(funcv);
+      f = fvalue(s2v(func));
      Cfunc: {
       int n;  /* number of returns */
       CallInfo *ci;

@@ -487,7 +487,7 @@
     }
     case LUA_TLCL: {  /* Lua function */
       CallInfo *ci;
-      Proto *p = clLvalue(funcv)->p;
+      Proto *p = clLvalue(s2v(func))->p;
       int narg = cast_int(L->top - func) - 1;  /* number of real arguments */
       int nfixparams = p->numparams;
       int fsize = p->maxstacksize;  /* frame size */

@@ -505,9 +505,9 @@
       break;
     }
     default: {  /* not a function */
+      checkstackp(L, 1, func);  /* space for metamethod */
       luaD_tryfuncTM(L, func);  /* try to get '__call' metamethod */
-      luaD_call(L, func, nresults);  /* now it must be a function */
-      break;
+      goto retry;  /* try again with metamethod */
     }
   }
 }

@@ -521,7 +521,7 @@
 */
 void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
   incXCcalls(L);
-  if (getCcalls(L) >= LUAI_MAXCSTACK)  /* possible stack overflow? */
+  if (getCcalls(L) <= CSTACKERR)  /* possible stack overflow? */
     luaE_freeCI(L);
   luaD_call(L, func, nResults);
   decXCcalls(L);

@@ -672,10 +672,10 @@
   else if (L->status != LUA_YIELD)  /* ended with errors? */
     return resume_error(L, "cannot resume dead coroutine", nargs);
   if (from == NULL)
-    L->nCcalls = 1;
+    L->nCcalls = CSTACKTHREAD;
   else  /* correct 'nCcalls' for this thread */
-    L->nCcalls = getCcalls(from) - from->nci + L->nci + CSTACKCF;
-  if (L->nCcalls >= LUAI_MAXCSTACK)
+    L->nCcalls = getCcalls(from) + from->nci - L->nci - CSTACKCF;
+  if (L->nCcalls <= CSTACKERR)
     return resume_error(L, "C stack overflow", nargs);
   luai_userstateresume(L, nargs);
   api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);

src/ldump.c

@@ -149,6 +149,7 @@
   for (i = 0; i < n; i++) {
     DumpByte(f->upvalues[i].instack, D);
     DumpByte(f->upvalues[i].idx, D);
+    DumpByte(f->upvalues[i].kind, D);
   }
 }
 

src/lfunc.c

@@ -59,14 +59,15 @@
 
 
 /*
-** Create a new upvalue with the given tag at the given level,
-** and link it to the list of open upvalues of 'L' after entry 'prev'.
+** Create a new upvalue at the given level, and link it to the list of
+** open upvalues of 'L' after entry 'prev'.
 **/
-static UpVal *newupval (lua_State *L, int tag, StkId level, UpVal **prev) {
-  GCObject *o = luaC_newobj(L, tag, sizeof(UpVal));
+static UpVal *newupval (lua_State *L, int tbc, StkId level, UpVal **prev) {
+  GCObject *o = luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal));
   UpVal *uv = gco2upv(o);
   UpVal *next = *prev;
   uv->v = s2v(level);  /* current value lives in the stack */
+  uv->tbc = tbc;
   uv->u.open.next = next;  /* link it to list of open upvalues */
   uv->u.open.previous = prev;
   if (next)

@@ -81,7 +82,7 @@
 
 
 /*
-** Find and reuse, or create if it does not exist, a regular upvalue
+** Find and reuse, or create if it does not exist, an upvalue
 ** at the given level.
 */
 UpVal *luaF_findupval (lua_State *L, StkId level) {

@@ -89,12 +90,13 @@
   UpVal *p;
   lua_assert(isintwups(L) || L->openupval == NULL);
   while ((p = *pp) != NULL && uplevel(p) >= level) {  /* search for it */
-    if (uplevel(p) == level && !isdead(G(L), p))  /* corresponding upvalue? */
+    lua_assert(!isdead(G(L), p));
+    if (uplevel(p) == level)  /* corresponding upvalue? */
       return p;  /* return it */
     pp = &p->u.open.next;
   }
   /* not found: create a new upvalue after 'pp' */
-  return newupval(L, LUA_TUPVAL, level, pp);
+  return newupval(L, 0, level, pp);
 }
 
 

@@ -122,38 +124,52 @@
 
 
 /*
+** Raise an error with message 'msg', inserting the name of the
+** local variable at position 'level' in the stack.
+*/
+static void varerror (lua_State *L, StkId level, const char *msg) {
+  int idx = cast_int(level - L->ci->func);
+  const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
+  if (vname == NULL) vname = "?";
+  luaG_runerror(L, msg, vname);
+}
+
+
+/*
 ** Prepare and call a closing method. If status is OK, code is still
 ** inside the original protected call, and so any error will be handled
-** there. Otherwise, a previous error already activated original
+** there. Otherwise, a previous error already activated the original
 ** protected call, and so the call to the closing method must be
-** protected here. (A status = CLOSEPROTECT behaves like a previous
+** protected here. (A status == CLOSEPROTECT behaves like a previous
 ** error, to also run the closing method in protected mode).
 ** If status is OK, the call to the closing method will be pushed
 ** at the top of the stack. Otherwise, values are pushed after
 ** the 'level' of the upvalue being closed, as everything after
 ** that won't be used again.
 */
-static int callclosemth (lua_State *L, TValue *uv, StkId level, int status) {
+static int callclosemth (lua_State *L, StkId level, int status) {
+  TValue *uv = s2v(level);  /* value being closed */
   if (likely(status == LUA_OK)) {
     if (prepclosingmethod(L, uv, &G(L)->nilvalue))  /* something to call? */
       callclose(L, NULL);  /* call closing method */
-    else if (!ttisnil(uv)) {  /* non-closable non-nil value? */
-      int idx = cast_int(level - L->ci->func);
-      const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
-      if (vname == NULL) vname = "?";
-      luaG_runerror(L, "attempt to close non-closable variable '%s'", vname);
-    }
+    else if (!l_isfalse(uv))  /* non-closable non-false value? */
+      varerror(L, level, "attempt to close non-closable variable '%s'");
   }
   else {  /* must close the object in protected mode */
-    ptrdiff_t oldtop = savestack(L, level + 1);
-    /* save error message and set stack top to 'level + 1' */
-    luaD_seterrorobj(L, status, level);
+    ptrdiff_t oldtop;
+    level++;  /* space for error message */
+    oldtop = savestack(L, level + 1);  /* top will be after that */
+    luaD_seterrorobj(L, status, level);  /* set error message */
     if (prepclosingmethod(L, uv, s2v(level))) {  /* something to call? */
       int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0);
       if (newstatus != LUA_OK && status == CLOSEPROTECT)  /* first error? */
         status = newstatus;  /* this will be the new error */
-      else  /* leave original error (or nil) on top */
+      else {
+        if (newstatus != LUA_OK)  /* supressed error? */
+          luaE_warnerror(L, "__close metamethod");
+        /* leave original error (or nil) on top */
         L->top = restorestack(L, oldtop);
+      }
     }
     /* else no metamethod; ignore this case and keep original error */
   }

@@ -166,9 +182,7 @@
 ** (can raise a memory-allocation error)
 */
 static void trynewtbcupval (lua_State *L, void *ud) {
-  StkId level = cast(StkId, ud);
-  lua_assert(L->openupval == NULL || uplevel(L->openupval) < level);
-  newupval(L, LUA_TUPVALTBC, level, &L->openupval);
+  newupval(L, 1, cast(StkId, ud), &L->openupval);
 }
 
 

@@ -178,13 +192,22 @@
 ** as there is no upvalue to call it later.
 */
 void luaF_newtbcupval (lua_State *L, StkId level) {
-  int status = luaD_rawrunprotected(L, trynewtbcupval, level);
-  if (unlikely(status != LUA_OK)) {  /* memory error creating upvalue? */
-    lua_assert(status == LUA_ERRMEM);
-    luaD_seterrorobj(L, LUA_ERRMEM, level + 1);  /* save error message */
-    if (prepclosingmethod(L, s2v(level), s2v(level + 1)))
+  TValue *obj = s2v(level);
+  lua_assert(L->openupval == NULL || uplevel(L->openupval) < level);
+  if (!l_isfalse(obj)) {  /* false doesn't need to be closed */
+    int status;
+    const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
+    if (ttisnil(tm))  /* no metamethod? */
+      varerror(L, level, "variable '%s' got a non-closable value");
+    status = luaD_rawrunprotected(L, trynewtbcupval, level);
+    if (unlikely(status != LUA_OK)) {  /* memory error creating upvalue? */
+      lua_assert(status == LUA_ERRMEM);
+      luaD_seterrorobj(L, LUA_ERRMEM, level + 1);  /* save error message */
+      /* next call must succeed, as object is closable */
+      prepclosingmethod(L, s2v(level), s2v(level + 1));
       callclose(L, NULL);  /* call closing method */
-    luaD_throw(L, LUA_ERRMEM);  /* throw memory error */
+      luaD_throw(L, LUA_ERRMEM);  /* throw memory error */
+    }
   }
 }
 

@@ -200,20 +223,20 @@
 int luaF_close (lua_State *L, StkId level, int status) {
   UpVal *uv;
   while ((uv = L->openupval) != NULL && uplevel(uv) >= level) {
-    StkId upl = uplevel(uv);
     TValue *slot = &uv->u.value;  /* new position for value */
+    lua_assert(uplevel(uv) < L->top);
+    if (uv->tbc && status != NOCLOSINGMETH) {
+      /* must run closing method, which may change the stack */
+      ptrdiff_t levelrel = savestack(L, level);
+      status = callclosemth(L, uplevel(uv), status);
+      level = restorestack(L, levelrel);
+    }
     luaF_unlinkupval(uv);
     setobj(L, slot, uv->v);  /* move value to upvalue slot */
     uv->v = slot;  /* now current value lives here */
     if (!iswhite(uv))
       gray2black(uv);  /* closed upvalues cannot be gray */
     luaC_barrier(L, uv, slot);
-    if (uv->tt == LUA_TUPVALTBC && status != NOCLOSINGMETH) {
-      /* must run closing method */
-      ptrdiff_t levelrel = savestack(L, level);
-      status = callclosemth(L, uv->v, upl, status);  /* may change the stack */
-      level = restorestack(L, levelrel);
-    }
   }
   return status;
 }

src/lgc.c

@@ -273,8 +273,7 @@
       gray2black(o);
       break;
     }
-    case LUA_TUPVAL:
-    case LUA_TUPVALTBC: {
+    case LUA_TUPVAL: {
       UpVal *uv = gco2upv(o);
       if (!upisopen(uv))  /* open upvalues are kept gray */
         gray2black(o);

@@ -414,13 +413,13 @@
 ** (in the atomic phase). In generational mode, it (like all visited
 ** tables) must be kept in some gray list for post-processing.
 */
-static int traverseephemeron (global_State *g, Table *h) {
+static int traverseephemeron (global_State *g, Table *h, int inv) {
   int marked = 0;  /* true if an object is marked in this traversal */
   int hasclears = 0;  /* true if table has white keys */
   int hasww = 0;  /* true if table has entry "white-key -> white-value" */
-  Node *n, *limit = gnodelast(h);
   unsigned int i;
   unsigned int asize = luaH_realasize(h);
+  unsigned int nsize = sizenode(h);
   /* traverse array part */
   for (i = 0; i < asize; i++) {
     if (valiswhite(&h->array[i])) {

@@ -428,8 +427,10 @@
       reallymarkobject(g, gcvalue(&h->array[i]));
     }
   }
-  /* traverse hash part */
-  for (n = gnode(h, 0); n < limit; n++) {
+  /* traverse hash part; if 'inv', traverse descending
+     (see 'convergeephemerons') */
+  for (i = 0; i < nsize; i++) {
+    Node *n = inv ? gnode(h, nsize - 1 - i) : gnode(h, i);
     if (isempty(gval(n)))  /* entry is empty? */
       clearkey(n);  /* clear its key */
     else if (iscleared(g, gckeyN(n))) {  /* key is not marked (yet)? */

@@ -491,7 +492,7 @@
     if (!weakkey)  /* strong keys? */
       traverseweakvalue(g, h);
     else if (!weakvalue)  /* strong values? */
-      traverseephemeron(g, h);
+      traverseephemeron(g, h, 0);
     else  /* all weak */
       linkgclist(h, g->allweak);  /* nothing to traverse now */
   }

@@ -570,10 +571,8 @@
              th->openupval == NULL || isintwups(th));
   for (; o < th->top; o++)  /* mark live elements in the stack */
     markvalue(g, s2v(o));
-  for (uv = th->openupval; uv != NULL; uv = uv->u.open.next) {
-    if (uv->tt == LUA_TUPVALTBC)  /* to be closed? */
-      markobject(g, uv);  /* cannot be collected */
-  }
+  for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
+    markobject(g, uv);  /* open upvalues cannot be collected */
   if (g->gcstate == GCSatomic) {  /* final traversal? */
     StkId lim = th->stack + th->stacksize;  /* real end of stack */
     for (; o < lim; o++)  /* clear not-marked stack slice */

@@ -623,21 +622,30 @@
 }
 
 
+/*
+** Traverse all ephemeron tables propagating marks from keys to values.
+** Repeat until it converges, that is, nothing new is marked. 'dir'
+** inverts the direction of the traversals, trying to speed up
+** convergence on chains in the same table.
+**
+*/
 static void convergeephemerons (global_State *g) {
   int changed;
+  int dir = 0;
   do {
     GCObject *w;
     GCObject *next = g->ephemeron;  /* get ephemeron list */
     g->ephemeron = NULL;  /* tables may return to this list when traversed */
     changed = 0;
-    while ((w = next) != NULL) {
-      next = gco2t(w)->gclist;
-      if (traverseephemeron(g, gco2t(w))) {  /* traverse marked some value? */
+    while ((w = next) != NULL) {  /* for each ephemeron table */
+      next = gco2t(w)->gclist;  /* list is rebuilt during loop */
+      if (traverseephemeron(g, gco2t(w), dir)) {  /* marked some value? */
         propagateall(g);  /* propagate changes */
         changed = 1;  /* will have to revisit all ephemeron tables */
       }
     }
-  } while (changed);
+    dir = !dir;  /* invert direction next time */
+  } while (changed);  /* repeat until no more changes */
 }
 
 /* }====================================================== */

@@ -706,7 +714,6 @@
       luaF_freeproto(L, gco2p(o));
       break;
     case LUA_TUPVAL:
-    case LUA_TUPVALTBC:
       freeupval(L, gco2upv(o));
       break;
     case LUA_TLCL:

@@ -794,10 +801,11 @@
 */
 static void checkSizes (lua_State *L, global_State *g) {
   if (!g->gcemergency) {
-    l_mem olddebt = g->GCdebt;
-    if (g->strt.nuse < g->strt.size / 4)  /* string table too big? */
+    if (g->strt.nuse < g->strt.size / 4) {  /* string table too big? */
+      l_mem olddebt = g->GCdebt;
       luaS_resize(L, g->strt.size / 2);
-    g->GCestimate += g->GCdebt - olddebt;  /* correct estimate */
+      g->GCestimate += g->GCdebt - olddebt;  /* correct estimate */
+    }
   }
 }
 

@@ -838,21 +846,16 @@
     int running  = g->gcrunning;
     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 + 1, &v);  /* ... and its argument */
-    L->top += 2;  /* and (next line) call the finalizer */
+    setobj2s(L, L->top++, tm);  /* push finalizer... */
+    setobj2s(L, L->top++, &v);  /* ... and its argument */
     L->ci->callstatus |= CIST_FIN;  /* will run a finalizer */
     status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
     L->ci->callstatus &= ~CIST_FIN;  /* not running a finalizer anymore */
     L->allowhook = oldah;  /* restore hooks */
     g->gcrunning = running;  /* restore state */
-    if (status != LUA_OK) {  /* error while running __gc? */
-      const char *msg = (ttisstring(s2v(L->top - 1)))
-                        ? svalue(s2v(L->top - 1))
-                        : "error object is not a string";
-      luaE_warning(L, "error in __gc metamethod (", 1);
-      luaE_warning(L, msg, 1);
-      luaE_warning(L, ")", 0);
+    if (unlikely(status != LUA_OK)) {  /* error while running __gc? */
+      luaE_warnerror(L, "__gc metamethod");
+      L->top--;  /* pops error object */
     }
   }
 }

@@ -1250,7 +1253,7 @@
 /*
 ** Does a major collection after last collection was a "bad collection".
 **
-** When the program is building a big struture, it allocates lots of
+** When the program is building a big structure, it allocates lots of
 ** memory but generates very little garbage. In those scenarios,
 ** the generational mode just wastes time doing small collections, and
 ** major collections are frequently what we call a "bad collection", a

src/liolib.c

@@ -153,7 +153,7 @@
   luaL_checkany(L, 1);
   p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE);
   if (p == NULL)
-    lua_pushnil(L);  /* not a file */
+    luaL_pushfail(L);  /* not a file */
   else if (isclosed(p))
     lua_pushliteral(L, "closed file");
   else

@@ -338,7 +338,7 @@
 #define MAXARGLINE	250
 
 /*
-** Auxiliar function to create the iteration function for 'lines'.
+** Auxiliary function to create the iteration function for 'lines'.
 ** The iteration function is a closure over 'io_readline', with
 ** the following upvalues:
 ** 1) The file being read (first value in the stack)

@@ -593,7 +593,7 @@
     return luaL_fileresult(L, 0, NULL);
   if (!success) {
     lua_pop(L, 1);  /* remove last result */
-    lua_pushnil(L);  /* push nil instead */
+    luaL_pushfail(L);  /* push nil instead */
   }
   return n - first;
 }

@@ -626,7 +626,7 @@
   lua_assert(n > 0);  /* should return at least a nil */
   if (lua_toboolean(L, -n))  /* read at least one value? */
     return n;  /* return them */
-  else {  /* first result is nil: EOF or error */
+  else {  /* first result is false: EOF or error */
     if (n > 1) {  /* is there error information? */
       /* 2nd result is error message */
       return luaL_error(L, "%s", lua_tostring(L, -n + 1));

@@ -742,14 +742,23 @@
 /*
 ** methods for file handles
 */
-static const luaL_Reg flib[] = {
-  {"close", f_close},
-  {"flush", f_flush},
-  {"lines", f_lines},
+static const luaL_Reg meth[] = {
   {"read", f_read},
+  {"write", f_write},
+  {"lines", f_lines},
+  {"flush", f_flush},
   {"seek", f_seek},
+  {"close", f_close},
   {"setvbuf", f_setvbuf},
-  {"write", f_write},
+  {NULL, NULL}
+};
+
+
+/*
+** metamethods for file handles
+*/
+static const luaL_Reg metameth[] = {
+  {"__index", NULL},  /* place holder */
   {"__gc", f_gc},
   {"__close", f_gc},
   {"__tostring", f_tostring},

@@ -758,11 +767,12 @@
 
 
 static void createmeta (lua_State *L) {
-  luaL_newmetatable(L, LUA_FILEHANDLE);  /* create metatable for file handles */
-  lua_pushvalue(L, -1);  /* push metatable */
-  lua_setfield(L, -2, "__index");  /* metatable.__index = metatable */
-  luaL_setfuncs(L, flib, 0);  /* add file methods to new metatable */
-  lua_pop(L, 1);  /* pop new metatable */
+  luaL_newmetatable(L, LUA_FILEHANDLE);  /* metatable for file handles */
+  luaL_setfuncs(L, metameth, 0);  /* add metamethods to new metatable */
+  luaL_newlibtable(L, meth);  /* create method table */
+  luaL_setfuncs(L, meth, 0);  /* add file methods to method table */
+  lua_setfield(L, -2, "__index");  /* metatable.__index = method table */
+  lua_pop(L, 1);  /* pop metatable */
 }
 
 

@@ -772,7 +782,7 @@
 static int io_noclose (lua_State *L) {
   LStream *p = tolstream(L);
   p->closef = &io_noclose;  /* keep file opened */
-  lua_pushnil(L);
+  luaL_pushfail(L);
   lua_pushliteral(L, "cannot close standard file");
   return 2;
 }

src/ljumptab.h

@@ -45,12 +45,6 @@
 &&L_OP_NEWTABLE,
 &&L_OP_SELF,
 &&L_OP_ADDI,
-&&L_OP_SUBI,
-&&L_OP_MULI,
-&&L_OP_MODI,
-&&L_OP_POWI,
-&&L_OP_DIVI,
-&&L_OP_IDIVI,
 &&L_OP_ADDK,
 &&L_OP_SUBK,
 &&L_OP_MULK,

@@ -75,6 +69,9 @@
 &&L_OP_BXOR,
 &&L_OP_SHL,
 &&L_OP_SHR,
+&&L_OP_MMBIN,
+&&L_OP_MMBINI,
+&&L_OP_MMBINK,
 &&L_OP_UNM,
 &&L_OP_BNOT,
 &&L_OP_NOT,

src/llex.c

@@ -211,8 +211,16 @@
 
 /* LUA_NUMBER */
 /*
-** this function is quite liberal in what it accepts, as 'luaO_str2num'
-** will reject ill-formed numerals.
+** This function is quite liberal in what it accepts, as 'luaO_str2num'
+** will reject ill-formed numerals. Roughly, it accepts the following
+** pattern:
+**
+**   %d(%x|%.|([Ee][+-]?))* | 0[Xx](%x|%.|([Pp][+-]?))*
+**
+** The only tricky part is to accept [+-] only after a valid exponent
+** mark, to avoid reading '3-4' or '0xe+1' as a single number.
+**
+** The caller might have already read an initial dot.
 */
 static int read_numeral (LexState *ls, SemInfo *seminfo) {
   TValue obj;

@@ -223,15 +231,13 @@
   if (first == '0' && check_next2(ls, "xX"))  /* hexadecimal? */
     expo = "Pp";
   for (;;) {
-    if (check_next2(ls, expo))  /* exponent part? */
+    if (check_next2(ls, expo))  /* exponent mark? */
       check_next2(ls, "-+");  /* optional exponent sign */
-    if (lisxdigit(ls->current))
-      save_and_next(ls);
-    else if (ls->current == '.')
+    else if (lisxdigit(ls->current) || ls->current == '.')  /* '%x|%.' */
       save_and_next(ls);
     else break;
   }
-  if (lislalnum(ls->current))  /* is numeral touching an alpha num? */
+  if (lislalpha(ls->current))  /* is numeral touching a letter? */
     save_and_next(ls);  /* force an error */
   save(ls, '\0');
   if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0)  /* format error? */

src/lmathlib.c

@@ -77,7 +77,7 @@
     lua_pushinteger(L, n);
   else {
     luaL_checkany(L, 1);
-    lua_pushnil(L);  /* value is not convertible to integer */
+    luaL_pushfail(L);  /* value is not convertible to integer */
   }
   return 1;
 }

@@ -235,7 +235,7 @@
     lua_pushstring(L, (lua_isinteger(L, 1)) ? "integer" : "float");
   else {
     luaL_checkany(L, 1);
-    lua_pushnil(L);
+    luaL_pushfail(L);
   }
   return 1;
 }

@@ -586,7 +586,8 @@
 }
 
 
-static void setseed (Rand64 *state, lua_Unsigned n1, lua_Unsigned n2) {
+static void setseed (lua_State *L, Rand64 *state,
+                     lua_Unsigned n1, lua_Unsigned n2) {
   int i;
   state[0] = Int2I(n1);
   state[1] = Int2I(0xff);  /* avoid a zero state */

@@ -594,6 +595,8 @@
   state[3] = Int2I(0);
   for (i = 0; i < 16; i++)
     nextrand(state);  /* discard initial values to "spread" seed */
+  lua_pushinteger(L, n1);
+  lua_pushinteger(L, n2);
 }
 
 

@@ -605,20 +608,21 @@
 static void randseed (lua_State *L, RanState *state) {
   lua_Unsigned seed1 = (lua_Unsigned)time(NULL);
   lua_Unsigned seed2 = (lua_Unsigned)(size_t)L;
-  setseed(state->s, seed1, seed2);
+  setseed(L, state->s, seed1, seed2);
 }
 
 
 static int math_randomseed (lua_State *L) {
   RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1));
-  if (lua_isnone(L, 1))
+  if (lua_isnone(L, 1)) {
     randseed(L, state);
+  }
   else {
     lua_Integer n1 = luaL_checkinteger(L, 1);
     lua_Integer n2 = luaL_optinteger(L, 2, 0);
-    setseed(state->s, n1, n2);
+    setseed(L, state->s, n1, n2);
   }
-  return 0;
+  return 2;  /* return seeds */
 }
 
 

@@ -635,6 +639,7 @@
 static void setrandfunc (lua_State *L) {
   RanState *state = (RanState *)lua_newuserdatauv(L, sizeof(RanState), 0);
   randseed(L, state);  /* initialize with a "random" seed */
+  lua_pop(L, 2);  /* remove pushed seeds */
   luaL_setfuncs(L, randfuncs, 1);
 }
 

src/lmem.c

@@ -23,33 +23,56 @@
 
 
 #if defined(HARDMEMTESTS)
-#define hardtest(L,os,s)  /* force a GC whenever possible */ \
-  if ((s) > (os) && (G(L))->gcrunning) luaC_fullgc(L, 1);
+/*
+** First allocation will fail whenever not building initial state
+** and not shrinking a block. (This fail will trigger 'tryagain' and
+** a full GC cycle at every alocation.)
+*/
+static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
+  if (ttisnil(&g->nilvalue) && ns > os)
+    return NULL;  /* fail */
+  else  /* normal allocation */
+    return (*g->frealloc)(g->ud, block, os, ns);
+}
 #else
-#define hardtest(L,os,s)  ((void)0)
+#define firsttry(g,block,os,ns)    ((*g->frealloc)(g->ud, block, os, ns))
 #endif
 
 
 
+
+
 /*
 ** About the realloc function:
-** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
+** void *frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
 ** ('osize' is the old size, 'nsize' is the new size)
 **
-** * frealloc(ud, NULL, x, s) creates a new block of size 's' (no
-** matter 'x').
+** - frealloc(ud, p, x, 0) frees the block 'p' and returns NULL.
+** Particularly, frealloc(ud, NULL, 0, 0) does nothing,
+** which is equivalent to free(NULL) in ISO C.
 **
-** * frealloc(ud, p, x, 0) frees the block 'p'
-** (in this specific case, frealloc must return NULL);
-** particularly, frealloc(ud, NULL, 0, 0) does nothing
-** (which is equivalent to free(NULL) in ISO C)
+** - frealloc(ud, NULL, x, s) creates a new block of size 's'
+** (no matter 'x'). Returns NULL if it cannot create the new block.
 **
-** frealloc returns NULL if it cannot create or reallocate the area
-** (any reallocation to an equal or smaller size cannot fail!)
+** - otherwise, frealloc(ud, b, x, y) reallocates the block 'b' from
+** size 'x' to size 'y'. Returns NULL if it cannot reallocate the
+** block to the new size.
 */
 
 
 
+
+/*
+** {==================================================================
+** Functions to allocate/deallocate arrays for the Parser
+** ===================================================================
+*/
+
+/*
+** Minimum size for arrays during parsing, to avoid overhead of
+** reallocating to size 1, then 2, and then 4. All these arrays
+** will be reallocated to exact sizes or erased when parsing ends.
+*/
 #define MINSIZEARRAY	4
 
 

@@ -71,32 +94,32 @@
   }
   lua_assert(nelems + 1 <= size && size <= limit);
   /* 'limit' ensures that multiplication will not overflow */
-  newblock = luaM_realloc_(L, block, cast_sizet(*psize) * size_elems,
-                                     cast_sizet(size) * size_elems);
-  if (unlikely(newblock == NULL))
-    luaM_error(L);
+  newblock = luaM_saferealloc_(L, block, cast_sizet(*psize) * size_elems,
+                                         cast_sizet(size) * size_elems);
   *psize = size;  /* update only when everything else is OK */
   return newblock;
 }
 
 
+/*
+** In prototypes, the size of the array is also its number of
+** elements (to save memory). So, if it cannot shrink an array
+** to its number of elements, the only option is to raise an
+** error.
+*/
 void *luaM_shrinkvector_ (lua_State *L, void *block, int *size,
                           int final_n, int size_elem) {
-  global_State *g = G(L);
   void *newblock;
   size_t oldsize = cast_sizet((*size) * size_elem);
   size_t newsize = cast_sizet(final_n * size_elem);
   lua_assert(newsize <= oldsize);
-  newblock = (*g->frealloc)(g->ud, block, oldsize, newsize);
-  if (unlikely(newblock == NULL && final_n > 0))  /* allocation failed? */
-    luaM_error(L);
-  else {
-    g->GCdebt += newsize - oldsize;
-    *size = final_n;
-    return newblock;
-  }
+  newblock = luaM_saferealloc_(L, block, oldsize, newsize);
+  *size = final_n;
+  return newblock;
 }
 
+/* }================================================================== */
+
 
 l_noret luaM_toobig (lua_State *L) {
   luaG_runerror(L, "memory allocation error: block too big");

@@ -132,19 +155,20 @@
 
 
 /*
-** generic allocation routine.
+** Generic allocation routine.
+** If allocation fails while shrinking a block, do not try again; the
+** GC shrinks some blocks and it is not reentrant.
 */
 void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
   void *newblock;
   global_State *g = G(L);
   lua_assert((osize == 0) == (block == NULL));
-  hardtest(L, osize, nsize);
-  newblock = (*g->frealloc)(g->ud, block, osize, nsize);
+  newblock = firsttry(g, block, osize, nsize);
   if (unlikely(newblock == NULL && nsize > 0)) {
     if (nsize > osize)  /* not shrinking a block? */
       newblock = tryagain(L, block, osize, nsize);
     if (newblock == NULL)  /* still no memory? */
-      return NULL;
+      return NULL;  /* do not update 'GCdebt' */
   }
   lua_assert((nsize == 0) == (newblock == NULL));
   g->GCdebt = (g->GCdebt + nsize) - osize;

@@ -162,12 +186,11 @@
 
 
 void *luaM_malloc_ (lua_State *L, size_t size, int tag) {
-  hardtest(L, 0, size);
   if (size == 0)
     return NULL;  /* that's all */
   else {
     global_State *g = G(L);
-    void *newblock = (*g->frealloc)(g->ud, NULL, tag, size);
+    void *newblock = firsttry(g, NULL, tag, size);
     if (unlikely(newblock == NULL)) {
       newblock = tryagain(L, NULL, tag, size);
       if (newblock == NULL)

src/loadlib.c

@@ -56,10 +56,10 @@
 
 
 /*
-** unique key for table in the registry that keeps handles
+** key for table in the registry that keeps handles
 ** for all loaded C libraries
 */
-static const int CLIBS = 0;
+static const char *CLIBS = "_CLIBS";
 
 #define LIB_FAIL	"open"
 

@@ -308,7 +308,7 @@
       luaL_addchar(&b, *LUA_PATH_SEP);
     }
     luaL_addstring(&b, dft);  /* add default */
-    if (dftmark < path + len - 2) {  /* is there a sufix after ';;'? */
+    if (dftmark < path + len - 2) {  /* is there a suffix after ';;'? */
       luaL_addchar(&b, *LUA_PATH_SEP);
       luaL_addlstring(&b, dftmark + 2, (path + len - 2) - dftmark);
     }

@@ -327,7 +327,7 @@
 */
 static void *checkclib (lua_State *L, const char *path) {
   void *plib;
-  lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS);
+  lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
   lua_getfield(L, -1, path);
   plib = lua_touserdata(L, -1);  /* plib = CLIBS[path] */
   lua_pop(L, 2);  /* pop CLIBS table and 'plib' */

@@ -340,7 +340,7 @@
 ** registry.CLIBS[#CLIBS + 1] = plib  -- also keep a list of all libraries
 */
 static void addtoclib (lua_State *L, const char *path, void *plib) {
-  lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS);
+  lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
   lua_pushlightuserdata(L, plib);
   lua_pushvalue(L, -1);
   lua_setfield(L, -3, path);  /* CLIBS[path] = plib */

@@ -408,10 +408,10 @@
   if (stat == 0)  /* no errors? */
     return 1;  /* return the loaded function */
   else {  /* error; error message is on stack top */
-    lua_pushnil(L);
+    luaL_pushfail(L);
     lua_insert(L, -2);
     lua_pushstring(L, (stat == ERRLIB) ?  LIB_FAIL : "init");
-    return 3;  /* return nil, error message, and where */
+    return 3;  /* return fail, error message, and where */
   }
 }
 

@@ -505,9 +505,9 @@
                                 luaL_optstring(L, 4, LUA_DIRSEP));
   if (f != NULL) return 1;
   else {  /* error message is on top of the stack */
-    lua_pushnil(L);
+    luaL_pushfail(L);
     lua_insert(L, -2);
-    return 2;  /* return nil + error message */
+    return 2;  /* return fail + error message */
   }
 }
 

@@ -716,12 +716,11 @@
 ** setting a finalizer to close all libraries when closing state.
 */
 static void createclibstable (lua_State *L) {
-  lua_newtable(L);  /* create CLIBS table */
+  luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS);  /* create CLIBS table */
   lua_createtable(L, 0, 1);  /* create metatable for CLIBS */
   lua_pushcfunction(L, gctm);
   lua_setfield(L, -2, "__gc");  /* set finalizer for CLIBS table */
   lua_setmetatable(L, -2);
-  lua_rawsetp(L, LUA_REGISTRYINDEX, &CLIBS);  /* set CLIBS table in registry */
 }
 
 

src/lobject.c

@@ -30,32 +30,6 @@
 
 
 /*
-** converts an integer to a "floating point byte", represented as
-** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
-** eeeee != 0 and (xxx) otherwise.
-*/
-int luaO_int2fb (unsigned int x) {
-  int e = 0;  /* exponent */
-  if (x < 8) return x;
-  while (x >= (8 << 4)) {  /* coarse steps */
-    x = (x + 0xf) >> 4;  /* x = ceil(x / 16) */
-    e += 4;
-  }
-  while (x >= (8 << 1)) {  /* fine steps */
-    x = (x + 1) >> 1;  /* x = ceil(x / 2) */
-    e++;
-  }
-  return ((e+1) << 3) | (cast_int(x) - 8);
-}
-
-
-/* converts back */
-int luaO_fb2int (int x) {
-  return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1);
-}
-
-
-/*
 ** Computes ceil(log2(x))
 */
 int luaO_ceillog2 (unsigned int x) {

src/lobject.h

@@ -89,8 +89,8 @@
 #define righttt(obj)		(ttypetag(obj) == gcvalue(obj)->tt)
 
 #define checkliveness(L,obj) \
-	lua_longassert(!iscollectable(obj) || \
-		(righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj)))))
+	((void)L, lua_longassert(!iscollectable(obj) || \
+		(righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj))))))
 
 
 /* Macros to set values */

@@ -100,7 +100,7 @@
 #define setobj(L,obj1,obj2) \
 	{ TValue *io1=(obj1); const TValue *io2=(obj2); \
           io1->value_ = io2->value_; io1->tt_ = io2->tt_; \
-	  (void)L; checkliveness(L,io1); lua_assert(!isreallyempty(io1)); }
+	  checkliveness(L,io1); lua_assert(!isreallyempty(io1)); }
 
 /*
 ** different types of assignments, according to destination

@@ -460,6 +460,7 @@
   TString *name;  /* upvalue name (for debug information) */
   lu_byte instack;  /* whether it is in stack (register) */
   lu_byte idx;  /* index of upvalue (in stack or in outer function's list) */
+  lu_byte kind;  /* kind of corresponding variable */
 } Upvaldesc;
 
 

@@ -567,6 +568,7 @@
 */
 typedef struct UpVal {
   CommonHeader;
+  lu_byte tbc;  /* true if it represents a to-be-closed variable */
   TValue *v;  /* points to stack or to its own value */
   union {
     struct {  /* (when open) */

@@ -578,9 +580,6 @@
 } UpVal;
 
 
-/* variant for "To Be Closed" upvalues */
-#define LUA_TUPVALTBC	(LUA_TUPVAL | (1 << 4))
-
 
 #define ClosureHeader \
 	CommonHeader; lu_byte nupvalues; GCObject *gclist

@@ -650,14 +649,14 @@
 #define setnodekey(L,node,obj) \
 	{ Node *n_=(node); const TValue *io_=(obj); \
 	  n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; \
-	  (void)L; checkliveness(L,io_); }
+	  checkliveness(L,io_); }
 
 
 /* copy a value from a key */
 #define getnodekey(L,obj,node) \
 	{ TValue *io_=(obj); const Node *n_=(node); \
 	  io_->value_ = n_->u.key_val; io_->tt_ = n_->u.key_tt; \
-	  (void)L; checkliveness(L,io_); }
+	  checkliveness(L,io_); }
 
 
 /*

@@ -733,8 +732,6 @@
 /* size of buffer for 'luaO_utf8esc' function */
 #define UTF8BUFFSZ	8
 
-LUAI_FUNC int luaO_int2fb (unsigned int x);
-LUAI_FUNC int luaO_fb2int (int x);
 LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x);
 LUAI_FUNC int luaO_ceillog2 (unsigned int x);
 LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1,

src/lopcodes.c

@@ -18,90 +18,87 @@
 /* ORDER OP */
 
 LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
-/*       OT IT T  A  mode		   opcode  */
-  opmode(0, 0, 0, 1, iABC)		/* OP_MOVE */
- ,opmode(0, 0, 0, 1, iAsBx)		/* OP_LOADI */
- ,opmode(0, 0, 0, 1, iAsBx)		/* OP_LOADF */
- ,opmode(0, 0, 0, 1, iABx)		/* OP_LOADK */
- ,opmode(0, 0, 0, 1, iABx)		/* OP_LOADKX */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_LOADBOOL */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_LOADNIL */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_GETUPVAL */
- ,opmode(0, 0, 0, 0, iABC)		/* OP_SETUPVAL */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_GETTABUP */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_GETTABLE */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_GETI */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_GETFIELD */
- ,opmode(0, 0, 0, 0, iABC)		/* OP_SETTABUP */
- ,opmode(0, 0, 0, 0, iABC)		/* OP_SETTABLE */
- ,opmode(0, 0, 0, 0, iABC)		/* OP_SETI */
- ,opmode(0, 0, 0, 0, iABC)		/* OP_SETFIELD */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_NEWTABLE */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_SELF */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_ADDI */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_SUBI */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_MULI */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_MODI */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_POWI */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_DIVI */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_IDIVI */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_ADDK */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_SUBK */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_MULK */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_MODK */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_POWK */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_DIVK */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_IDIVK */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_BANDK */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_BORK */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_BXORK */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_SHRI */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_SHLI */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_ADD */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_SUB */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_MUL */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_MOD */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_POW */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_DIV */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_IDIV */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_BAND */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_BOR */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_BXOR */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_SHL */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_SHR */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_UNM */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_BNOT */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_NOT */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_LEN */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_CONCAT */
- ,opmode(0, 0, 0, 0, iABC)		/* OP_CLOSE */
- ,opmode(0, 0, 0, 0, iABC)		/* OP_TBC */
- ,opmode(0, 0, 0, 0, isJ)		/* OP_JMP */
- ,opmode(0, 0, 1, 0, iABC)		/* OP_EQ */
- ,opmode(0, 0, 1, 0, iABC)		/* OP_LT */
- ,opmode(0, 0, 1, 0, iABC)		/* OP_LE */
- ,opmode(0, 0, 1, 0, iABC)		/* OP_EQK */
- ,opmode(0, 0, 1, 0, iABC)		/* OP_EQI */
- ,opmode(0, 0, 1, 0, iABC)		/* OP_LTI */
- ,opmode(0, 0, 1, 0, iABC)		/* OP_LEI */
- ,opmode(0, 0, 1, 0, iABC)		/* OP_GTI */
- ,opmode(0, 0, 1, 0, iABC)		/* OP_GEI */
- ,opmode(0, 0, 1, 0, iABC)		/* OP_TEST */
- ,opmode(0, 0, 1, 1, iABC)		/* OP_TESTSET */
- ,opmode(1, 1, 0, 1, iABC)		/* OP_CALL */
- ,opmode(1, 1, 0, 1, iABC)		/* OP_TAILCALL */
- ,opmode(0, 1, 0, 0, iABC)		/* OP_RETURN */
- ,opmode(0, 0, 0, 0, iABC)		/* OP_RETURN0 */
- ,opmode(0, 0, 0, 0, iABC)		/* OP_RETURN1 */
- ,opmode(0, 0, 0, 1, iABx)		/* OP_FORLOOP */
- ,opmode(0, 0, 0, 1, iABx)		/* OP_FORPREP */
- ,opmode(0, 0, 0, 0, iABx)		/* OP_TFORPREP */
- ,opmode(0, 0, 0, 0, iABC)		/* OP_TFORCALL */
- ,opmode(0, 0, 0, 1, iABx)		/* OP_TFORLOOP */
- ,opmode(0, 1, 0, 0, iABC)		/* OP_SETLIST */
- ,opmode(0, 0, 0, 1, iABx)		/* OP_CLOSURE */
- ,opmode(1, 0, 0, 1, iABC)		/* OP_VARARG */
- ,opmode(0, 0, 0, 1, iABC)		/* OP_VARARGPREP */
- ,opmode(0, 0, 0, 0, iAx)		/* OP_EXTRAARG */
+/*       MM OT IT T  A  mode		   opcode  */
+  opmode(0, 0, 0, 0, 1, iABC)		/* OP_MOVE */
+ ,opmode(0, 0, 0, 0, 1, iAsBx)		/* OP_LOADI */
+ ,opmode(0, 0, 0, 0, 1, iAsBx)		/* OP_LOADF */
+ ,opmode(0, 0, 0, 0, 1, iABx)		/* OP_LOADK */
+ ,opmode(0, 0, 0, 0, 1, iABx)		/* OP_LOADKX */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_LOADBOOL */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_LOADNIL */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_GETUPVAL */
+ ,opmode(0, 0, 0, 0, 0, iABC)		/* OP_SETUPVAL */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_GETTABUP */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_GETTABLE */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_GETI */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_GETFIELD */
+ ,opmode(0, 0, 0, 0, 0, iABC)		/* OP_SETTABUP */
+ ,opmode(0, 0, 0, 0, 0, iABC)		/* OP_SETTABLE */
+ ,opmode(0, 0, 0, 0, 0, iABC)		/* OP_SETI */
+ ,opmode(0, 0, 0, 0, 0, iABC)		/* OP_SETFIELD */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_NEWTABLE */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_SELF */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_ADDI */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_ADDK */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_SUBK */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_MULK */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_MODK */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_POWK */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_DIVK */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_IDIVK */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_BANDK */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_BORK */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_BXORK */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_SHRI */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_SHLI */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_ADD */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_SUB */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_MUL */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_MOD */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_POW */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_DIV */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_IDIV */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_BAND */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_BOR */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_BXOR */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_SHL */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_SHR */
+ ,opmode(1, 0, 0, 0, 0, iABC)		/* OP_MMBIN */
+ ,opmode(1, 0, 0, 0, 0, iABC)		/* OP_MMBINI*/
+ ,opmode(1, 0, 0, 0, 0, iABC)		/* OP_MMBINK*/
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_UNM */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_BNOT */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_NOT */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_LEN */
+ ,opmode(0, 0, 0, 0, 1, iABC)		/* OP_CONCAT */
+ ,opmode(0, 0, 0, 0, 0, iABC)		/* OP_CLOSE */
+ ,opmode(0, 0, 0, 0, 0, iABC)		/* OP_TBC */
+ ,opmode(0, 0, 0, 0, 0, isJ)		/* OP_JMP */
+ ,opmode(0, 0, 0, 1, 0, iABC)		/* OP_EQ */
+ ,opmode(0, 0, 0, 1, 0, iABC)		/* OP_LT */
+ ,opmode(0, 0, 0, 1, 0, iABC)		/* OP_LE */
+ ,opmode(0, 0, 0, 1, 0, iABC)		/* OP_EQK */
+ ,opmode(0, 0, 0, 1, 0, iABC)		/* OP_EQI */
+ ,opmode(0, 0, 0, 1, 0, iABC)		/* OP_LTI */
+ ,opmode(0, 0, 0, 1, 0, iABC)		/* OP_LEI */
+ ,opmode(0, 0, 0, 1, 0, iABC)		/* OP_GTI */
+ ,opmode(0, 0, 0, 1, 0, iABC)		/* OP_GEI */
+ ,opmode(0, 0, 0, 1, 0, iABC)		/* OP_TEST */
+ ,opmode(0, 0, 0, 1, 1, iABC)		/* OP_TESTSET */
+ ,opmode(0, 1, 1, 0, 1, iABC)		/* OP_CALL */
+ ,opmode(0, 1, 1, 0, 1, iABC)		/* OP_TAILCALL */
+ ,opmode(0, 0, 1, 0, 0, iABC)		/* OP_RETURN */
+ ,opmode(0, 0, 0, 0, 0, iABC)		/* OP_RETURN0 */
+ ,opmode(0, 0, 0, 0, 0, iABC)		/* OP_RETURN1 */
+ ,opmode(0, 0, 0, 0, 1, iABx)		/* OP_FORLOOP */
+ ,opmode(0, 0, 0, 0, 1, iABx)		/* OP_FORPREP */
+ ,opmode(0, 0, 0, 0, 0, iABx)		/* OP_TFORPREP */
+ ,opmode(0, 0, 0, 0, 0, iABC)		/* OP_TFORCALL */
+ ,opmode(0, 0, 0, 0, 1, iABx)		/* OP_TFORLOOP */
+ ,opmode(0, 0, 1, 0, 0, iABC)		/* OP_SETLIST */
+ ,opmode(0, 0, 0, 0, 1, iABx)		/* OP_CLOSURE */
+ ,opmode(0, 1, 0, 0, 1, iABC)		/* OP_VARARG */
+ ,opmode(0, 0, 1, 0, 1, iABC)		/* OP_VARARGPREP */
+ ,opmode(0, 0, 0, 0, 0, iAx)		/* OP_EXTRAARG */
 };
 

src/lopcodes.h

@@ -97,6 +97,9 @@
 #define MAXARG_C	((1<<SIZE_C)-1)
 #define OFFSET_sC	(MAXARG_C >> 1)
 
+#define int2sC(i)	((i) + OFFSET_sC)
+#define sC2int(i)	((i) - OFFSET_sC)
+
 
 /* creates a mask with 'n' 1 bits at position 'p' */
 #define MASK1(n,p)	((~((~(Instruction)0)<<(n)))<<(p))

@@ -123,11 +126,11 @@
 #define SETARG_A(i,v)	setarg(i, v, POS_A, SIZE_A)
 
 #define GETARG_B(i)	check_exp(checkopm(i, iABC), getarg(i, POS_B, SIZE_B))
-#define GETARG_sB(i)	(GETARG_B(i) - OFFSET_sC)
+#define GETARG_sB(i)	sC2int(GETARG_B(i))
 #define SETARG_B(i,v)	setarg(i, v, POS_B, SIZE_B)
 
 #define GETARG_C(i)	check_exp(checkopm(i, iABC), getarg(i, POS_C, SIZE_C))
-#define GETARG_sC(i)	(GETARG_C(i) - OFFSET_sC)
+#define GETARG_sC(i)	sC2int(GETARG_C(i))
 #define SETARG_C(i,v)	setarg(i, v, POS_C, SIZE_C)
 
 #define TESTARG_k(i)	(cast_int(((i) & (1u << POS_k))))

@@ -214,17 +217,11 @@
 OP_SETI,/*	A B C	R(A)[B] := RK(C)				*/
 OP_SETFIELD,/*	A B C	R(A)[K(B):string] := RK(C)			*/
 
-OP_NEWTABLE,/*	A B C	R(A) := {} (size = B,C)				*/
+OP_NEWTABLE,/*	A B C	R(A) := {}					*/
 
 OP_SELF,/*	A B C	R(A+1) := R(B); R(A) := R(B)[RK(C):string]	*/
 
-OP_ADDI,/*	A B sC	R(A) := R(B) + C				*/
-OP_SUBI,/*	A B sC	R(A) := R(B) - C				*/
-OP_MULI,/*	A B sC	R(A) := R(B) * C				*/
-OP_MODI,/*	A B sC	R(A) := R(B) % C				*/
-OP_POWI,/*	A B sC	R(A) := R(B) ^ C				*/
-OP_DIVI,/*	A B sC	R(A) := R(B) / C				*/
-OP_IDIVI,/*	A B sC	R(A) := R(B) // C				*/
+OP_ADDI,/*	A B sC	R(A) := R(B) + sC				*/
 
 OP_ADDK,/*	A B C	R(A) := R(B) + K(C)				*/
 OP_SUBK,/*	A B C	R(A) := R(B) - K(C)				*/

@@ -238,8 +235,8 @@
 OP_BORK,/*	A B C	R(A) := R(B) | K(C):integer			*/
 OP_BXORK,/*	A B C	R(A) := R(B) ~ K(C):integer			*/
 
-OP_SHRI,/*	A B sC	R(A) := R(B) >> C				*/
-OP_SHLI,/*	A B sC	R(A) := C << R(B)				*/
+OP_SHRI,/*	A B sC	R(A) := R(B) >> sC				*/
+OP_SHLI,/*	A B sC	R(A) := sC << R(B)				*/
 
 OP_ADD,/*	A B C	R(A) := R(B) + R(C)				*/
 OP_SUB,/*	A B C	R(A) := R(B) - R(C)				*/

@@ -255,6 +252,10 @@
 OP_SHL,/*	A B C	R(A) := R(B) << R(C)				*/
 OP_SHR,/*	A B C	R(A) := R(B) >> R(C)				*/
 
+OP_MMBIN,/*	A B C	call C metamethod over R(A) and R(B)		*/
+OP_MMBINI,/*	A sB C	call C metamethod over R(A) and sB		*/
+OP_MMBINK,/*	A B C	call C metamethod over R(A) and K(B)		*/
+
 OP_UNM,/*	A B	R(A) := -R(B)					*/
 OP_BNOT,/*	A B	R(A) := ~R(B)					*/
 OP_NOT,/*	A B	R(A) := not R(B)				*/

@@ -286,9 +287,9 @@
 OP_RETURN0,/*	  	return 						*/
 OP_RETURN1,/*	A 	return R(A)					*/
 
-OP_FORLOOP,/*	A Bx	R(A)+=R(A+2);
-			if R(A) <?= R(A+1) then { pc-=Bx; R(A+3)=R(A) }	*/
-OP_FORPREP,/*	A Bx	R(A)-=R(A+2); pc+=Bx				*/
+OP_FORLOOP,/*	A Bx	update counters; if loop continues then pc-=Bx; */
+OP_FORPREP,/*	A Bx	<check values and prepare counters>;
+                        if not to run then pc+=Bx+1;			*/
 
 OP_TFORPREP,/*	A Bx	create upvalue for R(A + 3); pc+=Bx		*/
 OP_TFORCALL,/*	A C	R(A+4), ... ,R(A+3+C) := R(A)(R(A+1), R(A+2));	*/

@@ -321,10 +322,16 @@
 
   (*) In OP_RETURN, if (B == 0) then return up to 'top'.
 
-  (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if (C == 0) then
-  next 'instruction' is EXTRAARG(real C).
+  (*) In OP_LOADKX and OP_NEWTABLE, the next instruction is always
+  EXTRAARG.
 
-  (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG.
+  (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if k, then
+  real C = EXTRAARG _ C (the bits of EXTRAARG concatenated with the
+  bits of C).
+
+  (*) In OP_NEWTABLE, B is log2 of the hash size (which is always a
+  power of 2) plus 1, or zero for size zero. If not k, the array size
+  is C. Otherwise, the array size is EXTRAARG _ C.
 
   (*) For comparisons, k specifies what condition the test should accept
   (true or false).

@@ -332,10 +339,9 @@
   (*) All 'skips' (pc++) assume that next instruction is a jump.
 
   (*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the
-  function either builds upvalues, which may need to be closed, or is
-  vararg, which must be corrected before returning. When 'k' is true,
-  C > 0 means the function is vararg and (C - 1) is its number of
-  fixed parameters.
+  function builds upvalues, which may need to be closed. C > 0 means
+  the function is vararg, so that its 'func' must be corrected before
+  returning; in this case, (C - 1) is its number of fixed parameters.
 
   (*) In comparisons with an immediate operand, C signals whether the
   original operand was a float.

@@ -350,6 +356,7 @@
 ** bit 4: operator is a test (next instruction must be a jump)
 ** bit 5: instruction uses 'L->top' set by previous instruction (when B == 0)
 ** bit 6: instruction sets 'L->top' for next instruction (when C == 0)
+** bit 7: instruction is an MM instruction (call a metamethod)
 */
 
 LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];)

@@ -359,6 +366,7 @@
 #define testTMode(m)	(luaP_opmodes[m] & (1 << 4))
 #define testITMode(m)	(luaP_opmodes[m] & (1 << 5))
 #define testOTMode(m)	(luaP_opmodes[m] & (1 << 6))
+#define testMMMode(m)	(luaP_opmodes[m] & (1 << 7))
 
 /* "out top" (set top for next instruction) */
 #define isOT(i)  \

@@ -368,11 +376,11 @@
 /* "in top" (uses top from previous instruction) */
 #define isIT(i)		(testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0)
 
-#define opmode(ot,it,t,a,m) (((ot)<<6) | ((it)<<5) | ((t)<<4) | ((a)<<3) | (m))
+#define opmode(mm,ot,it,t,a,m)  \
+    (((mm) << 7) | ((ot) << 6) | ((it) << 5) | ((t) << 4) | ((a) << 3) | (m))
 
 
 /* number of list items to accumulate before a SETLIST instruction */
 #define LFIELDS_PER_FLUSH	50
 
-
 #endif

src/lopnames.h

@@ -30,12 +30,6 @@
   "NEWTABLE",
   "SELF",
   "ADDI",
-  "SUBI",
-  "MULI",
-  "MODI",
-  "POWI",
-  "DIVI",
-  "IDIVI",
   "ADDK",
   "SUBK",
   "MULK",

@@ -60,6 +54,9 @@
   "BXOR",
   "SHL",
   "SHR",
+  "MMBIN",
+  "MMBINI",
+  "MMBINK",
   "UNM",
   "BNOT",
   "NOT",

src/loslib.c

@@ -58,18 +58,20 @@
 ** ===================================================================
 */
 
-#if !defined(l_time_t)		/* { */
 /*
 ** type to represent time_t in Lua
 */
+#if !defined(LUA_NUMTIME)	/* { */
+
 #define l_timet			lua_Integer
 #define l_pushtime(L,t)		lua_pushinteger(L,(lua_Integer)(t))
+#define l_gettime(L,arg)	luaL_checkinteger(L, arg)
 
-static time_t l_checktime (lua_State *L, int arg) {
-  lua_Integer t = luaL_checkinteger(L, arg);
-  luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds");
-  return (time_t)t;
-}
+#else				/* }{ */
+
+#define l_timet			lua_Number
+#define l_pushtime(L,t)		lua_pushnumber(L,(lua_Number)(t))
+#define l_gettime(L,arg)	luaL_checknumber(L, arg)
 
 #endif				/* } */
 

@@ -193,11 +195,25 @@
 ** =======================================================
 */
 
-static void setfield (lua_State *L, const char *key, int value) {
-  lua_pushinteger(L, value);
+/*
+** About the overflow check: an overflow cannot occurr when time
+** is represented by a lua_Integer, because either lua_Integer is
+** large enough to represent all int fields or it is not large enough
+** to represent a time that cause a field to overflow.  However, if
+** times are represented as doubles and lua_Integer is int, then the
+** time 0x1.e1853b0d184f6p+55 would cause an overflow when adding 1900
+** to compute the year.
+*/
+static void setfield (lua_State *L, const char *key, int value, int delta) {
+  #if (defined(LUA_NUMTIME) && LUA_MAXINTEGER <= INT_MAX)
+    if (value > LUA_MAXINTEGER - delta)
+      luaL_error(L, "field '%s' is out-of-bound", key);
+  #endif
+  lua_pushinteger(L, (lua_Integer)value + delta);
   lua_setfield(L, -2, key);
 }
 
+
 static void setboolfield (lua_State *L, const char *key, int value) {
   if (value < 0)  /* undefined? */
     return;  /* does not set field */

@@ -210,14 +226,14 @@
 ** Set all fields from structure 'tm' in the table on top of the stack
 */
 static void setallfields (lua_State *L, struct tm *stm) {
-  setfield(L, "sec", stm->tm_sec);
-  setfield(L, "min", stm->tm_min);
-  setfield(L, "hour", stm->tm_hour);
-  setfield(L, "day", stm->tm_mday);
-  setfield(L, "month", stm->tm_mon + 1);
-  setfield(L, "year", stm->tm_year + 1900);
-  setfield(L, "wday", stm->tm_wday + 1);
-  setfield(L, "yday", stm->tm_yday + 1);
+  setfield(L, "year", stm->tm_year, 1900);
+  setfield(L, "month", stm->tm_mon, 1);
+  setfield(L, "day", stm->tm_mday, 0);
+  setfield(L, "hour", stm->tm_hour, 0);
+  setfield(L, "min", stm->tm_min, 0);
+  setfield(L, "sec", stm->tm_sec, 0);
+  setfield(L, "yday", stm->tm_yday, 1);
+  setfield(L, "wday", stm->tm_wday, 1);
   setboolfield(L, "isdst", stm->tm_isdst);
 }
 

@@ -230,11 +246,6 @@
 }
 
 
-/* maximum value for date fields (to avoid arithmetic overflows with 'int') */
-#if !defined(L_MAXDATEFIELD)
-#define L_MAXDATEFIELD	(INT_MAX / 2)
-#endif
-
 static int getfield (lua_State *L, const char *key, int d, int delta) {
   int isnum;
   int t = lua_getfield(L, -1, key);  /* get field and its type */

@@ -247,7 +258,9 @@
     res = d;
   }
   else {
-    if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))
+    /* 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))
       return luaL_error(L, "field '%s' is out-of-bound", key);
     res -= delta;
   }

@@ -275,6 +288,13 @@
 }
 
 
+static time_t l_checktime (lua_State *L, int arg) {
+  l_timet t = l_gettime(L, arg);
+  luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds");
+  return (time_t)t;
+}
+
+
 /* maximum size for an individual 'strftime' item */
 #define SIZETIMEFMT	250
 

@@ -293,7 +313,7 @@
     stm = l_localtime(&t, &tmr);
   if (stm == NULL)  /* invalid date? */
     return luaL_error(L,
-                 "time result cannot be represented in this installation");
+                 "date result cannot be represented in this installation");
   if (strcmp(s, "*t") == 0) {
     lua_createtable(L, 0, 9);  /* 9 = number of fields */
     setallfields(L, stm);

@@ -329,12 +349,12 @@
     struct tm ts;
     luaL_checktype(L, 1, LUA_TTABLE);
     lua_settop(L, 1);  /* make sure table is at the top */
-    ts.tm_sec = getfield(L, "sec", 0, 0);
-    ts.tm_min = getfield(L, "min", 0, 0);
-    ts.tm_hour = getfield(L, "hour", 12, 0);
-    ts.tm_mday = getfield(L, "day", -1, 0);
-    ts.tm_mon = getfield(L, "month", -1, 1);
     ts.tm_year = getfield(L, "year", -1, 1900);
+    ts.tm_mon = getfield(L, "month", -1, 1);
+    ts.tm_mday = getfield(L, "day", -1, 0);
+    ts.tm_hour = getfield(L, "hour", 12, 0);
+    ts.tm_min = getfield(L, "min", 0, 0);
+    ts.tm_sec = getfield(L, "sec", 0, 0);
     ts.tm_isdst = getboolfield(L, "isdst");
     t = mktime(&ts);
     setallfields(L, &ts);  /* update fields with normalized values */

src/lparser.c

@@ -156,20 +156,15 @@
 }
 
 
-static void init_var (expdesc *e, expkind k, int i) {
+static void codestring (expdesc *e, TString *s) {
   e->f = e->t = NO_JUMP;
-  e->k = k;
-  e->u.var.idx = i;
-}
-
-
-static void codestring (LexState *ls, expdesc *e, TString *s) {
-  init_exp(e, VK, luaK_stringK(ls->fs, s));
+  e->k = VKSTR;
+  e->u.strval = s;
 }
 
 
 static void codename (LexState *ls, expdesc *e) {
-  codestring(ls, e, str_checkname(ls));
+  codestring(e, str_checkname(ls));
 }
 
 

@@ -177,41 +172,42 @@
 ** Register a new local variable in the active 'Proto' (for debug
 ** information).
 */
-static int registerlocalvar (LexState *ls, TString *varname) {
-  FuncState *fs = ls->fs;
+static int registerlocalvar (LexState *ls, FuncState *fs, TString *varname) {
   Proto *f = fs->f;
   int oldsize = f->sizelocvars;
-  luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
+  luaM_growvector(ls->L, f->locvars, fs->ndebugvars, f->sizelocvars,
                   LocVar, SHRT_MAX, "local variables");
   while (oldsize < f->sizelocvars)
     f->locvars[oldsize++].varname = NULL;
-  f->locvars[fs->nlocvars].varname = varname;
+  f->locvars[fs->ndebugvars].varname = varname;
+  f->locvars[fs->ndebugvars].startpc = fs->pc;
   luaC_objbarrier(ls->L, f, varname);
-  return fs->nlocvars++;
+  return fs->ndebugvars++;
 }
 
 
 /*
-** Create a new local variable with the given 'name'.
+** Create a new local variable with the given 'name'. Return its index
+** in the function.
 */
-static Vardesc *new_localvar (LexState *ls, TString *name) {
+static int new_localvar (LexState *ls, TString *name) {
+  lua_State *L = ls->L;
   FuncState *fs = ls->fs;
   Dyndata *dyd = ls->dyd;
   Vardesc *var;
-  int reg = registerlocalvar(ls, name);
   checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
-                  MAXVARS, "local variables");
-  luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,
-                  dyd->actvar.size, Vardesc, MAX_INT, "local variables");
+                 MAXVARS, "local variables");
+  luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1,
+                  dyd->actvar.size, Vardesc, USHRT_MAX, "local variables");
   var = &dyd->actvar.arr[dyd->actvar.n++];
-  var->idx = cast(short, reg);
-  var->name = name;
-  var->ro = 0;
-  return var;
+  var->vd.kind = VDKREG;  /* default */
+  var->vd.name = name;
+  return dyd->actvar.n - 1 - fs->firstlocal;
 }
 
 #define new_localvarliteral(ls,v) \
-    new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1));
+    new_localvar(ls,  \
+      luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1));
 
 
 

@@ -223,48 +219,80 @@
   return &fs->ls->dyd->actvar.arr[fs->firstlocal + i];
 }
 
+
 /*
-** Get the debug-information entry for current variable 'i'.
+** Convert 'nvar' (number of active variables at some point) to
+** number of variables in the stack at that point.
 */
-static LocVar *getlocvar (FuncState *fs, int i) {
-  int idx = getlocalvardesc(fs, i)->idx;
-  lua_assert(idx < fs->nlocvars);
-  return &fs->f->locvars[idx];
+static int stacklevel (FuncState *fs, int nvar) {
+  while (nvar > 0) {
+    Vardesc *vd = getlocalvardesc(fs, nvar - 1);
+    if (vd->vd.kind != RDKCTC)  /* is in the stack? */
+      return vd->vd.sidx + 1;
+    else
+      nvar--;  /* try previous variable */
+  }
+  return 0;  /* no variables */
 }
 
 
 /*
-** Return the "variable description" (Vardesc) of a given
-** variable or upvalue
+** Return the number of variables in the stack for function 'fs'
 */
-static Vardesc *getvardesc (FuncState *fs, expdesc *e) {
-  if (e->k == VLOCAL)
-    return getlocalvardesc(fs, e->u.var.idx);
-  else if (e->k != VUPVAL)
-    return NULL;  /* not a local variable */
-  else {  /* upvalue: must go up all levels up to the original local */
-    int idx = e->u.var.idx;
-    for (;;) {
-      Upvaldesc *up = &fs->f->upvalues[idx];
-      fs = fs->prev;  /* must look at the previous level */
-      idx = up->idx;  /* at this index */
-      if (fs == NULL) {  /* no more levels? (can happen only with _ENV) */
-        lua_assert(strcmp(getstr(up->name), LUA_ENV) == 0);
-        return NULL;
-      }
-      else if (up->instack)  /* got to the original level? */
-        return getlocalvardesc(fs, idx);
-      /* else repeat for previous level */
-    }
+int luaY_nvarstack (FuncState *fs) {
+  return stacklevel(fs, fs->nactvar);
+}
+
+
+/*
+** Get the debug-information entry for current variable 'i'.
+*/
+static LocVar *localdebuginfo (FuncState *fs, int i) {
+  Vardesc *vd = getlocalvardesc(fs, i);
+  if (vd->vd.kind == RDKCTC)
+    return NULL;  /* no debug info. for constants */
+  else {
+    int idx = vd->vd.pidx;
+    lua_assert(idx < fs->ndebugvars);
+    return &fs->f->locvars[idx];
   }
 }
 
 
+static void init_var (FuncState *fs, expdesc *e, int i) {
+  e->f = e->t = NO_JUMP;
+  e->k = VLOCAL;
+  e->u.var.vidx = i;
+  e->u.var.sidx = getlocalvardesc(fs, i)->vd.sidx;
+}
+
+
 static void check_readonly (LexState *ls, expdesc *e) {
-  Vardesc *vardesc = getvardesc(ls->fs, e);
-  if (vardesc && vardesc->ro) {  /* is variable local and const? */
+  FuncState *fs = ls->fs;
+  TString *varname = NULL;  /* to be set if variable is const */
+  switch (e->k) {
+    case VCONST: {
+      varname = ls->dyd->actvar.arr[e->u.info].vd.name;
+      break;
+    }
+    case VLOCAL: {
+      Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx);
+      if (vardesc->vd.kind != VDKREG)  /* not a regular variable? */
+        varname = vardesc->vd.name;
+      break;
+    }
+    case VUPVAL: {
+      Upvaldesc *up = &fs->f->upvalues[e->u.info];
+      if (up->kind != VDKREG)
+        varname = up->name;
+      break;
+    }
+    default:
+      return;  /* other cases cannot be read-only */
+  }
+  if (varname) {
     const char *msg = luaO_pushfstring(ls->L,
-       "attempt to assign to const variable '%s'", getstr(vardesc->name));
+       "attempt to assign to const variable '%s'", getstr(varname));
     luaK_semerror(ls, msg);  /* error */
   }
 }

@@ -272,13 +300,16 @@
 
 /*
 ** Start the scope for the last 'nvars' created variables.
-** (debug info.)
 */
 static void adjustlocalvars (LexState *ls, int nvars) {
   FuncState *fs = ls->fs;
-  fs->nactvar = cast_byte(fs->nactvar + nvars);
-  for (; nvars; nvars--) {
-    getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc;
+  int stklevel = luaY_nvarstack(fs);
+  int i;
+  for (i = 0; i < nvars; i++) {
+    int varidx = fs->nactvar++;
+    Vardesc *var = getlocalvardesc(fs, varidx);
+    var->vd.sidx = stklevel++;
+    var->vd.pidx = registerlocalvar(ls, fs, var->vd.name);
   }
 }
 

@@ -289,8 +320,11 @@
 */
 static void removevars (FuncState *fs, int tolevel) {
   fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel);
-  while (fs->nactvar > tolevel)
-    getlocvar(fs, --fs->nactvar)->endpc = fs->pc;
+  while (fs->nactvar > tolevel) {
+    LocVar *var = localdebuginfo(fs, --fs->nactvar);
+    if (var)  /* does it have debug information? */
+      var->endpc = fs->pc;
+  }
 }
 
 

@@ -308,7 +342,7 @@
 }
 
 
-static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
+static Upvaldesc *allocupvalue (FuncState *fs) {
   Proto *f = fs->f;
   int oldsize = f->sizeupvalues;
   checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");

@@ -316,11 +350,28 @@
                   Upvaldesc, MAXUPVAL, "upvalues");
   while (oldsize < f->sizeupvalues)
     f->upvalues[oldsize++].name = NULL;
-  f->upvalues[fs->nups].instack = (v->k == VLOCAL);
-  f->upvalues[fs->nups].idx = cast_byte(v->u.var.idx);
-  f->upvalues[fs->nups].name = name;
-  luaC_objbarrier(fs->ls->L, f, name);
-  return fs->nups++;
+  return &f->upvalues[fs->nups++];
+}
+
+
+static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
+  Upvaldesc *up = allocupvalue(fs);
+  FuncState *prev = fs->prev;
+  if (v->k == VLOCAL) {
+    up->instack = 1;
+    up->idx = v->u.var.sidx;
+    up->kind = getlocalvardesc(prev, v->u.var.vidx)->vd.kind;
+    lua_assert(eqstr(name, getlocalvardesc(prev, v->u.var.vidx)->vd.name));
+  }
+  else {
+    up->instack = 0;
+    up->idx = cast_byte(v->u.info);
+    up->kind = prev->f->upvalues[v->u.info].kind;
+    lua_assert(eqstr(name, prev->f->upvalues[v->u.info].name));
+  }
+  up->name = name;
+  luaC_objbarrier(fs->ls->L, fs->f, name);
+  return fs->nups - 1;
 }
 
 

@@ -328,11 +379,17 @@
 ** Look for an active local variable with the name 'n' in the
 ** function 'fs'.
 */
-static int searchvar (FuncState *fs, TString *n) {
+static int searchvar (FuncState *fs, TString *n, expdesc *var) {
   int i;
   for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
-    if (eqstr(n, getlocvar(fs, i)->varname))
-      return i;
+    Vardesc *vd = getlocalvardesc(fs, i);
+    if (eqstr(n, vd->vd.name)) {  /* found? */
+      if (vd->vd.kind == RDKCTC)  /* compile-time constant? */
+        init_exp(var, VCONST, fs->firstlocal + i);
+      else  /* real variable */
+        init_var(fs, var, i);
+      return var->k;
+    }
   }
   return -1;  /* not found */
 }

@@ -360,22 +417,21 @@
   if (fs == NULL)  /* no more levels? */
     init_exp(var, VVOID, 0);  /* default is global */
   else {
-    int v = searchvar(fs, n);  /* look up locals at current level */
+    int v = searchvar(fs, n, var);  /* look up locals at current level */
     if (v >= 0) {  /* found? */
-      init_var(var, VLOCAL, v);  /* variable is local */
-      if (!base)
-        markupval(fs, v);  /* local will be used as an upval */
+      if (v == VLOCAL && !base)
+        markupval(fs, var->u.var.vidx);  /* local will be used as an upval */
     }
     else {  /* not found as local at current level; try upvalues */
       int idx = searchupvalue(fs, n);  /* try existing upvalues */
       if (idx < 0) {  /* not found? */
         singlevaraux(fs->prev, n, var, 0);  /* try upper levels */
-        if (var->k == VVOID)  /* not found? */
-          return;  /* it is a global */
-        /* else was LOCAL or UPVAL */
-        idx  = newupvalue(fs, n, var);  /* will be a new upvalue */
+        if (var->k == VLOCAL || var->k == VUPVAL)  /* local or upvalue? */
+          idx  = newupvalue(fs, n, var);  /* will be a new upvalue */
+        else  /* it is a global or a constant */
+          return;  /* don't need to do anything at this level */
       }
-      init_var(var, VUPVAL, idx);  /* new or old upvalue */
+      init_exp(var, VUPVAL, idx);  /* new or old upvalue */
     }
   }
 }

@@ -393,7 +449,7 @@
     expdesc key;
     singlevaraux(fs, ls->envn, var, 1);  /* get environment variable */
     lua_assert(var->k != VVOID);  /* this one must exist */
-    codestring(ls, &key, varname);  /* key is variable name */
+    codestring(&key, varname);  /* key is variable name */
     luaK_indexed(fs, var, &key);  /* env[varname] */
   }
 }

@@ -438,7 +494,7 @@
 ** local variable.
 */
 static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
-  const char *varname = getstr(getlocvar(ls->fs, gt->nactvar)->varname);
+  const char *varname = getstr(getlocalvardesc(ls->fs, gt->nactvar)->vd.name);
   const char *msg = "<goto %s> at line %d jumps into the scope of local '%s'";
   msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line, varname);
   luaK_semerror(ls, msg);  /* raise the error */

@@ -541,7 +597,7 @@
     ll->arr[l].nactvar = fs->bl->nactvar;
   }
   if (solvegotos(ls, &ll->arr[l])) {  /* need close? */
-    luaK_codeABC(fs, OP_CLOSE, fs->nactvar, 0, 0);
+    luaK_codeABC(fs, OP_CLOSE, luaY_nvarstack(fs), 0, 0);
     return 1;
   }
   return 0;

@@ -557,10 +613,10 @@
   /* correct pending gotos to current block */
   for (i = bl->firstgoto; i < gl->n; i++) {  /* for each pending goto */
     Labeldesc *gt = &gl->arr[i];
-    if (gt->nactvar > bl->nactvar) {  /* leaving a variable scope? */
-      gt->nactvar = bl->nactvar;  /* update goto level */
+    /* leaving a variable scope? */
+    if (stacklevel(fs, gt->nactvar) > stacklevel(fs, bl->nactvar))
       gt->close |= bl->upval;  /* jump may need a close */
-    }
+    gt->nactvar = bl->nactvar;  /* update goto level */
   }
 }
 

@@ -574,7 +630,7 @@
   bl->insidetbc = (fs->bl != NULL && fs->bl->insidetbc);
   bl->previous = fs->bl;
   fs->bl = bl;
-  lua_assert(fs->freereg == fs->nactvar);
+  lua_assert(fs->freereg == luaY_nvarstack(fs));
 }
 
 

@@ -599,14 +655,15 @@
   BlockCnt *bl = fs->bl;
   LexState *ls = fs->ls;
   int hasclose = 0;
+  int stklevel = stacklevel(fs, bl->nactvar);  /* level outside the block */
   if (bl->isloop)  /* fix pending breaks? */
     hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
   if (!hasclose && bl->previous && bl->upval)
-    luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 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 = fs->nactvar;  /* free registers */
+  fs->freereg = stklevel;  /* free registers */
   ls->dyd->label.n = bl->firstlabel;  /* remove local labels */
   if (bl->previous)  /* inner block? */
     movegotosout(fs, bl);  /* update pending gotos to outer block */

@@ -639,9 +696,10 @@
 
 /*
 ** codes instruction to create new closure in parent function.
-** The OP_CLOSURE instruction must use the last available register,
+** The OP_CLOSURE instruction uses the last available register,
 ** so that, if it invokes the GC, the GC knows which registers
 ** are in use at that time.
+
 */
 static void codeclosure (LexState *ls, expdesc *v) {
   FuncState *fs = ls->fs->prev;

@@ -664,7 +722,7 @@
   fs->nabslineinfo = 0;
   fs->np = 0;
   fs->nups = 0;
-  fs->nlocvars = 0;
+  fs->ndebugvars = 0;
   fs->nactvar = 0;
   fs->needclose = 0;
   fs->firstlocal = ls->dyd->actvar.n;

@@ -680,7 +738,7 @@
   lua_State *L = ls->L;
   FuncState *fs = ls->fs;
   Proto *f = fs->f;
-  luaK_ret(fs, fs->nactvar, 0);  /* final return */
+  luaK_ret(fs, luaY_nvarstack(fs), 0);  /* final return */
   leaveblock(fs);
   lua_assert(fs->bl == NULL);
   luaK_finish(fs);

@@ -690,7 +748,7 @@
                        fs->nabslineinfo, AbsLineInfo);
   luaM_shrinkvector(L, f->k, f->sizek, fs->nk, TValue);
   luaM_shrinkvector(L, f->p, f->sizep, fs->np, Proto *);
-  luaM_shrinkvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
+  luaM_shrinkvector(L, f->locvars, f->sizelocvars, fs->ndebugvars, LocVar);
   luaM_shrinkvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);
   ls->fs = fs->prev;
   luaC_checkGC(L);

@@ -758,16 +816,16 @@
 */
 
 
-struct ConsControl {
+typedef struct ConsControl {
   expdesc v;  /* last list item read */
   expdesc *t;  /* table descriptor */
   int nh;  /* total number of 'record' elements */
-  int na;  /* total number of array elements */
+  int na;  /* number of array elements already stored */
   int tostore;  /* number of array elements pending to be stored */
-};
+} ConsControl;
 
 
-static void recfield (LexState *ls, struct ConsControl *cc) {
+static void recfield (LexState *ls, ConsControl *cc) {
   /* recfield -> (NAME | '['exp']') = exp */
   FuncState *fs = ls->fs;
   int reg = ls->fs->freereg;

@@ -788,18 +846,19 @@
 }
 
 
-static void closelistfield (FuncState *fs, struct ConsControl *cc) {
+static void closelistfield (FuncState *fs, ConsControl *cc) {
   if (cc->v.k == VVOID) return;  /* there is no list item */
   luaK_exp2nextreg(fs, &cc->v);
   cc->v.k = VVOID;
   if (cc->tostore == LFIELDS_PER_FLUSH) {
     luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore);  /* flush */
+    cc->na += cc->tostore;
     cc->tostore = 0;  /* no more items pending */
   }
 }
 
 
-static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
+static void lastlistfield (FuncState *fs, ConsControl *cc) {
   if (cc->tostore == 0) return;
   if (hasmultret(cc->v.k)) {
     luaK_setmultret(fs, &cc->v);

@@ -811,19 +870,18 @@
       luaK_exp2nextreg(fs, &cc->v);
     luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore);
   }
+  cc->na += cc->tostore;
 }
 
 
-static void listfield (LexState *ls, struct ConsControl *cc) {
+static void listfield (LexState *ls, ConsControl *cc) {
   /* listfield -> exp */
   expr(ls, &cc->v);
-  checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor");
-  cc->na++;
   cc->tostore++;
 }
 
 
-static void field (LexState *ls, struct ConsControl *cc) {
+static void field (LexState *ls, ConsControl *cc) {
   /* field -> listfield | recfield */
   switch(ls->t.token) {
     case TK_NAME: {  /* may be 'listfield' or 'recfield' */

@@ -851,12 +909,13 @@
   FuncState *fs = ls->fs;
   int line = ls->linenumber;
   int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
-  struct ConsControl cc;
+  ConsControl cc;
+  luaK_code(fs, 0);  /* space for extra arg. */
   cc.na = cc.nh = cc.tostore = 0;
   cc.t = t;
-  init_exp(t, VRELOC, pc);
+  init_exp(t, VNONRELOC, fs->freereg);  /* table will be at stack top */
+  luaK_reserveregs(fs, 1);
   init_exp(&cc.v, VVOID, 0);  /* no value (yet) */
-  luaK_exp2nextreg(ls->fs, t);  /* fix it at stack top */
   checknext(ls, '{');
   do {
     lua_assert(cc.v.k == VVOID || cc.tostore > 0);

@@ -866,8 +925,7 @@
   } while (testnext(ls, ',') || testnext(ls, ';'));
   check_match(ls, '}', '{', line);
   lastlistfield(fs, &cc);
-  SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */
-  SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh));  /* set initial table size */
+  luaK_settablesize(fs, pc, t->u.info, cc.na, cc.nh);
 }
 
 /* }====================================================================== */

@@ -966,7 +1024,7 @@
       break;
     }
     case TK_STRING: {  /* funcargs -> STRING */
-      codestring(ls, &args, ls->t.seminfo.ts);
+      codestring(&args, ls->t.seminfo.ts);
       luaX_next(ls);  /* must use 'seminfo' before 'next' */
       break;
     }

@@ -1074,7 +1132,7 @@
       break;
     }
     case TK_STRING: {
-      codestring(ls, v, ls->t.seminfo.ts);
+      codestring(v, ls->t.seminfo.ts);
       break;
     }
     case TK_NIL: {

@@ -1257,20 +1315,20 @@
   for (; lh; lh = lh->prev) {  /* check all previous assignments */
     if (vkisindexed(lh->v.k)) {  /* assignment to table field? */
       if (lh->v.k == VINDEXUP) {  /* is table an upvalue? */
-        if (v->k == VUPVAL && lh->v.u.ind.t == v->u.var.idx) {
+        if (v->k == VUPVAL && lh->v.u.ind.t == v->u.info) {
           conflict = 1;  /* table is the upvalue being assigned now */
           lh->v.k = VINDEXSTR;
           lh->v.u.ind.t = extra;  /* assignment will use safe copy */
         }
       }
       else {  /* table is a register */
-        if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.idx) {
+        if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.sidx) {
           conflict = 1;  /* table is the local being assigned now */
           lh->v.u.ind.t = extra;  /* assignment will use safe copy */
         }
         /* is index the local being assigned? */
         if (lh->v.k == VINDEXED && v->k == VLOCAL &&
-            lh->v.u.ind.idx == v->u.var.idx) {
+            lh->v.u.ind.idx == v->u.var.sidx) {
           conflict = 1;
           lh->v.u.ind.idx = extra;  /* previous assignment will use safe copy */
         }

@@ -1279,14 +1337,16 @@
   }
   if (conflict) {
     /* copy upvalue/local value to a temporary (in position 'extra') */
-    OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;
-    luaK_codeABC(fs, op, extra, v->u.var.idx, 0);
+    if (v->k == VLOCAL)
+      luaK_codeABC(fs, OP_MOVE, extra, v->u.var.sidx, 0);
+    else
+      luaK_codeABC(fs, OP_GETUPVAL, extra, v->u.info, 0);
     luaK_reserveregs(fs, 1);
   }
 }
 
 /*
-** Parse and compile a mulitple assignment. The first "variable"
+** Parse and compile a multiple assignment. The first "variable"
 ** (a 'suffixedexp') was already read by the caller.
 **
 ** assignment -> suffixedexp restassign

@@ -1343,8 +1403,9 @@
     newgotoentry(ls, name, line, luaK_jump(fs));
   else {  /* found a label */
     /* backward jump; will be resolved here */
-    if (fs->nactvar > lb->nactvar)  /* leaving the scope of some variable? */
-      luaK_codeABC(fs, OP_CLOSE, lb->nactvar, 0, 0);
+    int lblevel = stacklevel(fs, lb->nactvar);  /* label level */
+    if (luaY_nvarstack(fs) > lblevel)  /* leaving the scope of a variable? */
+      luaK_codeABC(fs, OP_CLOSE, lblevel, 0, 0);
     /* create jump and link it to the label */
     luaK_patchlist(fs, luaK_jump(fs), lb->pc);
   }

@@ -1419,7 +1480,7 @@
   if (bl2.upval) {  /* upvalues? */
     int exit = luaK_jump(fs);  /* normal exit must jump over fix */
     luaK_patchtohere(fs, condexit);  /* repetition must close upvalues */
-    luaK_codeABC(fs, OP_CLOSE, bl2.nactvar, 0, 0);
+    luaK_codeABC(fs, OP_CLOSE, stacklevel(fs, bl2.nactvar), 0, 0);
     condexit = luaK_jump(fs);  /* repeat after closing upvalues */
     luaK_patchtohere(fs, exit);  /* normal exit comes to here */
   }

@@ -1478,7 +1539,6 @@
   if (isgen) {  /* generic for? */
     luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars);
     luaK_fixline(fs, line);
-    base += 2;  /* base for 'OP_TFORLOOP' (skips function and state) */
   }
   endfor = luaK_codeABx(fs, forloop[isgen], base, 0);
   fixforjump(fs, endfor, prep + 1, 1);

@@ -1490,9 +1550,9 @@
   /* fornum -> NAME = exp,exp[,exp] forbody */
   FuncState *fs = ls->fs;
   int base = fs->freereg;
-  new_localvarliteral(ls, "(for index)");
-  new_localvarliteral(ls, "(for limit)");
-  new_localvarliteral(ls, "(for step)");
+  new_localvarliteral(ls, "(for state)");
+  new_localvarliteral(ls, "(for state)");
+  new_localvarliteral(ls, "(for state)");
   new_localvar(ls, varname);
   checknext(ls, '=');
   exp1(ls);  /* initial value */

@@ -1517,11 +1577,10 @@
   int line;
   int base = fs->freereg;
   /* create control variables */
-  new_localvarliteral(ls, "(for generator)");
   new_localvarliteral(ls, "(for state)");
-  markupval(fs, fs->nactvar);  /* state may create an upvalue */
-  new_localvarliteral(ls, "(for control)");
-  new_localvarliteral(ls, "(for toclose)");
+  new_localvarliteral(ls, "(for state)");
+  new_localvarliteral(ls, "(for state)");
+  new_localvarliteral(ls, "(for state)");
   /* create declared variables */
   new_localvar(ls, indexname);
   while (testnext(ls, ',')) {

@@ -1532,6 +1591,7 @@
   line = ls->linenumber;
   adjust_assign(ls, 4, explist(ls, &e), &e);
   adjustlocalvars(ls, 4);  /* control variables */
+  markupval(fs, luaY_nvarstack(fs));  /* state may create an upvalue */
   luaK_checkstack(fs, 3);  /* extra space to call generator */
   forbody(ls, base, line, nvars - 4, 1);
 }

@@ -1574,7 +1634,8 @@
     TString *lname = ls->lookahead.seminfo.ts;  /* label's id */
     Labeldesc *lb = findlabel(ls, lname);
     if (lb) {  /* a backward jump? */
-      if (ls->fs->nactvar > lb->nactvar)  /* needs to close variables? */
+      /* does it need to close variables? */
+      if (luaY_nvarstack(ls->fs) > stacklevel(ls->fs, lb->nactvar))
         return 0;  /* not a single jump; cannot optimize */
       *target = lb->pc;
     }

@@ -1646,21 +1707,60 @@
 static void localfunc (LexState *ls) {
   expdesc b;
   FuncState *fs = ls->fs;
+  int fvar = fs->nactvar;  /* function's variable index */
   new_localvar(ls, str_checkname(ls));  /* new local variable */
   adjustlocalvars(ls, 1);  /* enter its scope */
   body(ls, &b, 0, ls->linenumber);  /* function created in next register */
   /* debug information will only see the variable after this point! */
-  getlocvar(fs, b.u.info)->startpc = fs->pc;
+  localdebuginfo(fs, fvar)->startpc = fs->pc;
 }
 
 
-static void commonlocalstat (LexState *ls) {
-  /* stat -> LOCAL NAME {',' NAME} ['=' explist] */
+static int getlocalattribute (LexState *ls) {
+  /* ATTRIB -> ['<' Name '>'] */
+  if (testnext(ls, '<')) {
+    const char *attr = getstr(str_checkname(ls));
+    checknext(ls, '>');
+    if (strcmp(attr, "const") == 0)
+      return RDKCONST;  /* read-only variable */
+    else if (strcmp(attr, "close") == 0)
+      return RDKTOCLOSE;  /* to-be-closed variable */
+    else
+      luaK_semerror(ls,
+        luaO_pushfstring(ls->L, "unknown attribute '%s'", attr));
+  }
+  return VDKREG;
+}
+
+
+static void checktoclose (LexState *ls, int level) {
+  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 */
+    luaK_codeABC(fs, OP_TBC, level, 0, 0);
+  }
+}
+
+
+static void localstat (LexState *ls) {
+  /* stat -> LOCAL ATTRIB NAME {',' ATTRIB NAME} ['=' explist] */
+  FuncState *fs = ls->fs;
+  int toclose = -1;  /* index of to-be-closed variable (if any) */
+  Vardesc *var;  /* last variable */
+  int ivar, kind;  /* index and kind of last variable */
   int nvars = 0;
   int nexps;
   expdesc e;
   do {
-    new_localvar(ls, str_checkname(ls));
+    ivar = new_localvar(ls, str_checkname(ls));
+    kind = getlocalattribute(ls);
+    getlocalvardesc(fs, ivar)->vd.kind = kind;
+    if (kind == RDKTOCLOSE) {  /* to-be-closed? */
+      if (toclose != -1)  /* one already present? */
+        luaK_semerror(ls, "multiple to-be-closed variables in local list");
+      toclose = luaY_nvarstack(fs) + nvars;
+    }
     nvars++;
   } while (testnext(ls, ','));
   if (testnext(ls, '='))

@@ -1669,45 +1769,19 @@
     e.k = VVOID;
     nexps = 0;
   }
-  adjust_assign(ls, nvars, nexps, &e);
-  adjustlocalvars(ls, nvars);
-}
-
-
-static void tocloselocalstat (LexState *ls, Vardesc *var) {
-  FuncState *fs = ls->fs;
-  var->ro = 1;  /* to-be-closed variables are always read-only */
-  markupval(fs, fs->nactvar);
-  fs->bl->insidetbc = 1;  /* in the scope of a to-be-closed variable */
-  luaK_codeABC(fs, OP_TBC, fs->nactvar - 1, 0, 0);
-}
-
-
-static void attriblocalstat (LexState *ls) {
-  Vardesc *var;
-  TString *attr = str_checkname(ls);
-  testnext(ls, '>');
-  var = new_localvar(ls, str_checkname(ls));
-  checknext(ls, '=');
-  exp1(ls);
-  adjustlocalvars(ls, 1);
-  if (strcmp(getstr(attr), "const") == 0)
-    var->ro = 1;  /* set variable as read-only */
-  else if (strcmp(getstr(attr), "toclose") == 0)
-    tocloselocalstat(ls, var);
-  else
-    luaK_semerror(ls,
-      luaO_pushfstring(ls->L, "unknown attribute '%s'", getstr(attr)));
-}
-
-
-static void localstat (LexState *ls) {
-  /* stat -> LOCAL NAME {',' NAME} ['=' explist]
-           | LOCAL *toclose NAME '=' exp */
-  if (testnext(ls, '<'))
-    attriblocalstat(ls);
-  else
-    commonlocalstat(ls);
+  var = getlocalvardesc(fs, ivar);  /* get last variable */
+  if (nvars == nexps &&  /* no adjustments? */
+      var->vd.kind == RDKCONST &&  /* last variable is const? */
+      luaK_exp2const(fs, &e, &var->k)) {  /* compile-time constant? */
+    var->vd.kind = RDKCTC;  /* variable is a compile-time constant */
+    adjustlocalvars(ls, nvars - 1);  /* exclude last variable */
+    fs->nactvar++;  /* but count it */
+  }
+  else {
+    adjust_assign(ls, nvars, nexps, &e);
+    adjustlocalvars(ls, nvars);
+  }
+  checktoclose(ls, toclose);
 }
 
 

@@ -1759,7 +1833,7 @@
   FuncState *fs = ls->fs;
   expdesc e;
   int nret;  /* number of values being returned */
-  int first = fs->nactvar;  /* first slot to be returned */
+  int first = luaY_nvarstack(fs);  /* first slot to be returned */
   if (block_follow(ls, 1) || ls->t.token == ';')
     nret = 0;  /* return no values */
   else {

@@ -1768,7 +1842,7 @@
       luaK_setmultret(fs, &e);
       if (e.k == VCALL && nret == 1 && !fs->bl->insidetbc) {  /* tail call? */
         SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);
-        lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar);
+        lua_assert(GETARG_A(getinstruction(fs,&e)) == luaY_nvarstack(fs));
       }
       nret = LUA_MULTRET;  /* return all values */
     }

@@ -1853,8 +1927,8 @@
     }
   }
   lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
-             ls->fs->freereg >= ls->fs->nactvar);
-  ls->fs->freereg = ls->fs->nactvar;  /* free registers */
+             ls->fs->freereg >= luaY_nvarstack(ls->fs));
+  ls->fs->freereg = luaY_nvarstack(ls->fs);  /* free registers */
   leavelevel(ls);
 }
 

@@ -1867,11 +1941,14 @@
 */
 static void mainfunc (LexState *ls, FuncState *fs) {
   BlockCnt bl;
-  expdesc v;
+  Upvaldesc *env;
   open_func(ls, fs, &bl);
   setvararg(fs, 0);  /* main function is always declared vararg */
-  init_var(&v, VLOCAL, 0);  /* create and... */
-  newupvalue(fs, ls->envn, &v);  /* ...set environment upvalue */
+  env = allocupvalue(fs);  /* ...set environment upvalue */
+  env->instack = 1;
+  env->idx = 0;
+  env->kind = VDKREG;
+  env->name = ls->envn;
   luaX_next(ls);  /* read first token */
   statlist(ls);  /* parse main body */
   check(ls, TK_EOS);

src/lparser.h

@@ -30,11 +30,15 @@
   VFALSE,  /* constant false */
   VK,  /* constant in 'k'; info = index of constant in 'k' */
   VKFLT,  /* floating constant; nval = numerical float value */
-  VKINT,  /* integer constant; nval = numerical integer value */
+  VKINT,  /* integer constant; ival = numerical integer value */
+  VKSTR,  /* string constant; strval = TString address;
+             (string is fixed by the lexer) */
   VNONRELOC,  /* expression has its value in a fixed register;
                  info = result register */
-  VLOCAL,  /* local variable; var.idx = local register */
-  VUPVAL,  /* upvalue variable; var.idx = index of upvalue in 'upvalues' */
+  VLOCAL,  /* local variable; var.ridx = local register;
+              var.vidx = relative index in 'actvar.arr'  */
+  VUPVAL,  /* upvalue variable; info = index of upvalue in 'upvalues' */
+  VCONST,  /* compile-time constant; info = absolute index in 'actvar.arr'  */
   VINDEXED,  /* indexed variable;
                 ind.t = table register;
                 ind.idx = key's R index */

@@ -65,13 +69,15 @@
   union {
     lua_Integer ival;    /* for VKINT */
     lua_Number nval;  /* for VKFLT */
+    TString *strval;  /* for VKSTR */
     int info;  /* for generic use */
     struct {  /* for indexed variables */
       short idx;  /* index (R or "long" K) */
       lu_byte t;  /* table (register or upvalue) */
     } ind;
-    struct {  /* for local variables and upvalues */
-      lu_byte idx;  /* index of the variable */
+    struct {  /* for local variables */
+      lu_byte sidx;  /* index in the stack */
+      unsigned short vidx;  /* index in 'actvar.arr'  */
     } var;
   } u;
   int t;  /* patch list of 'exit when true' */

@@ -79,20 +85,32 @@
 } expdesc;
 
 
+/* kinds of variables */
+#define VDKREG		0   /* regular */
+#define RDKCONST	1   /* constant */
+#define RDKTOCLOSE	2   /* to-be-closed */
+#define RDKCTC		3   /* compile-time constant */
+
 /* description of an active local variable */
-typedef struct Vardesc {
-  TString *name;
-  short idx;  /* index of the variable in the Proto's 'locvars' array */
-  lu_byte ro;  /* true if variable is 'const' */
+typedef union Vardesc {
+  struct {
+    TValuefields;  /* constant value (if it is a compile-time constant) */
+    lu_byte kind;
+    lu_byte sidx;  /* index of the variable in the stack */
+    short pidx;  /* index of the variable in the Proto's 'locvars' array */
+    TString *name;  /* variable name */
+  } vd;
+  TValue k;  /* constant value (if any) */
 } Vardesc;
 
 
+
 /* description of pending goto statements and label statements */
 typedef struct Labeldesc {
   TString *name;  /* label identifier */
   int pc;  /* position in code */
   int line;  /* line where it appeared */
-  lu_byte nactvar;  /* local level where it appears in current block */
+  lu_byte nactvar;  /* number of active variables in that position */
   lu_byte close;  /* goto that escapes upvalues */
 } Labeldesc;
 

@@ -135,7 +153,7 @@
   int nabslineinfo;  /* number of elements in 'abslineinfo' */
   int firstlocal;  /* index of first local var (in Dyndata array) */
   int firstlabel;  /* index of first label (in 'dyd->label->arr') */
-  short nlocvars;  /* number of elements in 'f->locvars' */
+  short ndebugvars;  /* number of elements in 'f->locvars' */
   lu_byte nactvar;  /* number of active local variables */
   lu_byte nups;  /* number of upvalues */
   lu_byte freereg;  /* first free register */

@@ -144,6 +162,7 @@
 } FuncState;
 
 
+LUAI_FUNC int luaY_nvarstack (FuncState *fs);
 LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
                                  Dyndata *dyd, const char *name, int firstchar);
 

src/lstate.c

@@ -96,36 +96,58 @@
 }
 
 
+LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) {
+  global_State *g = G(L);
+  int ccalls;
+  luaE_freeCI(L);  /* release unused CIs */
+  ccalls = getCcalls(L);
+  if (limit >= 40000)
+    return 0;  /* out of bounds */
+  limit += CSTACKERR;
+  if (L != g-> mainthread)
+    return 0;  /* only main thread can change the C stack */
+  else if (ccalls <= CSTACKERR)
+    return 0;  /* handling overflow */
+  else {
+    int diff = limit - g->Cstacklimit;
+    if (ccalls + diff <= CSTACKERR)
+      return 0;  /* new limit would cause an overflow */
+    g->Cstacklimit = limit;  /* set new limit */
+    L->nCcalls += diff;  /* correct 'nCcalls' */
+    return limit - diff - CSTACKERR;  /* success; return previous limit */
+  }
+}
+
+
 /*
-** Increment count of "C calls" and check for overflows. In case of
+** Decrement count of "C calls" and check for overflows. In case of
 ** a stack overflow, check appropriate error ("regular" overflow or
-** overflow while handling stack overflow).
-** If 'nCcalls' is larger than LUAI_MAXCSTACK but smaller than
-** LUAI_MAXCSTACK + CSTACKCF (plus 2 to avoid by-one errors), it means
-** it has just entered the "overflow zone", so the function raises an
-** overflow error.
-** If 'nCcalls' is larger than LUAI_MAXCSTACK + CSTACKCF + 2
-** (which means it is already handling an overflow) but smaller than
-** 9/8 of LUAI_MAXCSTACK, does not report an error (to allow message
-** handling to work).
-** Otherwise, report a stack overflow while handling a stack overflow
-** (probably caused by a repeating error in the message handling
-** function).
+** overflow while handling stack overflow).  If 'nCcalls' is smaller
+** than CSTACKERR but larger than CSTACKMARK, it means it has just
+** entered the "overflow zone", so the function raises an overflow
+** error.  If 'nCcalls' is smaller than CSTACKMARK (which means it is
+** already handling an overflow) but larger than CSTACKERRMARK, does
+** not report an error (to allow message handling to work). Otherwise,
+** report a stack overflow while handling a stack overflow (probably
+** caused by a repeating error in the message handling function).
 */
+
 void luaE_enterCcall (lua_State *L) {
   int ncalls = getCcalls(L);
-  L->nCcalls++;
-  if (ncalls >= LUAI_MAXCSTACK) {  /* possible overflow? */
+  L->nCcalls--;
+  if (ncalls <= CSTACKERR) {  /* possible overflow? */
     luaE_freeCI(L);  /* release unused CIs */
     ncalls = getCcalls(L);  /* update call count */
-    if (ncalls >= LUAI_MAXCSTACK) {  /* still overflow? */
-      if (ncalls <= LUAI_MAXCSTACK + CSTACKCF + 2) {
-        /* no error before increments; raise the error now */
-        L->nCcalls += (CSTACKCF + 4);  /* avoid raising it again */
+    if (ncalls <= CSTACKERR) {  /* still overflow? */
+      if (ncalls <= CSTACKERRMARK)  /* below error-handling zone? */
+        luaD_throw(L, LUA_ERRERR);  /* error while handling stack error */
+      else if (ncalls >= CSTACKMARK) {
+        /* not in error-handling zone; raise the error now */
+        L->nCcalls = (CSTACKMARK - 1);  /* enter error-handling zone */
         luaG_runerror(L, "C stack overflow");
       }
-      else if (ncalls >= (LUAI_MAXCSTACK + (LUAI_MAXCSTACK >> 3)))
-        luaD_throw(L, LUA_ERRERR);  /* error while handling stack error */
+      /* else stack is in the error-handling zone;
+         allow message handler to work */
     }
   }
 }

@@ -153,13 +175,13 @@
   CallInfo *ci = L->ci;
   CallInfo *next = ci->next;
   ci->next = NULL;
-  L->nCcalls -= L->nci;  /* subtract removed elements from 'nCcalls' */
+  L->nCcalls += L->nci;  /* add removed elements back to 'nCcalls' */
   while ((ci = next) != NULL) {
     next = ci->next;
     luaM_free(L, ci);
     L->nci--;
   }
-  L->nCcalls += L->nci;  /* adjust result */
+  L->nCcalls -= L->nci;  /* adjust result */
 }
 
 

@@ -169,7 +191,7 @@
 void luaE_shrinkCI (lua_State *L) {
   CallInfo *ci = L->ci;
   CallInfo *next2;  /* next's next */
-  L->nCcalls -= L->nci;  /* subtract removed elements from 'nCcalls' */
+  L->nCcalls += L->nci;  /* add removed elements back to 'nCcalls' */
   /* while there are two nexts */
   while (ci->next != NULL && (next2 = ci->next->next) != NULL) {
     luaM_free(L, ci->next);  /* free next */

@@ -178,7 +200,7 @@
     next2->previous = ci;
     ci = next2;  /* keep next's next */
   }
-  L->nCcalls += L->nci;  /* adjust result */
+  L->nCcalls -= L->nci;  /* adjust result */
 }
 
 

@@ -264,7 +286,7 @@
   L->stacksize = 0;
   L->twups = L;  /* thread has no upvalues */
   L->errorJmp = NULL;
-  L->nCcalls = 0;
+  L->nCcalls = CSTACKTHREAD;
   L->hook = NULL;
   L->hookmask = 0;
   L->basehookcount = 0;

@@ -366,6 +388,7 @@
   preinit_thread(L, g);
   g->allgc = obj2gco(L);  /* by now, only object is the main thread */
   L->next = NULL;
+  g->Cstacklimit = L->nCcalls = LUAI_MAXCSTACK + CSTACKERR;
   g->frealloc = f;
   g->ud = ud;
   g->warnf = NULL;

@@ -420,3 +443,19 @@
 }
 
 
+/*
+** Generate a warning from an error message
+*/
+void luaE_warnerror (lua_State *L, const char *where) {
+  TValue *errobj = s2v(L->top - 1);  /* error object */
+  const char *msg = (ttisstring(errobj))
+                  ? svalue(errobj)
+                  : "error object is not a string";
+  /* produce warning "error in %s (%s)" (where, msg) */
+  luaE_warning(L, "error in ", 1);
+  luaE_warning(L, where, 1);
+  luaE_warning(L, " (", 1);
+  luaE_warning(L, msg, 1);
+  luaE_warning(L, ")", 0);
+}
+

src/lstate.h

@@ -64,28 +64,49 @@
 
 /*
 ** About 'nCcalls': each thread in Lua (a lua_State) keeps a count of
-** how many "C calls" it can do in the C stack, to avoid C-stack overflow.
-** This count is very rough approximation; it considers only recursive
-** functions inside the interpreter, as non-recursive calls can be
-** considered using a fixed (although unknown) amount of stack space.
+** how many "C calls" it still can do in the C stack, to avoid C-stack
+** overflow.  This count is very rough approximation; it considers only
+** recursive functions inside the interpreter, as non-recursive calls
+** can be considered using a fixed (although unknown) amount of stack
+** space.
 **
-** The count itself has two parts: the lower part is the count itself;
-** the higher part counts the number of non-yieldable calls in the stack.
+** The count has two parts: the lower part is the count itself; the
+** higher part counts the number of non-yieldable calls in the stack.
+** (They are together so that we can change both with one instruction.)
 **
-** Because calls to external C functions can use of unkown amount
+** Because calls to external C functions can use an unknown amount
 ** of space (e.g., functions using an auxiliary buffer), calls
-** to these functions add more than one to the count.
+** to these functions add more than one to the count (see CSTACKCF).
 **
-** The proper count also includes the number of CallInfo structures
-** allocated by Lua, as a kind of "potential" calls. So, when Lua
-** calls a function (and "consumes" one CallInfo), it needs neither to
-** increment nor to check 'nCcalls', as its use of C stack is already
-** accounted for.
+** The proper count excludes the number of CallInfo structures allocated
+** by Lua, as a kind of "potential" calls. So, when Lua calls a function
+** (and "consumes" one CallInfo), it needs neither to decrement nor to
+** check 'nCcalls', as its use of C stack is already accounted for.
 */
 
 /* number of "C stack slots" used by an external C function */
 #define CSTACKCF	10
 
+
+/*
+** The C-stack size is sliced in the following zones:
+** - larger than CSTACKERR: normal stack;
+** - [CSTACKMARK, CSTACKERR]: buffer zone to signal a stack overflow;
+** - [CSTACKCF, CSTACKERRMARK]: error-handling zone;
+** - below CSTACKERRMARK: buffer zone to signal overflow during overflow;
+** (Because the counter can be decremented CSTACKCF at once, we need
+** the so called "buffer zones", with at least that size, to properly
+** detect a change from one zone to the next.)
+*/
+#define CSTACKERR	(8 * CSTACKCF)
+#define CSTACKMARK	(CSTACKERR - (CSTACKCF + 2))
+#define CSTACKERRMARK	(CSTACKCF + 2)
+
+
+/* initial limit for the C-stack of threads */
+#define CSTACKTHREAD	(2 * CSTACKERR)
+
+
 /* true if this thread does not have non-yieldable calls in the stack */
 #define yieldable(L)		(((L)->nCcalls & 0xffff0000) == 0)
 

@@ -99,11 +120,11 @@
 /* Decrement the number of non-yieldable calls */
 #define decnny(L)	((L)->nCcalls -= 0x10000)
 
-/* Increment the number of non-yieldable calls and nCcalls */
-#define incXCcalls(L)	((L)->nCcalls += 0x10000 + CSTACKCF)
+/* Increment the number of non-yieldable calls and decrement nCcalls */
+#define incXCcalls(L)	((L)->nCcalls += 0x10000 - CSTACKCF)
 
-/* Decrement the number of non-yieldable calls and nCcalls */
-#define decXCcalls(L)	((L)->nCcalls -= 0x10000 + CSTACKCF)
+/* Decrement the number of non-yieldable calls and increment nCcalls */
+#define decXCcalls(L)	((L)->nCcalls -= 0x10000 - CSTACKCF)
 
 
 

@@ -164,9 +185,9 @@
   union {
     int funcidx;  /* called-function index */
     int nyield;  /* number of values yielded */
-    struct {  /* info about transfered values (for call/return hooks) */
-      unsigned short ftransfer;  /* offset of first value transfered */
-      unsigned short ntransfer;  /* number of values transfered */
+    struct {  /* info about transferred values (for call/return hooks) */
+      unsigned short ftransfer;  /* offset of first value transferred */
+      unsigned short ntransfer;  /* number of values transferred */
     } transferinfo;
   } u2;
   short nresults;  /* expected number of results from this function */

@@ -250,6 +271,7 @@
   TString *strcache[STRCACHE_N][STRCACHE_M];  /* cache for strings in API */
   lua_WarnFunction warnf;  /* warning function */
   void *ud_warn;         /* auxiliary data to 'warnf' */
+  unsigned int Cstacklimit;  /* current limit for the C stack */
 } global_State;
 
 

@@ -313,8 +335,7 @@
 #define gco2t(o)  check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h))
 #define gco2p(o)  check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p))
 #define gco2th(o)  check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th))
-#define gco2upv(o)  \
-	check_exp(novariant((o)->tt) == LUA_TUPVAL, &((cast_u(o))->upv))
+#define gco2upv(o)	check_exp((o)->tt == LUA_TUPVAL, &((cast_u(o))->upv))
 
 
 /*

@@ -334,9 +355,10 @@
 LUAI_FUNC void luaE_shrinkCI (lua_State *L);
 LUAI_FUNC void luaE_enterCcall (lua_State *L);
 LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
+LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
 
 
-#define luaE_exitCcall(L)	((L)->nCcalls--)
+#define luaE_exitCcall(L)	((L)->nCcalls++)
 
 #endif
 

src/lstrlib.c

@@ -744,7 +744,7 @@
   const char *p = luaL_checklstring(L, 2, &lp);
   size_t init = posrelatI(luaL_optinteger(L, 3, 1), ls) - 1;
   if (init > ls) {  /* start after string's end? */
-    lua_pushnil(L);  /* cannot find anything */
+    luaL_pushfail(L);  /* cannot find anything */
     return 1;
   }
   /* explicit request or no special characters? */

@@ -779,7 +779,7 @@
       }
     } while (s1++ < ms.src_end && !anchor);
   }
-  lua_pushnil(L);  /* not found */
+  luaL_pushfail(L);  /* not found */
   return 1;
 }
 

@@ -1227,16 +1227,14 @@
           nb = lua_number2strx(L, buff, maxitem, form,
                                   luaL_checknumber(L, arg));
           break;
-        case 'e': case 'E': case 'f':
-        case 'g': case 'G': {
+        case 'f':
+          maxitem = MAX_ITEMF;  /* extra space for '%f' */
+          buff = luaL_prepbuffsize(&b, maxitem);
+          /* FALLTHROUGH */
+        case 'e': case 'E': case 'g': case 'G': {
           lua_Number n = luaL_checknumber(L, arg);
-          if (*(strfrmt - 1) == 'f' && l_mathop(fabs)(n) >= 1e100) {
-            /* 'n' needs more than 99 digits */
-            maxitem = MAX_ITEMF;  /* extra space for '%f' */
-            buff = luaL_prepbuffsize(&b, maxitem);
-          }
           addlenmod(form, LUA_NUMBER_FRMLEN);
-          nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n);
+          nb = snprintf(buff, maxitem, form, (LUAI_UACNUMBER)n);
           break;
         }
         case 'p': {

src/ltable.c

@@ -833,39 +833,41 @@
 ** and 'maxinteger' if t[maxinteger] is present.)
 ** (In the next explanation, we use Lua indices, that is, with base 1.
 ** The code itself uses base 0 when indexing the array part of the table.)
-** The code starts with 'limit', a position in the array part that may
-** be a boundary.
+** The code starts with 'limit = t->alimit', a position in the array
+** part that may be a boundary.
+**
 ** (1) If 't[limit]' is empty, there must be a boundary before it.
-** As a common case (e.g., after 't[#t]=nil'), check whether 'hint-1'
+** As a common case (e.g., after 't[#t]=nil'), check whether 'limit-1'
 ** is present. If so, it is a boundary. Otherwise, do a binary search
 ** between 0 and limit to find a boundary. In both cases, try to
-** use this boundary as the new 'limit', as a hint for the next call.
+** use this boundary as the new 'alimit', as a hint for the next call.
+**
 ** (2) If 't[limit]' is not empty and the array has more elements
 ** after 'limit', try to find a boundary there. Again, try first
 ** the special case (which should be quite frequent) where 'limit+1'
 ** is empty, so that 'limit' is a boundary. Otherwise, check the
-** last element of the array part (set it as a new limit). If it is empty,
-** there must be a boundary between the old limit (present) and the new
-** limit (absent), which is found with a binary search. (This boundary
-** always can be a new limit.)
+** last element of the array part. If it is empty, there must be a
+** boundary between the old limit (present) and the last element
+** (absent), which is found with a binary search. (This boundary always
+** can be a new limit.)
+**
 ** (3) The last case is when there are no elements in the array part
 ** (limit == 0) or its last element (the new limit) is present.
-** In this case, must check the hash part. If there is no hash part,
-** the boundary is 0. Otherwise, if 'limit+1' is absent, 'limit' is
-** a boundary. Finally, if 'limit+1' is present, call 'hash_search'
-** to find a boundary in the hash part of the table. (In those
-** cases, the boundary is not inside the array part, and therefore
-** cannot be used as a new limit.)
+** In this case, must check the hash part. If there is no hash part
+** or 'limit+1' is absent, 'limit' is a boundary.  Otherwise, call
+** 'hash_search' to find a boundary in the hash part of the table.
+** (In those cases, the boundary is not inside the array part, and
+** therefore cannot be used as a new limit.)
 */
 lua_Unsigned luaH_getn (Table *t) {
   unsigned int limit = t->alimit;
-  if (limit > 0 && isempty(&t->array[limit - 1])) {
-    /* (1) there must be a boundary before 'limit' */
+  if (limit > 0 && isempty(&t->array[limit - 1])) {  /* (1)? */
+    /* there must be a boundary before 'limit' */
     if (limit >= 2 && !isempty(&t->array[limit - 2])) {
       /* 'limit - 1' is a boundary; can it be a new limit? */
       if (ispow2realasize(t) && !ispow2(limit - 1)) {
         t->alimit = limit - 1;
-        setnorealasize(t);
+        setnorealasize(t);  /* now 'alimit' is not the real size */
       }
       return limit - 1;
     }

@@ -880,8 +882,8 @@
     }
   }
   /* 'limit' is zero or present in table */
-  if (!limitequalsasize(t)) {
-    /* (2) 'limit' > 0 and array has more elements after 'limit' */
+  if (!limitequalsasize(t)) {  /* (2)? */
+    /* 'limit' > 0 and array has more elements after 'limit' */
     if (isempty(&t->array[limit]))  /* 'limit + 1' is empty? */
       return limit;  /* this is the boundary */
     /* else, try last element in the array */

@@ -899,7 +901,7 @@
   lua_assert(limit == luaH_realasize(t) &&
              (limit == 0 || !isempty(&t->array[limit - 1])));
   if (isdummy(t) || isempty(luaH_getint(t, cast(lua_Integer, limit + 1))))
-    return limit;  /* 'limit + 1' is absent... */
+    return limit;  /* 'limit + 1' is absent */
   else  /* 'limit + 1' is also present */
     return hash_search(t, limit);
 }

@@ -908,6 +910,8 @@
 
 #if defined(LUA_DEBUG)
 
+/* export these functions for the test library */
+
 Node *luaH_mainposition (const Table *t, const TValue *key) {
   return mainpositionTV(t, key);
 }

src/ltablib.c

@@ -338,7 +338,7 @@
 
 
 /*
-** QuickSort algorithm (recursive function)
+** Quicksort algorithm (recursive function)
 */
 static void auxsort (lua_State *L, IdxT lo, IdxT up,
                                    unsigned int rnd) {

src/ltm.c

@@ -149,9 +149,6 @@
                     StkId res, TMS event) {
   if (!callbinTM(L, p1, p2, res, event)) {
     switch (event) {
-      case TM_CONCAT:
-        luaG_concaterror(L, p1, p2);
-      /* call never returns, but to avoid warnings: *//* FALLTHROUGH */
       case TM_BAND: case TM_BOR: case TM_BXOR:
       case TM_SHL: case TM_SHR: case TM_BNOT: {
         if (ttisnumber(p1) && ttisnumber(p2))

@@ -167,9 +164,16 @@
 }
 
 
+void luaT_tryconcatTM (lua_State *L) {
+  StkId top = L->top;
+  if (!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2, TM_CONCAT))
+    luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
+}
+
+
 void luaT_trybinassocTM (lua_State *L, const TValue *p1, const TValue *p2,
-                                       StkId res, int inv, TMS event) {
-  if (inv)
+                                       int flip, StkId res, TMS event) {
+  if (flip)
     luaT_trybinTM(L, p2, p1, res, event);
   else
     luaT_trybinTM(L, p1, p2, res, event);

@@ -177,10 +181,10 @@
 
 
 void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
-                                   int inv, StkId res, TMS event) {
+                                   int flip, StkId res, TMS event) {
   TValue aux;
   setivalue(&aux, i2);
-  luaT_trybinassocTM(L, p1, &aux, res, inv, event);
+  luaT_trybinassocTM(L, p1, &aux, flip, res, event);
 }
 
 

@@ -205,14 +209,14 @@
 
 
 int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
-                       int inv, int isfloat, TMS event) {
+                       int flip, int isfloat, TMS event) {
   TValue aux; const TValue *p2;
   if (isfloat) {
     setfltvalue(&aux, cast_num(v2));
   }
   else
     setivalue(&aux, v2);
-  if (inv) {  /* arguments were exchanged? */
+  if (flip) {  /* arguments were exchanged? */
     p2 = p1; p1 = &aux;  /* correct them */
   }
   else

src/ltm.h

@@ -75,8 +75,9 @@
                             const TValue *p1, const TValue *p2, StkId p3);
 LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
                               StkId res, TMS event);
+LUAI_FUNC void luaT_tryconcatTM (lua_State *L);
 LUAI_FUNC void luaT_trybinassocTM (lua_State *L, const TValue *p1,
-       const TValue *p2, StkId res, int inv, TMS event);
+       const TValue *p2, int inv, StkId res, TMS event);
 LUAI_FUNC void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
                                int inv, StkId res, TMS event);
 LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,

src/lua.c

@@ -73,6 +73,7 @@
   "  -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"
   ,

@@ -259,14 +260,18 @@
       case '\0':  /* '-' */
         return args;  /* script "name" is '-' */
       case 'E':
-        if (argv[i][2] != '\0')  /* extra characters after 1st? */
+        if (argv[i][2] != '\0')  /* extra characters? */
           return has_error;  /* invalid option */
         args |= has_E;
         break;
+      case 'W':
+        if (argv[i][2] != '\0')  /* extra characters? */
+          return has_error;  /* invalid option */
+        break;
       case 'i':
         args |= has_i;  /* (-i implies -v) *//* FALLTHROUGH */
       case 'v':
-        if (argv[i][2] != '\0')  /* extra characters after 1st? */
+        if (argv[i][2] != '\0')  /* extra characters? */
           return has_error;  /* invalid option */
         args |= has_v;
         break;

@@ -289,7 +294,8 @@
 
 
 /*
-** Processes options 'e' and 'l', which involve running Lua code.
+** Processes options 'e' and 'l', which involve running Lua code, and
+** 'W', which also affects the state.
 ** Returns 0 if some code raises an error.
 */
 static int runargs (lua_State *L, char **argv, int n) {

@@ -297,15 +303,21 @@
   for (i = 1; i < n; i++) {
     int option = argv[i][1];
     lua_assert(argv[i][0] == '-');  /* already checked */
-    if (option == 'e' || option == 'l') {
-      int status;
-      const char *extra = argv[i] + 2;  /* both options need an argument */
-      if (*extra == '\0') extra = argv[++i];
-      lua_assert(extra != NULL);
-      status = (option == 'e')
-               ? dostring(L, extra, "=(command line)")
-               : dolibrary(L, extra);
-      if (status != LUA_OK) return 0;
+    switch (option) {
+      case 'e':  case 'l': {
+        int status;
+        const char *extra = argv[i] + 2;  /* both options need an argument */
+        if (*extra == '\0') extra = argv[++i];
+        lua_assert(extra != NULL);
+        status = (option == 'e')
+                 ? dostring(L, extra, "=(command line)")
+                 : dolibrary(L, extra);
+        if (status != LUA_OK) return 0;
+        break;
+      }
+      case 'W':
+        lua_warning(L, "@on", 0);  /* warnings on */
+        break;
     }
   }
   return 1;

src/lua.h

@@ -462,6 +462,7 @@
 LUA_API int (lua_gethookmask) (lua_State *L);
 LUA_API int (lua_gethookcount) (lua_State *L);
 
+LUA_API int (lua_setcstacklimit) (lua_State *L, unsigned int limit);
 
 struct lua_Debug {
   int event;

src/luac.c

@@ -37,6 +37,7 @@
 static char Output[]={ OUTPUT };	/* default output file name */
 static const char* output=Output;	/* actual output file name */
 static const char* progname=PROGNAME;	/* actual program name */
+static TString **tmname;
 
 static void fatal(const char* message)
 {

@@ -171,6 +172,7 @@
  char** argv=(char**)lua_touserdata(L,2);
  const Proto* f;
  int i;
+ tmname=G(L)->tmname;
  if (!lua_checkstack(L,argc)) fatal("too many input files");
  for (i=0; i<argc; i++)
  {

@@ -214,6 +216,7 @@
 
 #define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-")
 #define VOID(p) ((const void*)(p))
+#define eventname(i) (getstr(tmname[i]))
 
 static void PrintString(const TString* ts)
 {

@@ -320,6 +323,8 @@
  }
 }
 
+#define COMMENT	"\t; "
+
 static void PrintCode(const Proto* f)
 {
  const Instruction* code=f->code;

@@ -354,30 +359,30 @@
 	break;
    case OP_LOADK:
 	printf("%d %d",a,bx);
-	printf("\t; "); PrintConstant(f,bx);
+	printf(COMMENT); PrintConstant(f,bx);
 	break;
    case OP_LOADKX:
 	printf("%d",a);
 	break;
    case OP_LOADBOOL:
 	printf("%d %d %d",a,b,c);
-	if (c) printf("\t; to %d",pc+2);
+	if (c) printf(COMMENT "to %d",pc+2);
 	break;
    case OP_LOADNIL:
 	printf("%d %d",a,b);
-	printf("\t; %d out",b+1);
+	printf(COMMENT "%d out",b+1);
 	break;
    case OP_GETUPVAL:
 	printf("%d %d",a,b);
-	printf("\t; %s",UPVALNAME(b));
+	printf(COMMENT "%s",UPVALNAME(b));
 	break;
    case OP_SETUPVAL:
 	printf("%d %d",a,b);
-	printf("\t; %s",UPVALNAME(b));
+	printf(COMMENT "%s",UPVALNAME(b));
 	break;
    case OP_GETTABUP:
 	printf("%d %d %d",a,b,c);
-	printf("\t; %s",UPVALNAME(b));
+	printf(COMMENT "%s",UPVALNAME(b));
 	printf(" "); PrintConstant(f,c);
 	break;
    case OP_GETTABLE:

@@ -388,25 +393,25 @@
 	break;
    case OP_GETFIELD:
 	printf("%d %d %d",a,b,c);
-	printf("\t; "); PrintConstant(f,c);
+	printf(COMMENT); PrintConstant(f,c);
 	break;
    case OP_SETTABUP:
 	printf("%d %d %d%s",a,b,c, isk ? "k" : "");
-	printf("\t; %s",UPVALNAME(a));
+	printf(COMMENT "%s",UPVALNAME(a));
 	printf(" "); PrintConstant(f,b);
 	if (isk) { printf(" "); PrintConstant(f,c); }
 	break;
    case OP_SETTABLE:
 	printf("%d %d %d%s",a,b,c, isk ? "k" : "");
-	if (isk) { printf("\t; "); PrintConstant(f,c); }
+	if (isk) { printf(COMMENT); PrintConstant(f,c); }
 	break;
    case OP_SETI:
 	printf("%d %d %d%s",a,b,c, isk ? "k" : "");
-	if (isk) { printf("\t; "); PrintConstant(f,c); }
+	if (isk) { printf(COMMENT); PrintConstant(f,c); }
 	break;
    case OP_SETFIELD:
 	printf("%d %d %d%s",a,b,c, isk ? "k" : "");
-	printf("\t; "); PrintConstant(f,b);
+	printf(COMMENT); PrintConstant(f,b);
 	if (isk) { printf(" "); PrintConstant(f,c); }
 	break;
    case OP_NEWTABLE:

@@ -414,74 +419,56 @@
 	break;
    case OP_SELF:
 	printf("%d %d %d%s",a,b,c, isk ? "k" : "");
-	if (isk) { printf("\t; "); PrintConstant(f,c); }
+	if (isk) { printf(COMMENT); PrintConstant(f,c); }
 	break;
    case OP_ADDI:
-	printf("%d %d %d",a,b,sc);
-	break;
-   case OP_SUBI:
-	printf("%d %d %d",a,b,sc);
-	break;
-   case OP_MULI:
-	printf("%d %d %d",a,b,sc);
-	break;
-   case OP_MODI:
-	printf("%d %d %d",a,b,sc);
-	break;
-   case OP_POWI:
-	printf("%d %d %d",a,b,sc);
-	break;
-   case OP_DIVI:
-	printf("%d %d %d",a,b,sc);
-	break;
-   case OP_IDIVI:
-	printf("%d %d %d",a,b,sc);
+	printf("%d %d %d %s",a,b,sc,isk ? "F" : "");
 	break;
    case OP_ADDK:
-	printf("%d %d %d",a,b,c);
-	printf("\t; "); PrintConstant(f,c);
+	printf("%d %d %d %s",a,b,c,isk ? "F" : "");
+	printf(COMMENT); PrintConstant(f,c);
 	break;
    case OP_SUBK:
 	printf("%d %d %d",a,b,c);
-	printf("\t; "); PrintConstant(f,c);
+	printf(COMMENT); PrintConstant(f,c);
 	break;
    case OP_MULK:
-	printf("%d %d %d",a,b,c);
-	printf("\t; "); PrintConstant(f,c);
+	printf("%d %d %d %s",a,b,c,isk ? "F" : "");
+	printf(COMMENT); PrintConstant(f,c);
 	break;
    case OP_MODK:
 	printf("%d %d %d",a,b,c);
-	printf("\t; "); PrintConstant(f,c);
+	printf(COMMENT); PrintConstant(f,c);
 	break;
    case OP_POWK:
 	printf("%d %d %d",a,b,c);
-	printf("\t; "); PrintConstant(f,c);
+	printf(COMMENT); PrintConstant(f,c);
 	break;
    case OP_DIVK:
 	printf("%d %d %d",a,b,c);
-	printf("\t; "); PrintConstant(f,c);
+	printf(COMMENT); PrintConstant(f,c);
 	break;
    case OP_IDIVK:
 	printf("%d %d %d",a,b,c);
-	printf("\t; "); PrintConstant(f,c);
+	printf(COMMENT); PrintConstant(f,c);
 	break;
    case OP_BANDK:
 	printf("%d %d %d",a,b,c);
-	printf("\t; "); PrintConstant(f,c);
+	printf(COMMENT); PrintConstant(f,c);
 	break;
    case OP_BORK:
 	printf("%d %d %d",a,b,c);
-	printf("\t; "); PrintConstant(f,c);
+	printf(COMMENT); PrintConstant(f,c);
 	break;
    case OP_BXORK:
 	printf("%d %d %d",a,b,c);
-	printf("\t; "); PrintConstant(f,c);
+	printf(COMMENT); PrintConstant(f,c);
 	break;
    case OP_SHRI:
-	printf("%d %d %d",a,b,c);
+	printf("%d %d %d",a,b,sc);
 	break;
    case OP_SHLI:
-	printf("%d %d %d",a,b,c);
+	printf("%d %d %d",a,b,sc);
 	break;
    case OP_ADD:
 	printf("%d %d %d",a,b,c);

@@ -519,6 +506,18 @@
    case OP_SHR:
 	printf("%d %d %d",a,b,c);
 	break;
+   case OP_MMBIN:
+	printf("%d %d %d",a,b,c);
+	break;
+	printf(COMMENT); printf("%s ",eventname(c));
+   case OP_MMBINI:
+	printf("%d %d %d",a,sb,c);
+	printf(COMMENT); printf("%s ",eventname(c));
+	break;
+   case OP_MMBINK:
+	printf("%d %d %d",a,b,c);
+	printf(COMMENT); printf("%s ",eventname(c)); PrintConstant(f,b);
+	break;
    case OP_UNM:
 	printf("%d %d",a,b);
 	break;

@@ -542,7 +541,7 @@
 	break;
    case OP_JMP:
 	printf("%d",GETARG_sJ(i));
-	printf("\t; to %d",GETARG_sJ(i)+pc+2);
+	printf(COMMENT "to %d",GETARG_sJ(i)+pc+2);
 	break;
    case OP_EQ:
 	printf("%d %d %d",a,b,isk);

@@ -555,7 +554,7 @@
 	break;
    case OP_EQK:
 	printf("%d %d %d",a,b,isk);
-	printf("\t; "); PrintConstant(f,b);
+	printf(COMMENT); PrintConstant(f,b);
 	break;
    case OP_EQI:
 	printf("%d %d %d",a,sb,isk);

@@ -580,17 +579,17 @@
 	break;
    case OP_CALL:
 	printf("%d %d %d",a,b,c);
-	printf("\t; ");
+	printf(COMMENT);
 	if (b==0) printf("all in "); else printf("%d in ",b-1);
 	if (c==0) printf("all out"); else printf("%d out",c-1);
 	break;
    case OP_TAILCALL:
 	printf("%d %d %d",a,b,c);
-	printf("\t; %d in",b-1);
+	printf(COMMENT "%d in",b-1);
 	break;
    case OP_RETURN:
 	printf("%d %d %d",a,b,c);
-	printf("\t; ");
+	printf(COMMENT);
 	if (b==0) printf("all out"); else printf("%d out",b-1);
 	break;
    case OP_RETURN0:

@@ -600,33 +599,33 @@
 	break;
    case OP_FORLOOP:
 	printf("%d %d",a,bx);
-	printf("\t; to %d",pc-bx+2);
+	printf(COMMENT "to %d",pc-bx+2);
 	break;
    case OP_FORPREP:
 	printf("%d %d",a,bx);
-	printf("\t; to %d",pc+bx+2);
+	printf(COMMENT "to %d",pc+bx+2);
 	break;
    case OP_TFORPREP:
 	printf("%d %d",a,bx);
-	printf("\t; to %d",pc+bx+2);
+	printf(COMMENT "to %d",pc+bx+2);
 	break;
    case OP_TFORCALL:
 	printf("%d %d",a,c);
 	break;
    case OP_TFORLOOP:
 	printf("%d %d",a,bx);
-	printf("\t; to %d",pc-bx+2);
+	printf(COMMENT "to %d",pc-bx+2);
 	break;
    case OP_SETLIST:
 	printf("%d %d %d",a,b,c);
 	break;
    case OP_CLOSURE:
 	printf("%d %d",a,bx);
-	printf("\t; %p",VOID(f->p[bx]));
+	printf(COMMENT "%p",VOID(f->p[bx]));
 	break;
    case OP_VARARG:
 	printf("%d %d",a,c);
-	printf("\t; ");
+	printf(COMMENT);
 	if (c==0) printf("all out"); else printf("%d out",c-1);
 	break;
    case OP_VARARGPREP:

@@ -634,7 +633,7 @@
 	break;
    case OP_EXTRAARG:
 	printf("%d",ax);
-	printf("\t; "); PrintConstant(f,ax);
+	printf(COMMENT); PrintConstant(f,ax);
 	break;
    //default: printf("not handled"); break;
 	//printf("%d %d %d",a,b,c);

src/luaconf.h

@@ -47,7 +47,7 @@
 ** (It will crash with a limit too high.)
 */
 #if !defined(LUAI_MAXCSTACK)
-#define LUAI_MAXCSTACK		2200
+#define LUAI_MAXCSTACK		2000
 #endif
 
 

@@ -493,7 +493,7 @@
 @@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
 **
 @@ LUAI_UACINT is the result of a 'default argument promotion'
-@@ over a lUA_INTEGER.
+@@ over a LUA_INTEGER.
 @@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
 @@ LUA_INTEGER_FMT is the format for writing integers.
 @@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.

src/lundump.c

@@ -198,11 +198,11 @@
   n = LoadInt(S);
   f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
   f->sizeupvalues = n;
-  for (i = 0; i < n; i++)
-    f->upvalues[i].name = NULL;
   for (i = 0; i < n; i++) {
+    f->upvalues[i].name = NULL;
     f->upvalues[i].instack = LoadByte(S);
     f->upvalues[i].idx = LoadByte(S);
+    f->upvalues[i].kind = LoadByte(S);
   }
 }
 

src/lutf8lib.c

@@ -103,7 +103,7 @@
   while (posi <= posj) {
     const char *s1 = utf8_decode(s + posi, NULL, !lax);
     if (s1 == NULL) {  /* conversion error? */
-      lua_pushnil(L);  /* return nil ... */
+      luaL_pushfail(L);  /* return fail ... */
       lua_pushinteger(L, posi + 1);  /* ... and current position */
       return 2;
     }

@@ -216,7 +216,7 @@
   if (n == 0)  /* did it find given character? */
     lua_pushinteger(L, posi + 1);
   else  /* no such character */
-    lua_pushnil(L);
+    luaL_pushfail(L);
   return 1;
 }
 

src/lvm.c

@@ -515,8 +515,10 @@
   }
   if (tm == NULL)  /* no TM? */
     return 0;  /* objects are different */
-  luaT_callTMres(L, tm, t1, t2, L->top);  /* call TM */
-  return !l_isfalse(s2v(L->top));
+  else {
+    luaT_callTMres(L, tm, t1, t2, L->top);  /* call TM */
+    return !l_isfalse(s2v(L->top));
+  }
 }
 
 

@@ -548,7 +550,7 @@
     int n = 2;  /* number of elements handled in this pass (at least 2) */
     if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) ||
         !tostring(L, s2v(top - 1)))
-      luaT_trybinTM(L, s2v(top - 2), s2v(top - 1), top - 2, TM_CONCAT);
+      luaT_tryconcatTM(L);
     else if (isemptystr(s2v(top - 1)))  /* second operand is empty? */
       cast_void(tostring(L, s2v(top - 2)));  /* result is first operand */
     else if (isemptystr(s2v(top - 2))) {  /* first operand is empty string? */

@@ -671,6 +673,8 @@
 /*
 ** Shift left operation. (Shift right just negates 'y'.)
 */
+#define luaV_shiftr(x,y)	luaV_shiftl(x,-(y))
+
 lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
   if (y < 0) {  /* shift right? */
     if (y <= -NBITS) return 0;

@@ -714,15 +718,10 @@
   Instruction inst = *(ci->u.l.savedpc - 1);  /* interrupted instruction */
   OpCode op = GET_OPCODE(inst);
   switch (op) {  /* finish its execution */
-    case OP_ADDI: case OP_SUBI:
-    case OP_MULI: case OP_DIVI: case OP_IDIVI:
-    case OP_MODI: case OP_POWI:
-    case OP_ADD: case OP_SUB:
-    case OP_MUL: case OP_DIV: case OP_IDIV:
-    case OP_BANDK: case OP_BORK: case OP_BXORK:
-    case OP_BAND: case OP_BOR: case OP_BXOR:
-    case OP_SHRI: case OP_SHL: case OP_SHR:
-    case OP_MOD: case OP_POW:
+    case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
+      setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top);
+      break;
+    }
     case OP_UNM: case OP_BNOT: case OP_LEN:
     case OP_GETTABUP: case OP_GETTABLE: case OP_GETI:
     case OP_GETFIELD: case OP_SELF: {

@@ -747,7 +746,7 @@
       break;
     }
     case OP_CONCAT: {
-      StkId top = L->top - 1;  /* top when 'luaT_trybinTM' was called */
+      StkId top = L->top - 1;  /* top when 'luaT_tryconcatTM' was called */
       int a = GETARG_A(inst);      /* first element to concatenate */
       int total = cast_int(top - 1 - (base + a));  /* yet to concatenate */
       setobjs2s(L, top - 2, top);  /* put TM result in proper position */

@@ -779,9 +778,9 @@
 #define l_addi(L,a,b)	intop(+, a, b)
 #define l_subi(L,a,b)	intop(-, a, b)
 #define l_muli(L,a,b)	intop(*, a, b)
-#define l_band(L,a,b)	intop(&, a, b)
-#define l_bor(L,a,b)	intop(|, a, b)
-#define l_bxor(L,a,b)	intop(^, a, b)
+#define l_band(a,b)	intop(&, a, b)
+#define l_bor(a,b)	intop(|, a, b)
+#define l_bxor(a,b)	intop(^, a, b)
 
 #define l_lti(a,b)	(a < b)
 #define l_lei(a,b)	(a <= b)

@@ -797,10 +796,9 @@
 #define op_arithfI_aux(L,v1,imm,fop,tm,flip) {  \
   lua_Number nb;  \
   if (tonumberns(v1, nb)) {  \
-    setfltvalue(s2v(ra), fop(L, nb, cast_num(imm)));  \
-  }  \
-  else  \
-    Protect(luaT_trybiniTM(L, v1, imm, flip, ra, tm)); }
+    lua_Number fimm = cast_num(imm);  \
+    pc++; setfltvalue(s2v(ra), fop(L, nb, fimm));  \
+  }}
 
 
 /*

@@ -819,7 +817,8 @@
   TValue *v1 = vRB(i);  \
   int imm = GETARG_sC(i);  \
   if (ttisinteger(v1)) {  \
-    setivalue(s2v(ra), iop(L, ivalue(v1), imm));  \
+    lua_Integer iv1 = ivalue(v1);  \
+    pc++; setivalue(s2v(ra), iop(L, iv1, imm));  \
   }  \
   else op_arithfI_aux(L, v1, imm, fop, tm, flip); }
 

@@ -828,97 +827,87 @@
 ** Auxiliary function for arithmetic operations over floats and others
 ** with two register operands.
 */
-#define op_arithf_aux(L,v1,v2,fop,tm) {  \
+#define op_arithf_aux(L,v1,v2,fop) {  \
   lua_Number n1; lua_Number n2;  \
   if (tonumberns(v1, n1) && tonumberns(v2, n2)) {  \
-    setfltvalue(s2v(ra), fop(L, n1, n2));  \
-  }  \
-  else  \
-    Protect(luaT_trybinTM(L, v1, v2, ra, tm)); }
+    pc++; setfltvalue(s2v(ra), fop(L, n1, n2));  \
+  }}
 
 
 /*
 ** Arithmetic operations over floats and others with register operands.
 */
-#define op_arithf(L,fop,tm) {  \
+#define op_arithf(L,fop) {  \
   TValue *v1 = vRB(i);  \
   TValue *v2 = vRC(i);  \
-  op_arithf_aux(L, v1, v2, fop, tm); }
+  op_arithf_aux(L, v1, v2, fop); }
 
 
 /*
 ** Arithmetic operations with register operands.
 */
-#define op_arith(L,iop,fop,tm) {  \
+#define op_arith(L,iop,fop) {  \
   TValue *v1 = vRB(i);  \
   TValue *v2 = vRC(i);  \
   if (ttisinteger(v1) && ttisinteger(v2)) {  \
     lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2);  \
-    setivalue(s2v(ra), iop(L, i1, i2));  \
+    pc++; setivalue(s2v(ra), iop(L, i1, i2));  \
   }  \
-  else op_arithf_aux(L, v1, v2, fop, tm); }
+  else op_arithf_aux(L, v1, v2, fop); }
 
 
 /*
 ** Arithmetic operations with K operands.
 */
-#define op_arithK(L,iop,fop,tm,flip) {  \
+#define op_arithK(L,iop,fop,flip) {  \
   TValue *v1 = vRB(i);  \
   TValue *v2 = KC(i);  \
   if (ttisinteger(v1) && ttisinteger(v2)) {  \
     lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2);  \
-    setivalue(s2v(ra), iop(L, i1, i2));  \
+    pc++; setivalue(s2v(ra), iop(L, i1, i2));  \
   }  \
   else { \
     lua_Number n1; lua_Number n2;  \
     if (tonumberns(v1, n1) && tonumberns(v2, n2)) {  \
-      setfltvalue(s2v(ra), fop(L, n1, n2));  \
-    }  \
-    else  \
-      Protect(luaT_trybinassocTM(L, v1, v2, ra, flip, tm)); } }
+      pc++; setfltvalue(s2v(ra), fop(L, n1, n2));  \
+    }}}
 
 
 /*
 ** Arithmetic operations with K operands for floats.
 */
-#define op_arithfK(L,fop,tm) {  \
+#define op_arithfK(L,fop) {  \
   TValue *v1 = vRB(i);  \
   TValue *v2 = KC(i);  \
   lua_Number n1; lua_Number n2;  \
   if (tonumberns(v1, n1) && tonumberns(v2, n2)) {  \
-    setfltvalue(s2v(ra), fop(L, n1, n2));  \
-  }  \
-  else  \
-    Protect(luaT_trybinTM(L, v1, v2, ra, tm)); }
+    pc++; setfltvalue(s2v(ra), fop(L, n1, n2));  \
+  }}
 
 
 /*
 ** Bitwise operations with constant operand.
 */
-#define op_bitwiseK(L,op,tm) {  \
+#define op_bitwiseK(L,op) {  \
   TValue *v1 = vRB(i);  \
   TValue *v2 = KC(i);  \
   lua_Integer i1;  \
   lua_Integer i2 = ivalue(v2);  \
   if (tointegerns(v1, &i1)) {  \
-    setivalue(s2v(ra), op(L, i1, i2));  \
-  }  \
-  else  \
-    Protect(luaT_trybiniTM(L, v1, i2, TESTARG_k(i), ra, tm)); }
+    pc++; setivalue(s2v(ra), op(i1, i2));  \
+  }}
 
 
 /*
 ** Bitwise operations with register operands.
 */
-#define op_bitwise(L,op,tm) {  \
+#define op_bitwise(L,op) {  \
   TValue *v1 = vRB(i);  \
   TValue *v2 = vRC(i);  \
   lua_Integer i1; lua_Integer i2;  \
   if (tointegerns(v1, &i1) && tointegerns(v2, &i2)) {  \
-    setivalue(s2v(ra), op(L, i1, i2));  \
-  }  \
-  else  \
-    Protect(luaT_trybinTM(L, v1, v2, ra, tm)); }
+    pc++; setivalue(s2v(ra), op(i1, i2));  \
+  }}
 
 
 /*

@@ -927,8 +916,11 @@
 #define op_order(L,opi,opf,other) {  \
         int cond;  \
         TValue *rb = vRB(i);  \
-        if (ttisinteger(s2v(ra)) && ttisinteger(rb))  \
-          cond = opi(ivalue(s2v(ra)), ivalue(rb));  \
+        if (ttisinteger(s2v(ra)) && ttisinteger(rb)) {  \
+          lua_Integer ia = ivalue(s2v(ra));  \
+          lua_Integer ib = ivalue(rb);  \
+          cond = opi(ia, ib);  \
+        }  \
         else if (ttisnumber(s2v(ra)) && ttisnumber(rb))  \
           cond = opf(s2v(ra), rb);  \
         else  \

@@ -944,8 +936,11 @@
         int im = GETARG_sB(i);  \
         if (ttisinteger(s2v(ra)))  \
           cond = opi(ivalue(s2v(ra)), im);  \
-        else if (ttisfloat(s2v(ra)))  \
-          cond = opf(fltvalue(s2v(ra)), cast_num(im));  \
+        else if (ttisfloat(s2v(ra))) {  \
+          lua_Number fa = fltvalue(s2v(ra));  \
+          lua_Number fim = cast_num(im);  \
+          cond = opf(fa, fim);  \
+        }  \
         else {  \
           int isf = GETARG_C(i);  \
           Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm));  \

@@ -993,7 +988,7 @@
 
 
 /* for test instructions, execute the jump instruction that follows it */
-#define donextjump(ci)	{ i = *pc; dojump(ci, i, 1); }
+#define donextjump(ci)	{ Instruction ni = *pc; dojump(ci, ni, 1); }
 
 /*
 ** do a conditional jump: skip next instruction if 'cond' is not what

@@ -1030,7 +1025,10 @@
 ** errors. (That is, it will not return to the interpreter main loop
 ** after changing the stack or hooks.)
 */
-#define halfProtect(exp)  (savepc(L), (exp))
+#define halfProtect(exp)  (savestate(L,ci), (exp))
+
+/* idem, but without changing the stack */
+#define halfProtectNT(exp)  (savepc(L), (exp))
 
 
 #define checkGC(L,c)  \

@@ -1083,17 +1081,13 @@
     vmfetch();
     lua_assert(base == ci->func + 1);
     lua_assert(base <= L->top && L->top < L->stack + L->stacksize);
-    lua_assert(ci->top < L->stack + L->stacksize);
+    /* invalidate top for instructions not expecting it */
+    lua_assert(isIT(i) || (L->top = base));
     vmdispatch (GET_OPCODE(i)) {
       vmcase(OP_MOVE) {
         setobjs2s(L, ra, RB(i));
         vmbreak;
       }
-      vmcase(OP_LOADK) {
-        TValue *rb = k + GETARG_Bx(i);
-        setobj2s(L, ra, rb);
-        vmbreak;
-      }
       vmcase(OP_LOADI) {
         lua_Integer b = GETARG_sBx(i);
         setivalue(s2v(ra), b);

@@ -1104,6 +1098,11 @@
         setfltvalue(s2v(ra), cast_num(b));
         vmbreak;
       }
+      vmcase(OP_LOADK) {
+        TValue *rb = k + GETARG_Bx(i);
+        setobj2s(L, ra, rb);
+        vmbreak;
+      }
       vmcase(OP_LOADKX) {
         TValue *rb;
         rb = k + GETARG_Ax(*pc); pc++;

@@ -1239,14 +1238,19 @@
         vmbreak;
       }
       vmcase(OP_NEWTABLE) {
-        int b = GETARG_B(i);
-        int c = GETARG_C(i);
+        int b = GETARG_B(i);  /* log2(hash size) + 1 */
+        int c = GETARG_C(i);  /* array size */
         Table *t;
-        L->top = ci->top;  /* correct top in case of GC */
+        if (b > 0)
+          b = 1 << (b - 1);  /* size is 2^(b - 1) */
+        if (TESTARG_k(i))
+          c += GETARG_Ax(*pc) * (MAXARG_C + 1);
+        pc++;  /* skip extra argument */
+        L->top = ra + 1;  /* correct top in case of emergency GC */
         t = luaH_new(L);  /* memory allocation */
         sethvalue2s(L, ra, t);
         if (b != 0 || c != 0)
-          luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c));  /* idem */
+          luaH_resize(L, t, c, b);  /* idem */
         checkGC(L, ra + 1);
         vmbreak;
       }

@@ -1267,157 +1271,137 @@
         op_arithI(L, l_addi, luai_numadd, TM_ADD, GETARG_k(i));
         vmbreak;
       }
-      vmcase(OP_SUBI) {
-        op_arithI(L, l_subi, luai_numsub, TM_SUB, 0);
-        vmbreak;
-      }
-      vmcase(OP_MULI) {
-        op_arithI(L, l_muli, luai_nummul, TM_MUL, GETARG_k(i));
+      vmcase(OP_ADDK) {
+        op_arithK(L, l_addi, luai_numadd, GETARG_k(i));
         vmbreak;
       }
-      vmcase(OP_MODI) {
-        op_arithI(L, luaV_mod, luaV_modf, TM_MOD, 0);
+      vmcase(OP_SUBK) {
+        op_arithK(L, l_subi, luai_numsub, 0);
         vmbreak;
       }
-      vmcase(OP_POWI) {
-        op_arithfI(L, luai_numpow, TM_POW);
+      vmcase(OP_MULK) {
+        op_arithK(L, l_muli, luai_nummul, GETARG_k(i));
         vmbreak;
       }
-      vmcase(OP_DIVI) {
-        op_arithfI(L, luai_numdiv, TM_DIV);
+      vmcase(OP_MODK) {
+        op_arithK(L, luaV_mod, luaV_modf, 0);
         vmbreak;
       }
-      vmcase(OP_IDIVI) {
-        op_arithI(L, luaV_idiv, luai_numidiv, TM_IDIV, 0);
+      vmcase(OP_POWK) {
+        op_arithfK(L, luai_numpow);
         vmbreak;
       }
-      vmcase(OP_ADDK) {
-        op_arithK(L, l_addi, luai_numadd, TM_ADD, GETARG_k(i));
+      vmcase(OP_DIVK) {
+        op_arithfK(L, luai_numdiv);
         vmbreak;
       }
-      vmcase(OP_SUBK) {
-        op_arithK(L, l_subi, luai_numsub, TM_SUB, 0);
+      vmcase(OP_IDIVK) {
+        op_arithK(L, luaV_idiv, luai_numidiv, 0);
         vmbreak;
       }
-      vmcase(OP_MULK) {
-        op_arithK(L, l_muli, luai_nummul, TM_MUL, GETARG_k(i));
+      vmcase(OP_BANDK) {
+        op_bitwiseK(L, l_band);
         vmbreak;
       }
-      vmcase(OP_MODK) {
-        op_arithK(L, luaV_mod, luaV_modf, TM_MOD, 0);
+      vmcase(OP_BORK) {
+        op_bitwiseK(L, l_bor);
         vmbreak;
       }
-      vmcase(OP_POWK) {
-        op_arithfK(L, luai_numpow, TM_POW);
+      vmcase(OP_BXORK) {
+        op_bitwiseK(L, l_bxor);
         vmbreak;
       }
-      vmcase(OP_DIVK) {
-        op_arithfK(L, luai_numdiv, TM_DIV);
+      vmcase(OP_SHRI) {
+        TValue *rb = vRB(i);
+        int ic = GETARG_sC(i);
+        lua_Integer ib;
+        if (tointegerns(rb, &ib)) {
+          pc++; setivalue(s2v(ra), luaV_shiftl(ib, -ic));
+        }
         vmbreak;
       }
-      vmcase(OP_IDIVK) {
-        op_arithK(L, luaV_idiv, luai_numidiv, TM_IDIV, 0);
+      vmcase(OP_SHLI) {
+        TValue *rb = vRB(i);
+        int ic = GETARG_sC(i);
+        lua_Integer ib;
+        if (tointegerns(rb, &ib)) {
+          pc++; setivalue(s2v(ra), luaV_shiftl(ic, ib));
+        }
         vmbreak;
       }
       vmcase(OP_ADD) {
-        op_arith(L, l_addi, luai_numadd, TM_ADD);
+        op_arith(L, l_addi, luai_numadd);
         vmbreak;
       }
       vmcase(OP_SUB) {
-        op_arith(L, l_subi, luai_numsub, TM_SUB);
+        op_arith(L, l_subi, luai_numsub);
         vmbreak;
       }
       vmcase(OP_MUL) {
-        op_arith(L, l_muli, luai_nummul, TM_MUL);
+        op_arith(L, l_muli, luai_nummul);
         vmbreak;
       }
       vmcase(OP_MOD) {
-        op_arith(L, luaV_mod, luaV_modf, TM_MOD);
+        op_arith(L, luaV_mod, luaV_modf);
         vmbreak;
       }
       vmcase(OP_POW) {
-        op_arithf(L, luai_numpow, TM_POW);
+        op_arithf(L, luai_numpow);
         vmbreak;
       }
       vmcase(OP_DIV) {  /* float division (always with floats) */
-        op_arithf(L, luai_numdiv, TM_DIV);
+        op_arithf(L, luai_numdiv);
         vmbreak;
       }
       vmcase(OP_IDIV) {  /* floor division */
-        op_arith(L, luaV_idiv, luai_numidiv, TM_IDIV);
-        vmbreak;
-      }
-      vmcase(OP_BANDK) {
-        op_bitwiseK(L, l_band, TM_BAND);
-        vmbreak;
-      }
-      vmcase(OP_BORK) {
-        op_bitwiseK(L, l_bor, TM_BOR);
-        vmbreak;
-      }
-      vmcase(OP_BXORK) {
-        op_bitwiseK(L, l_bxor, TM_BXOR);
+        op_arith(L, luaV_idiv, luai_numidiv);
         vmbreak;
       }
       vmcase(OP_BAND) {
-        op_bitwise(L, l_band, TM_BAND);
+        op_bitwise(L, l_band);
         vmbreak;
       }
       vmcase(OP_BOR) {
-        op_bitwise(L, l_bor, TM_BOR);
+        op_bitwise(L, l_bor);
         vmbreak;
       }
       vmcase(OP_BXOR) {
-        op_bitwise(L, l_bxor, TM_BXOR);
-        vmbreak;
-      }
-      vmcase(OP_SHRI) {
-        TValue *rb = vRB(i);
-        int ic = GETARG_sC(i);
-        lua_Integer ib;
-        if (tointegerns(rb, &ib)) {
-          setivalue(s2v(ra), luaV_shiftl(ib, -ic));
-        }
-        else {
-          TMS ev = TM_SHR;
-          if (TESTARG_k(i)) {
-            ic = -ic;  ev = TM_SHL;
-          }
-          Protect(luaT_trybiniTM(L, rb, ic, 0, ra, ev));
-        }
-        vmbreak;
-      }
-      vmcase(OP_SHLI) {
-        TValue *rb = vRB(i);
-        int ic = GETARG_sC(i);
-        lua_Integer ib;
-        if (tointegerns(rb, &ib)) {
-          setivalue(s2v(ra), luaV_shiftl(ic, ib));
-        }
-        else
-          Protect(luaT_trybiniTM(L, rb, ic, 1, ra, TM_SHL));
+        op_bitwise(L, l_bxor);
         vmbreak;
       }
       vmcase(OP_SHR) {
-        TValue *rb = vRB(i);
-        TValue *rc = vRC(i);
-        lua_Integer ib; lua_Integer ic;
-        if (tointegerns(rb, &ib) && tointegerns(rc, &ic)) {
-          setivalue(s2v(ra), luaV_shiftl(ib, -ic));
-        }
-        else
-          Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR));
+        op_bitwise(L, luaV_shiftr);
         vmbreak;
       }
       vmcase(OP_SHL) {
+        op_bitwise(L, luaV_shiftl);
+        vmbreak;
+      }
+      vmcase(OP_MMBIN) {
+        Instruction pi = *(pc - 2);  /* original arith. expression */
         TValue *rb = vRB(i);
-        TValue *rc = vRC(i);
-        lua_Integer ib; lua_Integer ic;
-        if (tointegerns(rb, &ib) && tointegerns(rc, &ic)) {
-          setivalue(s2v(ra), luaV_shiftl(ib, ic));
-        }
-        else
-          Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL));
+        TMS tm = (TMS)GETARG_C(i);
+        StkId result = RA(pi);
+        lua_assert(OP_ADD <= GET_OPCODE(pi) && GET_OPCODE(pi) <= OP_SHR);
+        Protect(luaT_trybinTM(L, s2v(ra), rb, result, tm));
+        vmbreak;
+      }
+      vmcase(OP_MMBINI) {
+        Instruction pi = *(pc - 2);  /* original arith. expression */
+        int imm = GETARG_sB(i);
+        TMS tm = (TMS)GETARG_C(i);
+        int flip = GETARG_k(i);
+        StkId result = RA(pi);
+        Protect(luaT_trybiniTM(L, s2v(ra), imm, flip, result, tm));
+        vmbreak;
+      }
+      vmcase(OP_MMBINK) {
+        Instruction pi = *(pc - 2);  /* original arith. expression */
+        TValue *imm = KB(i);
+        TMS tm = (TMS)GETARG_C(i);
+        int flip = GETARG_k(i);
+        StkId result = RA(pi);
+        Protect(luaT_trybinassocTM(L, s2v(ra), imm, flip, result, tm));
         vmbreak;
       }
       vmcase(OP_UNM) {

@@ -1462,7 +1446,6 @@
         vmbreak;
       }
       vmcase(OP_CLOSE) {
-        L->top = ra + 1;  /* everything is free after this slot */
         Protect(luaF_close(L, ra, LUA_OK));
         vmbreak;
       }

@@ -1551,19 +1534,20 @@
       }
       vmcase(OP_TAILCALL) {
         int b = GETARG_B(i);  /* number of arguments + 1 (function) */
-        int delta = 0;  /* virtual 'func' - real 'func' (vararg functions) */
+        int nparams1 = GETARG_C(i);
+        /* delat is virtual 'func' - real 'func' (vararg functions) */
+        int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
         if (b != 0)
           L->top = ra + b;
         else  /* previous instruction set top */
           b = cast_int(L->top - ra);
         savepc(ci);  /* some calls here can raise errors */
         if (TESTARG_k(i)) {
-          int nparams1 = GETARG_C(i);
-          if (nparams1)  /* vararg function? */
-            delta = ci->u.l.nextraargs + nparams1;
           /* close upvalues from current call; the compiler ensures
-             that there are no to-be-closed variables here */
+             that there are no to-be-closed variables here, so this
+             call cannot change the stack */
           luaF_close(L, base, NOCLOSINGMETH);
+          lua_assert(base == ci->func + 1);
         }
         if (!ttisfunction(s2v(ra))) {  /* not a function? */
           luaD_tryfuncTM(L, ra);  /* try '__call' metamethod */

@@ -1586,24 +1570,27 @@
       }
       vmcase(OP_RETURN) {
         int n = GETARG_B(i) - 1;  /* number of results */
+        int nparams1 = GETARG_C(i);
         if (n < 0)  /* not fixed? */
           n = cast_int(L->top - ra);  /* get what is available */
-        else
-          L->top = ra + n;  /* set call for 'luaD_poscall' */
         savepc(ci);
-        if (TESTARG_k(i)) {
-          int nparams1 = GETARG_C(i);
-          luaF_close(L, base, LUA_OK);  /* there may be open upvalues */
-          if (nparams1)  /* vararg function? */
-            ci->func -= ci->u.l.nextraargs + nparams1;
+        if (TESTARG_k(i)) {  /* may there be open upvalues? */
+          if (L->top < ci->top)
+            L->top = ci->top;
+          luaF_close(L, base, LUA_OK);
+          updatetrap(ci);
+          updatestack(ci);
         }
+        if (nparams1)  /* vararg function? */
+          ci->func -= ci->u.l.nextraargs + nparams1;
+        L->top = ra + n;  /* set call for 'luaD_poscall' */
         luaD_poscall(L, ci, n);
         return;
       }
       vmcase(OP_RETURN0) {
         if (L->hookmask) {
           L->top = ra;
-          halfProtect(luaD_poscall(L, ci, 0));  /* no hurry... */
+          halfProtectNT(luaD_poscall(L, ci, 0));  /* no hurry... */
         }
         else {  /* do the 'poscall' here */
           int nres = ci->nresults;

@@ -1617,7 +1604,7 @@
       vmcase(OP_RETURN1) {
         if (L->hookmask) {
           L->top = ra + 1;
-          halfProtect(luaD_poscall(L, ci, 1));  /* no hurry... */
+          halfProtectNT(luaD_poscall(L, ci, 1));  /* no hurry... */
         }
         else {  /* do the 'poscall' here */
           int nres = ci->nresults;

@@ -1716,10 +1703,8 @@
         vmbreak;
       }
       vmcase(OP_TFORPREP) {
-        if (!ttisnil(s2v(ra + 3))) {  /* is 'toclose' not nil? */
-          /* create to-be-closed upvalue for it */
-          halfProtect(luaF_newtbcupval(L, ra + 3));
-        }
+        /* create to-be-closed upvalue (if needed) */
+        halfProtect(luaF_newtbcupval(L, ra + 3));
         pc += GETARG_Bx(i);
         i = *(pc++);  /* go to next instruction */
         lua_assert(GET_OPCODE(i) == OP_TFORCALL && ra == RA(i));

@@ -1735,35 +1720,33 @@
         /* push function, state, and control variable */
         memcpy(ra + 4, ra, 3 * sizeof(*ra));
         L->top = ra + 4 + 3;
-        Protect(luaD_call(L, ra + 4, GETARG_C(i)));  /* do the call */
+        ProtectNT(luaD_call(L, ra + 4, GETARG_C(i)));  /* do the call */
         updatestack(ci);  /* stack may have changed */
         i = *(pc++);  /* go to next instruction */
-        ra += 2;  /* adjust for next instruction */
         lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));
         goto l_tforloop;
       }
       vmcase(OP_TFORLOOP) {
         l_tforloop:
-        if (!ttisnil(s2v(ra + 2))) {  /* continue loop? */
-          setobjs2s(L, ra, ra + 2);  /* save control variable */
+        if (!ttisnil(s2v(ra + 4))) {  /* continue loop? */
+          setobjs2s(L, ra + 2, ra + 4);  /* save control variable */
           pc -= GETARG_Bx(i);  /* jump back */
         }
         vmbreak;
       }
       vmcase(OP_SETLIST) {
         int n = GETARG_B(i);
-        int c = GETARG_C(i);
-        unsigned int last;
-        Table *h;
+        unsigned int last = GETARG_C(i);
+        Table *h = hvalue(s2v(ra));
         if (n == 0)
-          n = cast_int(L->top - ra) - 1;
+          n = cast_int(L->top - ra) - 1;  /* get up to the top */
         else
-          L->top = ci->top;  /* correct top in case of GC */
-        if (c == 0) {
-          c = GETARG_Ax(*pc); pc++;
+          L->top = ci->top;  /* correct top in case of emergency GC */
+        last += n;
+        if (TESTARG_k(i)) {
+          last += GETARG_Ax(*pc) * (MAXARG_C + 1);
+          pc++;
         }
-        h = hvalue(s2v(ra));
-        last = ((c-1)*LFIELDS_PER_FLUSH) + n;
         if (last > luaH_realasize(h))  /* needs more space? */
           luaH_resizearray(L, h, last);  /* preallocate it at once */
         for (; n > 0; n--) {

@@ -1804,4 +1787,3 @@
 }
 
 /* }================================================================== */
-