aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWarner Losh <imp@FreeBSD.org>2023-07-15 17:25:52 +0000
committerWarner Losh <imp@FreeBSD.org>2023-07-15 17:25:52 +0000
commit71944acbe7e51ac849d2baae287d867c2276ce4e (patch)
tree9813a14737667d113cc9fc8f8ca072122ac0458f
parent755d9301ca89f02956fd17858b9d4d821ab5c972 (diff)
downloadsrc-vendor/lua.tar.gz
src-vendor/lua.zip
lua: Update to 5.4.6vendor/lua/5.4.6vendor/lua
Sponsored by: Netflix
-rw-r--r--Makefile4
-rw-r--r--README2
-rw-r--r--doc/contents.html12
-rw-r--r--doc/lua.116
-rw-r--r--doc/manual.html311
-rw-r--r--doc/readme.html13
-rw-r--r--src/Makefile5
-rw-r--r--src/lapi.c249
-rw-r--r--src/lapi.h17
-rw-r--r--src/lauxlib.c56
-rw-r--r--src/lcode.c137
-rw-r--r--src/lcorolib.c4
-rw-r--r--src/ldebug.c80
-rw-r--r--src/ldebug.h2
-rw-r--r--src/ldo.c229
-rw-r--r--src/ldo.h17
-rw-r--r--src/ldump.c8
-rw-r--r--src/lfunc.c54
-rw-r--r--src/lfunc.h6
-rw-r--r--src/lgc.c106
-rw-r--r--src/lgc.h19
-rw-r--r--src/llex.c6
-rw-r--r--src/llimits.h21
-rw-r--r--src/lmathlib.c10
-rw-r--r--src/lmem.c68
-rw-r--r--src/loadlib.c9
-rw-r--r--src/lobject.c38
-rw-r--r--src/lobject.h19
-rw-r--r--src/lopcodes.h2
-rw-r--r--src/loslib.c36
-rw-r--r--src/lparser.c31
-rw-r--r--src/lstate.c65
-rw-r--r--src/lstate.h25
-rw-r--r--src/lstrlib.c2
-rw-r--r--src/ltable.c8
-rw-r--r--src/ltable.h1
-rw-r--r--src/ltablib.c2
-rw-r--r--src/ltests.c1977
-rw-r--r--src/ltests.h151
-rw-r--r--src/ltm.c38
-rw-r--r--src/ltm.h5
-rw-r--r--src/lua.c39
-rw-r--r--src/lua.h27
-rw-r--r--src/luac.c6
-rw-r--r--src/luaconf.h13
-rw-r--r--src/lundump.c8
-rw-r--r--src/lutf8lib.c27
-rw-r--r--src/lvm.c235
-rw-r--r--src/lvm.h5
49 files changed, 3355 insertions, 866 deletions
diff --git a/Makefile b/Makefile
index fef1af4821e6..8efa2eb3fdd6 100644
--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@ RM= rm -f
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
# Convenience platforms targets.
-PLATS= guess aix bsd c89 freebsd generic linux linux-readline macosx mingw posix solaris
+PLATS= guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
# What to install.
TO_BIN= lua luac
@@ -46,7 +46,7 @@ TO_MAN= lua.1 luac.1
# Lua version and release.
V= 5.4
-R= $V.4
+R= $V.6
# Targets start here.
all: $(PLAT)
diff --git a/README b/README
index c394c69828b5..1ae97165babe 100644
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
-This is Lua 5.4.4, released on 13 Jan 2022.
+This is Lua 5.4.6, released on 02 May 2023.
For installation instructions, license details, and
further information about Lua, see doc/readme.html.
diff --git a/doc/contents.html b/doc/contents.html
index ab82eb4a9278..1231e6d2481d 100644
--- a/doc/contents.html
+++ b/doc/contents.html
@@ -32,7 +32,7 @@ For a complete introduction to Lua programming, see the book
<P>
<SMALL>
-Copyright &copy; 2020&ndash;2022 Lua.org, PUC-Rio.
+Copyright &copy; 2020&ndash;2023 Lua.org, PUC-Rio.
Freely available under the terms of the
<A HREF="http://www.lua.org/license.html">Lua license</A>.
</SMALL>
@@ -85,6 +85,8 @@ Freely available under the terms of the
<LI><A HREF="manual.html#3.4.9">3.4.9 &ndash; Table Constructors</A>
<LI><A HREF="manual.html#3.4.10">3.4.10 &ndash; Function Calls</A>
<LI><A HREF="manual.html#3.4.11">3.4.11 &ndash; Function Definitions</A>
+<LI><A HREF="manual.html#3.4.12">3.4.12 &ndash; Lists of expressions, multiple results, and adjustment<A>
+
</UL>
<LI><A HREF="manual.html#3.5">3.5 &ndash; Visibility Rules</A>
</UL>
@@ -613,7 +615,7 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-LUA_HOOKLINE">LUA_HOOKLINE</A><BR>
<A HREF="manual.html#pdf-LUA_HOOKRET">LUA_HOOKRET</A><BR>
<A HREF="manual.html#pdf-LUA_HOOKTAILCALL">LUA_HOOKTAILCALL</A><BR>
-<A HREF="manual.html#pdf-LUAL_BUFFERSIZE">LUAL_BUFFERSIZE</A><BR>
+<A HREF="manual.html#pdf-LUA_LOADED_TABLE">LUA_LOADED_TABLE</A><BR>
<A HREF="manual.html#pdf-LUA_MASKCALL">LUA_MASKCALL</A><BR>
<A HREF="manual.html#pdf-LUA_MASKCOUNT">LUA_MASKCOUNT</A><BR>
<A HREF="manual.html#pdf-LUA_MASKLINE">LUA_MASKLINE</A><BR>
@@ -641,6 +643,7 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-LUA_OPSHR">LUA_OPSHR</A><BR>
<A HREF="manual.html#pdf-LUA_OPSUB">LUA_OPSUB</A><BR>
<A HREF="manual.html#pdf-LUA_OPUNM">LUA_OPUNM</A><BR>
+<A HREF="manual.html#pdf-LUA_PRELOAD_TABLE">LUA_PRELOAD_TABLE</A><BR>
<A HREF="manual.html#pdf-LUA_REFNIL">LUA_REFNIL</A><BR>
<A HREF="manual.html#pdf-LUA_REGISTRYINDEX">LUA_REGISTRYINDEX</A><BR>
<A HREF="manual.html#pdf-LUA_RIDX_GLOBALS">LUA_RIDX_GLOBALS</A><BR>
@@ -657,6 +660,7 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-LUA_TUSERDATA">LUA_TUSERDATA</A><BR>
<A HREF="manual.html#pdf-LUA_USE_APICHECK">LUA_USE_APICHECK</A><BR>
<A HREF="manual.html#pdf-LUA_YIELD">LUA_YIELD</A><BR>
+<A HREF="manual.html#pdf-LUAL_BUFFERSIZE">LUAL_BUFFERSIZE</A><BR>
</TD>
</TR>
@@ -664,10 +668,10 @@ Freely available under the terms of the
<P CLASS="footer">
Last update:
-Thu Jan 13 11:32:22 UTC 2022
+Sat Apr 1 17:57:05 UTC 2023
</P>
<!--
-Last change: revised for Lua 5.4.4
+Last change: revised for Lua 5.4.5
-->
</BODY>
diff --git a/doc/lua.1 b/doc/lua.1
index a46a1a67dd04..3f472fd81f62 100644
--- a/doc/lua.1
+++ b/doc/lua.1
@@ -1,5 +1,5 @@
-.\" $Id: lua.man,v 1.14 2020/05/21 19:31:21 lhf Exp $
-.TH LUA 1 "$Date: 2020/05/21 19:31:21 $"
+.\" $Id: lua.man,v 1.14 2022/09/23 09:06:36 lhf Exp $
+.TH LUA 1 "$Date: 2022/09/23 09:06:36 $"
.SH NAME
lua \- Lua interpreter
.SH SYNOPSIS
@@ -86,11 +86,17 @@ execute statement
enter interactive mode after executing
.IR script .
.TP
-.BI \-l " name"
+.BI \-l " mod"
require library
-.I name
+.I mod
into global
-.IR name .
+.IR mod .
+.TP
+.BI \-l " g=mod"
+require library
+.I mod
+into global
+.IR g .
.TP
.B \-v
show version information.
diff --git a/doc/manual.html b/doc/manual.html
index 61a8220d7fd1..0af688b343c7 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -19,7 +19,7 @@ by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
<P>
<SMALL>
-Copyright &copy; 2020&ndash;2022 Lua.org, PUC-Rio.
+Copyright &copy; 2020&ndash;2023 Lua.org, PUC-Rio.
Freely available under the terms of the
<a href="http://www.lua.org/license.html">Lua license</a>.
</SMALL>
@@ -63,7 +63,7 @@ and rapid prototyping.
<p>
Lua is implemented as a library, written in <em>clean C</em>,
-the common subset of Standard&nbsp;C and C++.
+the common subset of standard&nbsp;C and C++.
The Lua distribution includes a host program called <code>lua</code>,
which uses the Lua library to offer a complete,
standalone Lua interpreter,
@@ -1379,7 +1379,9 @@ Lua also accepts hexadecimal constants,
which start with <code>0x</code> or <code>0X</code>.
Hexadecimal constants also accept an optional fractional part
plus an optional binary exponent,
-marked by a letter '<code>p</code>' or '<code>P</code>'.
+marked by a letter '<code>p</code>' or '<code>P</code>' and written in decimal.
+(For instance, <code>0x1.fp10</code> denotes 1984,
+which is <em>0x1f / 16</em> multiplied by <em>2<sup>10</sup></em>.)
<p>
@@ -1621,21 +1623,13 @@ Expressions are discussed in <a href="#3.4">&sect;3.4</a>.
<p>
Before the assignment,
the list of values is <em>adjusted</em> to the length of
-the list of variables.
-If there are more values than needed,
-the excess values are thrown away.
-If there are fewer values than needed,
-the list is extended with <b>nil</b>'s.
-If the list of expressions ends with a function call,
-then all values returned by that call enter the list of values,
-before the adjustment
-(except when the call is enclosed in parentheses; see <a href="#3.4">&sect;3.4</a>).
+the list of variables (see <a href="#3.4.12">&sect;3.4.12</a>).
<p>
If a variable is both assigned and read
inside a multiple assignment,
-Lua ensures all reads get the value of the variable
+Lua ensures that all reads get the value of the variable
before the assignment.
Thus the code
@@ -1739,11 +1733,6 @@ even if this other label has been declared in an enclosing block.
<p>
-Labels and empty statements are called <em>void statements</em>,
-as they perform no actions.
-
-
-<p>
The <b>break</b> statement terminates the execution of a
<b>while</b>, <b>repeat</b>, or <b>for</b> loop,
skipping to the next statement after the loop:
@@ -2059,7 +2048,7 @@ function calls are explained in <a href="#3.4.10">&sect;3.4.10</a>;
table constructors are explained in <a href="#3.4.9">&sect;3.4.9</a>.
Vararg expressions,
denoted by three dots ('<code>...</code>'), can only be used when
-directly inside a vararg function;
+directly inside a variadic function;
they are explained in <a href="#3.4.11">&sect;3.4.11</a>.
@@ -2074,52 +2063,6 @@ the unary logical <b>not</b> (see <a href="#3.4.5">&sect;3.4.5</a>),
and the unary <em>length operator</em> (see <a href="#3.4.7">&sect;3.4.7</a>).
-<p>
-Both function calls and vararg expressions can result in multiple values.
-If a function call is used as a statement (see <a href="#3.3.6">&sect;3.3.6</a>),
-then its return list is adjusted to zero elements,
-thus discarding all returned values.
-If an expression is used as the last (or the only) element
-of a list of expressions,
-then no adjustment is made
-(unless the expression is enclosed in parentheses).
-In all other contexts,
-Lua adjusts the result list to one element,
-either discarding all values except the first one
-or adding a single <b>nil</b> if there are no values.
-
-
-<p>
-Here are some examples:
-
-<pre>
- f() -- adjusted to 0 results
- g(f(), x) -- f() is adjusted to 1 result
- g(x, f()) -- g gets x plus all results from f()
- a,b,c = f(), x -- f() is adjusted to 1 result (c gets nil)
- a,b = ... -- a gets the first vararg argument, b gets
- -- the second (both a and b can get nil if there
- -- is no corresponding vararg argument)
-
- a,b,c = x, f() -- f() is adjusted to 2 results
- a,b,c = f() -- f() is adjusted to 3 results
- return f() -- returns all results from f()
- return ... -- returns all received vararg arguments
- return x,y,f() -- returns x, y, and all results from f()
- {f()} -- creates a list with all results from f()
- {...} -- creates a list with all vararg arguments
- {f(), nil} -- f() is adjusted to 1 result
-</pre>
-
-<p>
-Any expression enclosed in parentheses always results in only one value.
-Thus,
-<code>(f(x,y,z))</code> is always a single value,
-even if <code>f</code> returns several values.
-(The value of <code>(f(x,y,z))</code> is the first value returned by <code>f</code>
-or <b>nil</b> if <code>f</code> does not return any values.)
-
-
@@ -2252,8 +2195,9 @@ Note that bitwise operators do not do this coercion.
<p>
-Nonetheless, it is always a good practice not to rely on these
-implicit coercions, as they are not always applied;
+It is always a good practice not to rely on the
+implicit coercions from strings to numbers,
+as they are not always applied;
in particular, <code>"1"==1</code> is false and <code>"1"&lt;1</code> raises an error
(see <a href="#3.4.4">&sect;3.4.4</a>).
These coercions exist mainly for compatibility and may be removed
@@ -2558,9 +2502,9 @@ The order of the assignments in a constructor is undefined.
<p>
If the last field in the list has the form <code>exp</code>
-and the expression is a function call or a vararg expression,
+and the expression is a multires expression,
then all values returned by this expression enter the list consecutively
-(see <a href="#3.4.10">&sect;3.4.10</a>).
+(see <a href="#3.4.12">&sect;3.4.12</a>).
<p>
@@ -2624,7 +2568,7 @@ A call of the form <code>return <em>functioncall</em></code> not in the
scope of a to-be-closed variable is called a <em>tail call</em>.
Lua implements <em>proper tail calls</em>
(or <em>proper tail recursion</em>):
-in a tail call,
+In a tail call,
the called function reuses the stack entry of the calling function.
Therefore, there is no limit on the number of nested tail calls that
a program can execute.
@@ -2727,22 +2671,16 @@ initialized with the argument values:
</pre><p>
When a Lua function is called,
it adjusts its list of arguments to
-the length of its list of parameters,
-unless the function is a <em>vararg function</em>,
+the length of its list of parameters (see <a href="#3.4.12">&sect;3.4.12</a>),
+unless the function is a <em>variadic function</em>,
which is indicated by three dots ('<code>...</code>')
at the end of its parameter list.
-A vararg function does not adjust its argument list;
+A variadic function does not adjust its argument list;
instead, it collects all extra arguments and supplies them
to the function through a <em>vararg expression</em>,
which is also written as three dots.
The value of this expression is a list of all actual extra arguments,
-similar to a function with multiple results.
-If a vararg expression is used inside another expression
-or in the middle of a list of expressions,
-then its return list is adjusted to one element.
-If the expression is used as the last element of a list of expressions,
-then no adjustment is made
-(unless that last expression is enclosed in parentheses).
+similar to a function with multiple results (see <a href="#3.4.12">&sect;3.4.12</a>).
<p>
@@ -2803,6 +2741,122 @@ is syntactic sugar for
+<h3>3.4.12 &ndash; <a name="3.4.12">Lists of expressions, multiple results,
+and adjustment</a></h3>
+
+<p>
+Both function calls and vararg expressions can result in multiple values.
+These expressions are called <em>multires expressions</em>.
+
+
+<p>
+When a multires expression is used as the last element
+of a list of expressions,
+all results from the expression are added to the
+list of values produced by the list of expressions.
+Note that a single expression
+in a place that expects a list of expressions
+is the last expression in that (singleton) list.
+
+
+<p>
+These are the places where Lua expects a list of expressions:
+
+<ul>
+
+<li>A <b>return</b> statement,
+for instance <code>return e1, e2, e3</code> (see <a href="#3.3.4">&sect;3.3.4</a>).</li>
+
+<li>A table constructor,
+for instance <code>{e1, e2, e3}</code> (see <a href="#3.4.9">&sect;3.4.9</a>).</li>
+
+<li>The arguments of a function call,
+for instance <code>foo(e1, e2, e3)</code> (see <a href="#3.4.10">&sect;3.4.10</a>).</li>
+
+<li>A multiple assignment,
+for instance <code>a , b, c = e1, e2, e3</code> (see <a href="#3.3.3">&sect;3.3.3</a>).</li>
+
+<li>A local declaration,
+for instance <code>local a , b, c = e1, e2, e3</code> (see <a href="#3.3.7">&sect;3.3.7</a>).</li>
+
+<li>The initial values in a generic <b>for</b> loop,
+for instance <code>for k in e1, e2, e3 do ... end</code> (see <a href="#3.3.5">&sect;3.3.5</a>).</li>
+
+</ul><p>
+In the last four cases,
+the list of values from the list of expressions
+must be <em>adjusted</em> to a specific length:
+the number of parameters in a call to a non-variadic function
+(see <a href="#3.4.11">&sect;3.4.11</a>),
+the number of variables in a multiple assignment or
+a local declaration,
+and exactly four values for a generic <b>for</b> loop.
+The <em>adjustment</em> follows these rules:
+If there are more values than needed,
+the extra values are thrown away;
+if there are fewer values than needed,
+the list is extended with <b>nil</b>'s.
+When the list of expressions ends with a multires expression,
+all results from that expression enter the list of values
+before the adjustment.
+
+
+<p>
+When a multires expression is used
+in a list of expressions without being the last element,
+or in a place where the syntax expects a single expression,
+Lua adjusts the result list of that expression to one element.
+As a particular case,
+the syntax expects a single expression inside a parenthesized expression;
+therefore, adding parentheses around a multires expression
+forces it to produce exactly one result.
+
+
+<p>
+We seldom need to use a vararg expression in a place
+where the syntax expects a single expression.
+(Usually it is simpler to add a regular parameter before
+the variadic part and use that parameter.)
+When there is such a need,
+we recommend assigning the vararg expression
+to a single variable and using that variable
+in its place.
+
+
+<p>
+Here are some examples of uses of mutlres expressions.
+In all cases, when the construction needs
+"the n-th result" and there is no such result,
+it uses a <b>nil</b>.
+
+<pre>
+ print(x, f()) -- prints x and all results from f().
+ print(x, (f())) -- prints x and the first result from f().
+ print(f(), x) -- prints the first result from f() and x.
+ print(1 + f()) -- prints 1 added to the first result from f().
+ local x = ... -- x gets the first vararg argument.
+ x,y = ... -- x gets the first vararg argument,
+ -- y gets the second vararg argument.
+ x,y,z = w, f() -- x gets w, y gets the first result from f(),
+ -- z gets the second result from f().
+ x,y,z = f() -- x gets the first result from f(),
+ -- y gets the second result from f(),
+ -- z gets the third result from f().
+ x,y,z = f(), g() -- x gets the first result from f(),
+ -- y gets the first result from g(),
+ -- z gets the second result from g().
+ x,y,z = (f()) -- x gets the first result from f(), y and z get nil.
+ return f() -- returns all results from f().
+ return x, ... -- returns x and all received vararg arguments.
+ return x,y,f() -- returns x, y, and all results from f().
+ {f()} -- creates a list with all results from f().
+ {...} -- creates a list with all vararg arguments.
+ {f(), 5} -- creates a list with the first result from f() and 5.
+</pre>
+
+
+
+
<h2>3.5 &ndash; <a name="3.5">Visibility Rules</a></h2>
@@ -2813,6 +2867,7 @@ Lua is a lexically scoped language.
The scope of a local variable begins at the first statement after
its declaration and lasts until the last non-void statement
of the innermost block that includes the declaration.
+(<em>Void statements</em> are labels and empty statements.)
Consider the following example:
<pre>
@@ -3071,7 +3126,7 @@ In general,
Lua's garbage collection can free or move internal memory
and then invalidate pointers to internal strings.
To allow a safe use of these pointers,
-The API guarantees that any pointer to a string in a stack index
+the API guarantees that any pointer to a string in a stack index
is valid while the string value at that index is not removed from the stack.
(It can be moved to another index, though.)
When the index is a pseudo-index (referring to an upvalue),
@@ -3537,7 +3592,7 @@ It is used in the auxiliary library by <a href="#luaL_newstate"><code>luaL_newst
return realloc(ptr, nsize);
}
</pre><p>
-Note that Standard&nbsp;C ensures
+Note that ISO&nbsp;C ensures
that <code>free(NULL)</code> has no effect and that
<code>realloc(NULL,size)</code> is equivalent to <code>malloc(size)</code>.
@@ -3785,8 +3840,36 @@ when called through this function.
<p>
-(Exceptionally, this function was introduced in release 5.4.3.
-It is not present in previous 5.4 releases.)
+(This function was introduced in release&nbsp;5.4.3.)
+
+
+
+
+
+<hr><h3><a name="lua_closethread"><code>lua_closethread</code></a></h3><p>
+<span class="apii">[-0, +?, &ndash;]</span>
+<pre>int lua_closethread (lua_State *L, lua_State *from);</pre>
+
+<p>
+Resets a thread, cleaning its call stack and closing all pending
+to-be-closed variables.
+Returns a status code:
+<a href="#pdf-LUA_OK"><code>LUA_OK</code></a> for no errors in the thread
+(either the original error that stopped the thread or
+errors in closing methods),
+or an error status otherwise.
+In case of error,
+leaves the error object on the top of the stack.
+
+
+<p>
+The parameter <code>from</code> represents the coroutine that is resetting <code>L</code>.
+If there is no such coroutine,
+this parameter can be <code>NULL</code>.
+
+
+<p>
+(This function was introduced in release&nbsp;5.4.6.)
@@ -4542,7 +4625,7 @@ Pops a key from the stack,
and pushes a key&ndash;value pair from the table at the given index,
the "next" pair after the given key.
If there are no more elements in the table,
-then <a href="#lua_next"><code>lua_next</code></a> returns 0 and pushes nothing.
+then <a href="#lua_next"><code>lua_next</code></a> returns&nbsp;0 and pushes nothing.
<p>
@@ -4985,6 +5068,7 @@ Also returns&nbsp;0 if any of the indices are not valid.
<p>
Similar to <a href="#lua_gettable"><code>lua_gettable</code></a>, but does a raw access
(i.e., without metamethods).
+The value at <code>index</code> must be a table.
@@ -5051,6 +5135,7 @@ For other values, this call returns&nbsp;0.
<p>
Similar to <a href="#lua_settable"><code>lua_settable</code></a>, but does a raw assignment
(i.e., without metamethods).
+The value at <code>index</code> must be a table.
@@ -5166,15 +5251,9 @@ and then pops the top element.
<pre>int lua_resetthread (lua_State *L);</pre>
<p>
-Resets a thread, cleaning its call stack and closing all pending
-to-be-closed variables.
-Returns a status code:
-<a href="#pdf-LUA_OK"><code>LUA_OK</code></a> for no errors in the thread
-(either the original error that stopped the thread or
-errors in closing methods),
-or an error status otherwise.
-In case of error,
-leaves the error object on the top of the stack.
+This function is deprecated;
+it is equivalent to <a href="#lua_closethread"><code>lua_closethread</code></a> with
+<code>from</code> being <code>NULL</code>.
@@ -6033,7 +6112,7 @@ the number of parameters of the function
</li>
<li><b><code>isvararg</code>: </b>
-true if the function is a vararg function
+true if the function is a variadic function
(always true for C&nbsp;functions).
</li>
@@ -6773,7 +6852,7 @@ Equivalent to the sequence
<pre>void luaL_buffsub (luaL_Buffer *B, int n);</pre>
<p>
-Removes <code>n</code> bytes from the the buffer <code>B</code>
+Removes <code>n</code> bytes from the buffer <code>B</code>
(see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>).
The buffer must have at least that many bytes.
@@ -6968,8 +7047,8 @@ It is defined as the following macro:
<pre>
(luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))
</pre><p>
-It returns <a href="#pdf-LUA_OK"><code>LUA_OK</code></a> if there are no errors,
-or an error code in case of errors (see <a href="#4.4.1">&sect;4.4.1</a>).
+It returns&nbsp;0 (<a href="#pdf-LUA_OK"><code>LUA_OK</code></a>) if there are no errors,
+or 1 in case of errors.
@@ -6986,8 +7065,8 @@ It is defined as the following macro:
<pre>
(luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))
</pre><p>
-It returns <a href="#pdf-LUA_OK"><code>LUA_OK</code></a> if there are no errors,
-or an error code in case of errors (see <a href="#4.4.1">&sect;4.4.1</a>).
+It returns&nbsp;0 (<a href="#pdf-LUA_OK"><code>LUA_OK</code></a>) if there are no errors,
+or 1 in case of errors.
@@ -7294,7 +7373,7 @@ with <code>tname</code> in the registry.
<p>
Creates a new Lua state.
It calls <a href="#lua_newstate"><code>lua_newstate</code></a> with an
-allocator based on the standard&nbsp;C allocation functions
+allocator based on the ISO&nbsp;C allocation functions
and then sets a warning function and a panic function (see <a href="#4.4">&sect;4.4</a>)
that print messages to the standard error output.
@@ -7685,9 +7764,7 @@ to start the traceback.
<hr><h3><a name="luaL_typeerror"><code>luaL_typeerror</code></a></h3><p>
<span class="apii">[-0, +0, <em>v</em>]</span>
-<pre>const char *luaL_typeerror (lua_State *L,
- int arg,
- const char *tname);</pre>
+<pre>int luaL_typeerror (lua_State *L, int arg, const char *tname);</pre>
<p>
Raises a type error for the argument <code>arg</code>
@@ -8708,6 +8785,8 @@ When you require a module <code>modname</code> and
This variable is only a reference to the real table;
assignments to this variable do not change the
table used by <a href="#pdf-require"><code>require</code></a>.
+The real table is stored in the C registry (see <a href="#4.3">&sect;4.3</a>),
+indexed by the key <a name="pdf-LUA_LOADED_TABLE"><code>LUA_LOADED_TABLE</code></a>, a string.
@@ -8745,7 +8824,7 @@ including if necessary a path and an extension.
<p>
-This function is not supported by Standard&nbsp;C.
+This functionality is not supported by ISO&nbsp;C.
As such, it is only available on some platforms
(Windows, Linux, Mac OS X, Solaris, BSD,
plus other Unix systems that support the <code>dlfcn</code> standard).
@@ -8799,6 +8878,8 @@ A table to store loaders for specific modules
This variable is only a reference to the real table;
assignments to this variable do not change the
table used by <a href="#pdf-require"><code>require</code></a>.
+The real table is stored in the C registry (see <a href="#4.3">&sect;4.3</a>),
+indexed by the key <a name="pdf-LUA_PRELOAD_TABLE"><code>LUA_PRELOAD_TABLE</code></a>, a string.
@@ -9311,7 +9392,7 @@ according to the format string <code>fmt</code> (see <a href="#6.4.2">&sect;6.4.
<p>
-Returns the size of a string resulting from <a href="#pdf-string.pack"><code>string.pack</code></a>
+Returns the length of a string resulting from <a href="#pdf-string.pack"><code>string.pack</code></a>
with the given format.
The format string cannot have the variable-length options
'<code>s</code>' or '<code>z</code>' (see <a href="#6.4.2">&sect;6.4.2</a>).
@@ -10091,9 +10172,9 @@ Returns the arc sine of <code>x</code> (in radians).
<p>
-
+
Returns the arc tangent of <code>y/x</code> (in radians),
-but uses the signs of both arguments to find the
+using the signs of both arguments to find the
quadrant of the result.
It also handles correctly the case of <code>x</code> being zero.
@@ -10953,7 +11034,7 @@ The default value for <code>code</code> is <b>true</b>.
<p>
If the optional second argument <code>close</code> is true,
-closes the Lua state before exiting.
+the function closes the Lua state before exiting (see <a href="#lua_close"><code>lua_close</code></a>).
@@ -11503,12 +11584,18 @@ The options are:
<li><b><code>-i</code>: </b> enter interactive mode after running <em>script</em>;</li>
<li><b><code>-l <em>mod</em></code>: </b> "require" <em>mod</em> and assign the
result to global <em>mod</em>;</li>
+<li><b><code>-l <em>g=mod</em></code>: </b> "require" <em>mod</em> and assign the
+ result to global <em>g</em>;</li>
<li><b><code>-v</code>: </b> print version information;</li>
<li><b><code>-E</code>: </b> ignore environment variables;</li>
<li><b><code>-W</code>: </b> turn warnings on;</li>
<li><b><code>--</code>: </b> stop handling options;</li>
<li><b><code>-</code>: </b> execute <code>stdin</code> as a file and stop handling options.</li>
</ul><p>
+(The form <code>-l <em>g=mod</em></code> was introduced in release&nbsp;5.4.4.)
+
+
+<p>
After handling its options, <code>lua</code> runs the given <em>script</em>.
When called without arguments,
<code>lua</code> behaves as <code>lua -v -i</code>
@@ -11582,7 +11669,7 @@ If there is a script,
the script is called with arguments
<code>arg[1]</code>, &middot;&middot;&middot;, <code>arg[#arg]</code>.
Like all chunks in Lua,
-the script is compiled as a vararg function.
+the script is compiled as a variadic function.
<p>
@@ -11949,10 +12036,10 @@ and LiteralString, see <a href="#3.1">&sect;3.1</a>.)
<P CLASS="footer">
Last update:
-Thu Jan 13 11:33:16 UTC 2022
+Tue May 2 20:09:38 UTC 2023
</P>
<!--
-Last change: revised for Lua 5.4.4
+Last change: revised for Lua 5.4.6
-->
</body></html>
diff --git a/doc/readme.html b/doc/readme.html
index 8afe38de923b..918ec8ed9378 100644
--- a/doc/readme.html
+++ b/doc/readme.html
@@ -98,9 +98,6 @@ and
If you don't have the time or the inclination to compile Lua yourself,
get a binary from
<A HREF="http://lua-users.org/wiki/LuaBinaries">LuaBinaries</A>.
-Try also
-<A HREF="http://luadist.org/">LuaDist</A>,
-a multi-platform distribution of Lua that includes batteries.
<H3>Building Lua</H3>
<P>
@@ -110,7 +107,7 @@ Here are the details.
<OL>
<LI>
Open a terminal window and move to
-the top-level directory, which is named <TT>lua-5.4.4</TT>.
+the top-level directory, which is named <TT>lua-5.4.6</TT>.
The <TT>Makefile</TT> there controls both the build process and the installation process.
<P>
<LI>
@@ -121,7 +118,7 @@ The <TT>Makefile</TT> there controls both the build process and the installation
The platforms currently supported are:
<P>
<P CLASS="display">
- guess aix bsd c89 freebsd generic linux linux-readline macosx mingw posix solaris
+ guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
</P>
<P>
If your platform is listed, just do "<KBD>make xxx</KBD>", where xxx
@@ -303,7 +300,7 @@ For details, see
<A HREF="http://www.lua.org/license.html">this</A>.
<BLOCKQUOTE STYLE="padding-bottom: 0em">
-Copyright &copy; 1994&ndash;2022 Lua.org, PUC-Rio.
+Copyright &copy; 1994&ndash;2023 Lua.org, PUC-Rio.
<P>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -330,10 +327,10 @@ THE SOFTWARE.
<P CLASS="footer">
Last update:
-Mon Jan 3 09:54:18 UTC 2022
+Tue May 2 20:08:55 UTC 2023
</P>
<!--
-Last change: revised for Lua 5.4.4
+Last change: revised for Lua 5.4.6
-->
</BODY>
diff --git a/src/Makefile b/src/Makefile
index 1907381fef0a..b7711963bccd 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -30,7 +30,7 @@ CMCFLAGS=
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
-PLATS= guess aix bsd c89 freebsd generic linux linux-readline macosx mingw posix solaris
+PLATS= guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
LUA_A= liblua.a
CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o
@@ -117,6 +117,9 @@ FreeBSD NetBSD OpenBSD freebsd:
generic: $(ALL)
+ios:
+ $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_IOS"
+
Linux linux: linux-noreadline
linux-noreadline:
diff --git a/src/lapi.c b/src/lapi.c
index 5ee65792d277..34e64af1428c 100644
--- a/src/lapi.c
+++ b/src/lapi.c
@@ -60,27 +60,28 @@ const char lua_ident[] =
static TValue *index2value (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
- StkId o = ci->func + idx;
- api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index");
- if (o >= L->top) return &G(L)->nilvalue;
+ StkId o = ci->func.p + idx;
+ api_check(L, idx <= ci->top.p - (ci->func.p + 1), "unacceptable index");
+ if (o >= L->top.p) return &G(L)->nilvalue;
else return s2v(o);
}
else if (!ispseudo(idx)) { /* negative index */
- api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
- return s2v(L->top + idx);
+ api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
+ "invalid index");
+ return s2v(L->top.p + idx);
}
else if (idx == LUA_REGISTRYINDEX)
return &G(L)->l_registry;
else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx;
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
- if (ttisCclosure(s2v(ci->func))) { /* C closure? */
- CClosure *func = clCvalue(s2v(ci->func));
+ if (ttisCclosure(s2v(ci->func.p))) { /* C closure? */
+ CClosure *func = clCvalue(s2v(ci->func.p));
return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
: &G(L)->nilvalue;
}
else { /* light C function or Lua function (through a hook)?) */
- api_check(L, ttislcf(s2v(ci->func)), "caller not a C function");
+ api_check(L, ttislcf(s2v(ci->func.p)), "caller not a C function");
return &G(L)->nilvalue; /* no upvalues */
}
}
@@ -94,14 +95,15 @@ static TValue *index2value (lua_State *L, int idx) {
l_sinline StkId index2stack (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
- StkId o = ci->func + idx;
- api_check(L, o < L->top, "invalid index");
+ StkId o = ci->func.p + idx;
+ api_check(L, o < L->top.p, "invalid index");
return o;
}
else { /* non-positive index */
- api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
+ api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
+ "invalid index");
api_check(L, !ispseudo(idx), "invalid index");
- return L->top + idx;
+ return L->top.p + idx;
}
}
@@ -112,17 +114,12 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
lua_lock(L);
ci = L->ci;
api_check(L, n >= 0, "negative 'n'");
- if (L->stack_last - L->top > n) /* stack large enough? */
+ if (L->stack_last.p - L->top.p > n) /* stack large enough? */
res = 1; /* yes; check is OK */
- else { /* no; need to grow stack */
- int inuse = cast_int(L->top - L->stack) + EXTRA_STACK;
- if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */
- res = 0; /* no */
- else /* try to grow stack */
- res = luaD_growstack(L, n, 0);
- }
- if (res && ci->top < L->top + n)
- ci->top = L->top + n; /* adjust frame top */
+ else /* need to grow stack */
+ res = luaD_growstack(L, n, 0);
+ if (res && ci->top.p < L->top.p + n)
+ ci->top.p = L->top.p + n; /* adjust frame top */
lua_unlock(L);
return res;
}
@@ -134,11 +131,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
lua_lock(to);
api_checknelems(from, n);
api_check(from, G(from) == G(to), "moving among independent states");
- api_check(from, to->ci->top - to->top >= n, "stack overflow");
- from->top -= n;
+ api_check(from, to->ci->top.p - to->top.p >= n, "stack overflow");
+ from->top.p -= n;
for (i = 0; i < n; i++) {
- setobjs2s(to, to->top, from->top + i);
- to->top++; /* stack already checked by previous 'api_check' */
+ setobjs2s(to, to->top.p, from->top.p + i);
+ to->top.p++; /* stack already checked by previous 'api_check' */
}
lua_unlock(to);
}
@@ -172,12 +169,12 @@ LUA_API lua_Number lua_version (lua_State *L) {
LUA_API int lua_absindex (lua_State *L, int idx) {
return (idx > 0 || ispseudo(idx))
? idx
- : cast_int(L->top - L->ci->func) + idx;
+ : cast_int(L->top.p - L->ci->func.p) + idx;
}
LUA_API int lua_gettop (lua_State *L) {
- return cast_int(L->top - (L->ci->func + 1));
+ return cast_int(L->top.p - (L->ci->func.p + 1));
}
@@ -187,24 +184,24 @@ LUA_API void lua_settop (lua_State *L, int idx) {
ptrdiff_t diff; /* difference for new top */
lua_lock(L);
ci = L->ci;
- func = ci->func;
+ func = ci->func.p;
if (idx >= 0) {
- api_check(L, idx <= ci->top - (func + 1), "new top too large");
- diff = ((func + 1) + idx) - L->top;
+ api_check(L, idx <= ci->top.p - (func + 1), "new top too large");
+ diff = ((func + 1) + idx) - L->top.p;
for (; diff > 0; diff--)
- setnilvalue(s2v(L->top++)); /* clear new slots */
+ setnilvalue(s2v(L->top.p++)); /* clear new slots */
}
else {
- api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
+ api_check(L, -(idx+1) <= (L->top.p - (func + 1)), "invalid new top");
diff = idx + 1; /* will "subtract" index (as it is negative) */
}
- api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot");
- newtop = L->top + diff;
- if (diff < 0 && L->tbclist >= newtop) {
+ api_check(L, L->tbclist.p < L->top.p, "previous pop of an unclosed slot");
+ newtop = L->top.p + diff;
+ if (diff < 0 && L->tbclist.p >= newtop) {
lua_assert(hastocloseCfunc(ci->nresults));
- luaF_close(L, newtop, CLOSEKTOP, 0);
+ newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
}
- L->top = newtop; /* correct top only after closing any upvalue */
+ L->top.p = newtop; /* correct top only after closing any upvalue */
lua_unlock(L);
}
@@ -213,10 +210,9 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
StkId level;
lua_lock(L);
level = index2stack(L, idx);
- api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level,
+ api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level,
"no variable to close at given level");
- luaF_close(L, level, CLOSEKTOP, 0);
- level = index2stack(L, idx); /* stack may be moved */
+ level = luaF_close(L, level, CLOSEKTOP, 0);
setnilvalue(s2v(level));
lua_unlock(L);
}
@@ -245,7 +241,7 @@ l_sinline void reverse (lua_State *L, StkId from, StkId to) {
LUA_API void lua_rotate (lua_State *L, int idx, int n) {
StkId p, t, m;
lua_lock(L);
- t = L->top - 1; /* end of stack segment being rotated */
+ t = L->top.p - 1; /* end of stack segment being rotated */
p = index2stack(L, idx); /* start of segment */
api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
@@ -264,7 +260,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
api_check(L, isvalid(L, to), "invalid index");
setobj(L, to, fr);
if (isupvalue(toidx)) /* function upvalue? */
- luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr);
+ luaC_barrier(L, clCvalue(s2v(L->ci->func.p)), fr);
/* LUA_REGISTRYINDEX does not need gc barrier
(collector revisits it before finishing collection) */
lua_unlock(L);
@@ -273,7 +269,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
LUA_API void lua_pushvalue (lua_State *L, int idx) {
lua_lock(L);
- setobj2s(L, L->top, index2value(L, idx));
+ setobj2s(L, L->top.p, index2value(L, idx));
api_incr_top(L);
lua_unlock(L);
}
@@ -342,12 +338,12 @@ LUA_API void lua_arith (lua_State *L, int op) {
api_checknelems(L, 2); /* all other operations expect two operands */
else { /* for unary operations, add fake 2nd operand */
api_checknelems(L, 1);
- setobjs2s(L, L->top, L->top - 1);
+ setobjs2s(L, L->top.p, L->top.p - 1);
api_incr_top(L);
}
/* first operand at top - 2, second at top - 1; result go to top - 2 */
- luaO_arith(L, op, s2v(L->top - 2), s2v(L->top - 1), L->top - 2);
- L->top--; /* remove second operand */
+ luaO_arith(L, op, s2v(L->top.p - 2), s2v(L->top.p - 1), L->top.p - 2);
+ L->top.p--; /* remove second operand */
lua_unlock(L);
}
@@ -373,7 +369,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
- size_t sz = luaO_str2num(s, s2v(L->top));
+ size_t sz = luaO_str2num(s, s2v(L->top.p));
if (sz != 0)
api_incr_top(L);
return sz;
@@ -500,7 +496,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
LUA_API void lua_pushnil (lua_State *L) {
lua_lock(L);
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
api_incr_top(L);
lua_unlock(L);
}
@@ -508,7 +504,7 @@ LUA_API void lua_pushnil (lua_State *L) {
LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
lua_lock(L);
- setfltvalue(s2v(L->top), n);
+ setfltvalue(s2v(L->top.p), n);
api_incr_top(L);
lua_unlock(L);
}
@@ -516,7 +512,7 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
lua_lock(L);
- setivalue(s2v(L->top), n);
+ setivalue(s2v(L->top.p), n);
api_incr_top(L);
lua_unlock(L);
}
@@ -531,7 +527,7 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts;
lua_lock(L);
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
- setsvalue2s(L, L->top, ts);
+ setsvalue2s(L, L->top.p, ts);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
@@ -542,11 +538,11 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
lua_lock(L);
if (s == NULL)
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
else {
TString *ts;
ts = luaS_new(L, s);
- setsvalue2s(L, L->top, ts);
+ setsvalue2s(L, L->top.p, ts);
s = getstr(ts); /* internal copy's address */
}
api_incr_top(L);
@@ -583,7 +579,7 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
lua_lock(L);
if (n == 0) {
- setfvalue(s2v(L->top), fn);
+ setfvalue(s2v(L->top.p), fn);
api_incr_top(L);
}
else {
@@ -592,13 +588,13 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
api_check(L, n <= MAXUPVAL, "upvalue index too large");
cl = luaF_newCclosure(L, n);
cl->f = fn;
- L->top -= n;
+ L->top.p -= n;
while (n--) {
- setobj2n(L, &cl->upvalue[n], s2v(L->top + n));
+ setobj2n(L, &cl->upvalue[n], s2v(L->top.p + n));
/* does not need barrier because closure is white */
lua_assert(iswhite(cl));
}
- setclCvalue(L, s2v(L->top), cl);
+ setclCvalue(L, s2v(L->top.p), cl);
api_incr_top(L);
luaC_checkGC(L);
}
@@ -609,9 +605,9 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
LUA_API void lua_pushboolean (lua_State *L, int b) {
lua_lock(L);
if (b)
- setbtvalue(s2v(L->top));
+ setbtvalue(s2v(L->top.p));
else
- setbfvalue(s2v(L->top));
+ setbfvalue(s2v(L->top.p));
api_incr_top(L);
lua_unlock(L);
}
@@ -619,7 +615,7 @@ LUA_API void lua_pushboolean (lua_State *L, int b) {
LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
lua_lock(L);
- setpvalue(s2v(L->top), p);
+ setpvalue(s2v(L->top.p), p);
api_incr_top(L);
lua_unlock(L);
}
@@ -627,7 +623,7 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
LUA_API int lua_pushthread (lua_State *L) {
lua_lock(L);
- setthvalue(L, s2v(L->top), L);
+ setthvalue(L, s2v(L->top.p), L);
api_incr_top(L);
lua_unlock(L);
return (G(L)->mainthread == L);
@@ -644,16 +640,16 @@ l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot;
TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
- setobj2s(L, L->top, slot);
+ setobj2s(L, L->top.p, slot);
api_incr_top(L);
}
else {
- setsvalue2s(L, L->top, str);
+ setsvalue2s(L, L->top.p, str);
api_incr_top(L);
- luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
+ luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
}
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
@@ -680,13 +676,13 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
TValue *t;
lua_lock(L);
t = index2value(L, idx);
- if (luaV_fastget(L, t, s2v(L->top - 1), slot, luaH_get)) {
- setobj2s(L, L->top - 1, slot);
+ if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) {
+ setobj2s(L, L->top.p - 1, slot);
}
else
- luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
+ luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
@@ -702,27 +698,27 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L);
t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) {
- setobj2s(L, L->top, slot);
+ setobj2s(L, L->top.p, slot);
}
else {
TValue aux;
setivalue(&aux, n);
- luaV_finishget(L, t, &aux, L->top, slot);
+ luaV_finishget(L, t, &aux, L->top.p, slot);
}
api_incr_top(L);
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
l_sinline int finishrawget (lua_State *L, const TValue *val) {
if (isempty(val)) /* avoid copying empty items to the stack */
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
else
- setobj2s(L, L->top, val);
+ setobj2s(L, L->top.p, val);
api_incr_top(L);
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
@@ -739,8 +735,8 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
- val = luaH_get(t, s2v(L->top - 1));
- L->top--; /* remove key */
+ val = luaH_get(t, s2v(L->top.p - 1));
+ L->top.p--; /* remove key */
return finishrawget(L, val);
}
@@ -767,7 +763,7 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t;
lua_lock(L);
t = luaH_new(L);
- sethvalue2s(L, L->top, t);
+ sethvalue2s(L, L->top.p, t);
api_incr_top(L);
if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec);
@@ -794,7 +790,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
break;
}
if (mt != NULL) {
- sethvalue2s(L, L->top, mt);
+ sethvalue2s(L, L->top.p, mt);
api_incr_top(L);
res = 1;
}
@@ -810,12 +806,12 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
o = index2value(L, idx);
api_check(L, ttisfulluserdata(o), "full userdata expected");
if (n <= 0 || n > uvalue(o)->nuvalue) {
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
t = LUA_TNONE;
}
else {
- setobj2s(L, L->top, &uvalue(o)->uv[n - 1].uv);
- t = ttype(s2v(L->top));
+ setobj2s(L, L->top.p, &uvalue(o)->uv[n - 1].uv);
+ t = ttype(s2v(L->top.p));
}
api_incr_top(L);
lua_unlock(L);
@@ -835,14 +831,14 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
TString *str = luaS_new(L, k);
api_checknelems(L, 1);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
- luaV_finishfastset(L, t, slot, s2v(L->top - 1));
- L->top--; /* pop value */
+ luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
+ L->top.p--; /* pop value */
}
else {
- setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
+ setsvalue2s(L, L->top.p, str); /* push 'str' (to make it a TValue) */
api_incr_top(L);
- luaV_finishset(L, t, s2v(L->top - 1), s2v(L->top - 2), slot);
- L->top -= 2; /* pop value and key */
+ luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), slot);
+ L->top.p -= 2; /* pop value and key */
}
lua_unlock(L); /* lock done by caller */
}
@@ -862,12 +858,12 @@ LUA_API void lua_settable (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 2);
t = index2value(L, idx);
- if (luaV_fastget(L, t, s2v(L->top - 2), slot, luaH_get)) {
- luaV_finishfastset(L, t, slot, s2v(L->top - 1));
+ if (luaV_fastget(L, t, s2v(L->top.p - 2), slot, luaH_get)) {
+ luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
}
else
- luaV_finishset(L, t, s2v(L->top - 2), s2v(L->top - 1), slot);
- L->top -= 2; /* pop index and value */
+ luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), slot);
+ L->top.p -= 2; /* pop index and value */
lua_unlock(L);
}
@@ -885,14 +881,14 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
api_checknelems(L, 1);
t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) {
- luaV_finishfastset(L, t, slot, s2v(L->top - 1));
+ luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
}
else {
TValue aux;
setivalue(&aux, n);
- luaV_finishset(L, t, &aux, s2v(L->top - 1), slot);
+ luaV_finishset(L, t, &aux, s2v(L->top.p - 1), slot);
}
- L->top--; /* pop value */
+ L->top.p--; /* pop value */
lua_unlock(L);
}
@@ -902,16 +898,16 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
lua_lock(L);
api_checknelems(L, n);
t = gettable(L, idx);
- luaH_set(L, t, key, s2v(L->top - 1));
+ luaH_set(L, t, key, s2v(L->top.p - 1));
invalidateTMcache(t);
- luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
- L->top -= n;
+ luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
+ L->top.p -= n;
lua_unlock(L);
}
LUA_API void lua_rawset (lua_State *L, int idx) {
- aux_rawset(L, idx, s2v(L->top - 2), 2);
+ aux_rawset(L, idx, s2v(L->top.p - 2), 2);
}
@@ -927,9 +923,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
- luaH_setint(L, t, n, s2v(L->top - 1));
- luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
- L->top--;
+ luaH_setint(L, t, n, s2v(L->top.p - 1));
+ luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
+ L->top.p--;
lua_unlock(L);
}
@@ -940,11 +936,11 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
lua_lock(L);
api_checknelems(L, 1);
obj = index2value(L, objindex);
- if (ttisnil(s2v(L->top - 1)))
+ if (ttisnil(s2v(L->top.p - 1)))
mt = NULL;
else {
- api_check(L, ttistable(s2v(L->top - 1)), "table expected");
- mt = hvalue(s2v(L->top - 1));
+ api_check(L, ttistable(s2v(L->top.p - 1)), "table expected");
+ mt = hvalue(s2v(L->top.p - 1));
}
switch (ttype(obj)) {
case LUA_TTABLE: {
@@ -968,7 +964,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
break;
}
}
- L->top--;
+ L->top.p--;
lua_unlock(L);
return 1;
}
@@ -984,11 +980,11 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue)))
res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */
else {
- setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top - 1));
- luaC_barrierback(L, gcvalue(o), s2v(L->top - 1));
+ setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top.p - 1));
+ luaC_barrierback(L, gcvalue(o), s2v(L->top.p - 1));
res = 1;
}
- L->top--;
+ L->top.p--;
lua_unlock(L);
return res;
}
@@ -1000,7 +996,8 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
#define checkresults(L,na,nr) \
- api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
+ api_check(L, (nr) == LUA_MULTRET \
+ || (L->ci->top.p - L->top.p >= (nr) - (na)), \
"results from function overflow current stack size")
@@ -1013,7 +1010,7 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
api_checknelems(L, nargs+1);
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults);
- func = L->top - (nargs+1);
+ func = L->top.p - (nargs+1);
if (k != NULL && yieldable(L)) { /* need to prepare continuation? */
L->ci->u.c.k = k; /* save continuation */
L->ci->u.c.ctx = ctx; /* save context */
@@ -1061,7 +1058,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
api_check(L, ttisfunction(s2v(o)), "error handler must be a function");
func = savestack(L, o);
}
- c.func = L->top - (nargs+1); /* function to be called */
+ c.func = L->top.p - (nargs+1); /* function to be called */
if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */
c.nresults = nresults; /* do a 'conventional' protected call */
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
@@ -1096,12 +1093,12 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
luaZ_init(L, &z, reader, data);
status = luaD_protectedparser(L, &z, chunkname, mode);
if (status == LUA_OK) { /* no errors? */
- LClosure *f = clLvalue(s2v(L->top - 1)); /* get newly created function */
+ LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */
if (f->nupvalues >= 1) { /* does it have an upvalue? */
/* get global table from registry */
const TValue *gt = getGtable(L);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
- setobj(L, f->upvals[0]->v, gt);
+ setobj(L, f->upvals[0]->v.p, gt);
luaC_barrier(L, f->upvals[0], gt);
}
}
@@ -1115,7 +1112,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
TValue *o;
lua_lock(L);
api_checknelems(L, 1);
- o = s2v(L->top - 1);
+ o = s2v(L->top.p - 1);
if (isLfunction(o))
status = luaU_dump(L, getproto(o), writer, data, strip);
else
@@ -1241,7 +1238,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
LUA_API int lua_error (lua_State *L) {
TValue *errobj;
lua_lock(L);
- errobj = s2v(L->top - 1);
+ errobj = s2v(L->top.p - 1);
api_checknelems(L, 1);
/* error object is the memory error message? */
if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
@@ -1259,12 +1256,12 @@ LUA_API int lua_next (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
- more = luaH_next(L, t, L->top - 1);
+ more = luaH_next(L, t, L->top.p - 1);
if (more) {
api_incr_top(L);
}
else /* no more elements */
- L->top -= 1; /* remove key */
+ L->top.p -= 1; /* remove key */
lua_unlock(L);
return more;
}
@@ -1276,7 +1273,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
lua_lock(L);
o = index2stack(L, idx);
nresults = L->ci->nresults;
- api_check(L, L->tbclist < o, "given index below or equal a marked one");
+ api_check(L, L->tbclist.p < o, "given index below or equal a marked one");
luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
if (!hastocloseCfunc(nresults)) /* function not marked yet? */
L->ci->nresults = codeNresults(nresults); /* mark it */
@@ -1291,7 +1288,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
if (n > 0)
luaV_concat(L, n);
else { /* nothing to concatenate */
- setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); /* push empty string */
+ setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */
api_incr_top(L);
}
luaC_checkGC(L);
@@ -1303,7 +1300,7 @@ LUA_API void lua_len (lua_State *L, int idx) {
TValue *t;
lua_lock(L);
t = index2value(L, idx);
- luaV_objlen(L, L->top, t);
+ luaV_objlen(L, L->top.p, t);
api_incr_top(L);
lua_unlock(L);
}
@@ -1348,7 +1345,7 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
lua_lock(L);
api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value");
u = luaS_newudata(L, size, nuvalue);
- setuvalue(L, s2v(L->top), u);
+ setuvalue(L, s2v(L->top.p), u);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
@@ -1374,7 +1371,7 @@ static const char *aux_upvalue (TValue *fi, int n, TValue **val,
Proto *p = f->p;
if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues)))
return NULL; /* 'n' not in [1, p->sizeupvalues] */
- *val = f->upvals[n-1]->v;
+ *val = f->upvals[n-1]->v.p;
if (owner) *owner = obj2gco(f->upvals[n - 1]);
name = p->upvalues[n-1].name;
return (name == NULL) ? "(no name)" : getstr(name);
@@ -1390,7 +1387,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
lua_lock(L);
name = aux_upvalue(index2value(L, funcindex), n, &val, NULL);
if (name) {
- setobj2s(L, L->top, val);
+ setobj2s(L, L->top.p, val);
api_incr_top(L);
}
lua_unlock(L);
@@ -1408,8 +1405,8 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
api_checknelems(L, 1);
name = aux_upvalue(fi, n, &val, &owner);
if (name) {
- L->top--;
- setobj(L, val, s2v(L->top));
+ L->top.p--;
+ setobj(L, val, s2v(L->top.p));
luaC_barrier(L, owner, val);
}
lua_unlock(L);
diff --git a/src/lapi.h b/src/lapi.h
index 9e99cc44824d..a742427cdc79 100644
--- a/src/lapi.h
+++ b/src/lapi.h
@@ -12,23 +12,26 @@
#include "lstate.h"
-/* Increments 'L->top', checking for stack overflows */
-#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
- "stack overflow");}
+/* Increments 'L->top.p', checking for stack overflows */
+#define api_incr_top(L) {L->top.p++; \
+ api_check(L, L->top.p <= L->ci->top.p, \
+ "stack overflow");}
/*
** If a call returns too many multiple returns, the callee may not have
** stack space to accommodate all results. In this case, this macro
-** increases its stack space ('L->ci->top').
+** increases its stack space ('L->ci->top.p').
*/
#define adjustresults(L,nres) \
- { if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
+ { if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
+ L->ci->top.p = L->top.p; }
/* Ensure the stack has at least 'n' elements */
-#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
- "not enough elements in the stack")
+#define api_checknelems(L,n) \
+ api_check(L, (n) < (L->top.p - L->ci->func.p), \
+ "not enough elements in the stack")
/*
diff --git a/src/lauxlib.c b/src/lauxlib.c
index 8ed1da1122fc..4ca6c6548899 100644
--- a/src/lauxlib.c
+++ b/src/lauxlib.c
@@ -526,13 +526,14 @@ static void newbox (lua_State *L) {
/*
** Compute new size for buffer 'B', enough to accommodate extra 'sz'
-** bytes.
+** bytes. (The test for "not big enough" also gets the case when the
+** computation of 'newsize' overflows.)
*/
static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
- size_t newsize = B->size * 2; /* double buffer size */
+ size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */
if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */
return luaL_error(B->L, "buffer too large");
- if (newsize < B->n + sz) /* double is not big enough? */
+ if (newsize < B->n + sz) /* not big enough? */
newsize = B->n + sz;
return newsize;
}
@@ -611,7 +612,7 @@ LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
** box (if existent) is not on the top of the stack. So, instead of
** calling 'luaL_addlstring', it replicates the code using -2 as the
** last argument to 'prepbuffsize', signaling that the box is (or will
-** be) bellow the string being added to the buffer. (Box creation can
+** be) below the string being added to the buffer. (Box creation can
** trigger an emergency GC, so we should not remove the string from the
** stack before we have the space guaranteed.)
*/
@@ -739,17 +740,18 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
}
-static int skipBOM (LoadF *lf) {
- const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
- int c;
- lf->n = 0;
- do {
- c = getc(lf->f);
- if (c == EOF || c != *(const unsigned char *)p++) return c;
- lf->buff[lf->n++] = c; /* to be read by the parser */
- } while (*p != '\0');
- lf->n = 0; /* prefix matched; discard it */
- return getc(lf->f); /* return next character */
+/*
+** Skip an optional BOM at the start of a stream. If there is an
+** incomplete BOM (the first character is correct but the rest is
+** not), returns the first character anyway to force an error
+** (as no chunk can start with 0xEF).
+*/
+static int skipBOM (FILE *f) {
+ int c = getc(f); /* read first character */
+ if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */
+ return getc(f); /* ignore BOM and return next char */
+ else /* no (valid) BOM */
+ return c; /* return first character */
}
@@ -760,13 +762,13 @@ static int skipBOM (LoadF *lf) {
** first "valid" character of the file (after the optional BOM and
** a first-line comment).
*/
-static int skipcomment (LoadF *lf, int *cp) {
- int c = *cp = skipBOM(lf);
+static int skipcomment (FILE *f, int *cp) {
+ int c = *cp = skipBOM(f);
if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */
- c = getc(lf->f);
+ c = getc(f);
} while (c != EOF && c != '\n');
- *cp = getc(lf->f); /* skip end-of-line, if present */
+ *cp = getc(f); /* next character after comment, if present */
return 1; /* there was a comment */
}
else return 0; /* no comment */
@@ -788,12 +790,16 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex);
}
- if (skipcomment(&lf, &c)) /* read initial portion */
- lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */
- if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
- lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
- if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
- skipcomment(&lf, &c); /* re-read initial portion */
+ lf.n = 0;
+ if (skipcomment(lf.f, &c)) /* read initial portion */
+ lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */
+ if (c == LUA_SIGNATURE[0]) { /* binary file? */
+ lf.n = 0; /* remove possible newline */
+ if (filename) { /* "real" file? */
+ lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
+ if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
+ skipcomment(lf.f, &c); /* re-read initial portion */
+ }
}
if (c != EOF)
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
diff --git a/src/lcode.c b/src/lcode.c
index 06425a1db800..1a371ca943ba 100644
--- a/src/lcode.c
+++ b/src/lcode.c
@@ -1352,6 +1352,35 @@ static int constfolding (FuncState *fs, int op, expdesc *e1,
/*
+** Convert a BinOpr to an OpCode (ORDER OPR - ORDER OP)
+*/
+l_sinline OpCode binopr2op (BinOpr opr, BinOpr baser, OpCode base) {
+ lua_assert(baser <= opr &&
+ ((baser == OPR_ADD && opr <= OPR_SHR) ||
+ (baser == OPR_LT && opr <= OPR_LE)));
+ return cast(OpCode, (cast_int(opr) - cast_int(baser)) + cast_int(base));
+}
+
+
+/*
+** Convert a UnOpr to an OpCode (ORDER OPR - ORDER OP)
+*/
+l_sinline OpCode unopr2op (UnOpr opr) {
+ return cast(OpCode, (cast_int(opr) - cast_int(OPR_MINUS)) +
+ cast_int(OP_UNM));
+}
+
+
+/*
+** Convert a BinOpr to a tag method (ORDER OPR - ORDER TM)
+*/
+l_sinline TMS binopr2TM (BinOpr opr) {
+ lua_assert(OPR_ADD <= opr && opr <= OPR_SHR);
+ return cast(TMS, (cast_int(opr) - cast_int(OPR_ADD)) + cast_int(TM_ADD));
+}
+
+
+/*
** Emit code for unary expressions that "produce values"
** (everything but 'not').
** Expression to produce final result will be encoded in 'e'.
@@ -1389,12 +1418,15 @@ static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2,
** Emit code for binary expressions that "produce values" over
** two registers.
*/
-static void codebinexpval (FuncState *fs, OpCode op,
+static void codebinexpval (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) {
- int v2 = luaK_exp2anyreg(fs, e2); /* both operands are in registers */
+ OpCode op = binopr2op(opr, OPR_ADD, OP_ADD);
+ int v2 = luaK_exp2anyreg(fs, e2); /* make sure 'e2' is in a register */
+ /* 'e1' must be already in a register or it is a constant */
+ lua_assert((VNIL <= e1->k && e1->k <= VKSTR) ||
+ e1->k == VNONRELOC || e1->k == VRELOC);
lua_assert(OP_ADD <= op && op <= OP_SHR);
- finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN,
- cast(TMS, (op - OP_ADD) + TM_ADD));
+ finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, binopr2TM(opr));
}
@@ -1410,6 +1442,18 @@ static void codebini (FuncState *fs, OpCode op,
}
+/*
+** Code binary operators with K operand.
+*/
+static void codebinK (FuncState *fs, BinOpr opr,
+ expdesc *e1, expdesc *e2, int flip, int line) {
+ TMS event = binopr2TM(opr);
+ int v2 = e2->u.info; /* K index */
+ OpCode op = binopr2op(opr, OPR_ADD, OP_ADDK);
+ finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
+}
+
+
/* Try to code a binary operator negating its second operand.
** For the metamethod, 2nd operand must keep its original value.
*/
@@ -1438,23 +1482,26 @@ static void swapexps (expdesc *e1, expdesc *e2) {
/*
+** Code binary operators with no constant operand.
+*/
+static void codebinNoK (FuncState *fs, BinOpr opr,
+ expdesc *e1, expdesc *e2, int flip, int line) {
+ if (flip)
+ swapexps(e1, e2); /* back to original order */
+ codebinexpval(fs, opr, e1, e2, line); /* use standard operators */
+}
+
+
+/*
** Code arithmetic operators ('+', '-', ...). If second operand is a
** constant in the proper range, use variant opcodes with K operands.
*/
static void codearith (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
- TMS event = cast(TMS, opr + TM_ADD);
- if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */
- int v2 = e2->u.info; /* K index */
- OpCode op = cast(OpCode, opr + OP_ADDK);
- finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
- }
- else { /* 'e2' is neither an immediate nor a K operand */
- OpCode op = cast(OpCode, opr + OP_ADD);
- if (flip)
- swapexps(e1, e2); /* back to original order */
- codebinexpval(fs, op, e1, e2, line); /* use standard operators */
- }
+ if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) /* K operand? */
+ codebinK(fs, opr, e1, e2, flip, line);
+ else /* 'e2' is neither an immediate nor a K operand */
+ codebinNoK(fs, opr, e1, e2, flip, line);
}
@@ -1471,35 +1518,27 @@ static void codecommutative (FuncState *fs, BinOpr op,
flip = 1;
}
if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */
- codebini(fs, cast(OpCode, OP_ADDI), e1, e2, flip, line, TM_ADD);
+ codebini(fs, OP_ADDI, e1, e2, flip, line, TM_ADD);
else
codearith(fs, op, e1, e2, flip, line);
}
/*
-** Code bitwise operations; they are all associative, so the function
+** Code bitwise operations; they are all commutative, so the function
** tries to put an integer constant as the 2nd operand (a K operand).
*/
static void codebitwise (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) {
int flip = 0;
- int v2;
- OpCode op;
- if (e1->k == VKINT && luaK_exp2RK(fs, e1)) {
+ if (e1->k == VKINT) {
swapexps(e1, e2); /* 'e2' will be the constant operand */
flip = 1;
}
- else if (!(e2->k == VKINT && luaK_exp2RK(fs, e2))) { /* no constants? */
- op = cast(OpCode, opr + OP_ADD);
- codebinexpval(fs, op, e1, e2, line); /* all-register opcodes */
- return;
- }
- v2 = e2->u.info; /* index in K array */
- op = cast(OpCode, opr + OP_ADDK);
- lua_assert(ttisinteger(&fs->f->k[v2]));
- finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK,
- cast(TMS, opr + TM_ADD));
+ if (e2->k == VKINT && luaK_exp2K(fs, e2)) /* K operand? */
+ codebinK(fs, opr, e1, e2, flip, line);
+ else /* no constants */
+ codebinNoK(fs, opr, e1, e2, flip, line);
}
@@ -1507,25 +1546,27 @@ static void codebitwise (FuncState *fs, BinOpr opr,
** Emit code for order comparisons. When using an immediate operand,
** 'isfloat' tells whether the original value was a float.
*/
-static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
+static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
int r1, r2;
int im;
int isfloat = 0;
+ OpCode op;
if (isSCnumber(e2, &im, &isfloat)) {
/* use immediate operand */
r1 = luaK_exp2anyreg(fs, e1);
r2 = im;
- op = cast(OpCode, (op - OP_LT) + OP_LTI);
+ op = binopr2op(opr, OPR_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 = im;
- op = (op == OP_LT) ? OP_GTI : OP_GEI;
+ op = binopr2op(opr, OPR_LT, OP_GTI);
}
else { /* regular case, compare two registers */
r1 = luaK_exp2anyreg(fs, e1);
r2 = luaK_exp2anyreg(fs, e2);
+ op = binopr2op(opr, OPR_LT, OP_LT);
}
freeexps(fs, e1, e2);
e1->u.info = condjump(fs, op, r1, r2, isfloat, 1);
@@ -1551,7 +1592,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
op = OP_EQI;
r2 = im; /* immediate operand */
}
- else if (luaK_exp2RK(fs, e2)) { /* 1st expression is constant? */
+ else if (luaK_exp2RK(fs, e2)) { /* 2nd expression is constant? */
op = OP_EQK;
r2 = e2->u.info; /* constant index */
}
@@ -1568,16 +1609,16 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
/*
** Apply prefix operation 'op' to expression 'e'.
*/
-void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
+void luaK_prefix (FuncState *fs, UnOpr opr, expdesc *e, int line) {
static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
luaK_dischargevars(fs, e);
- switch (op) {
+ switch (opr) {
case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */
- if (constfolding(fs, op + LUA_OPUNM, e, &ef))
+ if (constfolding(fs, opr + LUA_OPUNM, e, &ef))
break;
/* else */ /* FALLTHROUGH */
case OPR_LEN:
- codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);
+ codeunexpval(fs, unopr2op(opr), e, line);
break;
case OPR_NOT: codenot(fs, e); break;
default: lua_assert(0);
@@ -1611,7 +1652,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
case OPR_SHL: case OPR_SHR: {
if (!tonumeral(v, NULL))
luaK_exp2anyreg(fs, v);
- /* else keep numeral, which may be folded with 2nd operand */
+ /* else keep numeral, which may be folded or used as an immediate
+ operand */
break;
}
case OPR_EQ: case OPR_NE: {
@@ -1706,30 +1748,27 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
/* coded as (r1 >> -I) */;
}
else /* regular case (two registers) */
- codebinexpval(fs, OP_SHL, e1, e2, line);
+ codebinexpval(fs, opr, e1, e2, line);
break;
}
case OPR_SHR: {
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);
+ codebinexpval(fs, opr, e1, e2, line);
break;
}
case OPR_EQ: case OPR_NE: {
codeeq(fs, opr, e1, e2);
break;
}
- case OPR_LT: case OPR_LE: {
- OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
- codeorder(fs, op, e1, e2);
- break;
- }
case OPR_GT: case OPR_GE: {
/* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */
- OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
swapexps(e1, e2);
- codeorder(fs, op, e1, e2);
+ opr = cast(BinOpr, (opr - OPR_GT) + OPR_LT);
+ } /* FALLTHROUGH */
+ case OPR_LT: case OPR_LE: {
+ codeorder(fs, opr, e1, e2);
break;
}
default: lua_assert(0);
diff --git a/src/lcorolib.c b/src/lcorolib.c
index 785a1e81aa0a..c64adf08a8e1 100644
--- a/src/lcorolib.c
+++ b/src/lcorolib.c
@@ -76,7 +76,7 @@ static int luaB_auxwrap (lua_State *L) {
if (l_unlikely(r < 0)) { /* error? */
int stat = lua_status(co);
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
- stat = lua_resetthread(co); /* close its tbc variables */
+ stat = lua_closethread(co, L); /* close its tbc variables */
lua_assert(stat != LUA_OK);
lua_xmove(co, L, 1); /* move error message to the caller */
}
@@ -172,7 +172,7 @@ static int luaB_close (lua_State *L) {
int status = auxstatus(L, co);
switch (status) {
case COS_DEAD: case COS_YIELD: {
- status = lua_resetthread(co);
+ status = lua_closethread(co, L);
if (status == LUA_OK) {
lua_pushboolean(L, 1);
return 1;
diff --git a/src/ldebug.c b/src/ldebug.c
index a716d95e22f6..28b1caabf77e 100644
--- a/src/ldebug.c
+++ b/src/ldebug.c
@@ -182,10 +182,10 @@ static const char *upvalname (const Proto *p, int uv) {
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
- if (clLvalue(s2v(ci->func))->p->is_vararg) {
+ if (clLvalue(s2v(ci->func.p))->p->is_vararg) {
int nextra = ci->u.l.nextraargs;
if (n >= -nextra) { /* 'n' is negative */
- *pos = ci->func - nextra - (n + 1);
+ *pos = ci->func.p - nextra - (n + 1);
return "(vararg)"; /* generic name for any vararg */
}
}
@@ -194,7 +194,7 @@ static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
- StkId base = ci->func + 1;
+ StkId base = ci->func.p + 1;
const char *name = NULL;
if (isLua(ci)) {
if (n < 0) /* access to vararg values? */
@@ -203,7 +203,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
}
if (name == NULL) { /* no 'standard' name? */
- StkId limit = (ci == L->ci) ? L->top : ci->next->func;
+ StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
/* generic name for any valid slot */
name = isLua(ci) ? "(temporary)" : "(C temporary)";
@@ -221,16 +221,16 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
const char *name;
lua_lock(L);
if (ar == NULL) { /* information about non-active function? */
- if (!isLfunction(s2v(L->top - 1))) /* not a Lua function? */
+ if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */
name = NULL;
else /* consider live variables at function start (parameters) */
- name = luaF_getlocalname(clLvalue(s2v(L->top - 1))->p, n, 0);
+ name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
}
else { /* active function; get information through 'ar' */
StkId pos = NULL; /* to avoid warnings */
name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) {
- setobjs2s(L, L->top, pos);
+ setobjs2s(L, L->top.p, pos);
api_incr_top(L);
}
}
@@ -245,8 +245,8 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
lua_lock(L);
name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) {
- setobjs2s(L, pos, L->top - 1);
- L->top--; /* pop value */
+ setobjs2s(L, pos, L->top.p - 1);
+ L->top.p--; /* pop value */
}
lua_unlock(L);
return name;
@@ -289,7 +289,7 @@ static int nextline (const Proto *p, int currentline, int pc) {
static void collectvalidlines (lua_State *L, Closure *f) {
if (noLuaClosure(f)) {
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
api_incr_top(L);
}
else {
@@ -298,7 +298,7 @@ static void collectvalidlines (lua_State *L, Closure *f) {
const Proto *p = f->l.p;
int currentline = p->linedefined;
Table *t = luaH_new(L); /* new table to store active lines */
- sethvalue2s(L, L->top, t); /* push it on stack */
+ sethvalue2s(L, L->top.p, t); /* push it on stack */
api_incr_top(L);
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
if (!p->is_vararg) /* regular function? */
@@ -388,20 +388,20 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
lua_lock(L);
if (*what == '>') {
ci = NULL;
- func = s2v(L->top - 1);
+ func = s2v(L->top.p - 1);
api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */
- L->top--; /* pop function */
+ L->top.p--; /* pop function */
}
else {
ci = ar->i_ci;
- func = s2v(ci->func);
+ func = s2v(ci->func.p);
lua_assert(ttisfunction(func));
}
cl = ttisclosure(func) ? clvalue(func) : NULL;
status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) {
- setobj2s(L, L->top, func);
+ setobj2s(L, L->top.p, func);
api_incr_top(L);
}
if (strchr(what, 'L'))
@@ -656,18 +656,19 @@ static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
/*
-** Check whether pointer 'o' points to some value in the stack
-** frame of the current function. Because 'o' may not point to a
-** value in this stack, we cannot compare it with the region
-** boundaries (undefined behaviour in ISO C).
+** Check whether pointer 'o' points to some value in the stack frame of
+** the current function and, if so, returns its index. Because 'o' may
+** not point to a value in this stack, we cannot compare it with the
+** region boundaries (undefined behavior in ISO C).
*/
-static int isinstack (CallInfo *ci, const TValue *o) {
- StkId pos;
- for (pos = ci->func + 1; pos < ci->top; pos++) {
- if (o == s2v(pos))
- return 1;
+static int instack (CallInfo *ci, const TValue *o) {
+ int pos;
+ StkId base = ci->func.p + 1;
+ for (pos = 0; base + pos < ci->top.p; pos++) {
+ if (o == s2v(base + pos))
+ return pos;
}
- return 0; /* not found */
+ return -1; /* not found */
}
@@ -681,7 +682,7 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
LClosure *c = ci_func(ci);
int i;
for (i = 0; i < c->nupvalues; i++) {
- if (c->upvals[i]->v == o) {
+ if (c->upvals[i]->v.p == o) {
*name = upvalname(c->p, i);
return "upvalue";
}
@@ -708,9 +709,11 @@ static const char *varinfo (lua_State *L, const TValue *o) {
const char *kind = NULL;
if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
- if (!kind && isinstack(ci, o)) /* no? try a register */
- kind = getobjname(ci_func(ci)->p, currentpc(ci),
- cast_int(cast(StkId, o) - (ci->func + 1)), &name);
+ if (!kind) { /* not an upvalue? */
+ int reg = instack(ci, o); /* try a register */
+ if (reg >= 0) /* is 'o' a register? */
+ kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name);
+ }
}
return formatvarinfo(L, kind, name);
}
@@ -807,10 +810,10 @@ l_noret luaG_errormsg (lua_State *L) {
if (L->errfunc != 0) { /* is there an error handling function? */
StkId errfunc = restorestack(L, L->errfunc);
lua_assert(ttisfunction(s2v(errfunc)));
- setobjs2s(L, L->top, L->top - 1); /* move argument */
- setobjs2s(L, L->top - 1, errfunc); /* push function */
- L->top++; /* assume EXTRA_STACK */
- luaD_callnoyield(L, L->top - 2, 1); /* call it */
+ setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */
+ setobjs2s(L, L->top.p - 1, errfunc); /* push function */
+ L->top.p++; /* assume EXTRA_STACK */
+ luaD_callnoyield(L, L->top.p - 2, 1); /* call it */
}
luaD_throw(L, LUA_ERRRUN);
}
@@ -824,8 +827,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
va_start(argp, fmt);
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp);
- if (isLua(ci)) /* if Lua function, add source:line information */
+ if (isLua(ci)) { /* if Lua function, add source:line information */
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
+ setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
+ L->top.p--;
+ }
luaG_errormsg(L);
}
@@ -842,7 +848,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
if (p->lineinfo == NULL) /* no debug information? */
return 0;
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
- int delta = 0; /* line diference */
+ int delta = 0; /* line difference */
int pc = oldpc;
for (;;) {
int lineinfo = p->lineinfo[++pc];
@@ -869,7 +875,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
** at most causes an extra call to a line hook.)
** This function is not "Protected" when called, so it should correct
-** 'L->top' before calling anything that can run the GC.
+** 'L->top.p' before calling anything that can run the GC.
*/
int luaG_traceexec (lua_State *L, const Instruction *pc) {
CallInfo *ci = L->ci;
@@ -892,7 +898,7 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
return 1; /* do not call hook again (VM yielded, so it did not move) */
}
if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
- L->top = ci->top; /* correct top */
+ L->top.p = ci->top.p; /* correct top */
if (counthook)
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
if (mask & LUA_MASKLINE) {
diff --git a/src/ldebug.h b/src/ldebug.h
index 974960e99da0..2c3074c61b6f 100644
--- a/src/ldebug.h
+++ b/src/ldebug.h
@@ -15,7 +15,7 @@
/* Active Lua function (given call info) */
-#define ci_func(ci) (clLvalue(s2v((ci)->func)))
+#define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
#define resethookcount(L) (L->hookcount = L->basehookcount)
diff --git a/src/ldo.c b/src/ldo.c
index a48e35f9dba9..2a0017ca62a3 100644
--- a/src/ldo.c
+++ b/src/ldo.c
@@ -104,11 +104,11 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
}
default: {
lua_assert(errorstatus(errcode)); /* real error */
- setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
+ setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */
break;
}
}
- L->top = oldtop + 1;
+ L->top.p = oldtop + 1;
}
@@ -121,7 +121,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
global_State *g = G(L);
errcode = luaE_resetthread(L, errcode); /* close all upvalues */
if (g->mainthread->errorJmp) { /* main thread has a handler? */
- setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */
+ setobjs2s(L, g->mainthread->top.p++, L->top.p - 1); /* copy error obj. */
luaD_throw(g->mainthread, errcode); /* re-throw in main thread */
}
else { /* no handler at all; abort */
@@ -157,16 +157,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
** Stack reallocation
** ===================================================================
*/
-static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
+
+
+/*
+** Change all pointers to the stack into offsets.
+*/
+static void relstack (lua_State *L) {
+ CallInfo *ci;
+ UpVal *up;
+ L->top.offset = savestack(L, L->top.p);
+ L->tbclist.offset = savestack(L, L->tbclist.p);
+ for (up = L->openupval; up != NULL; up = up->u.open.next)
+ up->v.offset = savestack(L, uplevel(up));
+ for (ci = L->ci; ci != NULL; ci = ci->previous) {
+ ci->top.offset = savestack(L, ci->top.p);
+ ci->func.offset = savestack(L, ci->func.p);
+ }
+}
+
+
+/*
+** Change back all offsets into pointers.
+*/
+static void correctstack (lua_State *L) {
CallInfo *ci;
UpVal *up;
- L->top = (L->top - oldstack) + newstack;
- L->tbclist = (L->tbclist - oldstack) + newstack;
+ L->top.p = restorestack(L, L->top.offset);
+ L->tbclist.p = restorestack(L, L->tbclist.offset);
for (up = L->openupval; up != NULL; up = up->u.open.next)
- up->v = s2v((uplevel(up) - oldstack) + newstack);
+ up->v.p = s2v(restorestack(L, up->v.offset));
for (ci = L->ci; ci != NULL; ci = ci->previous) {
- ci->top = (ci->top - oldstack) + newstack;
- ci->func = (ci->func - oldstack) + newstack;
+ ci->top.p = restorestack(L, ci->top.offset);
+ ci->func.p = restorestack(L, ci->func.offset);
if (isLua(ci))
ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
}
@@ -176,44 +198,45 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
/* some space for error handling */
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
-
/*
-** Reallocate the stack to a new size, correcting all pointers into
-** it. (There are pointers to a stack from its upvalues, from its list
-** of call infos, plus a few individual pointers.) The reallocation is
-** done in two steps (allocation + free) because the correction must be
-** done while both addresses (the old stack and the new one) are valid.
-** (In ISO C, any pointer use after the pointer has been deallocated is
-** undefined behavior.)
+** Reallocate the stack to a new size, correcting all pointers into it.
+** In ISO C, any pointer use after the pointer has been deallocated is
+** undefined behavior. So, before the reallocation, all pointers are
+** changed to offsets, and after the reallocation they are changed back
+** to pointers. As during the reallocation the pointers are invalid, the
+** reallocation cannot run emergency collections.
+**
** In case of allocation error, raise an error or return false according
** to 'raiseerror'.
*/
int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
int oldsize = stacksize(L);
int i;
- StkId newstack = luaM_reallocvector(L, NULL, 0,
- newsize + EXTRA_STACK, StackValue);
+ StkId newstack;
+ int oldgcstop = G(L)->gcstopem;
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
+ relstack(L); /* change pointers to offsets */
+ G(L)->gcstopem = 1; /* stop emergency collection */
+ newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
+ newsize + EXTRA_STACK, StackValue);
+ G(L)->gcstopem = oldgcstop; /* restore emergency collection */
if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
+ correctstack(L); /* change offsets back to pointers */
if (raiseerror)
luaM_error(L);
else return 0; /* do not raise an error */
}
- /* number of elements to be copied to the new stack */
- i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK;
- memcpy(newstack, L->stack, i * sizeof(StackValue));
- for (; i < newsize + EXTRA_STACK; i++)
+ L->stack.p = newstack;
+ correctstack(L); /* change offsets back to pointers */
+ L->stack_last.p = L->stack.p + newsize;
+ for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
setnilvalue(s2v(newstack + i)); /* erase new segment */
- correctstack(L, L->stack, newstack);
- luaM_freearray(L, L->stack, oldsize + EXTRA_STACK);
- L->stack = newstack;
- L->stack_last = L->stack + newsize;
return 1;
}
/*
-** Try to grow the stack by at least 'n' elements. when 'raiseerror'
+** Try to grow the stack by at least 'n' elements. When 'raiseerror'
** is true, raises any error; otherwise, return 0 in case of errors.
*/
int luaD_growstack (lua_State *L, int n, int raiseerror) {
@@ -227,35 +250,38 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) {
luaD_throw(L, LUA_ERRERR); /* error inside message handler */
return 0; /* if not 'raiseerror', just signal it */
}
- else {
+ else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */
int newsize = 2 * size; /* tentative new size */
- int needed = cast_int(L->top - L->stack) + n;
+ int needed = cast_int(L->top.p - L->stack.p) + n;
if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */
newsize = LUAI_MAXSTACK;
if (newsize < needed) /* but must respect what was asked for */
newsize = needed;
if (l_likely(newsize <= LUAI_MAXSTACK))
return luaD_reallocstack(L, newsize, raiseerror);
- else { /* stack overflow */
- /* add extra size to be able to handle the error message */
- luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
- if (raiseerror)
- luaG_runerror(L, "stack overflow");
- return 0;
- }
}
+ /* else stack overflow */
+ /* add extra size to be able to handle the error message */
+ luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
+ if (raiseerror)
+ luaG_runerror(L, "stack overflow");
+ return 0;
}
+/*
+** Compute how much of the stack is being used, by computing the
+** maximum top of all call frames in the stack and the current top.
+*/
static int stackinuse (lua_State *L) {
CallInfo *ci;
int res;
- StkId lim = L->top;
+ StkId lim = L->top.p;
for (ci = L->ci; ci != NULL; ci = ci->previous) {
- if (lim < ci->top) lim = ci->top;
+ if (lim < ci->top.p) lim = ci->top.p;
}
- lua_assert(lim <= L->stack_last);
- res = cast_int(lim - L->stack) + 1; /* part of stack in use */
+ lua_assert(lim <= L->stack_last.p + EXTRA_STACK);
+ res = cast_int(lim - L->stack.p) + 1; /* part of stack in use */
if (res < LUA_MINSTACK)
res = LUA_MINSTACK; /* ensure a minimum size */
return res;
@@ -273,17 +299,13 @@ static int stackinuse (lua_State *L) {
*/
void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L);
- int nsize = inuse * 2; /* proposed new size */
- int max = inuse * 3; /* maximum "reasonable" size */
- if (max > LUAI_MAXSTACK) {
- max = LUAI_MAXSTACK; /* respect stack limit */
- if (nsize > LUAI_MAXSTACK)
- nsize = LUAI_MAXSTACK;
- }
+ int max = (inuse > LUAI_MAXSTACK / 3) ? LUAI_MAXSTACK : inuse * 3;
/* if thread is currently not handling a stack overflow and its
size is larger than maximum "reasonable" size, shrink it */
- if (inuse <= LUAI_MAXSTACK && stacksize(L) > max)
+ if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) {
+ int nsize = (inuse > LUAI_MAXSTACK / 2) ? LUAI_MAXSTACK : inuse * 2;
luaD_reallocstack(L, nsize, 0); /* ok if that fails */
+ }
else /* don't change stack */
condmovestack(L,{},{}); /* (change only for debugging) */
luaE_shrinkCI(L); /* shrink CI list */
@@ -292,7 +314,7 @@ void luaD_shrinkstack (lua_State *L) {
void luaD_inctop (lua_State *L) {
luaD_checkstack(L, 1);
- L->top++;
+ L->top.p++;
}
/* }================================================================== */
@@ -309,8 +331,8 @@ void luaD_hook (lua_State *L, int event, int line,
if (hook && L->allowhook) { /* make sure there is a hook */
int mask = CIST_HOOKED;
CallInfo *ci = L->ci;
- ptrdiff_t top = savestack(L, L->top); /* preserve original 'top' */
- ptrdiff_t ci_top = savestack(L, ci->top); /* idem for 'ci->top' */
+ ptrdiff_t top = savestack(L, L->top.p); /* preserve original 'top' */
+ ptrdiff_t ci_top = savestack(L, ci->top.p); /* idem for 'ci->top' */
lua_Debug ar;
ar.event = event;
ar.currentline = line;
@@ -320,11 +342,11 @@ void luaD_hook (lua_State *L, int event, int line,
ci->u2.transferinfo.ftransfer = ftransfer;
ci->u2.transferinfo.ntransfer = ntransfer;
}
- if (isLua(ci) && L->top < ci->top)
- L->top = ci->top; /* protect entire activation register */
+ if (isLua(ci) && L->top.p < ci->top.p)
+ L->top.p = ci->top.p; /* protect entire activation register */
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
- if (ci->top < L->top + LUA_MINSTACK)
- ci->top = L->top + LUA_MINSTACK;
+ if (ci->top.p < L->top.p + LUA_MINSTACK)
+ ci->top.p = L->top.p + LUA_MINSTACK;
L->allowhook = 0; /* cannot call hooks inside a hook */
ci->callstatus |= mask;
lua_unlock(L);
@@ -332,8 +354,8 @@ void luaD_hook (lua_State *L, int event, int line,
lua_lock(L);
lua_assert(!L->allowhook);
L->allowhook = 1;
- ci->top = restorestack(L, ci_top);
- L->top = restorestack(L, top);
+ ci->top.p = restorestack(L, ci_top);
+ L->top.p = restorestack(L, top);
ci->callstatus &= ~mask;
}
}
@@ -364,7 +386,7 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) {
*/
static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (L->hookmask & LUA_MASKRET) { /* is return hook on? */
- StkId firstres = L->top - nres; /* index of first result */
+ StkId firstres = L->top.p - nres; /* index of first result */
int delta = 0; /* correction for vararg functions */
int ftransfer;
if (isLua(ci)) {
@@ -372,10 +394,10 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (p->is_vararg)
delta = ci->u.l.nextraargs + p->numparams + 1;
}
- ci->func += delta; /* if vararg, back to virtual 'func' */
- ftransfer = cast(unsigned short, firstres - ci->func);
+ ci->func.p += delta; /* if vararg, back to virtual 'func' */
+ ftransfer = cast(unsigned short, firstres - ci->func.p);
luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */
- ci->func -= delta;
+ ci->func.p -= delta;
}
if (isLua(ci = ci->previous))
L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */
@@ -394,9 +416,9 @@ StkId luaD_tryfuncTM (lua_State *L, StkId func) {
tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */
if (l_unlikely(ttisnil(tm)))
luaG_callerror(L, s2v(func)); /* nothing to call */
- for (p = L->top; p > func; p--) /* open space for metamethod */
+ for (p = L->top.p; p > func; p--) /* open space for metamethod */
setobjs2s(L, p, p-1);
- L->top++; /* stack space pre-allocated by the caller */
+ L->top.p++; /* stack space pre-allocated by the caller */
setobj2s(L, func, tm); /* metamethod is the new function to be called */
return func;
}
@@ -413,28 +435,29 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
int i;
switch (wanted) { /* handle typical cases separately */
case 0: /* no values needed */
- L->top = res;
+ L->top.p = res;
return;
case 1: /* one value needed */
if (nres == 0) /* no results? */
setnilvalue(s2v(res)); /* adjust with nil */
else /* at least one result */
- setobjs2s(L, res, L->top - nres); /* move it to proper place */
- L->top = res + 1;
+ setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
+ L->top.p = res + 1;
return;
case LUA_MULTRET:
wanted = nres; /* we want all results */
break;
default: /* two/more results and/or to-be-closed variables */
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
- ptrdiff_t savedres = savestack(L, res);
L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
L->ci->u2.nres = nres;
- luaF_close(L, res, CLOSEKTOP, 1);
+ res = luaF_close(L, res, CLOSEKTOP, 1);
L->ci->callstatus &= ~CIST_CLSRET;
- if (L->hookmask) /* if needed, call hook after '__close's */
+ if (L->hookmask) { /* if needed, call hook after '__close's */
+ ptrdiff_t savedres = savestack(L, res);
rethook(L, L->ci, nres);
- res = restorestack(L, savedres); /* close and hook can move stack */
+ res = restorestack(L, savedres); /* hook can move stack */
+ }
wanted = decodeNresults(wanted);
if (wanted == LUA_MULTRET)
wanted = nres; /* we want all results */
@@ -442,14 +465,14 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
break;
}
/* generic case */
- firstresult = L->top - nres; /* index of first result */
+ firstresult = L->top.p - nres; /* index of first result */
if (nres > wanted) /* extra results? */
nres = wanted; /* don't need them */
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstresult + i);
for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(s2v(res + i));
- L->top = res + wanted; /* top points after the last result */
+ L->top.p = res + wanted; /* top points after the last result */
}
@@ -464,7 +487,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
rethook(L, ci, nres);
/* move results to proper place */
- moveresults(L, ci->func, nres, wanted);
+ moveresults(L, ci->func.p, nres, wanted);
/* function cannot be in any of these cases when returning */
lua_assert(!(ci->callstatus &
(CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
@@ -479,10 +502,10 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,
int mask, StkId top) {
CallInfo *ci = L->ci = next_ci(L); /* new frame */
- ci->func = func;
+ ci->func.p = func;
ci->nresults = nret;
ci->callstatus = mask;
- ci->top = top;
+ ci->top.p = top;
return ci;
}
@@ -496,10 +519,10 @@ l_sinline int precallC (lua_State *L, StkId func, int nresults,
CallInfo *ci;
checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
L->ci = ci = prepCallInfo(L, func, nresults, CIST_C,
- L->top + LUA_MINSTACK);
- lua_assert(ci->top <= L->stack_last);
+ L->top.p + LUA_MINSTACK);
+ lua_assert(ci->top.p <= L->stack_last.p);
if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
- int narg = cast_int(L->top - func) - 1;
+ int narg = cast_int(L->top.p - func) - 1;
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
}
lua_unlock(L);
@@ -531,17 +554,17 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int nfixparams = p->numparams;
int i;
checkstackGCp(L, fsize - delta, func);
- ci->func -= delta; /* restore 'func' (if vararg) */
+ ci->func.p -= delta; /* restore 'func' (if vararg) */
for (i = 0; i < narg1; i++) /* move down function and arguments */
- setobjs2s(L, ci->func + i, func + i);
- func = ci->func; /* moved-down function */
+ setobjs2s(L, ci->func.p + i, func + i);
+ func = ci->func.p; /* moved-down function */
for (; narg1 <= nfixparams; narg1++)
setnilvalue(s2v(func + narg1)); /* complete missing arguments */
- ci->top = func + 1 + fsize; /* top for new function */
- lua_assert(ci->top <= L->stack_last);
+ ci->top.p = func + 1 + fsize; /* top for new function */
+ lua_assert(ci->top.p <= L->stack_last.p);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus |= CIST_TAIL;
- L->top = func + narg1; /* set top */
+ L->top.p = func + narg1; /* set top */
return -1;
}
default: { /* not a function */
@@ -574,15 +597,15 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
case LUA_VLCL: { /* Lua function */
CallInfo *ci;
Proto *p = clLvalue(s2v(func))->p;
- int narg = cast_int(L->top - func) - 1; /* number of real arguments */
+ int narg = cast_int(L->top.p - func) - 1; /* number of real arguments */
int nfixparams = p->numparams;
int fsize = p->maxstacksize; /* frame size */
checkstackGCp(L, fsize, func);
L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize);
ci->u.l.savedpc = p->code; /* starting point */
for (; narg < nfixparams; narg++)
- setnilvalue(s2v(L->top++)); /* complete missing arguments */
- lua_assert(ci->top <= L->stack_last);
+ setnilvalue(s2v(L->top.p++)); /* complete missing arguments */
+ lua_assert(ci->top.p <= L->stack_last.p);
return ci;
}
default: { /* not a function */
@@ -598,12 +621,17 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
** Call a function (C or Lua) through C. 'inc' can be 1 (increment
** number of recursive invocations in the C stack) or nyci (the same
** plus increment number of non-yieldable calls).
+** This function can be called with some use of EXTRA_STACK, so it should
+** check the stack before doing anything else. 'luaD_precall' already
+** does that.
*/
-l_sinline void ccall (lua_State *L, StkId func, int nResults, int inc) {
+l_sinline void ccall (lua_State *L, StkId func, int nResults, l_uint32 inc) {
CallInfo *ci;
L->nCcalls += inc;
- if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
+ if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) {
+ checkstackp(L, 0, func); /* free any use of EXTRA_STACK */
luaE_checkcstack(L);
+ }
if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */
ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */
luaV_execute(L, ci); /* call it */
@@ -651,8 +679,7 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
else { /* error */
StkId func = restorestack(L, ci->u2.funcidx);
L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */
- luaF_close(L, func, status, 1); /* can yield or raise an error */
- func = restorestack(L, ci->u2.funcidx); /* stack may be moved */
+ func = luaF_close(L, func, status, 1); /* can yield or raise an error */
luaD_seterrorobj(L, status, func);
luaD_shrinkstack(L); /* restore stack size in case of overflow */
setcistrecst(ci, LUA_OK); /* clear original status */
@@ -740,8 +767,8 @@ static CallInfo *findpcall (lua_State *L) {
** coroutine error handler and should not kill the coroutine.)
*/
static int resume_error (lua_State *L, const char *msg, int narg) {
- L->top -= narg; /* remove args from the stack */
- setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
+ L->top.p -= narg; /* remove args from the stack */
+ setsvalue2s(L, L->top.p, luaS_new(L, msg)); /* push error message */
api_incr_top(L);
lua_unlock(L);
return LUA_ERRRUN;
@@ -757,7 +784,7 @@ static int resume_error (lua_State *L, const char *msg, int narg) {
*/
static void resume (lua_State *L, void *ud) {
int n = *(cast(int*, ud)); /* number of arguments */
- StkId firstArg = L->top - n; /* first argument */
+ StkId firstArg = L->top.p - n; /* first argument */
CallInfo *ci = L->ci;
if (L->status == LUA_OK) /* starting a coroutine? */
ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */
@@ -765,7 +792,7 @@ static void resume (lua_State *L, void *ud) {
lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */
if (isLua(ci)) { /* yielded inside a hook? */
- L->top = firstArg; /* discard arguments */
+ L->top.p = firstArg; /* discard arguments */
luaV_execute(L, ci); /* just continue running Lua code */
}
else { /* 'common' yield */
@@ -808,7 +835,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
if (L->status == LUA_OK) { /* may be starting a coroutine */
if (L->ci != &L->base_ci) /* not in base level? */
return resume_error(L, "cannot resume non-suspended coroutine", nargs);
- else if (L->top - (L->ci->func + 1) == nargs) /* no function? */
+ else if (L->top.p - (L->ci->func.p + 1) == nargs) /* no function? */
return resume_error(L, "cannot resume dead coroutine", nargs);
}
else if (L->status != LUA_YIELD) /* ended with errors? */
@@ -826,11 +853,11 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
lua_assert(status == L->status); /* normal end or yield */
else { /* unrecoverable error */
L->status = cast_byte(status); /* mark thread as 'dead' */
- luaD_seterrorobj(L, status, L->top); /* push error message */
- L->ci->top = L->top;
+ luaD_seterrorobj(L, status, L->top.p); /* push error message */
+ L->ci->top.p = L->top.p;
}
*nresults = (status == LUA_YIELD) ? L->ci->u2.nyield
- : cast_int(L->top - (L->ci->func + 1));
+ : cast_int(L->top.p - (L->ci->func.p + 1));
lua_unlock(L);
return status;
}
@@ -985,7 +1012,7 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
p.dyd.label.arr = NULL; p.dyd.label.size = 0;
luaZ_initbuffer(L, &p.buff);
- status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
+ status = luaD_pcall(L, f_parser, &p, savestack(L, L->top.p), L->errfunc);
luaZ_freebuffer(L, &p.buff);
luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);
diff --git a/src/ldo.h b/src/ldo.h
index 911e67f660a1..1aa446ad09e9 100644
--- a/src/ldo.h
+++ b/src/ldo.h
@@ -8,6 +8,7 @@
#define ldo_h
+#include "llimits.h"
#include "lobject.h"
#include "lstate.h"
#include "lzio.h"
@@ -23,7 +24,7 @@
** at every check.
*/
#define luaD_checkstackaux(L,n,pre,pos) \
- if (l_unlikely(L->stack_last - L->top <= (n))) \
+ if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \
{ pre; luaD_growstack(L, n, 1); pos; } \
else { condmovestack(L,pre,pos); }
@@ -32,11 +33,18 @@
-#define savestack(L,p) ((char *)(p) - (char *)L->stack)
-#define restorestack(L,n) ((StkId)((char *)L->stack + (n)))
+#define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p))
+#define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n))
/* macro to check stack size, preserving 'p' */
+#define checkstackp(L,n,p) \
+ luaD_checkstackaux(L, n, \
+ ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
+ p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
+
+
+/* macro to check stack size and GC, preserving 'p' */
#define checkstackGCp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
@@ -58,7 +66,8 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
int fTransfer, int nTransfer);
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
-LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1, int delta);
+LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
+ int narg1, int delta);
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
diff --git a/src/ldump.c b/src/ldump.c
index f848b669cbdd..f231691b7795 100644
--- a/src/ldump.c
+++ b/src/ldump.c
@@ -10,6 +10,7 @@
#include "lprefix.h"
+#include <limits.h>
#include <stddef.h>
#include "lua.h"
@@ -55,8 +56,11 @@ static void dumpByte (DumpState *D, int y) {
}
-/* dumpInt Buff Size */
-#define DIBS ((sizeof(size_t) * 8 / 7) + 1)
+/*
+** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6"
+** rounds up the division.)
+*/
+#define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7)
static void dumpSize (DumpState *D, size_t x) {
lu_byte buff[DIBS];
diff --git a/src/lfunc.c b/src/lfunc.c
index f5889a21d12e..0945f241de2d 100644
--- a/src/lfunc.c
+++ b/src/lfunc.c
@@ -50,8 +50,8 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
for (i = 0; i < cl->nupvalues; i++) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o);
- uv->v = &uv->u.value; /* make it closed */
- setnilvalue(uv->v);
+ uv->v.p = &uv->u.value; /* make it closed */
+ setnilvalue(uv->v.p);
cl->upvals[i] = uv;
luaC_objbarrier(L, cl, uv);
}
@@ -62,12 +62,11 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
** Create a new upvalue at the given level, and link it to the list of
** open upvalues of 'L' after entry 'prev'.
**/
-static UpVal *newupval (lua_State *L, int tbc, StkId level, UpVal **prev) {
+static UpVal *newupval (lua_State *L, StkId level, UpVal **prev) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o);
UpVal *next = *prev;
- uv->v = s2v(level); /* current value lives in the stack */
- uv->tbc = tbc;
+ uv->v.p = s2v(level); /* current value lives in the stack */
uv->u.open.next = next; /* link it to list of open upvalues */
uv->u.open.previous = prev;
if (next)
@@ -96,7 +95,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
pp = &p->u.open.next;
}
/* not found: create a new upvalue after 'pp' */
- return newupval(L, 0, level, pp);
+ return newupval(L, level, pp);
}
@@ -106,12 +105,12 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
** (This function assumes EXTRA_STACK.)
*/
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
- StkId top = L->top;
+ StkId top = L->top.p;
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
setobj2s(L, top, tm); /* will call metamethod... */
setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
- L->top = top + 3; /* add function and arguments */
+ L->top.p = top + 3; /* add function and arguments */
if (yy)
luaD_call(L, top, 0);
else
@@ -126,7 +125,7 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
static void checkclosemth (lua_State *L, StkId level) {
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
if (ttisnil(tm)) { /* no metamethod? */
- int idx = cast_int(level - L->ci->func); /* variable index */
+ int idx = cast_int(level - L->ci->func.p); /* variable index */
const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
if (vname == NULL) vname = "?";
luaG_runerror(L, "variable '%s' got a non-closable value", vname);
@@ -160,23 +159,23 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
** is used.)
*/
#define MAXDELTA \
- ((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1)
+ ((256ul << ((sizeof(L->stack.p->tbclist.delta) - 1) * 8)) - 1)
/*
** Insert a variable in the list of to-be-closed variables.
*/
void luaF_newtbcupval (lua_State *L, StkId level) {
- lua_assert(level > L->tbclist);
+ lua_assert(level > L->tbclist.p);
if (l_isfalse(s2v(level)))
return; /* false doesn't need to be closed */
checkclosemth(L, level); /* value must have a close method */
- while (cast_uint(level - L->tbclist) > MAXDELTA) {
- L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */
- L->tbclist->tbclist.delta = 0;
+ while (cast_uint(level - L->tbclist.p) > MAXDELTA) {
+ L->tbclist.p += MAXDELTA; /* create a dummy node at maximum delta */
+ L->tbclist.p->tbclist.delta = 0;
}
- level->tbclist.delta = cast(unsigned short, level - L->tbclist);
- L->tbclist = level;
+ level->tbclist.delta = cast(unsigned short, level - L->tbclist.p);
+ L->tbclist.p = level;
}
@@ -196,10 +195,10 @@ void luaF_closeupval (lua_State *L, StkId level) {
StkId upl; /* stack index pointed by 'uv' */
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
TValue *slot = &uv->u.value; /* new position for value */
- lua_assert(uplevel(uv) < L->top);
+ lua_assert(uplevel(uv) < L->top.p);
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
- setobj(L, slot, uv->v); /* move value to upvalue slot */
- uv->v = slot; /* now current value lives here */
+ setobj(L, slot, uv->v.p); /* move value to upvalue slot */
+ uv->v.p = slot; /* now current value lives here */
if (!iswhite(uv)) { /* neither white nor dead? */
nw2black(uv); /* closed upvalues cannot be gray */
luaC_barrier(L, uv, slot);
@@ -209,31 +208,32 @@ void luaF_closeupval (lua_State *L, StkId level) {
/*
-** Remove firt element from the tbclist plus its dummy nodes.
+** Remove first element from the tbclist plus its dummy nodes.
*/
static void poptbclist (lua_State *L) {
- StkId tbc = L->tbclist;
+ StkId tbc = L->tbclist.p;
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
tbc -= tbc->tbclist.delta;
- while (tbc > L->stack && tbc->tbclist.delta == 0)
+ while (tbc > L->stack.p && tbc->tbclist.delta == 0)
tbc -= MAXDELTA; /* remove dummy nodes */
- L->tbclist = tbc;
+ L->tbclist.p = tbc;
}
/*
** Close all upvalues and to-be-closed variables up to the given stack
-** level.
+** level. Return restored 'level'.
*/
-void luaF_close (lua_State *L, StkId level, int status, int yy) {
+StkId luaF_close (lua_State *L, StkId level, int status, int yy) {
ptrdiff_t levelrel = savestack(L, level);
luaF_closeupval(L, level); /* first, close the upvalues */
- while (L->tbclist >= level) { /* traverse tbc's down to that level */
- StkId tbc = L->tbclist; /* get variable index */
+ while (L->tbclist.p >= level) { /* traverse tbc's down to that level */
+ StkId tbc = L->tbclist.p; /* get variable index */
poptbclist(L); /* remove it from list */
prepcallclosemth(L, tbc, status, yy); /* close variable */
level = restorestack(L, levelrel);
}
+ return level;
}
diff --git a/src/lfunc.h b/src/lfunc.h
index dc1cebccd1bc..3be265efb584 100644
--- a/src/lfunc.h
+++ b/src/lfunc.h
@@ -29,10 +29,10 @@
#define MAXUPVAL 255
-#define upisopen(up) ((up)->v != &(up)->u.value)
+#define upisopen(up) ((up)->v.p != &(up)->u.value)
-#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v))
+#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p))
/*
@@ -54,7 +54,7 @@ LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
-LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy);
+LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy);
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
diff --git a/src/lgc.c b/src/lgc.c
index 42a73d813acc..a3094ff57126 100644
--- a/src/lgc.c
+++ b/src/lgc.c
@@ -252,12 +252,13 @@ void luaC_fix (lua_State *L, GCObject *o) {
/*
-** create a new collectable object (with given type and size) and link
-** it to 'allgc' list.
+** create a new collectable object (with given type, size, and offset)
+** and link it to 'allgc' list.
*/
-GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
+GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
global_State *g = G(L);
- GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz));
+ char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
+ GCObject *o = cast(GCObject *, p + offset);
o->marked = luaC_white(g);
o->tt = tt;
o->next = g->allgc;
@@ -265,6 +266,11 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return o;
}
+
+GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
+ return luaC_newobjdt(L, tt, sz, 0);
+}
+
/* }====================================================== */
@@ -301,7 +307,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
set2gray(uv); /* open upvalues are kept gray */
else
set2black(uv); /* closed upvalues are visited here */
- markvalue(g, uv->v); /* mark its content */
+ markvalue(g, uv->v.p); /* mark its content */
break;
}
case LUA_VUSERDATA: {
@@ -376,7 +382,7 @@ static int remarkupvals (global_State *g) {
work++;
if (!iswhite(uv)) { /* upvalue already visited? */
lua_assert(upisopen(uv) && isgray(uv));
- markvalue(g, uv->v); /* mark its value */
+ markvalue(g, uv->v.p); /* mark its value */
}
}
}
@@ -620,19 +626,19 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
*/
static int traversethread (global_State *g, lua_State *th) {
UpVal *uv;
- StkId o = th->stack;
+ StkId o = th->stack.p;
if (isold(th) || g->gcstate == GCSpropagate)
linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
if (o == NULL)
return 1; /* stack not completely built yet */
lua_assert(g->gcstate == GCSatomic ||
th->openupval == NULL || isintwups(th));
- for (; o < th->top; o++) /* mark live elements in the stack */
+ for (; o < th->top.p; o++) /* mark live elements in the stack */
markvalue(g, s2v(o));
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? */
- for (; o < th->stack_last + EXTRA_STACK; o++)
+ for (; o < th->stack_last.p + EXTRA_STACK; o++)
setnilvalue(s2v(o)); /* clear dead stack slice */
/* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) {
@@ -892,7 +898,7 @@ static GCObject *udata2finalize (global_State *g) {
static void dothecall (lua_State *L, void *ud) {
UNUSED(ud);
- luaD_callnoyield(L, L->top - 2, 0);
+ luaD_callnoyield(L, L->top.p - 2, 0);
}
@@ -909,16 +915,16 @@ static void GCTM (lua_State *L) {
int oldgcstp = g->gcstp;
g->gcstp |= GCSTPGC; /* avoid GC steps */
L->allowhook = 0; /* stop debug hooks during GC metamethod */
- setobj2s(L, L->top++, tm); /* push finalizer... */
- setobj2s(L, L->top++, &v); /* ... and its argument */
+ setobj2s(L, L->top.p++, tm); /* push finalizer... */
+ setobj2s(L, L->top.p++, &v); /* ... and its argument */
L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
- status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
+ status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0);
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */
g->gcstp = oldgcstp; /* restore state */
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
luaE_warnerror(L, "__gc");
- L->top--; /* pops error object */
+ L->top.p--; /* pops error object */
}
}
}
@@ -1041,7 +1047,25 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
** =======================================================
*/
-static void setpause (global_State *g);
+
+/*
+** Set the "time" to wait before starting a new GC cycle; cycle will
+** start when memory use hits the threshold of ('estimate' * pause /
+** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
+** because Lua cannot even start with less than PAUSEADJ bytes).
+*/
+static void setpause (global_State *g) {
+ l_mem threshold, debt;
+ int pause = getgcparam(g->gcpause);
+ l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
+ lua_assert(estimate > 0);
+ threshold = (pause < MAX_LMEM / estimate) /* overflow? */
+ ? estimate * pause /* no overflow */
+ : MAX_LMEM; /* overflow; truncate to maximum */
+ debt = gettotalbytes(g) - threshold;
+ if (debt > 0) debt = 0;
+ luaE_setdebt(g, debt);
+}
/*
@@ -1286,6 +1310,15 @@ static void atomic2gen (lua_State *L, global_State *g) {
/*
+** Set debt for the next minor collection, which will happen when
+** memory grows 'genminormul'%.
+*/
+static void setminordebt (global_State *g) {
+ luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
+}
+
+
+/*
** Enter generational mode. Must go until the end of an atomic cycle
** to ensure that all objects are correctly marked and weak tables
** are cleared. Then, turn all objects into old and finishes the
@@ -1297,6 +1330,7 @@ static lu_mem entergen (lua_State *L, global_State *g) {
luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
numobjs = atomic(L); /* propagates all and then do the atomic stuff */
atomic2gen(L, g);
+ setminordebt(g); /* set debt assuming next cycle will be minor */
return numobjs;
}
@@ -1343,15 +1377,6 @@ static lu_mem fullgen (lua_State *L, global_State *g) {
/*
-** Set debt for the next minor collection, which will happen when
-** memory grows 'genminormul'%.
-*/
-static void setminordebt (global_State *g) {
- luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
-}
-
-
-/*
** Does a major collection after last collection was a "bad collection".
**
** When the program is building a big structure, it allocates lots of
@@ -1422,8 +1447,8 @@ static void genstep (lua_State *L, global_State *g) {
lu_mem numobjs = fullgen(L, g); /* do a major collection */
if (gettotalbytes(g) < majorbase + (majorinc / 2)) {
/* collected at least half of memory growth since last major
- collection; keep doing minor collections */
- setminordebt(g);
+ collection; keep doing minor collections. */
+ lua_assert(g->lastatomic == 0);
}
else { /* bad collection */
g->lastatomic = numobjs; /* signal that last collection was bad */
@@ -1450,26 +1475,6 @@ static void genstep (lua_State *L, global_State *g) {
/*
-** Set the "time" to wait before starting a new GC cycle; cycle will
-** start when memory use hits the threshold of ('estimate' * pause /
-** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
-** because Lua cannot even start with less than PAUSEADJ bytes).
-*/
-static void setpause (global_State *g) {
- l_mem threshold, debt;
- int pause = getgcparam(g->gcpause);
- l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
- lua_assert(estimate > 0);
- threshold = (pause < MAX_LMEM / estimate) /* overflow? */
- ? estimate * pause /* no overflow */
- : MAX_LMEM; /* overflow; truncate to maximum */
- debt = gettotalbytes(g) - threshold;
- if (debt > 0) debt = 0;
- luaE_setdebt(g, debt);
-}
-
-
-/*
** Enter first sweep phase.
** The call to 'sweeptolive' makes the pointer point to an object
** inside the list (instead of to the header), so that the real sweep do
@@ -1676,12 +1681,15 @@ static void incstep (lua_State *L, global_State *g) {
}
/*
-** performs a basic GC step if collector is running
+** Performs a basic GC step if collector is running. (If collector is
+** not running, set a reasonable debt to avoid it being called at
+** every single check.)
*/
void luaC_step (lua_State *L) {
global_State *g = G(L);
- lua_assert(!g->gcemergency);
- if (gcrunning(g)) { /* running? */
+ if (!gcrunning(g)) /* not running? */
+ luaE_setdebt(g, -2000);
+ else {
if(isdecGCmodegen(g))
genstep(L, g);
else
diff --git a/src/lgc.h b/src/lgc.h
index 4a125634b9ea..538f6edcccf2 100644
--- a/src/lgc.h
+++ b/src/lgc.h
@@ -172,24 +172,27 @@
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
-#define luaC_barrier(L,p,v) ( \
- (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
- luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
-
-#define luaC_barrierback(L,p,v) ( \
- (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
- luaC_barrierback_(L,p) : cast_void(0))
-
#define luaC_objbarrier(L,p,o) ( \
(isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
+#define luaC_barrier(L,p,v) ( \
+ iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0))
+
+#define luaC_objbarrierback(L,p,o) ( \
+ (isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0))
+
+#define luaC_barrierback(L,p,v) ( \
+ iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0))
+
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L);
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
+LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz,
+ size_t offset);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
diff --git a/src/llex.c b/src/llex.c
index e99151787a63..5fc39a5cdec1 100644
--- a/src/llex.c
+++ b/src/llex.c
@@ -128,7 +128,7 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
** ensuring there is only one copy of each unique string. The table
** here is used as a set: the string enters as the key, while its value
** is irrelevant. We use the string itself as the value only because it
-** is a TValue readly available. Later, the code generation can change
+** is a TValue readily available. Later, the code generation can change
** this value.
*/
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
@@ -138,12 +138,12 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
if (!ttisnil(o)) /* string already present? */
ts = keystrval(nodefromval(o)); /* get saved copy */
else { /* not in use yet */
- TValue *stv = s2v(L->top++); /* reserve stack space for string */
+ TValue *stv = s2v(L->top.p++); /* reserve stack space for string */
setsvalue(L, stv, ts); /* temporarily anchor the string */
luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */
/* table is not a metatable, so it does not need to invalidate cache */
luaC_checkGC(L);
- L->top--; /* remove string from stack */
+ L->top.p--; /* remove string from stack */
}
return ts;
}
diff --git a/src/llimits.h b/src/llimits.h
index 52a32f92e302..1c826f7be205 100644
--- a/src/llimits.h
+++ b/src/llimits.h
@@ -71,11 +71,24 @@ typedef signed char ls_byte;
/*
-** conversion of pointer to unsigned integer:
-** this is for hashing only; there is no problem if the integer
-** cannot hold the whole pointer value
+** conversion of pointer to unsigned integer: this is for hashing only;
+** there is no problem if the integer cannot hold the whole pointer
+** value. (In strict ISO C this may cause undefined behavior, but no
+** actual machine seems to bother.)
*/
-#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX))
+#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
+ __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+#if defined(UINTPTR_MAX) /* even in C99 this type is optional */
+#define L_P2I uintptr_t
+#else /* no 'intptr'? */
+#define L_P2I uintmax_t /* use the largest available integer */
+#endif
+#else /* C89 option */
+#define L_P2I size_t
+#endif
+
+#define point2uint(p) ((unsigned int)((L_P2I)(p) & UINT_MAX))
diff --git a/src/lmathlib.c b/src/lmathlib.c
index e0c61a168d98..d0b1e1e5d6f5 100644
--- a/src/lmathlib.c
+++ b/src/lmathlib.c
@@ -267,7 +267,7 @@ static int math_type (lua_State *L) {
/* try to find an integer type with at least 64 bits */
-#if (ULONG_MAX >> 31 >> 31) >= 3
+#if ((ULONG_MAX >> 31) >> 31) >= 3
/* 'long' has at least 64 bits */
#define Rand64 unsigned long
@@ -277,9 +277,9 @@ static int math_type (lua_State *L) {
/* there is a 'long long' type (which must have at least 64 bits) */
#define Rand64 unsigned long long
-#elif (LUA_MAXUNSIGNED >> 31 >> 31) >= 3
+#elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
-/* 'lua_Integer' has at least 64 bits */
+/* 'lua_Unsigned' has at least 64 bits */
#define Rand64 lua_Unsigned
#endif
@@ -500,12 +500,12 @@ static lua_Number I2d (Rand64 x) {
/* convert a 'Rand64' to a 'lua_Unsigned' */
static lua_Unsigned I2UInt (Rand64 x) {
- return ((lua_Unsigned)trim32(x.h) << 31 << 1) | (lua_Unsigned)trim32(x.l);
+ return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l);
}
/* convert a 'lua_Unsigned' to a 'Rand64' */
static Rand64 Int2I (lua_Unsigned n) {
- return packI((lu_int32)(n >> 31 >> 1), (lu_int32)n);
+ return packI((lu_int32)((n >> 31) >> 1), (lu_int32)n);
}
#endif /* } */
diff --git a/src/lmem.c b/src/lmem.c
index 9029d588c12e..9800a86fc024 100644
--- a/src/lmem.c
+++ b/src/lmem.c
@@ -22,25 +22,6 @@
#include "lstate.h"
-#if defined(EMERGENCYGCTESTS)
-/*
-** First allocation will fail whenever not building initial state.
-** (This fail will trigger 'tryagain' and a full GC cycle at every
-** allocation.)
-*/
-static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
- if (completestate(g) && ns > 0) /* frees never fail */
- return NULL; /* fail */
- else /* normal allocation */
- return (*g->frealloc)(g->ud, block, os, ns);
-}
-#else
-#define firsttry(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
-#endif
-
-
-
-
/*
** About the realloc function:
@@ -60,6 +41,43 @@ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
*/
+/*
+** Macro to call the allocation function.
+*/
+#define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
+
+
+/*
+** When an allocation fails, it will try again after an emergency
+** collection, except when it cannot run a collection. The GC should
+** not be called while the state is not fully built, as the collector
+** is not yet fully initialized. Also, it should not be called when
+** 'gcstopem' is true, because then the interpreter is in the middle of
+** a collection step.
+*/
+#define cantryagain(g) (completestate(g) && !g->gcstopem)
+
+
+
+
+#if defined(EMERGENCYGCTESTS)
+/*
+** First allocation will fail except when freeing a block (frees never
+** fail) and when it cannot try again; this fail will trigger 'tryagain'
+** and a full GC cycle at every allocation.
+*/
+static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
+ if (ns > 0 && cantryagain(g))
+ return NULL; /* fail */
+ else /* normal allocation */
+ return callfrealloc(g, block, os, ns);
+}
+#else
+#define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns)
+#endif
+
+
+
/*
@@ -132,7 +150,7 @@ l_noret luaM_toobig (lua_State *L) {
void luaM_free_ (lua_State *L, void *block, size_t osize) {
global_State *g = G(L);
lua_assert((osize == 0) == (block == NULL));
- (*g->frealloc)(g->ud, block, osize, 0);
+ callfrealloc(g, block, osize, 0);
g->GCdebt -= osize;
}
@@ -140,19 +158,15 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
/*
** In case of allocation fail, this function will do an emergency
** collection to free some memory and then try the allocation again.
-** The GC should not be called while state is not fully built, as the
-** collector is not yet fully initialized. Also, it should not be called
-** when 'gcstopem' is true, because then the interpreter is in the
-** middle of a collection step.
*/
static void *tryagain (lua_State *L, void *block,
size_t osize, size_t nsize) {
global_State *g = G(L);
- if (completestate(g) && !g->gcstopem) {
+ if (cantryagain(g)) {
luaC_fullgc(L, 1); /* try to free some memory... */
- return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
+ return callfrealloc(g, block, osize, nsize); /* try again */
}
- else return NULL; /* cannot free any memory without a full state */
+ else return NULL; /* cannot run an emergency collection */
}
diff --git a/src/loadlib.c b/src/loadlib.c
index 6f9fa37366e4..d792dffaa03b 100644
--- a/src/loadlib.c
+++ b/src/loadlib.c
@@ -708,8 +708,13 @@ static const luaL_Reg ll_funcs[] = {
static void createsearcherstable (lua_State *L) {
- static const lua_CFunction searchers[] =
- {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
+ static const lua_CFunction searchers[] = {
+ searcher_preload,
+ searcher_Lua,
+ searcher_C,
+ searcher_Croot,
+ NULL
+ };
int i;
/* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
diff --git a/src/lobject.c b/src/lobject.c
index 301aa900be0a..f73ffc6d92bd 100644
--- a/src/lobject.c
+++ b/src/lobject.c
@@ -62,7 +62,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
case LUA_OPBOR: return intop(|, v1, v2);
case LUA_OPBXOR: return intop(^, v1, v2);
case LUA_OPSHL: return luaV_shiftl(v1, v2);
- case LUA_OPSHR: return luaV_shiftl(v1, -v2);
+ case LUA_OPSHR: return luaV_shiftr(v1, v2);
case LUA_OPUNM: return intop(-, 0, v1);
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
default: lua_assert(0); return 0;
@@ -386,29 +386,39 @@ void luaO_tostring (lua_State *L, TValue *obj) {
** ===================================================================
*/
-/* size for buffer space used by 'luaO_pushvfstring' */
-#define BUFVFS 200
+/*
+** Size for buffer space used by 'luaO_pushvfstring'. It should be
+** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages,
+** so that 'luaG_addinfo' can work directly on the buffer.
+*/
+#define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95)
/* buffer used by 'luaO_pushvfstring' */
typedef struct BuffFS {
lua_State *L;
- int pushed; /* number of string pieces already on the stack */
+ int pushed; /* true if there is a part of the result on the stack */
int blen; /* length of partial string in 'space' */
char space[BUFVFS]; /* holds last part of the result */
} BuffFS;
/*
-** Push given string to the stack, as part of the buffer, and
-** join the partial strings in the stack into one.
+** Push given string to the stack, as part of the result, and
+** join it to previous partial result if there is one.
+** It may call 'luaV_concat' while using one slot from EXTRA_STACK.
+** This call cannot invoke metamethods, as both operands must be
+** strings. It can, however, raise an error if the result is too
+** long. In that case, 'luaV_concat' frees the extra slot before
+** raising the error.
*/
-static void pushstr (BuffFS *buff, const char *str, size_t l) {
+static void pushstr (BuffFS *buff, const char *str, size_t lstr) {
lua_State *L = buff->L;
- setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
- L->top++; /* may use one extra slot */
- buff->pushed++;
- luaV_concat(L, buff->pushed); /* join partial results into one */
- buff->pushed = 1;
+ setsvalue2s(L, L->top.p, luaS_newlstr(L, str, lstr));
+ L->top.p++; /* may use one slot from EXTRA_STACK */
+ if (!buff->pushed) /* no previous string on the stack? */
+ buff->pushed = 1; /* now there is one */
+ else /* join previous string with new one */
+ luaV_concat(L, 2);
}
@@ -454,7 +464,7 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
/*
-** Add a number to the buffer.
+** Add a numeral to the buffer.
*/
static void addnum2buff (BuffFS *buff, TValue *num) {
char *numbuff = getbuff(buff, MAXNUMBER2STR);
@@ -532,7 +542,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
clearbuff(&buff); /* empty buffer into the stack */
lua_assert(buff.pushed == 1);
- return svalue(s2v(L->top - 1));
+ return svalue(s2v(L->top.p - 1));
}
diff --git a/src/lobject.h b/src/lobject.h
index 0e05b3e42ea9..556608e4aa21 100644
--- a/src/lobject.h
+++ b/src/lobject.h
@@ -52,6 +52,8 @@ typedef union Value {
lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
+ /* not used, but may avoid warnings for uninitialized value */
+ lu_byte ub;
} Value;
@@ -155,6 +157,17 @@ typedef union StackValue {
/* index to stack elements */
typedef StackValue *StkId;
+
+/*
+** When reallocating the stack, change all pointers to the stack into
+** proper offsets.
+*/
+typedef union {
+ StkId p; /* actual pointer */
+ ptrdiff_t offset; /* used while the stack is being reallocated */
+} StkIdRel;
+
+
/* convert a 'StackValue' to a 'TValue' */
#define s2v(o) (&(o)->val)
@@ -615,8 +628,10 @@ typedef struct Proto {
*/
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 {
+ TValue *p; /* points to stack or to its own value */
+ ptrdiff_t offset; /* used while the stack is being reallocated */
+ } v;
union {
struct { /* (when open) */
struct UpVal *next; /* linked list */
diff --git a/src/lopcodes.h b/src/lopcodes.h
index 7c2745159606..4c55145399ff 100644
--- a/src/lopcodes.h
+++ b/src/lopcodes.h
@@ -21,7 +21,7 @@ iABC C(8) | B(8) |k| A(8) | Op(7) |
iABx Bx(17) | A(8) | Op(7) |
iAsBx sBx (signed)(17) | A(8) | Op(7) |
iAx Ax(25) | Op(7) |
-isJ sJ(25) | Op(7) |
+isJ sJ (signed)(25) | Op(7) |
A signed argument is represented in excess K: the represented value is
the written unsigned value minus K, where K is half the maximum for the
diff --git a/src/loslib.c b/src/loslib.c
index 3e20d622bacd..ad5a92768852 100644
--- a/src/loslib.c
+++ b/src/loslib.c
@@ -30,23 +30,14 @@
*/
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
-/* options for ANSI C 89 (only 1-char options) */
-#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
-
-/* options for ISO C 99 and POSIX */
-#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
- "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
-
-/* options for Windows */
-#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
- "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
-
#if defined(LUA_USE_WINDOWS)
-#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
-#elif defined(LUA_USE_C89)
-#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
+#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
+ "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
+#elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */
+#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
#else /* C99 specification */
-#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
+#define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
+ "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
#endif
#endif /* } */
@@ -138,12 +129,21 @@
/* }================================================================== */
+#if !defined(l_system)
+#if defined(LUA_USE_IOS)
+/* Despite claiming to be ISO C, iOS does not implement 'system'. */
+#define l_system(cmd) ((cmd) == NULL ? 0 : -1)
+#else
+#define l_system(cmd) system(cmd) /* default definition */
+#endif
+#endif
+
static int os_execute (lua_State *L) {
const char *cmd = luaL_optstring(L, 1, NULL);
int stat;
errno = 0;
- stat = system(cmd);
+ stat = l_system(cmd);
if (cmd != NULL)
return luaL_execresult(L, stat);
else {
@@ -260,9 +260,7 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
res = d;
}
else {
- /* unsigned avoids overflow when lua_Integer has 32 bits */
- if (!(res >= 0 ? (lua_Unsigned)res <= (lua_Unsigned)INT_MAX + delta
- : (lua_Integer)INT_MIN + delta <= res))
+ if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res))
return luaL_error(L, "field '%s' is out-of-bound", key);
res -= delta;
}
diff --git a/src/lparser.c b/src/lparser.c
index 3abe3d75187b..b745f236f068 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -468,6 +468,7 @@ static void singlevar (LexState *ls, expdesc *var) {
expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k != VVOID); /* this one must exist */
+ luaK_exp2anyregup(fs, var); /* but could be a constant */
codestring(&key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */
}
@@ -520,12 +521,12 @@ static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
/*
** Solves the goto at index 'g' to given 'label' and removes it
-** from the list of pending goto's.
+** from the list of pending gotos.
** If it jumps into the scope of some variable, raises an error.
*/
static void solvegoto (LexState *ls, int g, Labeldesc *label) {
int i;
- Labellist *gl = &ls->dyd->gt; /* list of goto's */
+ Labellist *gl = &ls->dyd->gt; /* list of gotos */
Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */
lua_assert(eqstr(gt->name, label->name));
if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */
@@ -579,7 +580,7 @@ static int newgotoentry (LexState *ls, TString *name, int line, int pc) {
/*
** Solves forward jumps. Check whether new label 'lb' matches any
** pending gotos in current block and solves them. Return true
-** if any of the goto's need to close upvalues.
+** if any of the gotos need to close upvalues.
*/
static int solvegotos (LexState *ls, Labeldesc *lb) {
Labellist *gl = &ls->dyd->gt;
@@ -600,7 +601,7 @@ static int solvegotos (LexState *ls, Labeldesc *lb) {
/*
** Create a new label with the given 'name' at the given 'line'.
** 'last' tells whether label is the last non-op statement in its
-** block. Solves all pending goto's to this new label and adds
+** block. Solves all pending gotos to this new label and adds
** a close instruction if necessary.
** Returns true iff it added a close instruction.
*/
@@ -673,19 +674,19 @@ static void leaveblock (FuncState *fs) {
LexState *ls = fs->ls;
int hasclose = 0;
int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */
- if (bl->isloop) /* fix pending breaks? */
+ removevars(fs, bl->nactvar); /* remove block locals */
+ lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */
+ if (bl->isloop) /* has to fix pending breaks? */
hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
- if (!hasclose && bl->previous && bl->upval)
+ if (!hasclose && bl->previous && bl->upval) /* still need a 'close'? */
luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0);
- fs->bl = bl->previous;
- removevars(fs, bl->nactvar);
- lua_assert(bl->nactvar == fs->nactvar);
fs->freereg = stklevel; /* free registers */
ls->dyd->label.n = bl->firstlabel; /* remove local labels */
- if (bl->previous) /* inner block? */
- movegotosout(fs, bl); /* update pending gotos to outer block */
+ fs->bl = bl->previous; /* current block now is previous one */
+ if (bl->previous) /* was it a nested block? */
+ movegotosout(fs, bl); /* update pending gotos to enclosing block */
else {
- if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */
+ if (bl->firstgoto < ls->dyd->gt.n) /* still pending gotos? */
undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
}
}
@@ -1943,10 +1944,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
LexState lexstate;
FuncState funcstate;
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
- setclLvalue2s(L, L->top, cl); /* anchor it (to avoid being collected) */
+ setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */
luaD_inctop(L);
lexstate.h = luaH_new(L); /* create table for scanner */
- sethvalue2s(L, L->top, lexstate.h); /* anchor it */
+ sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */
luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
@@ -1960,7 +1961,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
/* all scopes should be correctly finished */
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
- L->top--; /* remove scanner's table */
+ L->top.p--; /* remove scanner's table */
return cl; /* closure is on the stack, too */
}
diff --git a/src/lstate.c b/src/lstate.c
index 1ffe1a0f71cd..1e925e5ad4cb 100644
--- a/src/lstate.c
+++ b/src/lstate.c
@@ -180,33 +180,33 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) {
static void stack_init (lua_State *L1, lua_State *L) {
int i; CallInfo *ci;
/* initialize stack array */
- L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
- L1->tbclist = L1->stack;
+ L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
+ L1->tbclist.p = L1->stack.p;
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
- setnilvalue(s2v(L1->stack + i)); /* erase new stack */
- L1->top = L1->stack;
- L1->stack_last = L1->stack + BASIC_STACK_SIZE;
+ setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */
+ L1->top.p = L1->stack.p;
+ L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
/* initialize first ci */
ci = &L1->base_ci;
ci->next = ci->previous = NULL;
ci->callstatus = CIST_C;
- ci->func = L1->top;
+ ci->func.p = L1->top.p;
ci->u.c.k = NULL;
ci->nresults = 0;
- setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */
- L1->top++;
- ci->top = L1->top + LUA_MINSTACK;
+ setnilvalue(s2v(L1->top.p)); /* 'function' entry for this 'ci' */
+ L1->top.p++;
+ ci->top.p = L1->top.p + LUA_MINSTACK;
L1->ci = ci;
}
static void freestack (lua_State *L) {
- if (L->stack == NULL)
+ if (L->stack.p == NULL)
return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L);
lua_assert(L->nci == 0);
- luaM_freearray(L, L->stack, stacksize(L) + EXTRA_STACK); /* free stack */
+ luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */
}
@@ -248,7 +248,7 @@ static void f_luaopen (lua_State *L, void *ud) {
*/
static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g;
- L->stack = NULL;
+ L->stack.p = NULL;
L->ci = NULL;
L->nci = 0;
L->twups = L; /* thread has no upvalues */
@@ -284,20 +284,16 @@ static void close_state (lua_State *L) {
LUA_API lua_State *lua_newthread (lua_State *L) {
- global_State *g;
+ global_State *g = G(L);
+ GCObject *o;
lua_State *L1;
lua_lock(L);
- g = G(L);
luaC_checkGC(L);
/* create new thread */
- L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;
- L1->marked = luaC_white(g);
- L1->tt = LUA_VTHREAD;
- /* link it on list 'allgc' */
- L1->next = g->allgc;
- g->allgc = obj2gco(L1);
+ o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l));
+ L1 = gco2th(o);
/* anchor it on L stack */
- setthvalue2s(L, L->top, L1);
+ setthvalue2s(L, L->top.p, L1);
api_incr_top(L);
preinit_thread(L1, g);
L1->hookmask = L->hookmask;
@@ -316,7 +312,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
void luaE_freethread (lua_State *L, lua_State *L1) {
LX *l = fromstate(L1);
- luaF_closeupval(L1, L1->stack); /* close all upvalues */
+ luaF_closeupval(L1, L1->stack.p); /* close all upvalues */
lua_assert(L1->openupval == NULL);
luai_userstatefree(L, L1);
freestack(L1);
@@ -326,32 +322,41 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
int luaE_resetthread (lua_State *L, int status) {
CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
- setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */
- ci->func = L->stack;
+ setnilvalue(s2v(L->stack.p)); /* 'function' entry for basic 'ci' */
+ ci->func.p = L->stack.p;
ci->callstatus = CIST_C;
if (status == LUA_YIELD)
status = LUA_OK;
L->status = LUA_OK; /* so it can run __close metamethods */
status = luaD_closeprotected(L, 1, status);
if (status != LUA_OK) /* errors? */
- luaD_seterrorobj(L, status, L->stack + 1);
+ luaD_seterrorobj(L, status, L->stack.p + 1);
else
- L->top = L->stack + 1;
- ci->top = L->top + LUA_MINSTACK;
- luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
+ L->top.p = L->stack.p + 1;
+ ci->top.p = L->top.p + LUA_MINSTACK;
+ luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0);
return status;
}
-LUA_API int lua_resetthread (lua_State *L) {
+LUA_API int lua_closethread (lua_State *L, lua_State *from) {
int status;
lua_lock(L);
+ L->nCcalls = (from) ? getCcalls(from) : 0;
status = luaE_resetthread(L, L->status);
lua_unlock(L);
return status;
}
+/*
+** Deprecated! Use 'lua_closethread' instead.
+*/
+LUA_API int lua_resetthread (lua_State *L) {
+ return lua_closethread(L, NULL);
+}
+
+
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i;
lua_State *L;
@@ -426,7 +431,7 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
** Generate a warning from an error message
*/
void luaE_warnerror (lua_State *L, const char *where) {
- TValue *errobj = s2v(L->top - 1); /* error object */
+ TValue *errobj = s2v(L->top.p - 1); /* error object */
const char *msg = (ttisstring(errobj))
? svalue(errobj)
: "error object is not a string";
diff --git a/src/lstate.h b/src/lstate.h
index 61e82cde7253..8bf6600e3441 100644
--- a/src/lstate.h
+++ b/src/lstate.h
@@ -9,6 +9,11 @@
#include "lua.h"
+
+/* Some header files included here need this definition */
+typedef struct CallInfo CallInfo;
+
+
#include "lobject.h"
#include "ltm.h"
#include "lzio.h"
@@ -139,7 +144,7 @@ struct lua_longjmp; /* defined in ldo.c */
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
-#define stacksize(th) cast_int((th)->stack_last - (th)->stack)
+#define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p)
/* kinds of Garbage Collection */
@@ -169,9 +174,9 @@ typedef struct stringtable {
** - field 'transferinfo' is used only during call/returnhooks,
** before the function starts or after it ends.
*/
-typedef struct CallInfo {
- StkId func; /* function index in the stack */
- StkId top; /* top for this function */
+struct CallInfo {
+ StkIdRel func; /* function index in the stack */
+ StkIdRel top; /* top for this function */
struct CallInfo *previous, *next; /* dynamic call link */
union {
struct { /* only for Lua functions */
@@ -196,7 +201,7 @@ typedef struct CallInfo {
} u2;
short nresults; /* expected number of results from this function */
unsigned short callstatus;
-} CallInfo;
+};
/*
@@ -291,7 +296,7 @@ typedef struct global_State {
struct lua_State *mainthread;
TString *memerrmsg; /* message for memory-allocation errors */
TString *tmname[TM_N]; /* array with tag-method names */
- struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
+ struct Table *mt[LUA_NUMTYPES]; /* metatables for basic types */
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
lua_WarnFunction warnf; /* warning function */
void *ud_warn; /* auxiliary data to 'warnf' */
@@ -306,13 +311,13 @@ struct lua_State {
lu_byte status;
lu_byte allowhook;
unsigned short nci; /* number of items in 'ci' list */
- StkId top; /* first free slot in the stack */
+ StkIdRel top; /* first free slot in the stack */
global_State *l_G;
CallInfo *ci; /* call info for current function */
- StkId stack_last; /* end of stack (last element + 1) */
- StkId stack; /* stack base */
+ StkIdRel stack_last; /* end of stack (last element + 1) */
+ StkIdRel stack; /* stack base */
UpVal *openupval; /* list of open upvalues in this stack */
- StkId tbclist; /* list of to-be-closed variables */
+ StkIdRel tbclist; /* list of to-be-closed variables */
GCObject *gclist;
struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */
diff --git a/src/lstrlib.c b/src/lstrlib.c
index 0b4fdbb7b5bf..03167161df18 100644
--- a/src/lstrlib.c
+++ b/src/lstrlib.c
@@ -570,7 +570,7 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
static const char *match (MatchState *ms, const char *s, const char *p) {
if (l_unlikely(ms->matchdepth-- == 0))
luaL_error(ms->L, "pattern too complex");
- init: /* using goto's to optimize tail recursion */
+ init: /* using goto to optimize tail recursion */
if (p != ms->p_end) { /* end of pattern? */
switch (*p) {
case '(': { /* start capture */
diff --git a/src/ltable.c b/src/ltable.c
index 1b1cd2415b60..3c690c5f1751 100644
--- a/src/ltable.c
+++ b/src/ltable.c
@@ -107,7 +107,7 @@ static const TValue absentkey = {ABSTKEYCONSTANT};
*/
static Node *hashint (const Table *t, lua_Integer i) {
lua_Unsigned ui = l_castS2U(i);
- if (ui <= (unsigned int)INT_MAX)
+ if (ui <= cast_uint(INT_MAX))
return hashmod(t, cast_int(ui));
else
return hashmod(t, ui);
@@ -257,10 +257,12 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t) {
size |= (size >> 2);
size |= (size >> 4);
size |= (size >> 8);
+#if (UINT_MAX >> 14) > 3 /* unsigned int has more than 16 bits */
size |= (size >> 16);
#if (UINT_MAX >> 30) > 3
size |= (size >> 32); /* unsigned int has more than 32 bits */
#endif
+#endif
size++;
lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size);
return size;
@@ -488,7 +490,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
luaG_runerror(L, "table overflow");
size = twoto(lsize);
t->node = luaM_newvector(L, size, Node);
- for (i = 0; i < (int)size; i++) {
+ for (i = 0; i < cast_int(size); i++) {
Node *n = gnode(t, i);
gnext(n) = 0;
setnilkey(n);
@@ -975,6 +977,4 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainpositionTV(t, key);
}
-int luaH_isdummy (const Table *t) { return isdummy(t); }
-
#endif
diff --git a/src/ltable.h b/src/ltable.h
index 7bbbcb213f8b..75dd9e26e015 100644
--- a/src/ltable.h
+++ b/src/ltable.h
@@ -59,7 +59,6 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t);
#if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
-LUAI_FUNC int luaH_isdummy (const Table *t);
#endif
diff --git a/src/ltablib.c b/src/ltablib.c
index 868d78fd83ec..e6bc4d04af47 100644
--- a/src/ltablib.c
+++ b/src/ltablib.c
@@ -93,7 +93,7 @@ static int tremove (lua_State *L) {
lua_Integer pos = luaL_optinteger(L, 2, size);
if (pos != size) /* validate 'pos' if given */
/* check whether 'pos' is in [1, size + 1] */
- luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1,
+ luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2,
"position out of bounds");
lua_geti(L, 1, pos); /* result = t[pos] */
for ( ; pos < size; pos++) {
diff --git a/src/ltests.c b/src/ltests.c
new file mode 100644
index 000000000000..7d184c0d8ee1
--- /dev/null
+++ b/src/ltests.c
@@ -0,0 +1,1977 @@
+/*
+** $Id: ltests.c $
+** Internal Module for Debugging of the Lua Implementation
+** See Copyright Notice in lua.h
+*/
+
+#define ltests_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <limits.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "lauxlib.h"
+#include "lcode.h"
+#include "lctype.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lmem.h"
+#include "lopcodes.h"
+#include "lopnames.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "lualib.h"
+
+
+
+/*
+** The whole module only makes sense with LUA_DEBUG on
+*/
+#if defined(LUA_DEBUG)
+
+
+void *l_Trick = 0;
+
+
+#define obj_at(L,k) s2v(L->ci->func.p + (k))
+
+
+static int runC (lua_State *L, lua_State *L1, const char *pc);
+
+
+static void setnameval (lua_State *L, const char *name, int val) {
+ lua_pushinteger(L, val);
+ lua_setfield(L, -2, name);
+}
+
+
+static void pushobject (lua_State *L, const TValue *o) {
+ setobj2s(L, L->top.p, o);
+ api_incr_top(L);
+}
+
+
+static void badexit (const char *fmt, const char *s1, const char *s2) {
+ fprintf(stderr, fmt, s1);
+ if (s2)
+ fprintf(stderr, "extra info: %s\n", s2);
+ /* avoid assertion failures when exiting */
+ l_memcontrol.numblocks = l_memcontrol.total = 0;
+ exit(EXIT_FAILURE);
+}
+
+
+static int tpanic (lua_State *L) {
+ const char *msg = lua_tostring(L, -1);
+ if (msg == NULL) msg = "error object is not a string";
+ return (badexit("PANIC: unprotected error in call to Lua API (%s)\n",
+ msg, NULL),
+ 0); /* do not return to Lua */
+}
+
+
+/*
+** Warning function for tests. First, it concatenates all parts of
+** a warning in buffer 'buff'. Then, it has three modes:
+** - 0.normal: messages starting with '#' are shown on standard output;
+** - other messages abort the tests (they represent real warning
+** conditions; the standard tests should not generate these conditions
+** unexpectedly);
+** - 1.allow: all messages are shown;
+** - 2.store: all warnings go to the global '_WARN';
+*/
+static void warnf (void *ud, const char *msg, int tocont) {
+ lua_State *L = cast(lua_State *, ud);
+ static char buff[200] = ""; /* should be enough for tests... */
+ static int onoff = 0;
+ static int mode = 0; /* start in normal mode */
+ static int lasttocont = 0;
+ if (!lasttocont && !tocont && *msg == '@') { /* control message? */
+ if (buff[0] != '\0')
+ badexit("Control warning during warning: %s\naborting...\n", msg, buff);
+ if (strcmp(msg, "@off") == 0)
+ onoff = 0;
+ else if (strcmp(msg, "@on") == 0)
+ onoff = 1;
+ else if (strcmp(msg, "@normal") == 0)
+ mode = 0;
+ else if (strcmp(msg, "@allow") == 0)
+ mode = 1;
+ else if (strcmp(msg, "@store") == 0)
+ mode = 2;
+ else
+ badexit("Invalid control warning in test mode: %s\naborting...\n",
+ msg, NULL);
+ return;
+ }
+ lasttocont = tocont;
+ if (strlen(msg) >= sizeof(buff) - strlen(buff))
+ badexit("warnf-buffer overflow (%s)\n", msg, buff);
+ strcat(buff, msg); /* add new message to current warning */
+ if (!tocont) { /* message finished? */
+ lua_unlock(L);
+ luaL_checkstack(L, 1, "warn stack space");
+ lua_getglobal(L, "_WARN");
+ if (!lua_toboolean(L, -1))
+ lua_pop(L, 1); /* ok, no previous unexpected warning */
+ else {
+ badexit("Unhandled warning in store mode: %s\naborting...\n",
+ lua_tostring(L, -1), buff);
+ }
+ lua_lock(L);
+ switch (mode) {
+ case 0: { /* normal */
+ if (buff[0] != '#' && onoff) /* unexpected warning? */
+ badexit("Unexpected warning in test mode: %s\naborting...\n",
+ buff, NULL);
+ } /* FALLTHROUGH */
+ case 1: { /* allow */
+ if (onoff)
+ fprintf(stderr, "Lua warning: %s\n", buff); /* print warning */
+ break;
+ }
+ case 2: { /* store */
+ lua_unlock(L);
+ luaL_checkstack(L, 1, "warn stack space");
+ lua_pushstring(L, buff);
+ lua_setglobal(L, "_WARN"); /* assign message to global '_WARN' */
+ lua_lock(L);
+ break;
+ }
+ }
+ buff[0] = '\0'; /* prepare buffer for next warning */
+ }
+}
+
+
+/*
+** {======================================================================
+** Controlled version for realloc.
+** =======================================================================
+*/
+
+#define MARK 0x55 /* 01010101 (a nice pattern) */
+
+typedef union Header {
+ LUAI_MAXALIGN;
+ struct {
+ size_t size;
+ int type;
+ } d;
+} Header;
+
+
+#if !defined(EXTERNMEMCHECK)
+
+/* full memory check */
+#define MARKSIZE 16 /* size of marks after each block */
+#define fillmem(mem,size) memset(mem, -MARK, size)
+
+#else
+
+/* external memory check: don't do it twice */
+#define MARKSIZE 0
+#define fillmem(mem,size) /* empty */
+
+#endif
+
+
+Memcontrol l_memcontrol =
+ {0, 0UL, 0UL, 0UL, 0UL, (~0UL),
+ {0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL}};
+
+
+static void freeblock (Memcontrol *mc, Header *block) {
+ if (block) {
+ size_t size = block->d.size;
+ int i;
+ for (i = 0; i < MARKSIZE; i++) /* check marks after block */
+ lua_assert(*(cast_charp(block + 1) + size + i) == MARK);
+ mc->objcount[block->d.type]--;
+ fillmem(block, sizeof(Header) + size + MARKSIZE); /* erase block */
+ free(block); /* actually free block */
+ mc->numblocks--; /* update counts */
+ mc->total -= size;
+ }
+}
+
+
+void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) {
+ Memcontrol *mc = cast(Memcontrol *, ud);
+ Header *block = cast(Header *, b);
+ int type;
+ if (mc->memlimit == 0) { /* first time? */
+ char *limit = getenv("MEMLIMIT"); /* initialize memory limit */
+ mc->memlimit = limit ? strtoul(limit, NULL, 10) : ULONG_MAX;
+ }
+ if (block == NULL) {
+ type = (oldsize < LUA_NUMTAGS) ? oldsize : 0;
+ oldsize = 0;
+ }
+ else {
+ block--; /* go to real header */
+ type = block->d.type;
+ lua_assert(oldsize == block->d.size);
+ }
+ if (size == 0) {
+ freeblock(mc, block);
+ return NULL;
+ }
+ if (mc->failnext) {
+ mc->failnext = 0;
+ return NULL; /* fake a single memory allocation error */
+ }
+ if (mc->countlimit != ~0UL && size != oldsize) { /* count limit in use? */
+ if (mc->countlimit == 0)
+ return NULL; /* fake a memory allocation error */
+ mc->countlimit--;
+ }
+ if (size > oldsize && mc->total+size-oldsize > mc->memlimit)
+ return NULL; /* fake a memory allocation error */
+ else {
+ Header *newblock;
+ int i;
+ size_t commonsize = (oldsize < size) ? oldsize : size;
+ size_t realsize = sizeof(Header) + size + MARKSIZE;
+ if (realsize < size) return NULL; /* arithmetic overflow! */
+ newblock = cast(Header *, malloc(realsize)); /* alloc a new block */
+ if (newblock == NULL)
+ return NULL; /* really out of memory? */
+ if (block) {
+ memcpy(newblock + 1, block + 1, commonsize); /* copy old contents */
+ freeblock(mc, block); /* erase (and check) old copy */
+ }
+ /* initialize new part of the block with something weird */
+ fillmem(cast_charp(newblock + 1) + commonsize, size - commonsize);
+ /* initialize marks after block */
+ for (i = 0; i < MARKSIZE; i++)
+ *(cast_charp(newblock + 1) + size + i) = MARK;
+ newblock->d.size = size;
+ newblock->d.type = type;
+ mc->total += size;
+ if (mc->total > mc->maxmem)
+ mc->maxmem = mc->total;
+ mc->numblocks++;
+ mc->objcount[type]++;
+ return newblock + 1;
+ }
+}
+
+
+/* }====================================================================== */
+
+
+
+/*
+** {=====================================================================
+** Functions to check memory consistency.
+** Most of these checks are done through asserts, so this code does
+** not make sense with asserts off. For this reason, it uses 'assert'
+** directly, instead of 'lua_assert'.
+** ======================================================================
+*/
+
+#include <assert.h>
+
+/*
+** Check GC invariants. For incremental mode, a black object cannot
+** point to a white one. For generational mode, really old objects
+** cannot point to young objects. Both old1 and touched2 objects
+** cannot point to new objects (but can point to survivals).
+** (Threads and open upvalues, despite being marked "really old",
+** continue to be visited in all collections, and therefore can point to
+** new objects. They, and only they, are old but gray.)
+*/
+static int testobjref1 (global_State *g, GCObject *f, GCObject *t) {
+ if (isdead(g,t)) return 0;
+ if (issweepphase(g))
+ return 1; /* no invariants */
+ else if (g->gckind == KGC_INC)
+ return !(isblack(f) && iswhite(t)); /* basic incremental invariant */
+ else { /* generational mode */
+ if ((getage(f) == G_OLD && isblack(f)) && !isold(t))
+ return 0;
+ if (((getage(f) == G_OLD1 || getage(f) == G_TOUCHED2) && isblack(f)) &&
+ getage(t) == G_NEW)
+ return 0;
+ return 1;
+ }
+}
+
+
+static void printobj (global_State *g, GCObject *o) {
+ printf("||%s(%p)-%c%c(%02X)||",
+ ttypename(novariant(o->tt)), (void *)o,
+ isdead(g,o) ? 'd' : isblack(o) ? 'b' : iswhite(o) ? 'w' : 'g',
+ "ns01oTt"[getage(o)], o->marked);
+ if (o->tt == LUA_VSHRSTR || o->tt == LUA_VLNGSTR)
+ printf(" '%s'", getstr(gco2ts(o)));
+}
+
+
+void lua_printobj (lua_State *L, struct GCObject *o) {
+ printobj(G(L), o);
+}
+
+static int testobjref (global_State *g, GCObject *f, GCObject *t) {
+ int r1 = testobjref1(g, f, t);
+ if (!r1) {
+ printf("%d(%02X) - ", g->gcstate, g->currentwhite);
+ printobj(g, f);
+ printf(" -> ");
+ printobj(g, t);
+ printf("\n");
+ }
+ return r1;
+}
+
+
+static void checkobjref (global_State *g, GCObject *f, GCObject *t) {
+ assert(testobjref(g, f, t));
+}
+
+
+/*
+** Version where 't' can be NULL. In that case, it should not apply the
+** macro 'obj2gco' over the object. ('t' may have several types, so this
+** definition must be a macro.) Most checks need this version, because
+** the check may run while an object is still being created.
+*/
+#define checkobjrefN(g,f,t) { if (t) checkobjref(g,f,obj2gco(t)); }
+
+
+static void checkvalref (global_State *g, GCObject *f, const TValue *t) {
+ assert(!iscollectable(t) || (righttt(t) && testobjref(g, f, gcvalue(t))));
+}
+
+
+static void checktable (global_State *g, Table *h) {
+ unsigned int i;
+ unsigned int asize = luaH_realasize(h);
+ Node *n, *limit = gnode(h, sizenode(h));
+ GCObject *hgc = obj2gco(h);
+ checkobjrefN(g, hgc, h->metatable);
+ for (i = 0; i < asize; i++)
+ checkvalref(g, hgc, &h->array[i]);
+ for (n = gnode(h, 0); n < limit; n++) {
+ if (!isempty(gval(n))) {
+ TValue k;
+ getnodekey(g->mainthread, &k, n);
+ assert(!keyisnil(n));
+ checkvalref(g, hgc, &k);
+ checkvalref(g, hgc, gval(n));
+ }
+ }
+}
+
+
+static void checkudata (global_State *g, Udata *u) {
+ int i;
+ GCObject *hgc = obj2gco(u);
+ checkobjrefN(g, hgc, u->metatable);
+ for (i = 0; i < u->nuvalue; i++)
+ checkvalref(g, hgc, &u->uv[i].uv);
+}
+
+
+static void checkproto (global_State *g, Proto *f) {
+ int i;
+ GCObject *fgc = obj2gco(f);
+ checkobjrefN(g, fgc, f->source);
+ for (i=0; i<f->sizek; i++) {
+ if (iscollectable(f->k + i))
+ checkobjref(g, fgc, gcvalue(f->k + i));
+ }
+ for (i=0; i<f->sizeupvalues; i++)
+ checkobjrefN(g, fgc, f->upvalues[i].name);
+ for (i=0; i<f->sizep; i++)
+ checkobjrefN(g, fgc, f->p[i]);
+ for (i=0; i<f->sizelocvars; i++)
+ checkobjrefN(g, fgc, f->locvars[i].varname);
+}
+
+
+static void checkCclosure (global_State *g, CClosure *cl) {
+ GCObject *clgc = obj2gco(cl);
+ int i;
+ for (i = 0; i < cl->nupvalues; i++)
+ checkvalref(g, clgc, &cl->upvalue[i]);
+}
+
+
+static void checkLclosure (global_State *g, LClosure *cl) {
+ GCObject *clgc = obj2gco(cl);
+ int i;
+ checkobjrefN(g, clgc, cl->p);
+ for (i=0; i<cl->nupvalues; i++) {
+ UpVal *uv = cl->upvals[i];
+ if (uv) {
+ checkobjrefN(g, clgc, uv);
+ if (!upisopen(uv))
+ checkvalref(g, obj2gco(uv), uv->v.p);
+ }
+ }
+}
+
+
+static int lua_checkpc (CallInfo *ci) {
+ if (!isLua(ci)) return 1;
+ else {
+ StkId f = ci->func.p;
+ Proto *p = clLvalue(s2v(f))->p;
+ return p->code <= ci->u.l.savedpc &&
+ ci->u.l.savedpc <= p->code + p->sizecode;
+ }
+}
+
+
+static void checkstack (global_State *g, lua_State *L1) {
+ StkId o;
+ CallInfo *ci;
+ UpVal *uv;
+ assert(!isdead(g, L1));
+ if (L1->stack.p == NULL) { /* incomplete thread? */
+ assert(L1->openupval == NULL && L1->ci == NULL);
+ return;
+ }
+ for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next)
+ assert(upisopen(uv)); /* must be open */
+ assert(L1->top.p <= L1->stack_last.p);
+ assert(L1->tbclist.p <= L1->top.p);
+ for (ci = L1->ci; ci != NULL; ci = ci->previous) {
+ assert(ci->top.p <= L1->stack_last.p);
+ assert(lua_checkpc(ci));
+ }
+ for (o = L1->stack.p; o < L1->stack_last.p; o++)
+ checkliveness(L1, s2v(o)); /* entire stack must have valid values */
+}
+
+
+static void checkrefs (global_State *g, GCObject *o) {
+ switch (o->tt) {
+ case LUA_VUSERDATA: {
+ checkudata(g, gco2u(o));
+ break;
+ }
+ case LUA_VUPVAL: {
+ checkvalref(g, o, gco2upv(o)->v.p);
+ break;
+ }
+ case LUA_VTABLE: {
+ checktable(g, gco2t(o));
+ break;
+ }
+ case LUA_VTHREAD: {
+ checkstack(g, gco2th(o));
+ break;
+ }
+ case LUA_VLCL: {
+ checkLclosure(g, gco2lcl(o));
+ break;
+ }
+ case LUA_VCCL: {
+ checkCclosure(g, gco2ccl(o));
+ break;
+ }
+ case LUA_VPROTO: {
+ checkproto(g, gco2p(o));
+ break;
+ }
+ case LUA_VSHRSTR:
+ case LUA_VLNGSTR: {
+ assert(!isgray(o)); /* strings are never gray */
+ break;
+ }
+ default: assert(0);
+ }
+}
+
+
+/*
+** Check consistency of an object:
+** - Dead objects can only happen in the 'allgc' list during a sweep
+** phase (controlled by the caller through 'maybedead').
+** - During pause, all objects must be white.
+** - In generational mode:
+** * objects must be old enough for their lists ('listage').
+** * old objects cannot be white.
+** * old objects must be black, except for 'touched1', 'old0',
+** threads, and open upvalues.
+*/
+static void checkobject (global_State *g, GCObject *o, int maybedead,
+ int listage) {
+ if (isdead(g, o))
+ assert(maybedead);
+ else {
+ assert(g->gcstate != GCSpause || iswhite(o));
+ if (g->gckind == KGC_GEN) { /* generational mode? */
+ assert(getage(o) >= listage);
+ assert(!iswhite(o) || !isold(o));
+ if (isold(o)) {
+ assert(isblack(o) ||
+ getage(o) == G_TOUCHED1 ||
+ getage(o) == G_OLD0 ||
+ o->tt == LUA_VTHREAD ||
+ (o->tt == LUA_VUPVAL && upisopen(gco2upv(o))));
+ }
+ }
+ checkrefs(g, o);
+ }
+}
+
+
+static lu_mem checkgraylist (global_State *g, GCObject *o) {
+ int total = 0; /* count number of elements in the list */
+ cast_void(g); /* better to keep it if we need to print an object */
+ while (o) {
+ assert(!!isgray(o) ^ (getage(o) == G_TOUCHED2));
+ assert(!testbit(o->marked, TESTBIT));
+ if (keepinvariant(g))
+ l_setbit(o->marked, TESTBIT); /* mark that object is in a gray list */
+ total++;
+ switch (o->tt) {
+ case LUA_VTABLE: o = gco2t(o)->gclist; break;
+ case LUA_VLCL: o = gco2lcl(o)->gclist; break;
+ case LUA_VCCL: o = gco2ccl(o)->gclist; break;
+ case LUA_VTHREAD: o = gco2th(o)->gclist; break;
+ case LUA_VPROTO: o = gco2p(o)->gclist; break;
+ case LUA_VUSERDATA:
+ assert(gco2u(o)->nuvalue > 0);
+ o = gco2u(o)->gclist;
+ break;
+ default: assert(0); /* other objects cannot be in a gray list */
+ }
+ }
+ return total;
+}
+
+
+/*
+** Check objects in gray lists.
+*/
+static lu_mem checkgrays (global_State *g) {
+ int total = 0; /* count number of elements in all lists */
+ if (!keepinvariant(g)) return total;
+ total += checkgraylist(g, g->gray);
+ total += checkgraylist(g, g->grayagain);
+ total += checkgraylist(g, g->weak);
+ total += checkgraylist(g, g->allweak);
+ total += checkgraylist(g, g->ephemeron);
+ return total;
+}
+
+
+/*
+** Check whether 'o' should be in a gray list. If so, increment
+** 'count' and check its TESTBIT. (It must have been previously set by
+** 'checkgraylist'.)
+*/
+static void incifingray (global_State *g, GCObject *o, lu_mem *count) {
+ if (!keepinvariant(g))
+ return; /* gray lists not being kept in these phases */
+ if (o->tt == LUA_VUPVAL) {
+ /* only open upvalues can be gray */
+ assert(!isgray(o) || upisopen(gco2upv(o)));
+ return; /* upvalues are never in gray lists */
+ }
+ /* these are the ones that must be in gray lists */
+ if (isgray(o) || getage(o) == G_TOUCHED2) {
+ (*count)++;
+ assert(testbit(o->marked, TESTBIT));
+ resetbit(o->marked, TESTBIT); /* prepare for next cycle */
+ }
+}
+
+
+static lu_mem checklist (global_State *g, int maybedead, int tof,
+ GCObject *newl, GCObject *survival, GCObject *old, GCObject *reallyold) {
+ GCObject *o;
+ lu_mem total = 0; /* number of object that should be in gray lists */
+ for (o = newl; o != survival; o = o->next) {
+ checkobject(g, o, maybedead, G_NEW);
+ incifingray(g, o, &total);
+ assert(!tof == !tofinalize(o));
+ }
+ for (o = survival; o != old; o = o->next) {
+ checkobject(g, o, 0, G_SURVIVAL);
+ incifingray(g, o, &total);
+ assert(!tof == !tofinalize(o));
+ }
+ for (o = old; o != reallyold; o = o->next) {
+ checkobject(g, o, 0, G_OLD1);
+ incifingray(g, o, &total);
+ assert(!tof == !tofinalize(o));
+ }
+ for (o = reallyold; o != NULL; o = o->next) {
+ checkobject(g, o, 0, G_OLD);
+ incifingray(g, o, &total);
+ assert(!tof == !tofinalize(o));
+ }
+ return total;
+}
+
+
+int lua_checkmemory (lua_State *L) {
+ global_State *g = G(L);
+ GCObject *o;
+ int maybedead;
+ lu_mem totalin; /* total of objects that are in gray lists */
+ lu_mem totalshould; /* total of objects that should be in gray lists */
+ if (keepinvariant(g)) {
+ assert(!iswhite(g->mainthread));
+ assert(!iswhite(gcvalue(&g->l_registry)));
+ }
+ assert(!isdead(g, gcvalue(&g->l_registry)));
+ assert(g->sweepgc == NULL || issweepphase(g));
+ totalin = checkgrays(g);
+
+ /* check 'fixedgc' list */
+ for (o = g->fixedgc; o != NULL; o = o->next) {
+ assert(o->tt == LUA_VSHRSTR && isgray(o) && getage(o) == G_OLD);
+ }
+
+ /* check 'allgc' list */
+ maybedead = (GCSatomic < g->gcstate && g->gcstate <= GCSswpallgc);
+ totalshould = checklist(g, maybedead, 0, g->allgc,
+ g->survival, g->old1, g->reallyold);
+
+ /* check 'finobj' list */
+ totalshould += checklist(g, 0, 1, g->finobj,
+ g->finobjsur, g->finobjold1, g->finobjrold);
+
+ /* check 'tobefnz' list */
+ for (o = g->tobefnz; o != NULL; o = o->next) {
+ checkobject(g, o, 0, G_NEW);
+ incifingray(g, o, &totalshould);
+ assert(tofinalize(o));
+ assert(o->tt == LUA_VUSERDATA || o->tt == LUA_VTABLE);
+ }
+ if (keepinvariant(g))
+ assert(totalin == totalshould);
+ return 0;
+}
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** Disassembler
+** =======================================================
+*/
+
+
+static char *buildop (Proto *p, int pc, char *buff) {
+ char *obuff = buff;
+ Instruction i = p->code[pc];
+ OpCode o = GET_OPCODE(i);
+ const char *name = opnames[o];
+ int line = luaG_getfuncline(p, pc);
+ int lineinfo = (p->lineinfo != NULL) ? p->lineinfo[pc] : 0;
+ if (lineinfo == ABSLINEINFO)
+ buff += sprintf(buff, "(__");
+ else
+ buff += sprintf(buff, "(%2d", lineinfo);
+ buff += sprintf(buff, " - %4d) %4d - ", line, pc);
+ switch (getOpMode(o)) {
+ case iABC:
+ sprintf(buff, "%-12s%4d %4d %4d%s", name,
+ GETARG_A(i), GETARG_B(i), GETARG_C(i),
+ GETARG_k(i) ? " (k)" : "");
+ break;
+ case iABx:
+ sprintf(buff, "%-12s%4d %4d", name, GETARG_A(i), GETARG_Bx(i));
+ break;
+ case iAsBx:
+ sprintf(buff, "%-12s%4d %4d", name, GETARG_A(i), GETARG_sBx(i));
+ break;
+ case iAx:
+ sprintf(buff, "%-12s%4d", name, GETARG_Ax(i));
+ break;
+ case isJ:
+ sprintf(buff, "%-12s%4d", name, GETARG_sJ(i));
+ break;
+ }
+ return obuff;
+}
+
+
+#if 0
+void luaI_printcode (Proto *pt, int size) {
+ int pc;
+ for (pc=0; pc<size; pc++) {
+ char buff[100];
+ printf("%s\n", buildop(pt, pc, buff));
+ }
+ printf("-------\n");
+}
+
+
+void luaI_printinst (Proto *pt, int pc) {
+ char buff[100];
+ printf("%s\n", buildop(pt, pc, buff));
+}
+#endif
+
+
+static int listcode (lua_State *L) {
+ int pc;
+ Proto *p;
+ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = getproto(obj_at(L, 1));
+ lua_newtable(L);
+ setnameval(L, "maxstack", p->maxstacksize);
+ setnameval(L, "numparams", p->numparams);
+ for (pc=0; pc<p->sizecode; pc++) {
+ char buff[100];
+ lua_pushinteger(L, pc+1);
+ lua_pushstring(L, buildop(p, pc, buff));
+ lua_settable(L, -3);
+ }
+ return 1;
+}
+
+
+static int printcode (lua_State *L) {
+ int pc;
+ Proto *p;
+ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = getproto(obj_at(L, 1));
+ printf("maxstack: %d\n", p->maxstacksize);
+ printf("numparams: %d\n", p->numparams);
+ for (pc=0; pc<p->sizecode; pc++) {
+ char buff[100];
+ printf("%s\n", buildop(p, pc, buff));
+ }
+ return 0;
+}
+
+
+static int listk (lua_State *L) {
+ Proto *p;
+ int i;
+ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = getproto(obj_at(L, 1));
+ lua_createtable(L, p->sizek, 0);
+ for (i=0; i<p->sizek; i++) {
+ pushobject(L, p->k+i);
+ lua_rawseti(L, -2, i+1);
+ }
+ return 1;
+}
+
+
+static int listabslineinfo (lua_State *L) {
+ Proto *p;
+ int i;
+ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = getproto(obj_at(L, 1));
+ luaL_argcheck(L, p->abslineinfo != NULL, 1, "function has no debug info");
+ lua_createtable(L, 2 * p->sizeabslineinfo, 0);
+ for (i=0; i < p->sizeabslineinfo; i++) {
+ lua_pushinteger(L, p->abslineinfo[i].pc);
+ lua_rawseti(L, -2, 2 * i + 1);
+ lua_pushinteger(L, p->abslineinfo[i].line);
+ lua_rawseti(L, -2, 2 * i + 2);
+ }
+ return 1;
+}
+
+
+static int listlocals (lua_State *L) {
+ Proto *p;
+ int pc = cast_int(luaL_checkinteger(L, 2)) - 1;
+ int i = 0;
+ const char *name;
+ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = getproto(obj_at(L, 1));
+ while ((name = luaF_getlocalname(p, ++i, pc)) != NULL)
+ lua_pushstring(L, name);
+ return i-1;
+}
+
+/* }====================================================== */
+
+
+
+static void printstack (lua_State *L) {
+ int i;
+ int n = lua_gettop(L);
+ printf("stack: >>\n");
+ for (i = 1; i <= n; i++) {
+ printf("%3d: %s\n", i, luaL_tolstring(L, i, NULL));
+ lua_pop(L, 1);
+ }
+ printf("<<\n");
+}
+
+
+static int get_limits (lua_State *L) {
+ lua_createtable(L, 0, 6);
+ setnameval(L, "IS32INT", LUAI_IS32INT);
+ setnameval(L, "MAXARG_Ax", MAXARG_Ax);
+ setnameval(L, "MAXARG_Bx", MAXARG_Bx);
+ setnameval(L, "OFFSET_sBx", OFFSET_sBx);
+ setnameval(L, "LFPF", LFIELDS_PER_FLUSH);
+ setnameval(L, "NUM_OPCODES", NUM_OPCODES);
+ return 1;
+}
+
+
+static int mem_query (lua_State *L) {
+ if (lua_isnone(L, 1)) {
+ lua_pushinteger(L, l_memcontrol.total);
+ lua_pushinteger(L, l_memcontrol.numblocks);
+ lua_pushinteger(L, l_memcontrol.maxmem);
+ return 3;
+ }
+ else if (lua_isnumber(L, 1)) {
+ unsigned long limit = cast(unsigned long, luaL_checkinteger(L, 1));
+ if (limit == 0) limit = ULONG_MAX;
+ l_memcontrol.memlimit = limit;
+ return 0;
+ }
+ else {
+ const char *t = luaL_checkstring(L, 1);
+ int i;
+ for (i = LUA_NUMTAGS - 1; i >= 0; i--) {
+ if (strcmp(t, ttypename(i)) == 0) {
+ lua_pushinteger(L, l_memcontrol.objcount[i]);
+ return 1;
+ }
+ }
+ return luaL_error(L, "unknown type '%s'", t);
+ }
+}
+
+
+static int alloc_count (lua_State *L) {
+ if (lua_isnone(L, 1))
+ l_memcontrol.countlimit = ~0L;
+ else
+ l_memcontrol.countlimit = luaL_checkinteger(L, 1);
+ return 0;
+}
+
+
+static int alloc_failnext (lua_State *L) {
+ UNUSED(L);
+ l_memcontrol.failnext = 1;
+ return 0;
+}
+
+
+static int settrick (lua_State *L) {
+ if (ttisnil(obj_at(L, 1)))
+ l_Trick = NULL;
+ else
+ l_Trick = gcvalue(obj_at(L, 1));
+ return 0;
+}
+
+
+static int gc_color (lua_State *L) {
+ TValue *o;
+ luaL_checkany(L, 1);
+ o = obj_at(L, 1);
+ if (!iscollectable(o))
+ lua_pushstring(L, "no collectable");
+ else {
+ GCObject *obj = gcvalue(o);
+ lua_pushstring(L, isdead(G(L), obj) ? "dead" :
+ iswhite(obj) ? "white" :
+ isblack(obj) ? "black" : "gray");
+ }
+ return 1;
+}
+
+
+static int gc_age (lua_State *L) {
+ TValue *o;
+ luaL_checkany(L, 1);
+ o = obj_at(L, 1);
+ if (!iscollectable(o))
+ lua_pushstring(L, "no collectable");
+ else {
+ static const char *gennames[] = {"new", "survival", "old0", "old1",
+ "old", "touched1", "touched2"};
+ GCObject *obj = gcvalue(o);
+ lua_pushstring(L, gennames[getage(obj)]);
+ }
+ return 1;
+}
+
+
+static int gc_printobj (lua_State *L) {
+ TValue *o;
+ luaL_checkany(L, 1);
+ o = obj_at(L, 1);
+ if (!iscollectable(o))
+ printf("no collectable\n");
+ else {
+ GCObject *obj = gcvalue(o);
+ printobj(G(L), obj);
+ printf("\n");
+ }
+ return 0;
+}
+
+
+static int gc_state (lua_State *L) {
+ static const char *statenames[] = {
+ "propagate", "atomic", "enteratomic", "sweepallgc", "sweepfinobj",
+ "sweeptobefnz", "sweepend", "callfin", "pause", ""};
+ static const int states[] = {
+ GCSpropagate, GCSenteratomic, GCSatomic, GCSswpallgc, GCSswpfinobj,
+ GCSswptobefnz, GCSswpend, GCScallfin, GCSpause, -1};
+ int option = states[luaL_checkoption(L, 1, "", statenames)];
+ if (option == -1) {
+ lua_pushstring(L, statenames[G(L)->gcstate]);
+ return 1;
+ }
+ else {
+ global_State *g = G(L);
+ if (G(L)->gckind == KGC_GEN)
+ luaL_error(L, "cannot change states in generational mode");
+ lua_lock(L);
+ if (option < g->gcstate) { /* must cross 'pause'? */
+ luaC_runtilstate(L, bitmask(GCSpause)); /* run until pause */
+ }
+ luaC_runtilstate(L, bitmask(option));
+ lua_assert(G(L)->gcstate == option);
+ lua_unlock(L);
+ return 0;
+ }
+}
+
+
+static int hash_query (lua_State *L) {
+ if (lua_isnone(L, 2)) {
+ luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected");
+ lua_pushinteger(L, tsvalue(obj_at(L, 1))->hash);
+ }
+ else {
+ TValue *o = obj_at(L, 1);
+ Table *t;
+ luaL_checktype(L, 2, LUA_TTABLE);
+ t = hvalue(obj_at(L, 2));
+ lua_pushinteger(L, luaH_mainposition(t, o) - t->node);
+ }
+ return 1;
+}
+
+
+static int stacklevel (lua_State *L) {
+ unsigned long a = 0;
+ lua_pushinteger(L, (L->top.p - L->stack.p));
+ lua_pushinteger(L, stacksize(L));
+ lua_pushinteger(L, L->nCcalls);
+ lua_pushinteger(L, L->nci);
+ lua_pushinteger(L, (unsigned long)&a);
+ return 5;
+}
+
+
+static int table_query (lua_State *L) {
+ const Table *t;
+ int i = cast_int(luaL_optinteger(L, 2, -1));
+ unsigned int asize;
+ luaL_checktype(L, 1, LUA_TTABLE);
+ t = hvalue(obj_at(L, 1));
+ asize = luaH_realasize(t);
+ if (i == -1) {
+ lua_pushinteger(L, asize);
+ lua_pushinteger(L, allocsizenode(t));
+ lua_pushinteger(L, isdummy(t) ? 0 : t->lastfree - t->node);
+ lua_pushinteger(L, t->alimit);
+ return 4;
+ }
+ else if ((unsigned int)i < asize) {
+ lua_pushinteger(L, i);
+ pushobject(L, &t->array[i]);
+ lua_pushnil(L);
+ }
+ else if ((i -= asize) < sizenode(t)) {
+ TValue k;
+ getnodekey(L, &k, gnode(t, i));
+ if (!isempty(gval(gnode(t, i))) ||
+ ttisnil(&k) ||
+ ttisnumber(&k)) {
+ pushobject(L, &k);
+ }
+ else
+ lua_pushliteral(L, "<undef>");
+ pushobject(L, gval(gnode(t, i)));
+ if (gnext(&t->node[i]) != 0)
+ lua_pushinteger(L, gnext(&t->node[i]));
+ else
+ lua_pushnil(L);
+ }
+ return 3;
+}
+
+
+static int string_query (lua_State *L) {
+ stringtable *tb = &G(L)->strt;
+ int s = cast_int(luaL_optinteger(L, 1, 0)) - 1;
+ if (s == -1) {
+ lua_pushinteger(L ,tb->size);
+ lua_pushinteger(L ,tb->nuse);
+ return 2;
+ }
+ else if (s < tb->size) {
+ TString *ts;
+ int n = 0;
+ for (ts = tb->hash[s]; ts != NULL; ts = ts->u.hnext) {
+ setsvalue2s(L, L->top.p, ts);
+ api_incr_top(L);
+ n++;
+ }
+ return n;
+ }
+ else return 0;
+}
+
+
+static int tref (lua_State *L) {
+ int level = lua_gettop(L);
+ luaL_checkany(L, 1);
+ lua_pushvalue(L, 1);
+ lua_pushinteger(L, luaL_ref(L, LUA_REGISTRYINDEX));
+ cast_void(level); /* to avoid warnings */
+ lua_assert(lua_gettop(L) == level+1); /* +1 for result */
+ return 1;
+}
+
+static int getref (lua_State *L) {
+ int level = lua_gettop(L);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_checkinteger(L, 1));
+ cast_void(level); /* to avoid warnings */
+ lua_assert(lua_gettop(L) == level+1);
+ return 1;
+}
+
+static int unref (lua_State *L) {
+ int level = lua_gettop(L);
+ luaL_unref(L, LUA_REGISTRYINDEX, cast_int(luaL_checkinteger(L, 1)));
+ cast_void(level); /* to avoid warnings */
+ lua_assert(lua_gettop(L) == level);
+ return 0;
+}
+
+
+static int upvalue (lua_State *L) {
+ int n = cast_int(luaL_checkinteger(L, 2));
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ if (lua_isnone(L, 3)) {
+ const char *name = lua_getupvalue(L, 1, n);
+ if (name == NULL) return 0;
+ lua_pushstring(L, name);
+ return 2;
+ }
+ else {
+ const char *name = lua_setupvalue(L, 1, n);
+ lua_pushstring(L, name);
+ return 1;
+ }
+}
+
+
+static int newuserdata (lua_State *L) {
+ size_t size = cast_sizet(luaL_optinteger(L, 1, 0));
+ int nuv = luaL_optinteger(L, 2, 0);
+ char *p = cast_charp(lua_newuserdatauv(L, size, nuv));
+ while (size--) *p++ = '\0';
+ return 1;
+}
+
+
+static int pushuserdata (lua_State *L) {
+ lua_Integer u = luaL_checkinteger(L, 1);
+ lua_pushlightuserdata(L, cast_voidp(cast_sizet(u)));
+ return 1;
+}
+
+
+static int udataval (lua_State *L) {
+ lua_pushinteger(L, cast(long, lua_touserdata(L, 1)));
+ return 1;
+}
+
+
+static int doonnewstack (lua_State *L) {
+ lua_State *L1 = lua_newthread(L);
+ size_t l;
+ const char *s = luaL_checklstring(L, 1, &l);
+ int status = luaL_loadbuffer(L1, s, l, s);
+ if (status == LUA_OK)
+ status = lua_pcall(L1, 0, 0, 0);
+ lua_pushinteger(L, status);
+ return 1;
+}
+
+
+static int s2d (lua_State *L) {
+ lua_pushnumber(L, cast_num(*cast(const double *, luaL_checkstring(L, 1))));
+ return 1;
+}
+
+
+static int d2s (lua_State *L) {
+ double d = cast(double, luaL_checknumber(L, 1));
+ lua_pushlstring(L, cast_charp(&d), sizeof(d));
+ return 1;
+}
+
+
+static int num2int (lua_State *L) {
+ lua_pushinteger(L, lua_tointeger(L, 1));
+ return 1;
+}
+
+
+static int newstate (lua_State *L) {
+ void *ud;
+ lua_Alloc f = lua_getallocf(L, &ud);
+ lua_State *L1 = lua_newstate(f, ud);
+ if (L1) {
+ lua_atpanic(L1, tpanic);
+ lua_pushlightuserdata(L, L1);
+ }
+ else
+ lua_pushnil(L);
+ return 1;
+}
+
+
+static lua_State *getstate (lua_State *L) {
+ lua_State *L1 = cast(lua_State *, lua_touserdata(L, 1));
+ luaL_argcheck(L, L1 != NULL, 1, "state expected");
+ return L1;
+}
+
+
+static int loadlib (lua_State *L) {
+ static const luaL_Reg libs[] = {
+ {LUA_GNAME, luaopen_base},
+ {"coroutine", luaopen_coroutine},
+ {"debug", luaopen_debug},
+ {"io", luaopen_io},
+ {"os", luaopen_os},
+ {"math", luaopen_math},
+ {"string", luaopen_string},
+ {"table", luaopen_table},
+ {"T", luaB_opentests},
+ {NULL, NULL}
+ };
+ lua_State *L1 = getstate(L);
+ int i;
+ luaL_requiref(L1, "package", luaopen_package, 0);
+ lua_assert(lua_type(L1, -1) == LUA_TTABLE);
+ /* 'requiref' should not reload module already loaded... */
+ luaL_requiref(L1, "package", NULL, 1); /* seg. fault if it reloads */
+ /* ...but should return the same module */
+ lua_assert(lua_compare(L1, -1, -2, LUA_OPEQ));
+ luaL_getsubtable(L1, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
+ for (i = 0; libs[i].name; i++) {
+ lua_pushcfunction(L1, libs[i].func);
+ lua_setfield(L1, -2, libs[i].name);
+ }
+ return 0;
+}
+
+static int closestate (lua_State *L) {
+ lua_State *L1 = getstate(L);
+ lua_close(L1);
+ return 0;
+}
+
+static int doremote (lua_State *L) {
+ lua_State *L1 = getstate(L);
+ size_t lcode;
+ const char *code = luaL_checklstring(L, 2, &lcode);
+ int status;
+ lua_settop(L1, 0);
+ status = luaL_loadbuffer(L1, code, lcode, code);
+ if (status == LUA_OK)
+ status = lua_pcall(L1, 0, LUA_MULTRET, 0);
+ if (status != LUA_OK) {
+ lua_pushnil(L);
+ lua_pushstring(L, lua_tostring(L1, -1));
+ lua_pushinteger(L, status);
+ return 3;
+ }
+ else {
+ int i = 0;
+ while (!lua_isnone(L1, ++i))
+ lua_pushstring(L, lua_tostring(L1, i));
+ lua_pop(L1, i-1);
+ return i-1;
+ }
+}
+
+
+static int log2_aux (lua_State *L) {
+ unsigned int x = (unsigned int)luaL_checkinteger(L, 1);
+ lua_pushinteger(L, luaO_ceillog2(x));
+ return 1;
+}
+
+
+struct Aux { jmp_buf jb; const char *paniccode; lua_State *L; };
+
+/*
+** does a long-jump back to "main program".
+*/
+static int panicback (lua_State *L) {
+ struct Aux *b;
+ lua_checkstack(L, 1); /* open space for 'Aux' struct */
+ lua_getfield(L, LUA_REGISTRYINDEX, "_jmpbuf"); /* get 'Aux' struct */
+ b = (struct Aux *)lua_touserdata(L, -1);
+ lua_pop(L, 1); /* remove 'Aux' struct */
+ runC(b->L, L, b->paniccode); /* run optional panic code */
+ longjmp(b->jb, 1);
+ return 1; /* to avoid warnings */
+}
+
+static int checkpanic (lua_State *L) {
+ struct Aux b;
+ void *ud;
+ lua_State *L1;
+ const char *code = luaL_checkstring(L, 1);
+ lua_Alloc f = lua_getallocf(L, &ud);
+ b.paniccode = luaL_optstring(L, 2, "");
+ b.L = L;
+ L1 = lua_newstate(f, ud); /* create new state */
+ if (L1 == NULL) { /* error? */
+ lua_pushnil(L);
+ return 1;
+ }
+ lua_atpanic(L1, panicback); /* set its panic function */
+ lua_pushlightuserdata(L1, &b);
+ lua_setfield(L1, LUA_REGISTRYINDEX, "_jmpbuf"); /* store 'Aux' struct */
+ if (setjmp(b.jb) == 0) { /* set jump buffer */
+ runC(L, L1, code); /* run code unprotected */
+ lua_pushliteral(L, "no errors");
+ }
+ else { /* error handling */
+ /* move error message to original state */
+ lua_pushstring(L, lua_tostring(L1, -1));
+ }
+ lua_close(L1);
+ return 1;
+}
+
+
+
+/*
+** {====================================================================
+** function to test the API with C. It interprets a kind of assembler
+** language with calls to the API, so the test can be driven by Lua code
+** =====================================================================
+*/
+
+
+static void sethookaux (lua_State *L, int mask, int count, const char *code);
+
+static const char *const delimits = " \t\n,;";
+
+static void skip (const char **pc) {
+ for (;;) {
+ if (**pc != '\0' && strchr(delimits, **pc)) (*pc)++;
+ else if (**pc == '#') { /* comment? */
+ while (**pc != '\n' && **pc != '\0') (*pc)++; /* until end-of-line */
+ }
+ else break;
+ }
+}
+
+static int getnum_aux (lua_State *L, lua_State *L1, const char **pc) {
+ int res = 0;
+ int sig = 1;
+ skip(pc);
+ if (**pc == '.') {
+ res = cast_int(lua_tointeger(L1, -1));
+ lua_pop(L1, 1);
+ (*pc)++;
+ return res;
+ }
+ else if (**pc == '*') {
+ res = lua_gettop(L1);
+ (*pc)++;
+ return res;
+ }
+ else if (**pc == '-') {
+ sig = -1;
+ (*pc)++;
+ }
+ if (!lisdigit(cast_uchar(**pc)))
+ luaL_error(L, "number expected (%s)", *pc);
+ while (lisdigit(cast_uchar(**pc))) res = res*10 + (*(*pc)++) - '0';
+ return sig*res;
+}
+
+static const char *getstring_aux (lua_State *L, char *buff, const char **pc) {
+ int i = 0;
+ skip(pc);
+ if (**pc == '"' || **pc == '\'') { /* quoted string? */
+ int quote = *(*pc)++;
+ while (**pc != quote) {
+ if (**pc == '\0') luaL_error(L, "unfinished string in C script");
+ buff[i++] = *(*pc)++;
+ }
+ (*pc)++;
+ }
+ else {
+ while (**pc != '\0' && !strchr(delimits, **pc))
+ buff[i++] = *(*pc)++;
+ }
+ buff[i] = '\0';
+ return buff;
+}
+
+
+static int getindex_aux (lua_State *L, lua_State *L1, const char **pc) {
+ skip(pc);
+ switch (*(*pc)++) {
+ case 'R': return LUA_REGISTRYINDEX;
+ case 'G': return luaL_error(L, "deprecated index 'G'");
+ case 'U': return lua_upvalueindex(getnum_aux(L, L1, pc));
+ default: (*pc)--; return getnum_aux(L, L1, pc);
+ }
+}
+
+
+static const char *const statcodes[] = {"OK", "YIELD", "ERRRUN",
+ "ERRSYNTAX", MEMERRMSG, "ERRGCMM", "ERRERR"};
+
+/*
+** Avoid these stat codes from being collected, to avoid possible
+** memory error when pushing them.
+*/
+static void regcodes (lua_State *L) {
+ unsigned int i;
+ for (i = 0; i < sizeof(statcodes) / sizeof(statcodes[0]); i++) {
+ lua_pushboolean(L, 1);
+ lua_setfield(L, LUA_REGISTRYINDEX, statcodes[i]);
+ }
+}
+
+
+#define EQ(s1) (strcmp(s1, inst) == 0)
+
+#define getnum (getnum_aux(L, L1, &pc))
+#define getstring (getstring_aux(L, buff, &pc))
+#define getindex (getindex_aux(L, L1, &pc))
+
+
+static int testC (lua_State *L);
+static int Cfunck (lua_State *L, int status, lua_KContext ctx);
+
+/*
+** arithmetic operation encoding for 'arith' instruction
+** LUA_OPIDIV -> \
+** LUA_OPSHL -> <
+** LUA_OPSHR -> >
+** LUA_OPUNM -> _
+** LUA_OPBNOT -> !
+*/
+static const char ops[] = "+-*%^/\\&|~<>_!";
+
+static int runC (lua_State *L, lua_State *L1, const char *pc) {
+ char buff[300];
+ int status = 0;
+ if (pc == NULL) return luaL_error(L, "attempt to runC null script");
+ for (;;) {
+ const char *inst = getstring;
+ if EQ("") return 0;
+ else if EQ("absindex") {
+ lua_pushnumber(L1, lua_absindex(L1, getindex));
+ }
+ else if EQ("append") {
+ int t = getindex;
+ int i = lua_rawlen(L1, t);
+ lua_rawseti(L1, t, i + 1);
+ }
+ else if EQ("arith") {
+ int op;
+ skip(&pc);
+ op = strchr(ops, *pc++) - ops;
+ lua_arith(L1, op);
+ }
+ else if EQ("call") {
+ int narg = getnum;
+ int nres = getnum;
+ lua_call(L1, narg, nres);
+ }
+ else if EQ("callk") {
+ int narg = getnum;
+ int nres = getnum;
+ int i = getindex;
+ lua_callk(L1, narg, nres, i, Cfunck);
+ }
+ else if EQ("checkstack") {
+ int sz = getnum;
+ const char *msg = getstring;
+ if (*msg == '\0')
+ msg = NULL; /* to test 'luaL_checkstack' with no message */
+ luaL_checkstack(L1, sz, msg);
+ }
+ else if EQ("rawcheckstack") {
+ int sz = getnum;
+ lua_pushboolean(L1, lua_checkstack(L1, sz));
+ }
+ else if EQ("compare") {
+ const char *opt = getstring; /* EQ, LT, or LE */
+ int op = (opt[0] == 'E') ? LUA_OPEQ
+ : (opt[1] == 'T') ? LUA_OPLT : LUA_OPLE;
+ int a = getindex;
+ int b = getindex;
+ lua_pushboolean(L1, lua_compare(L1, a, b, op));
+ }
+ else if EQ("concat") {
+ lua_concat(L1, getnum);
+ }
+ else if EQ("copy") {
+ int f = getindex;
+ lua_copy(L1, f, getindex);
+ }
+ else if EQ("func2num") {
+ lua_CFunction func = lua_tocfunction(L1, getindex);
+ lua_pushnumber(L1, cast_sizet(func));
+ }
+ else if EQ("getfield") {
+ int t = getindex;
+ lua_getfield(L1, t, getstring);
+ }
+ else if EQ("getglobal") {
+ lua_getglobal(L1, getstring);
+ }
+ else if EQ("getmetatable") {
+ if (lua_getmetatable(L1, getindex) == 0)
+ lua_pushnil(L1);
+ }
+ else if EQ("gettable") {
+ lua_gettable(L1, getindex);
+ }
+ else if EQ("gettop") {
+ lua_pushinteger(L1, lua_gettop(L1));
+ }
+ else if EQ("gsub") {
+ int a = getnum; int b = getnum; int c = getnum;
+ luaL_gsub(L1, lua_tostring(L1, a),
+ lua_tostring(L1, b),
+ lua_tostring(L1, c));
+ }
+ else if EQ("insert") {
+ lua_insert(L1, getnum);
+ }
+ else if EQ("iscfunction") {
+ lua_pushboolean(L1, lua_iscfunction(L1, getindex));
+ }
+ else if EQ("isfunction") {
+ lua_pushboolean(L1, lua_isfunction(L1, getindex));
+ }
+ else if EQ("isnil") {
+ lua_pushboolean(L1, lua_isnil(L1, getindex));
+ }
+ else if EQ("isnull") {
+ lua_pushboolean(L1, lua_isnone(L1, getindex));
+ }
+ else if EQ("isnumber") {
+ lua_pushboolean(L1, lua_isnumber(L1, getindex));
+ }
+ else if EQ("isstring") {
+ lua_pushboolean(L1, lua_isstring(L1, getindex));
+ }
+ else if EQ("istable") {
+ lua_pushboolean(L1, lua_istable(L1, getindex));
+ }
+ else if EQ("isudataval") {
+ lua_pushboolean(L1, lua_islightuserdata(L1, getindex));
+ }
+ else if EQ("isuserdata") {
+ lua_pushboolean(L1, lua_isuserdata(L1, getindex));
+ }
+ else if EQ("len") {
+ lua_len(L1, getindex);
+ }
+ else if EQ("Llen") {
+ lua_pushinteger(L1, luaL_len(L1, getindex));
+ }
+ else if EQ("loadfile") {
+ luaL_loadfile(L1, luaL_checkstring(L1, getnum));
+ }
+ else if EQ("loadstring") {
+ const char *s = luaL_checkstring(L1, getnum);
+ luaL_loadstring(L1, s);
+ }
+ else if EQ("newmetatable") {
+ lua_pushboolean(L1, luaL_newmetatable(L1, getstring));
+ }
+ else if EQ("newtable") {
+ lua_newtable(L1);
+ }
+ else if EQ("newthread") {
+ lua_newthread(L1);
+ }
+ else if EQ("resetthread") {
+ lua_pushinteger(L1, lua_resetthread(L1)); /* deprecated */
+ }
+ else if EQ("newuserdata") {
+ lua_newuserdata(L1, getnum);
+ }
+ else if EQ("next") {
+ lua_next(L1, -2);
+ }
+ else if EQ("objsize") {
+ lua_pushinteger(L1, lua_rawlen(L1, getindex));
+ }
+ else if EQ("pcall") {
+ int narg = getnum;
+ int nres = getnum;
+ status = lua_pcall(L1, narg, nres, getnum);
+ }
+ else if EQ("pcallk") {
+ int narg = getnum;
+ int nres = getnum;
+ int i = getindex;
+ status = lua_pcallk(L1, narg, nres, 0, i, Cfunck);
+ }
+ else if EQ("pop") {
+ lua_pop(L1, getnum);
+ }
+ else if EQ("printstack") {
+ int n = getnum;
+ if (n != 0) {
+ printf("%s\n", luaL_tolstring(L1, n, NULL));
+ lua_pop(L1, 1);
+ }
+ else printstack(L1);
+ }
+ else if EQ("print") {
+ const char *msg = getstring;
+ printf("%s\n", msg);
+ }
+ else if EQ("warningC") {
+ const char *msg = getstring;
+ lua_warning(L1, msg, 1);
+ }
+ else if EQ("warning") {
+ const char *msg = getstring;
+ lua_warning(L1, msg, 0);
+ }
+ else if EQ("pushbool") {
+ lua_pushboolean(L1, getnum);
+ }
+ else if EQ("pushcclosure") {
+ lua_pushcclosure(L1, testC, getnum);
+ }
+ else if EQ("pushint") {
+ lua_pushinteger(L1, getnum);
+ }
+ else if EQ("pushnil") {
+ lua_pushnil(L1);
+ }
+ else if EQ("pushnum") {
+ lua_pushnumber(L1, (lua_Number)getnum);
+ }
+ else if EQ("pushstatus") {
+ lua_pushstring(L1, statcodes[status]);
+ }
+ else if EQ("pushstring") {
+ lua_pushstring(L1, getstring);
+ }
+ else if EQ("pushupvalueindex") {
+ lua_pushinteger(L1, lua_upvalueindex(getnum));
+ }
+ else if EQ("pushvalue") {
+ lua_pushvalue(L1, getindex);
+ }
+ else if EQ("pushfstringI") {
+ lua_pushfstring(L1, lua_tostring(L, -2), (int)lua_tointeger(L, -1));
+ }
+ else if EQ("pushfstringS") {
+ lua_pushfstring(L1, lua_tostring(L, -2), lua_tostring(L, -1));
+ }
+ else if EQ("pushfstringP") {
+ lua_pushfstring(L1, lua_tostring(L, -2), lua_topointer(L, -1));
+ }
+ else if EQ("rawget") {
+ int t = getindex;
+ lua_rawget(L1, t);
+ }
+ else if EQ("rawgeti") {
+ int t = getindex;
+ lua_rawgeti(L1, t, getnum);
+ }
+ else if EQ("rawgetp") {
+ int t = getindex;
+ lua_rawgetp(L1, t, cast_voidp(cast_sizet(getnum)));
+ }
+ else if EQ("rawset") {
+ int t = getindex;
+ lua_rawset(L1, t);
+ }
+ else if EQ("rawseti") {
+ int t = getindex;
+ lua_rawseti(L1, t, getnum);
+ }
+ else if EQ("rawsetp") {
+ int t = getindex;
+ lua_rawsetp(L1, t, cast_voidp(cast_sizet(getnum)));
+ }
+ else if EQ("remove") {
+ lua_remove(L1, getnum);
+ }
+ else if EQ("replace") {
+ lua_replace(L1, getindex);
+ }
+ else if EQ("resume") {
+ int i = getindex;
+ int nres;
+ status = lua_resume(lua_tothread(L1, i), L, getnum, &nres);
+ }
+ else if EQ("return") {
+ int n = getnum;
+ if (L1 != L) {
+ int i;
+ for (i = 0; i < n; i++) {
+ int idx = -(n - i);
+ switch (lua_type(L1, idx)) {
+ case LUA_TBOOLEAN:
+ lua_pushboolean(L, lua_toboolean(L1, idx));
+ break;
+ default:
+ lua_pushstring(L, lua_tostring(L1, idx));
+ break;
+ }
+ }
+ }
+ return n;
+ }
+ else if EQ("rotate") {
+ int i = getindex;
+ lua_rotate(L1, i, getnum);
+ }
+ else if EQ("setfield") {
+ int t = getindex;
+ const char *s = getstring;
+ lua_setfield(L1, t, s);
+ }
+ else if EQ("seti") {
+ int t = getindex;
+ lua_seti(L1, t, getnum);
+ }
+ else if EQ("setglobal") {
+ const char *s = getstring;
+ lua_setglobal(L1, s);
+ }
+ else if EQ("sethook") {
+ int mask = getnum;
+ int count = getnum;
+ const char *s = getstring;
+ sethookaux(L1, mask, count, s);
+ }
+ else if EQ("setmetatable") {
+ int idx = getindex;
+ lua_setmetatable(L1, idx);
+ }
+ else if EQ("settable") {
+ lua_settable(L1, getindex);
+ }
+ else if EQ("settop") {
+ lua_settop(L1, getnum);
+ }
+ else if EQ("testudata") {
+ int i = getindex;
+ lua_pushboolean(L1, luaL_testudata(L1, i, getstring) != NULL);
+ }
+ else if EQ("error") {
+ lua_error(L1);
+ }
+ else if EQ("abort") {
+ abort();
+ }
+ else if EQ("throw") {
+#if defined(__cplusplus)
+static struct X { int x; } x;
+ throw x;
+#else
+ luaL_error(L1, "C++");
+#endif
+ break;
+ }
+ else if EQ("tobool") {
+ lua_pushboolean(L1, lua_toboolean(L1, getindex));
+ }
+ else if EQ("tocfunction") {
+ lua_pushcfunction(L1, lua_tocfunction(L1, getindex));
+ }
+ else if EQ("tointeger") {
+ lua_pushinteger(L1, lua_tointeger(L1, getindex));
+ }
+ else if EQ("tonumber") {
+ lua_pushnumber(L1, lua_tonumber(L1, getindex));
+ }
+ else if EQ("topointer") {
+ lua_pushlightuserdata(L1, cast_voidp(lua_topointer(L1, getindex)));
+ }
+ else if EQ("touserdata") {
+ lua_pushlightuserdata(L1, lua_touserdata(L1, getindex));
+ }
+ else if EQ("tostring") {
+ const char *s = lua_tostring(L1, getindex);
+ const char *s1 = lua_pushstring(L1, s);
+ cast_void(s1); /* to avoid warnings */
+ lua_longassert((s == NULL && s1 == NULL) || strcmp(s, s1) == 0);
+ }
+ else if EQ("Ltolstring") {
+ luaL_tolstring(L1, getindex, NULL);
+ }
+ else if EQ("type") {
+ lua_pushstring(L1, luaL_typename(L1, getnum));
+ }
+ else if EQ("xmove") {
+ int f = getindex;
+ int t = getindex;
+ lua_State *fs = (f == 0) ? L1 : lua_tothread(L1, f);
+ lua_State *ts = (t == 0) ? L1 : lua_tothread(L1, t);
+ int n = getnum;
+ if (n == 0) n = lua_gettop(fs);
+ lua_xmove(fs, ts, n);
+ }
+ else if EQ("isyieldable") {
+ lua_pushboolean(L1, lua_isyieldable(lua_tothread(L1, getindex)));
+ }
+ else if EQ("yield") {
+ return lua_yield(L1, getnum);
+ }
+ else if EQ("yieldk") {
+ int nres = getnum;
+ int i = getindex;
+ return lua_yieldk(L1, nres, i, Cfunck);
+ }
+ else if EQ("toclose") {
+ lua_toclose(L1, getnum);
+ }
+ else if EQ("closeslot") {
+ lua_closeslot(L1, getnum);
+ }
+ else luaL_error(L, "unknown instruction %s", buff);
+ }
+ return 0;
+}
+
+
+static int testC (lua_State *L) {
+ lua_State *L1;
+ const char *pc;
+ if (lua_isuserdata(L, 1)) {
+ L1 = getstate(L);
+ pc = luaL_checkstring(L, 2);
+ }
+ else if (lua_isthread(L, 1)) {
+ L1 = lua_tothread(L, 1);
+ pc = luaL_checkstring(L, 2);
+ }
+ else {
+ L1 = L;
+ pc = luaL_checkstring(L, 1);
+ }
+ return runC(L, L1, pc);
+}
+
+
+static int Cfunc (lua_State *L) {
+ return runC(L, L, lua_tostring(L, lua_upvalueindex(1)));
+}
+
+
+static int Cfunck (lua_State *L, int status, lua_KContext ctx) {
+ lua_pushstring(L, statcodes[status]);
+ lua_setglobal(L, "status");
+ lua_pushinteger(L, ctx);
+ lua_setglobal(L, "ctx");
+ return runC(L, L, lua_tostring(L, ctx));
+}
+
+
+static int makeCfunc (lua_State *L) {
+ luaL_checkstring(L, 1);
+ lua_pushcclosure(L, Cfunc, lua_gettop(L));
+ return 1;
+}
+
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** tests for C hooks
+** =======================================================
+*/
+
+/*
+** C hook that runs the C script stored in registry.C_HOOK[L]
+*/
+static void Chook (lua_State *L, lua_Debug *ar) {
+ const char *scpt;
+ const char *const events [] = {"call", "ret", "line", "count", "tailcall"};
+ lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK");
+ lua_pushlightuserdata(L, L);
+ lua_gettable(L, -2); /* get C_HOOK[L] (script saved by sethookaux) */
+ scpt = lua_tostring(L, -1); /* not very religious (string will be popped) */
+ lua_pop(L, 2); /* remove C_HOOK and script */
+ lua_pushstring(L, events[ar->event]); /* may be used by script */
+ lua_pushinteger(L, ar->currentline); /* may be used by script */
+ runC(L, L, scpt); /* run script from C_HOOK[L] */
+}
+
+
+/*
+** sets 'registry.C_HOOK[L] = scpt' and sets 'Chook' as a hook
+*/
+static void sethookaux (lua_State *L, int mask, int count, const char *scpt) {
+ if (*scpt == '\0') { /* no script? */
+ lua_sethook(L, NULL, 0, 0); /* turn off hooks */
+ return;
+ }
+ lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK"); /* get C_HOOK table */
+ if (!lua_istable(L, -1)) { /* no hook table? */
+ lua_pop(L, 1); /* remove previous value */
+ lua_newtable(L); /* create new C_HOOK table */
+ lua_pushvalue(L, -1);
+ lua_setfield(L, LUA_REGISTRYINDEX, "C_HOOK"); /* register it */
+ }
+ lua_pushlightuserdata(L, L);
+ lua_pushstring(L, scpt);
+ lua_settable(L, -3); /* C_HOOK[L] = script */
+ lua_sethook(L, Chook, mask, count);
+}
+
+
+static int sethook (lua_State *L) {
+ if (lua_isnoneornil(L, 1))
+ lua_sethook(L, NULL, 0, 0); /* turn off hooks */
+ else {
+ const char *scpt = luaL_checkstring(L, 1);
+ const char *smask = luaL_checkstring(L, 2);
+ int count = cast_int(luaL_optinteger(L, 3, 0));
+ int mask = 0;
+ if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
+ if (strchr(smask, 'r')) mask |= LUA_MASKRET;
+ if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
+ if (count > 0) mask |= LUA_MASKCOUNT;
+ sethookaux(L, mask, count, scpt);
+ }
+ return 0;
+}
+
+
+static int coresume (lua_State *L) {
+ int status, nres;
+ lua_State *co = lua_tothread(L, 1);
+ luaL_argcheck(L, co, 1, "coroutine expected");
+ status = lua_resume(co, L, 0, &nres);
+ if (status != LUA_OK && status != LUA_YIELD) {
+ lua_pushboolean(L, 0);
+ lua_insert(L, -2);
+ return 2; /* return false + error message */
+ }
+ else {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+}
+
+/* }====================================================== */
+
+
+
+static const struct luaL_Reg tests_funcs[] = {
+ {"checkmemory", lua_checkmemory},
+ {"closestate", closestate},
+ {"d2s", d2s},
+ {"doonnewstack", doonnewstack},
+ {"doremote", doremote},
+ {"gccolor", gc_color},
+ {"gcage", gc_age},
+ {"gcstate", gc_state},
+ {"pobj", gc_printobj},
+ {"getref", getref},
+ {"hash", hash_query},
+ {"log2", log2_aux},
+ {"limits", get_limits},
+ {"listcode", listcode},
+ {"printcode", printcode},
+ {"listk", listk},
+ {"listabslineinfo", listabslineinfo},
+ {"listlocals", listlocals},
+ {"loadlib", loadlib},
+ {"checkpanic", checkpanic},
+ {"newstate", newstate},
+ {"newuserdata", newuserdata},
+ {"num2int", num2int},
+ {"pushuserdata", pushuserdata},
+ {"querystr", string_query},
+ {"querytab", table_query},
+ {"ref", tref},
+ {"resume", coresume},
+ {"s2d", s2d},
+ {"sethook", sethook},
+ {"stacklevel", stacklevel},
+ {"testC", testC},
+ {"makeCfunc", makeCfunc},
+ {"totalmem", mem_query},
+ {"alloccount", alloc_count},
+ {"allocfailnext", alloc_failnext},
+ {"trick", settrick},
+ {"udataval", udataval},
+ {"unref", unref},
+ {"upvalue", upvalue},
+ {NULL, NULL}
+};
+
+
+static void checkfinalmem (void) {
+ lua_assert(l_memcontrol.numblocks == 0);
+ lua_assert(l_memcontrol.total == 0);
+}
+
+
+int luaB_opentests (lua_State *L) {
+ void *ud;
+ lua_Alloc f = lua_getallocf(L, &ud);
+ lua_atpanic(L, &tpanic);
+ lua_setwarnf(L, &warnf, L);
+ lua_pushboolean(L, 0);
+ lua_setglobal(L, "_WARN"); /* _WARN = false */
+ regcodes(L);
+ atexit(checkfinalmem);
+ lua_assert(f == debug_realloc && ud == cast_voidp(&l_memcontrol));
+ lua_setallocf(L, f, ud); /* exercise this function */
+ luaL_newlib(L, tests_funcs);
+ return 1;
+}
+
+#endif
+
diff --git a/src/ltests.h b/src/ltests.h
new file mode 100644
index 000000000000..ec520498bde4
--- /dev/null
+++ b/src/ltests.h
@@ -0,0 +1,151 @@
+/*
+** $Id: ltests.h $
+** Internal Header for Debugging of the Lua Implementation
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ltests_h
+#define ltests_h
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* test Lua with compatibility code */
+#define LUA_COMPAT_MATHLIB
+#define LUA_COMPAT_LT_LE
+
+
+#define LUA_DEBUG
+
+
+/* turn on assertions */
+#define LUAI_ASSERT
+
+
+/* to avoid warnings, and to make sure value is really unused */
+#define UNUSED(x) (x=0, (void)(x))
+
+
+/* test for sizes in 'l_sprintf' (make sure whole buffer is available) */
+#undef l_sprintf
+#if !defined(LUA_USE_C89)
+#define l_sprintf(s,sz,f,i) (memset(s,0xAB,sz), snprintf(s,sz,f,i))
+#else
+#define l_sprintf(s,sz,f,i) (memset(s,0xAB,sz), sprintf(s,f,i))
+#endif
+
+
+/* get a chance to test code without jump tables */
+#define LUA_USE_JUMPTABLE 0
+
+
+/* use 32-bit integers in random generator */
+#define LUA_RAND32
+
+
+/* memory-allocator control variables */
+typedef struct Memcontrol {
+ int failnext;
+ unsigned long numblocks;
+ unsigned long total;
+ unsigned long maxmem;
+ unsigned long memlimit;
+ unsigned long countlimit;
+ unsigned long objcount[LUA_NUMTYPES];
+} Memcontrol;
+
+LUA_API Memcontrol l_memcontrol;
+
+
+/*
+** generic variable for debug tricks
+*/
+extern void *l_Trick;
+
+
+
+/*
+** Function to traverse and check all memory used by Lua
+*/
+LUAI_FUNC int lua_checkmemory (lua_State *L);
+
+/*
+** Function to print an object GC-friendly
+*/
+struct GCObject;
+LUAI_FUNC void lua_printobj (lua_State *L, struct GCObject *o);
+
+
+/* test for lock/unlock */
+
+struct L_EXTRA { int lock; int *plock; };
+#undef LUA_EXTRASPACE
+#define LUA_EXTRASPACE sizeof(struct L_EXTRA)
+#define getlock(l) cast(struct L_EXTRA*, lua_getextraspace(l))
+#define luai_userstateopen(l) \
+ (getlock(l)->lock = 0, getlock(l)->plock = &(getlock(l)->lock))
+#define luai_userstateclose(l) \
+ lua_assert(getlock(l)->lock == 1 && getlock(l)->plock == &(getlock(l)->lock))
+#define luai_userstatethread(l,l1) \
+ lua_assert(getlock(l1)->plock == getlock(l)->plock)
+#define luai_userstatefree(l,l1) \
+ lua_assert(getlock(l)->plock == getlock(l1)->plock)
+#define lua_lock(l) lua_assert((*getlock(l)->plock)++ == 0)
+#define lua_unlock(l) lua_assert(--(*getlock(l)->plock) == 0)
+
+
+
+LUA_API int luaB_opentests (lua_State *L);
+
+LUA_API void *debug_realloc (void *ud, void *block,
+ size_t osize, size_t nsize);
+
+#if defined(lua_c)
+#define luaL_newstate() lua_newstate(debug_realloc, &l_memcontrol)
+#define luaL_openlibs(L) \
+ { (luaL_openlibs)(L); \
+ luaL_requiref(L, "T", luaB_opentests, 1); \
+ lua_pop(L, 1); }
+#endif
+
+
+
+/* change some sizes to give some bugs a chance */
+
+#undef LUAL_BUFFERSIZE
+#define LUAL_BUFFERSIZE 23
+#define MINSTRTABSIZE 2
+#define MAXIWTHABS 3
+
+#define STRCACHE_N 23
+#define STRCACHE_M 5
+
+#undef LUAI_USER_ALIGNMENT_T
+#define LUAI_USER_ALIGNMENT_T union { char b[sizeof(void*) * 8]; }
+
+
+/*
+** This one is not compatible with tests for opcode optimizations,
+** as it blocks some optimizations
+#define MAXINDEXRK 0
+*/
+
+
+/* make stack-overflow tests run faster */
+#undef LUAI_MAXSTACK
+#define LUAI_MAXSTACK 50000
+
+
+/* test mode uses more stack space */
+#undef LUAI_MAXCCALLS
+#define LUAI_MAXCCALLS 180
+
+
+/* force Lua to use its own implementations */
+#undef lua_strx2number
+#undef lua_number2strx
+
+
+#endif
+
diff --git a/src/ltm.c b/src/ltm.c
index b657b783a801..07a060811d5c 100644
--- a/src/ltm.c
+++ b/src/ltm.c
@@ -102,12 +102,12 @@ const char *luaT_objtypename (lua_State *L, const TValue *o) {
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, const TValue *p3) {
- StkId func = L->top;
+ StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
setobj2s(L, func + 3, p3); /* 3rd argument */
- L->top = func + 4;
+ L->top.p = func + 4;
/* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci))
luaD_call(L, func, 0);
@@ -119,18 +119,18 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, StkId res) {
ptrdiff_t result = savestack(L, res);
- StkId func = L->top;
+ StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
- L->top += 3;
+ L->top.p += 3;
/* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci))
luaD_call(L, func, 1);
else
luaD_callnoyield(L, func, 1);
res = restorestack(L, result);
- setobjs2s(L, res, --L->top); /* move result to its place */
+ setobjs2s(L, res, --L->top.p); /* move result to its place */
}
@@ -165,7 +165,7 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
void luaT_tryconcatTM (lua_State *L) {
- StkId top = L->top;
+ StkId top = L->top.p;
if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
TM_CONCAT)))
luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
@@ -200,15 +200,15 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
*/
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
TMS event) {
- if (callbinTM(L, p1, p2, L->top, event)) /* try original event */
- return !l_isfalse(s2v(L->top));
+ if (callbinTM(L, p1, p2, L->top.p, event)) /* try original event */
+ return !l_isfalse(s2v(L->top.p));
#if defined(LUA_COMPAT_LT_LE)
else if (event == TM_LE) {
/* try '!(p2 < p1)' for '(p1 <= p2)' */
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
- if (callbinTM(L, p2, p1, L->top, TM_LT)) {
+ if (callbinTM(L, p2, p1, L->top.p, TM_LT)) {
L->ci->callstatus ^= CIST_LEQ; /* clear mark */
- return l_isfalse(s2v(L->top));
+ return l_isfalse(s2v(L->top.p));
}
/* else error will remove this 'ci'; no need to clear mark */
}
@@ -238,20 +238,20 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
const Proto *p) {
int i;
- int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */
+ int actual = cast_int(L->top.p - ci->func.p) - 1; /* number of arguments */
int nextra = actual - nfixparams; /* number of extra arguments */
ci->u.l.nextraargs = nextra;
luaD_checkstack(L, p->maxstacksize + 1);
/* copy function to the top of the stack */
- setobjs2s(L, L->top++, ci->func);
+ setobjs2s(L, L->top.p++, ci->func.p);
/* move fixed parameters to the top of the stack */
for (i = 1; i <= nfixparams; i++) {
- setobjs2s(L, L->top++, ci->func + i);
- setnilvalue(s2v(ci->func + i)); /* erase original parameter (for GC) */
+ setobjs2s(L, L->top.p++, ci->func.p + i);
+ setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
}
- ci->func += actual + 1;
- ci->top += actual + 1;
- lua_assert(L->top <= ci->top && ci->top <= L->stack_last);
+ ci->func.p += actual + 1;
+ ci->top.p += actual + 1;
+ lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
}
@@ -261,10 +261,10 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
if (wanted < 0) {
wanted = nextra; /* get all extra arguments available */
checkstackGCp(L, nextra, where); /* ensure stack space */
- L->top = where + nextra; /* next instruction will need top */
+ L->top.p = where + nextra; /* next instruction will need top */
}
for (i = 0; i < wanted && i < nextra; i++)
- setobjs2s(L, where + i, ci->func - nextra + i);
+ setobjs2s(L, where + i, ci->func.p - nextra + i);
for (; i < wanted; i++) /* complete required results with nil */
setnilvalue(s2v(where + i));
}
diff --git a/src/ltm.h b/src/ltm.h
index 73b833c605da..c309e2ae10e3 100644
--- a/src/ltm.h
+++ b/src/ltm.h
@@ -9,6 +9,7 @@
#include "lobject.h"
+#include "lstate.h"
/*
@@ -95,8 +96,8 @@ LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
int inv, int isfloat, TMS event);
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
- struct CallInfo *ci, const Proto *p);
-LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
+ CallInfo *ci, const Proto *p);
+LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci,
StkId where, int wanted);
diff --git a/src/lua.c b/src/lua.c
index 0f1900444499..0ff884545304 100644
--- a/src/lua.c
+++ b/src/lua.c
@@ -177,10 +177,11 @@ static void print_version (void) {
** to the script (everything after 'script') go to positive indices;
** other arguments (before the script name) go to negative indices.
** If there is no script name, assume interpreter's name as base.
+** (If there is no interpreter's name either, 'script' is -1, so
+** table sizes are zero.)
*/
static void createargtable (lua_State *L, char **argv, int argc, int script) {
int i, narg;
- if (script == argc) script = 0; /* no script name? */
narg = argc - (script + 1); /* number of positive indices */
lua_createtable(L, narg, script + 1);
for (i = 0; i < argc; i++) {
@@ -268,14 +269,23 @@ static int handle_script (lua_State *L, char **argv) {
/*
** Traverses all arguments from 'argv', returning a mask with those
-** needed before running any Lua code (or an error code if it finds
-** any invalid argument). 'first' returns the first not-handled argument
-** (either the script name or a bad argument in case of error).
+** needed before running any Lua code or an error code if it finds any
+** invalid argument. In case of error, 'first' is the index of the bad
+** argument. Otherwise, 'first' is -1 if there is no program name,
+** 0 if there is no script name, or the index of the script name.
*/
static int collectargs (char **argv, int *first) {
int args = 0;
int i;
- for (i = 1; argv[i] != NULL; i++) {
+ if (argv[0] != NULL) { /* is there a program name? */
+ if (argv[0][0]) /* not empty? */
+ progname = argv[0]; /* save it */
+ }
+ else { /* no program name */
+ *first = -1;
+ return 0;
+ }
+ for (i = 1; argv[i] != NULL; i++) { /* handle arguments */
*first = i;
if (argv[i][0] != '-') /* not an option? */
return args; /* stop handling options */
@@ -316,7 +326,7 @@ static int collectargs (char **argv, int *first) {
return has_error;
}
}
- *first = i; /* no script name */
+ *first = 0; /* no script name */
return args;
}
@@ -609,8 +619,8 @@ static int pmain (lua_State *L) {
char **argv = (char **)lua_touserdata(L, 2);
int script;
int args = collectargs(argv, &script);
+ int optlim = (script > 0) ? script : argc; /* first argv not an option */
luaL_checkversion(L); /* check that interpreter has correct version */
- if (argv[0] && argv[0][0]) progname = argv[0];
if (args == has_error) { /* bad arg? */
print_usage(argv[script]); /* 'script' has index of bad arg. */
return 0;
@@ -623,19 +633,21 @@ static int pmain (lua_State *L) {
}
luaL_openlibs(L); /* open standard libraries */
createargtable(L, argv, argc, script); /* create table 'arg' */
- lua_gc(L, LUA_GCGEN, 0, 0); /* GC in generational mode */
+ lua_gc(L, LUA_GCRESTART); /* start GC... */
+ lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */
if (!(args & has_E)) { /* no option '-E'? */
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
return 0; /* error running LUA_INIT */
}
- if (!runargs(L, argv, script)) /* execute arguments -e and -l */
+ if (!runargs(L, argv, optlim)) /* execute arguments -e and -l */
return 0; /* something failed */
- if (script < argc && /* execute main script (if there is one) */
- handle_script(L, argv + script) != LUA_OK)
- return 0;
+ if (script > 0) { /* execute main script (if there is one) */
+ if (handle_script(L, argv + script) != LUA_OK)
+ return 0; /* interrupt in case of error */
+ }
if (args & has_i) /* -i option? */
doREPL(L); /* do read-eval-print loop */
- else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */
+ else if (script < 1 && !(args & (has_e | has_v))) { /* no active option? */
if (lua_stdin_is_tty()) { /* running in interactive mode? */
print_version();
doREPL(L); /* do read-eval-print loop */
@@ -654,6 +666,7 @@ int main (int argc, char **argv) {
l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE;
}
+ lua_gc(L, LUA_GCSTOP); /* stop GC while building state */
lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */
lua_pushinteger(L, argc); /* 1st argument */
lua_pushlightuserdata(L, argv); /* 2nd argument */
diff --git a/src/lua.h b/src/lua.h
index e6618392cc7e..fd16cf8050b8 100644
--- a/src/lua.h
+++ b/src/lua.h
@@ -18,14 +18,14 @@
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "4"
-#define LUA_VERSION_RELEASE "4"
+#define LUA_VERSION_RELEASE "6"
#define LUA_VERSION_NUM 504
-#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 4)
+#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 6)
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
-#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2022 Lua.org, PUC-Rio"
+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -131,6 +131,16 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
+/*
+** Type used by the debug API to collect debug information
+*/
+typedef struct lua_Debug lua_Debug;
+
+
+/*
+** Functions to be called by the debugger in specific events
+*/
+typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
/*
@@ -153,7 +163,8 @@ extern const char lua_ident[];
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L);
-LUA_API int (lua_resetthread) (lua_State *L);
+LUA_API int (lua_closethread) (lua_State *L, lua_State *from);
+LUA_API int (lua_resetthread) (lua_State *L); /* Deprecated! */
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
@@ -442,12 +453,6 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
-typedef struct lua_Debug lua_Debug; /* activation record */
-
-
-/* Functions to be called by the debugger in specific events */
-typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
-
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
@@ -492,7 +497,7 @@ struct lua_Debug {
/******************************************************************************
-* Copyright (C) 1994-2022 Lua.org, PUC-Rio.
+* Copyright (C) 1994-2023 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
diff --git a/src/luac.c b/src/luac.c
index f6db9cf656bb..5f4a141bddd9 100644
--- a/src/luac.c
+++ b/src/luac.c
@@ -121,7 +121,7 @@ static int doargs(int argc, char* argv[])
return i;
}
-#define FUNCTION "(function()end)();"
+#define FUNCTION "(function()end)();\n"
static const char* reader(lua_State* L, void* ud, size_t* size)
{
@@ -138,7 +138,7 @@ static const char* reader(lua_State* L, void* ud, size_t* size)
}
}
-#define toproto(L,i) getproto(s2v(L->top+(i)))
+#define toproto(L,i) getproto(s2v(L->top.p+(i)))
static const Proto* combine(lua_State* L, int n)
{
@@ -155,8 +155,6 @@ static const Proto* combine(lua_State* L, int n)
f->p[i]=toproto(L,i-n-1);
if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
}
- luaM_freearray(L,f->lineinfo,f->sizelineinfo);
- f->sizelineinfo=0;
return f;
}
}
diff --git a/src/luaconf.h b/src/luaconf.h
index d42d14b7d5f1..137103edec4e 100644
--- a/src/luaconf.h
+++ b/src/luaconf.h
@@ -70,6 +70,12 @@
#endif
+#if defined(LUA_USE_IOS)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN
+#endif
+
+
/*
@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits.
*/
@@ -728,7 +734,7 @@
** CHANGE it if you need a different limit. This limit is arbitrary;
** its only purpose is to stop Lua from consuming unlimited stack
** space (and to reserve some numbers for pseudo-indices).
-** (It must fit into max(size_t)/32.)
+** (It must fit into max(size_t)/32 and max(int)/2.)
*/
#if LUAI_IS32INT
#define LUAI_MAXSTACK 1000000
@@ -747,14 +753,15 @@
/*
@@ LUA_IDSIZE gives the maximum size for the description of the source
-@@ of a function in debug information.
+** of a function in debug information.
** CHANGE it if you want a different size.
*/
#define LUA_IDSIZE 60
/*
-@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
+@@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib
+** buffer system.
*/
#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))
diff --git a/src/lundump.c b/src/lundump.c
index 5aa55c445789..02aed64fb622 100644
--- a/src/lundump.c
+++ b/src/lundump.c
@@ -120,10 +120,10 @@ static TString *loadStringN (LoadState *S, Proto *p) {
}
else { /* long string */
ts = luaS_createlngstrobj(L, size); /* create string */
- setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */
+ setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */
luaD_inctop(L);
loadVector(S, getstr(ts), size); /* load directly in final place */
- L->top--; /* pop string */
+ L->top.p--; /* pop string */
}
luaC_objbarrier(L, p, ts);
return ts;
@@ -248,6 +248,8 @@ static void loadDebug (LoadState *S, Proto *f) {
f->locvars[i].endpc = loadInt(S);
}
n = loadInt(S);
+ if (n != 0) /* does it have debug information? */
+ n = f->sizeupvalues; /* must be this many */
for (i = 0; i < n; i++)
f->upvalues[i].name = loadStringN(S, f);
}
@@ -321,7 +323,7 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
S.Z = Z;
checkHeader(&S);
cl = luaF_newLclosure(L, loadByte(&S));
- setclLvalue2s(L, L->top, cl);
+ setclLvalue2s(L, L->top.p, cl);
luaD_inctop(L);
cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
diff --git a/src/lutf8lib.c b/src/lutf8lib.c
index e7bf098f6d04..3a5b9bc38a5b 100644
--- a/src/lutf8lib.c
+++ b/src/lutf8lib.c
@@ -25,6 +25,9 @@
#define MAXUTF 0x7FFFFFFFu
+
+#define MSGInvalid "invalid UTF-8 code"
+
/*
** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
*/
@@ -35,7 +38,8 @@ typedef unsigned long utfint;
#endif
-#define iscont(p) ((*(p) & 0xC0) == 0x80)
+#define iscont(c) (((c) & 0xC0) == 0x80)
+#define iscontp(p) iscont(*(p))
/* from strlib */
@@ -65,7 +69,7 @@ static const char *utf8_decode (const char *s, utfint *val, int strict) {
int count = 0; /* to count number of continuation bytes */
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
unsigned int cc = (unsigned char)s[++count]; /* read next byte */
- if ((cc & 0xC0) != 0x80) /* not a continuation byte? */
+ if (!iscont(cc)) /* not a continuation byte? */
return NULL; /* invalid byte sequence */
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
}
@@ -140,7 +144,7 @@ static int codepoint (lua_State *L) {
utfint code;
s = utf8_decode(s, &code, !lax);
if (s == NULL)
- return luaL_error(L, "invalid UTF-8 code");
+ return luaL_error(L, MSGInvalid);
lua_pushinteger(L, code);
n++;
}
@@ -190,16 +194,16 @@ static int byteoffset (lua_State *L) {
"position out of bounds");
if (n == 0) {
/* find beginning of current byte sequence */
- while (posi > 0 && iscont(s + posi)) posi--;
+ while (posi > 0 && iscontp(s + posi)) posi--;
}
else {
- if (iscont(s + posi))
+ if (iscontp(s + posi))
return luaL_error(L, "initial position is a continuation byte");
if (n < 0) {
while (n < 0 && posi > 0) { /* move back */
do { /* find beginning of previous character */
posi--;
- } while (posi > 0 && iscont(s + posi));
+ } while (posi > 0 && iscontp(s + posi));
n++;
}
}
@@ -208,7 +212,7 @@ static int byteoffset (lua_State *L) {
while (n > 0 && posi < (lua_Integer)len) {
do { /* find beginning of next character */
posi++;
- } while (iscont(s + posi)); /* (cannot pass final '\0') */
+ } while (iscontp(s + posi)); /* (cannot pass final '\0') */
n--;
}
}
@@ -226,15 +230,15 @@ static int iter_aux (lua_State *L, int strict) {
const char *s = luaL_checklstring(L, 1, &len);
lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
if (n < len) {
- while (iscont(s + n)) n++; /* skip continuation bytes */
+ while (iscontp(s + n)) n++; /* go to next character */
}
if (n >= len) /* (also handles original 'n' being negative) */
return 0; /* no more codepoints */
else {
utfint code;
const char *next = utf8_decode(s + n, &code, strict);
- if (next == NULL)
- return luaL_error(L, "invalid UTF-8 code");
+ if (next == NULL || iscontp(next))
+ return luaL_error(L, MSGInvalid);
lua_pushinteger(L, n + 1);
lua_pushinteger(L, code);
return 2;
@@ -253,7 +257,8 @@ static int iter_auxlax (lua_State *L) {
static int iter_codes (lua_State *L) {
int lax = lua_toboolean(L, 2);
- luaL_checkstring(L, 1);
+ const char *s = luaL_checkstring(L, 1);
+ luaL_argcheck(L, !iscontp(s), 1, MSGInvalid);
lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
lua_pushvalue(L, 1);
lua_pushinteger(L, 0);
diff --git a/src/lvm.c b/src/lvm.c
index 2ec344003194..8493a770c56f 100644
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -608,8 +608,8 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
if (tm == NULL) /* no TM? */
return 0; /* objects are different */
else {
- luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */
- return !l_isfalse(s2v(L->top));
+ luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */
+ return !l_isfalse(s2v(L->top.p));
}
}
@@ -633,17 +633,17 @@ static void copy2buff (StkId top, int n, char *buff) {
/*
** Main operation for concatenation: concat 'total' values in the stack,
-** from 'L->top - total' up to 'L->top - 1'.
+** from 'L->top.p - total' up to 'L->top.p - 1'.
*/
void luaV_concat (lua_State *L, int total) {
if (total == 1)
return; /* "all" values already concatenated */
do {
- StkId top = L->top;
+ StkId top = L->top.p;
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_tryconcatTM(L);
+ luaT_tryconcatTM(L); /* may invalidate 'top' */
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? */
@@ -656,8 +656,10 @@ void luaV_concat (lua_State *L, int total) {
/* collect total length and number of strings */
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
size_t l = vslen(s2v(top - n - 1));
- if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl))
+ if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) {
+ L->top.p = top - total; /* pop strings to avoid wasting stack */
luaG_runerror(L, "string length overflow");
+ }
tl += l;
}
if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
@@ -671,8 +673,8 @@ void luaV_concat (lua_State *L, int total) {
}
setsvalue2s(L, top - n, ts); /* create result */
}
- total -= n-1; /* got 'n' strings to create 1 new */
- L->top -= n-1; /* popped 'n' strings and pushed one */
+ total -= n - 1; /* got 'n' strings to create one new */
+ L->top.p -= n - 1; /* popped 'n' strings and pushed one */
} while (total > 1); /* repeat until only 1 result left */
}
@@ -763,12 +765,10 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) {
/* number of bits in an integer */
#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT)
+
/*
** Shift left operation. (Shift right just negates 'y'.)
*/
-#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
-
-
lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
if (y < 0) { /* shift right? */
if (y <= -NBITS) return 0;
@@ -808,26 +808,26 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
*/
void luaV_finishOp (lua_State *L) {
CallInfo *ci = L->ci;
- StkId base = ci->func + 1;
+ StkId base = ci->func.p + 1;
Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */
OpCode op = GET_OPCODE(inst);
switch (op) { /* finish its execution */
case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
- setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top);
+ setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top.p);
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: {
- setobjs2s(L, base + GETARG_A(inst), --L->top);
+ setobjs2s(L, base + GETARG_A(inst), --L->top.p);
break;
}
case OP_LT: case OP_LE:
case OP_LTI: case OP_LEI:
case OP_GTI: case OP_GEI:
case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */
- int res = !l_isfalse(s2v(L->top - 1));
- L->top--;
+ int res = !l_isfalse(s2v(L->top.p - 1));
+ L->top.p--;
#if defined(LUA_COMPAT_LT_LE)
if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
ci->callstatus ^= CIST_LEQ; /* clear mark */
@@ -840,11 +840,11 @@ void luaV_finishOp (lua_State *L) {
break;
}
case OP_CONCAT: {
- StkId top = L->top - 1; /* top when 'luaT_tryconcatTM' was called */
+ StkId top = L->top.p - 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 */
- L->top = top - 1; /* top is one after last element (at top-2) */
+ L->top.p = top - 1; /* top is one after last element (at top-2) */
luaV_concat(L, total); /* concat them (may yield again) */
break;
}
@@ -856,7 +856,7 @@ void luaV_finishOp (lua_State *L) {
StkId ra = base + GETARG_A(inst);
/* adjust top to signal correct number of returns, in case the
return is "up to top" ('isIT') */
- L->top = ra + ci->u2.nres;
+ L->top.p = ra + ci->u2.nres;
/* repeat instruction to close other vars. and complete the return */
ci->u.l.savedpc--;
break;
@@ -898,6 +898,7 @@ void luaV_finishOp (lua_State *L) {
** operation, 'fop' is the float operation.
*/
#define op_arithI(L,iop,fop) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
int imm = GETARG_sC(i); \
if (ttisinteger(v1)) { \
@@ -926,6 +927,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over floats and others with register operands.
*/
#define op_arithf(L,fop) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
op_arithf_aux(L, v1, v2, fop); }
@@ -935,6 +937,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations with K operands for floats.
*/
#define op_arithfK(L,fop) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
op_arithf_aux(L, v1, v2, fop); }
@@ -944,6 +947,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over integers and floats.
*/
#define op_arith_aux(L,v1,v2,iop,fop) { \
+ StkId ra = RA(i); \
if (ttisinteger(v1) && ttisinteger(v2)) { \
lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \
pc++; setivalue(s2v(ra), iop(L, i1, i2)); \
@@ -973,6 +977,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with constant operand.
*/
#define op_bitwiseK(L,op) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); \
lua_Integer i1; \
@@ -986,6 +991,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with register operands.
*/
#define op_bitwise(L,op) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
lua_Integer i1; lua_Integer i2; \
@@ -1000,18 +1006,19 @@ void luaV_finishOp (lua_State *L) {
** integers.
*/
#define op_order(L,opi,opn,other) { \
- int cond; \
- TValue *rb = vRB(i); \
- 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 = opn(s2v(ra), rb); \
- else \
- Protect(cond = other(L, s2v(ra), rb)); \
- docondjump(); }
+ StkId ra = RA(i); \
+ int cond; \
+ TValue *rb = vRB(i); \
+ 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 = opn(s2v(ra), rb); \
+ else \
+ Protect(cond = other(L, s2v(ra), rb)); \
+ docondjump(); }
/*
@@ -1019,20 +1026,21 @@ void luaV_finishOp (lua_State *L) {
** always small enough to have an exact representation as a float.)
*/
#define op_orderI(L,opi,opf,inv,tm) { \
- int cond; \
- int im = GETARG_sB(i); \
- if (ttisinteger(s2v(ra))) \
- cond = opi(ivalue(s2v(ra)), 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)); \
- } \
- docondjump(); }
+ StkId ra = RA(i); \
+ int cond; \
+ int im = GETARG_sB(i); \
+ if (ttisinteger(s2v(ra))) \
+ cond = opi(ivalue(s2v(ra)), 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)); \
+ } \
+ docondjump(); }
/* }================================================================== */
@@ -1061,7 +1069,7 @@ void luaV_finishOp (lua_State *L) {
#define updatetrap(ci) (trap = ci->u.l.trap)
-#define updatebase(ci) (base = ci->func + 1)
+#define updatebase(ci) (base = ci->func.p + 1)
#define updatestack(ci) \
@@ -1096,7 +1104,7 @@ void luaV_finishOp (lua_State *L) {
** Whenever code can raise errors, the global 'pc' and the global
** 'top' must be correct to report occasional errors.
*/
-#define savestate(L,ci) (savepc(L), L->top = ci->top)
+#define savestate(L,ci) (savepc(L), L->top.p = ci->top.p)
/*
@@ -1116,7 +1124,7 @@ void luaV_finishOp (lua_State *L) {
/* 'c' is the limit of live values in the stack */
#define checkGC(L,c) \
- { luaC_condGC(L, (savepc(L), L->top = (c)), \
+ { luaC_condGC(L, (savepc(L), L->top.p = (c)), \
updatetrap(ci)); \
luai_threadyield(L); }
@@ -1128,7 +1136,6 @@ void luaV_finishOp (lua_State *L) {
updatebase(ci); /* correct stack */ \
} \
i = *(pc++); \
- ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
}
#define vmdispatch(o) switch(o)
@@ -1148,7 +1155,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
startfunc:
trap = L->hookmask;
returning: /* trap already set */
- cl = clLvalue(s2v(ci->func));
+ cl = clLvalue(s2v(ci->func.p));
k = cl->p->k;
pc = ci->u.l.savedpc;
if (l_unlikely(trap)) {
@@ -1160,60 +1167,68 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
}
ci->u.l.trap = 1; /* assume trap is on, for now */
}
- base = ci->func + 1;
+ base = ci->func.p + 1;
/* main loop of interpreter */
for (;;) {
Instruction i; /* instruction being executed */
- StkId ra; /* instruction's A register */
vmfetch();
#if 0
/* low-level line tracing for debugging Lua */
printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
#endif
- lua_assert(base == ci->func + 1);
- lua_assert(base <= L->top && L->top < L->stack_last);
+ lua_assert(base == ci->func.p + 1);
+ lua_assert(base <= L->top.p && L->top.p <= L->stack_last.p);
/* invalidate top for instructions not expecting it */
- lua_assert(isIT(i) || (cast_void(L->top = base), 1));
+ lua_assert(isIT(i) || (cast_void(L->top.p = base), 1));
vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) {
+ StkId ra = RA(i);
setobjs2s(L, ra, RB(i));
vmbreak;
}
vmcase(OP_LOADI) {
+ StkId ra = RA(i);
lua_Integer b = GETARG_sBx(i);
setivalue(s2v(ra), b);
vmbreak;
}
vmcase(OP_LOADF) {
+ StkId ra = RA(i);
int b = GETARG_sBx(i);
setfltvalue(s2v(ra), cast_num(b));
vmbreak;
}
vmcase(OP_LOADK) {
+ StkId ra = RA(i);
TValue *rb = k + GETARG_Bx(i);
setobj2s(L, ra, rb);
vmbreak;
}
vmcase(OP_LOADKX) {
+ StkId ra = RA(i);
TValue *rb;
rb = k + GETARG_Ax(*pc); pc++;
setobj2s(L, ra, rb);
vmbreak;
}
vmcase(OP_LOADFALSE) {
+ StkId ra = RA(i);
setbfvalue(s2v(ra));
vmbreak;
}
vmcase(OP_LFALSESKIP) {
+ StkId ra = RA(i);
setbfvalue(s2v(ra));
pc++; /* skip next instruction */
vmbreak;
}
vmcase(OP_LOADTRUE) {
+ StkId ra = RA(i);
setbtvalue(s2v(ra));
vmbreak;
}
vmcase(OP_LOADNIL) {
+ StkId ra = RA(i);
int b = GETARG_B(i);
do {
setnilvalue(s2v(ra++));
@@ -1221,19 +1236,22 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_GETUPVAL) {
+ StkId ra = RA(i);
int b = GETARG_B(i);
- setobj2s(L, ra, cl->upvals[b]->v);
+ setobj2s(L, ra, cl->upvals[b]->v.p);
vmbreak;
}
vmcase(OP_SETUPVAL) {
+ StkId ra = RA(i);
UpVal *uv = cl->upvals[GETARG_B(i)];
- setobj(L, uv->v, s2v(ra));
+ setobj(L, uv->v.p, s2v(ra));
luaC_barrier(L, uv, s2v(ra));
vmbreak;
}
vmcase(OP_GETTABUP) {
+ StkId ra = RA(i);
const TValue *slot;
- TValue *upval = cl->upvals[GETARG_B(i)]->v;
+ TValue *upval = cl->upvals[GETARG_B(i)]->v.p;
TValue *rc = KC(i);
TString *key = tsvalue(rc); /* key must be a string */
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
@@ -1244,6 +1262,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_GETTABLE) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = vRC(i);
@@ -1258,6 +1277,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_GETI) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
int c = GETARG_C(i);
@@ -1272,6 +1292,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_GETFIELD) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = KC(i);
@@ -1285,7 +1306,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
}
vmcase(OP_SETTABUP) {
const TValue *slot;
- TValue *upval = cl->upvals[GETARG_A(i)]->v;
+ TValue *upval = cl->upvals[GETARG_A(i)]->v.p;
TValue *rb = KB(i);
TValue *rc = RKC(i);
TString *key = tsvalue(rb); /* key must be a string */
@@ -1297,6 +1318,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SETTABLE) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i); /* key (table is in 'ra') */
TValue *rc = RKC(i); /* value */
@@ -1311,6 +1333,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SETI) {
+ StkId ra = RA(i);
const TValue *slot;
int c = GETARG_B(i);
TValue *rc = RKC(i);
@@ -1325,6 +1348,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SETFIELD) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = KB(i);
TValue *rc = RKC(i);
@@ -1337,6 +1361,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_NEWTABLE) {
+ StkId ra = RA(i);
int b = GETARG_B(i); /* log2(hash size) + 1 */
int c = GETARG_C(i); /* array size */
Table *t;
@@ -1346,7 +1371,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
if (TESTARG_k(i)) /* non-zero extra argument? */
c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */
pc++; /* skip extra argument */
- L->top = ra + 1; /* correct top in case of emergency GC */
+ L->top.p = ra + 1; /* correct top in case of emergency GC */
t = luaH_new(L); /* memory allocation */
sethvalue2s(L, ra, t);
if (b != 0 || c != 0)
@@ -1355,6 +1380,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SELF) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = RKC(i);
@@ -1384,6 +1410,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MODK) {
+ savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_mod, luaV_modf);
vmbreak;
}
@@ -1396,6 +1423,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_IDIVK) {
+ savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_idiv, luai_numidiv);
vmbreak;
}
@@ -1412,6 +1440,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SHRI) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
int ic = GETARG_sC(i);
lua_Integer ib;
@@ -1421,6 +1450,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SHLI) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
int ic = GETARG_sC(i);
lua_Integer ib;
@@ -1442,6 +1472,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MOD) {
+ savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_mod, luaV_modf);
vmbreak;
}
@@ -1454,6 +1485,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_IDIV) { /* floor division */
+ savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_idiv, luai_numidiv);
vmbreak;
}
@@ -1478,6 +1510,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MMBIN) {
+ StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
TValue *rb = vRB(i);
TMS tm = (TMS)GETARG_C(i);
@@ -1487,6 +1520,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MMBINI) {
+ StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
int imm = GETARG_sB(i);
TMS tm = (TMS)GETARG_C(i);
@@ -1496,6 +1530,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MMBINK) {
+ StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
TValue *imm = KB(i);
TMS tm = (TMS)GETARG_C(i);
@@ -1505,6 +1540,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_UNM) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
lua_Number nb;
if (ttisinteger(rb)) {
@@ -1519,6 +1555,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_BNOT) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
lua_Integer ib;
if (tointegerns(rb, &ib)) {
@@ -1529,6 +1566,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_NOT) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb))
setbtvalue(s2v(ra));
@@ -1537,21 +1575,25 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_LEN) {
+ StkId ra = RA(i);
Protect(luaV_objlen(L, ra, vRB(i)));
vmbreak;
}
vmcase(OP_CONCAT) {
+ StkId ra = RA(i);
int n = GETARG_B(i); /* number of elements to concatenate */
- L->top = ra + n; /* mark the end of concat operands */
+ L->top.p = ra + n; /* mark the end of concat operands */
ProtectNT(luaV_concat(L, n));
- checkGC(L, L->top); /* 'luaV_concat' ensures correct top */
+ checkGC(L, L->top.p); /* 'luaV_concat' ensures correct top */
vmbreak;
}
vmcase(OP_CLOSE) {
+ StkId ra = RA(i);
Protect(luaF_close(L, ra, LUA_OK, 1));
vmbreak;
}
vmcase(OP_TBC) {
+ StkId ra = RA(i);
/* create new to-be-closed upvalue */
halfProtect(luaF_newtbcupval(L, ra));
vmbreak;
@@ -1561,6 +1603,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_EQ) {
+ StkId ra = RA(i);
int cond;
TValue *rb = vRB(i);
Protect(cond = luaV_equalobj(L, s2v(ra), rb));
@@ -1576,6 +1619,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_EQK) {
+ StkId ra = RA(i);
TValue *rb = KB(i);
/* basic types do not use '__eq'; we can use raw equality */
int cond = luaV_rawequalobj(s2v(ra), rb);
@@ -1583,6 +1627,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_EQI) {
+ StkId ra = RA(i);
int cond;
int im = GETARG_sB(i);
if (ttisinteger(s2v(ra)))
@@ -1611,11 +1656,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_TEST) {
+ StkId ra = RA(i);
int cond = !l_isfalse(s2v(ra));
docondjump();
vmbreak;
}
vmcase(OP_TESTSET) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb) == GETARG_k(i))
pc++;
@@ -1626,11 +1673,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_CALL) {
+ StkId ra = RA(i);
CallInfo *newci;
int b = GETARG_B(i);
int nresults = GETARG_C(i) - 1;
if (b != 0) /* fixed number of arguments? */
- L->top = ra + b; /* top signals number of arguments */
+ L->top.p = ra + b; /* top signals number of arguments */
/* else previous instruction set top */
savepc(L); /* in case of errors */
if ((newci = luaD_precall(L, ra, nresults)) == NULL)
@@ -1642,54 +1690,57 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_TAILCALL) {
+ StkId ra = RA(i);
int b = GETARG_B(i); /* number of arguments + 1 (function) */
int n; /* number of results when calling a C function */
int nparams1 = GETARG_C(i);
/* delta is virtual 'func' - real 'func' (vararg functions) */
int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
if (b != 0)
- L->top = ra + b;
+ L->top.p = ra + b;
else /* previous instruction set top */
- b = cast_int(L->top - ra);
+ b = cast_int(L->top.p - ra);
savepc(ci); /* several calls here can raise errors */
if (TESTARG_k(i)) {
luaF_closeupval(L, base); /* close upvalues from current call */
- lua_assert(L->tbclist < base); /* no pending tbc variables */
- lua_assert(base == ci->func + 1);
+ lua_assert(L->tbclist.p < base); /* no pending tbc variables */
+ lua_assert(base == ci->func.p + 1);
}
if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */
goto startfunc; /* execute the callee */
else { /* C function? */
- ci->func -= delta; /* restore 'func' (if vararg) */
+ ci->func.p -= delta; /* restore 'func' (if vararg) */
luaD_poscall(L, ci, n); /* finish caller */
updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret; /* caller returns after the tail call */
}
}
vmcase(OP_RETURN) {
+ StkId ra = RA(i);
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 */
+ n = cast_int(L->top.p - ra); /* get what is available */
savepc(ci);
if (TESTARG_k(i)) { /* may there be open upvalues? */
ci->u2.nres = n; /* save number of returns */
- if (L->top < ci->top)
- L->top = ci->top;
+ if (L->top.p < ci->top.p)
+ L->top.p = ci->top.p;
luaF_close(L, base, CLOSEKTOP, 1);
updatetrap(ci);
updatestack(ci);
}
if (nparams1) /* vararg function? */
- ci->func -= ci->u.l.nextraargs + nparams1;
- L->top = ra + n; /* set call for 'luaD_poscall' */
+ ci->func.p -= ci->u.l.nextraargs + nparams1;
+ L->top.p = ra + n; /* set call for 'luaD_poscall' */
luaD_poscall(L, ci, n);
updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret;
}
vmcase(OP_RETURN0) {
if (l_unlikely(L->hookmask)) {
- L->top = ra;
+ StkId ra = RA(i);
+ L->top.p = ra;
savepc(ci);
luaD_poscall(L, ci, 0); /* no hurry... */
trap = 1;
@@ -1697,15 +1748,16 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
else { /* do the 'poscall' here */
int nres;
L->ci = ci->previous; /* back to caller */
- L->top = base - 1;
+ L->top.p = base - 1;
for (nres = ci->nresults; l_unlikely(nres > 0); nres--)
- setnilvalue(s2v(L->top++)); /* all results are nil */
+ setnilvalue(s2v(L->top.p++)); /* all results are nil */
}
goto ret;
}
vmcase(OP_RETURN1) {
if (l_unlikely(L->hookmask)) {
- L->top = ra + 1;
+ StkId ra = RA(i);
+ L->top.p = ra + 1;
savepc(ci);
luaD_poscall(L, ci, 1); /* no hurry... */
trap = 1;
@@ -1714,12 +1766,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
int nres = ci->nresults;
L->ci = ci->previous; /* back to caller */
if (nres == 0)
- L->top = base - 1; /* asked for no results */
+ L->top.p = base - 1; /* asked for no results */
else {
+ StkId ra = RA(i);
setobjs2s(L, base - 1, ra); /* at least this result */
- L->top = base;
+ L->top.p = base;
for (; l_unlikely(nres > 1); nres--)
- setnilvalue(s2v(L->top++)); /* complete missing results */
+ setnilvalue(s2v(L->top.p++)); /* complete missing results */
}
}
ret: /* return from a Lua function */
@@ -1731,6 +1784,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
}
}
vmcase(OP_FORLOOP) {
+ StkId ra = RA(i);
if (ttisinteger(s2v(ra + 2))) { /* integer loop? */
lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1)));
if (count > 0) { /* still more iterations? */
@@ -1749,12 +1803,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_FORPREP) {
+ StkId ra = RA(i);
savestate(L, ci); /* in case of errors */
if (forprep(L, ra))
pc += GETARG_Bx(i) + 1; /* skip the loop */
vmbreak;
}
vmcase(OP_TFORPREP) {
+ StkId ra = RA(i);
/* create to-be-closed upvalue (if needed) */
halfProtect(luaF_newtbcupval(L, ra + 3));
pc += GETARG_Bx(i);
@@ -1763,7 +1819,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
goto l_tforcall;
}
vmcase(OP_TFORCALL) {
- l_tforcall:
+ l_tforcall: {
+ StkId ra = RA(i);
/* 'ra' has the iterator function, 'ra + 1' has the state,
'ra + 2' has the control variable, and 'ra + 3' has the
to-be-closed variable. The call will use the stack after
@@ -1771,29 +1828,31 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
*/
/* push function, state, and control variable */
memcpy(ra + 4, ra, 3 * sizeof(*ra));
- L->top = ra + 4 + 3;
+ L->top.p = ra + 4 + 3;
ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */
updatestack(ci); /* stack may have changed */
i = *(pc++); /* go to next instruction */
lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));
goto l_tforloop;
- }
+ }}
vmcase(OP_TFORLOOP) {
- l_tforloop:
+ l_tforloop: {
+ StkId ra = RA(i);
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) {
+ StkId ra = RA(i);
int n = GETARG_B(i);
unsigned int last = GETARG_C(i);
Table *h = hvalue(s2v(ra));
if (n == 0)
- n = cast_int(L->top - ra) - 1; /* get up to the top */
+ n = cast_int(L->top.p - ra) - 1; /* get up to the top */
else
- L->top = ci->top; /* correct top in case of emergency GC */
+ L->top.p = ci->top.p; /* correct top in case of emergency GC */
last += n;
if (TESTARG_k(i)) {
last += GETARG_Ax(*pc) * (MAXARG_C + 1);
@@ -1810,12 +1869,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_CLOSURE) {
+ StkId ra = RA(i);
Proto *p = cl->p->p[GETARG_Bx(i)];
halfProtect(pushclosure(L, p, cl->upvals, base, ra));
checkGC(L, ra + 1);
vmbreak;
}
vmcase(OP_VARARG) {
+ StkId ra = RA(i);
int n = GETARG_C(i) - 1; /* required results */
Protect(luaT_getvarargs(L, ci, ra, n));
vmbreak;
diff --git a/src/lvm.h b/src/lvm.h
index 1bc16f3a50ba..dba1ad277025 100644
--- a/src/lvm.h
+++ b/src/lvm.h
@@ -110,6 +110,11 @@ typedef enum {
luaC_barrierback(L, gcvalue(t), v); }
+/*
+** Shift right is the same as shift left with a negative 'y'
+*/
+#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
+
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);