3rdparty/lua: Updated to Lua 5.4.7.

This commit is contained in:
Vas Crabb 2025-03-12 17:02:57 +11:00
parent f2e72d6318
commit d69383bfb6
54 changed files with 1632 additions and 1146 deletions

View File

@ -36,7 +36,7 @@ RM= rm -f
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE ======= # == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
# Convenience platforms targets. # Convenience platforms targets.
PLATS= 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. # What to install.
TO_BIN= lua luac TO_BIN= lua luac
@ -46,7 +46,7 @@ TO_MAN= lua.1 luac.1
# Lua version and release. # Lua version and release.
V= 5.4 V= 5.4
R= $V.4 R= $V.7
# Targets start here. # Targets start here.
all: $(PLAT) all: $(PLAT)

2
3rdparty/lua/README vendored
View File

@ -1,5 +1,5 @@
This is Lua 5.4.4, released on 13 Jan 2022. This is Lua 5.4.7, released on 13 Jun 2024.
For installation instructions, license details, and For installation instructions, license details, and
further information about Lua, see doc/readme.html. further information about Lua, see doc/readme.html.

BIN
3rdparty/lua/doc/OSIApproved_100X125.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -10,7 +10,7 @@
<BODY> <BODY>
<H1> <H1>
<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> <A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
Lua 5.4 Reference Manual Lua 5.4 Reference Manual
</H1> </H1>
@ -18,7 +18,7 @@ Lua 5.4 Reference Manual
The reference manual is the official definition of the Lua language. The reference manual is the official definition of the Lua language.
<BR> <BR>
For a complete introduction to Lua programming, see the book For a complete introduction to Lua programming, see the book
<A HREF="http://www.lua.org/pil/">Programming in Lua</A>. <A HREF="https://www.lua.org/pil/">Programming in Lua</A>.
<DIV CLASS="menubar"> <DIV CLASS="menubar">
<A HREF="manual.html">start</A> <A HREF="manual.html">start</A>
@ -27,14 +27,14 @@ For a complete introduction to Lua programming, see the book
&middot; &middot;
<A HREF="#index">index</A> <A HREF="#index">index</A>
&middot; &middot;
<A HREF="http://www.lua.org/manual/">other versions</A> <A HREF="https://www.lua.org/manual/">other versions</A>
</DIV> </DIV>
<P> <P>
<SMALL> <SMALL>
Copyright &copy; 2020&ndash;2022 Lua.org, PUC-Rio. Copyright &copy; 2020&ndash;2024 Lua.org, PUC-Rio.
Freely available under the terms of the Freely available under the terms of the
<A HREF="http://www.lua.org/license.html">Lua license</A>. <A HREF="https://www.lua.org/license.html">Lua license</A>.
</SMALL> </SMALL>
<H2><A NAME="contents">Contents</A></H2> <H2><A NAME="contents">Contents</A></H2>
@ -85,6 +85,8 @@ Freely available under the terms of the
<LI><A HREF="manual.html#3.4.9">3.4.9 &ndash; Table Constructors</A> <LI><A HREF="manual.html#3.4.9">3.4.9 &ndash; Table Constructors</A>
<LI><A HREF="manual.html#3.4.10">3.4.10 &ndash; Function Calls</A> <LI><A HREF="manual.html#3.4.10">3.4.10 &ndash; Function Calls</A>
<LI><A HREF="manual.html#3.4.11">3.4.11 &ndash; Function Definitions</A> <LI><A HREF="manual.html#3.4.11">3.4.11 &ndash; Function Definitions</A>
<LI><A HREF="manual.html#3.4.12">3.4.12 &ndash; Lists of expressions, multiple results, and adjustment<A>
</UL> </UL>
<LI><A HREF="manual.html#3.5">3.5 &ndash; Visibility Rules</A> <LI><A HREF="manual.html#3.5">3.5 &ndash; Visibility Rules</A>
</UL> </UL>
@ -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_HOOKLINE">LUA_HOOKLINE</A><BR>
<A HREF="manual.html#pdf-LUA_HOOKRET">LUA_HOOKRET</A><BR> <A HREF="manual.html#pdf-LUA_HOOKRET">LUA_HOOKRET</A><BR>
<A HREF="manual.html#pdf-LUA_HOOKTAILCALL">LUA_HOOKTAILCALL</A><BR> <A HREF="manual.html#pdf-LUA_HOOKTAILCALL">LUA_HOOKTAILCALL</A><BR>
<A HREF="manual.html#pdf-LUAL_BUFFERSIZE">LUAL_BUFFERSIZE</A><BR> <A HREF="manual.html#pdf-LUA_LOADED_TABLE">LUA_LOADED_TABLE</A><BR>
<A HREF="manual.html#pdf-LUA_MASKCALL">LUA_MASKCALL</A><BR> <A HREF="manual.html#pdf-LUA_MASKCALL">LUA_MASKCALL</A><BR>
<A HREF="manual.html#pdf-LUA_MASKCOUNT">LUA_MASKCOUNT</A><BR> <A HREF="manual.html#pdf-LUA_MASKCOUNT">LUA_MASKCOUNT</A><BR>
<A HREF="manual.html#pdf-LUA_MASKLINE">LUA_MASKLINE</A><BR> <A HREF="manual.html#pdf-LUA_MASKLINE">LUA_MASKLINE</A><BR>
@ -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_OPSHR">LUA_OPSHR</A><BR>
<A HREF="manual.html#pdf-LUA_OPSUB">LUA_OPSUB</A><BR> <A HREF="manual.html#pdf-LUA_OPSUB">LUA_OPSUB</A><BR>
<A HREF="manual.html#pdf-LUA_OPUNM">LUA_OPUNM</A><BR> <A HREF="manual.html#pdf-LUA_OPUNM">LUA_OPUNM</A><BR>
<A HREF="manual.html#pdf-LUA_PRELOAD_TABLE">LUA_PRELOAD_TABLE</A><BR>
<A HREF="manual.html#pdf-LUA_REFNIL">LUA_REFNIL</A><BR> <A HREF="manual.html#pdf-LUA_REFNIL">LUA_REFNIL</A><BR>
<A HREF="manual.html#pdf-LUA_REGISTRYINDEX">LUA_REGISTRYINDEX</A><BR> <A HREF="manual.html#pdf-LUA_REGISTRYINDEX">LUA_REGISTRYINDEX</A><BR>
<A HREF="manual.html#pdf-LUA_RIDX_GLOBALS">LUA_RIDX_GLOBALS</A><BR> <A HREF="manual.html#pdf-LUA_RIDX_GLOBALS">LUA_RIDX_GLOBALS</A><BR>
@ -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_TUSERDATA">LUA_TUSERDATA</A><BR>
<A HREF="manual.html#pdf-LUA_USE_APICHECK">LUA_USE_APICHECK</A><BR> <A HREF="manual.html#pdf-LUA_USE_APICHECK">LUA_USE_APICHECK</A><BR>
<A HREF="manual.html#pdf-LUA_YIELD">LUA_YIELD</A><BR> <A HREF="manual.html#pdf-LUA_YIELD">LUA_YIELD</A><BR>
<A HREF="manual.html#pdf-LUAL_BUFFERSIZE">LUAL_BUFFERSIZE</A><BR>
</TD> </TD>
</TR> </TR>
@ -664,10 +668,10 @@ Freely available under the terms of the
<P CLASS="footer"> <P CLASS="footer">
Last update: Last update:
Thu Jan 13 11:32:22 UTC 2022 Thu May 9 14:47:09 UTC 2024
</P> </P>
<!-- <!--
Last change: revised for Lua 5.4.4 Last change: revised for Lua 5.4.7
--> -->
</BODY> </BODY>

View File

@ -1,5 +1,5 @@
.\" $Id: lua.man,v 1.14 2020/05/21 19:31:21 lhf Exp $ .\" $Id: lua.man,v 1.14 2024/05/08 18:48:27 lhf Exp $
.TH LUA 1 "$Date: 2020/05/21 19:31:21 $" .TH LUA 1 "$Date: 2024/05/08 18:48:27 $"
.SH NAME .SH NAME
lua \- Lua interpreter lua \- Lua interpreter
.SH SYNOPSIS .SH SYNOPSIS
@ -86,11 +86,17 @@ execute statement
enter interactive mode after executing enter interactive mode after executing
.IR script . .IR script .
.TP .TP
.BI \-l " name" .BI \-l " mod"
require library require library
.I name .I mod
into global into global
.IR name . .IR mod .
.TP
.BI \-l " g=mod"
require library
.I mod
into global
.IR g .
.TP .TP
.B \-v .B \-v
show version information. show version information.
@ -117,7 +123,7 @@ and the version-neutral variants are ignored.
Code to be executed before command line options and scripts. Code to be executed before command line options and scripts.
.TP .TP
.B LUA_PATH, LUA_PATH_5_4 .B LUA_PATH, LUA_PATH_5_4
Initial value of package.cpath, Initial value of package.path,
the path used by require to search for Lua loaders. the path used by require to search for Lua loaders.
.TP .TP
.B LUA_CPATH, LUA_CPATH_5_4 .B LUA_CPATH, LUA_CPATH_5_4

View File

@ -143,6 +143,7 @@ table.book td.cover {
table.book img { table.book img {
border: solid #000080 1px ; border: solid #000080 1px ;
border-radius: 2px ;
} }
table.book span { table.book span {

View File

@ -10,7 +10,7 @@
<BODY> <BODY>
<H1> <H1>
<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> <A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
Lua 5.4 Reference Manual Lua 5.4 Reference Manual
</H1> </H1>
@ -19,9 +19,9 @@ by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
<P> <P>
<SMALL> <SMALL>
Copyright &copy; 2020&ndash;2022 Lua.org, PUC-Rio. Copyright &copy; 2020&ndash;2024 Lua.org, PUC-Rio.
Freely available under the terms of the Freely available under the terms of the
<a href="http://www.lua.org/license.html">Lua license</a>. <a href="https://www.lua.org/license.html">Lua license</a>.
</SMALL> </SMALL>
<DIV CLASS="menubar"> <DIV CLASS="menubar">
@ -29,7 +29,7 @@ Freely available under the terms of the
&middot; &middot;
<A HREF="contents.html#index">index</A> <A HREF="contents.html#index">index</A>
&middot; &middot;
<A HREF="http://www.lua.org/manual/">other versions</A> <A HREF="https://www.lua.org/manual/">other versions</A>
</DIV> </DIV>
<!-- ====================================================================== --> <!-- ====================================================================== -->
@ -63,7 +63,7 @@ and rapid prototyping.
<p> <p>
Lua is implemented as a library, written in <em>clean C</em>, 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>, The Lua distribution includes a host program called <code>lua</code>,
which uses the Lua library to offer a complete, which uses the Lua library to offer a complete,
standalone Lua interpreter, standalone Lua interpreter,
@ -391,7 +391,7 @@ Whenever there is an error,
an <em>error object</em> an <em>error object</em>
is propagated with information about the error. is propagated with information about the error.
Lua itself only generates errors whose error object is a string, Lua itself only generates errors whose error object is a string,
but programs may generate errors with but programs can generate errors with
any value as the error object. any value as the error object.
It is up to the Lua program or its host to handle such error objects. It is up to the Lua program or its host to handle such error objects.
For historical reasons, For historical reasons,
@ -401,7 +401,7 @@ even though it does not have to be a string.
<p> <p>
When you use <a href="#pdf-xpcall"><code>xpcall</code></a> (or <a href="#lua_pcall"><code>lua_pcall</code></a>, in C) When you use <a href="#pdf-xpcall"><code>xpcall</code></a> (or <a href="#lua_pcall"><code>lua_pcall</code></a>, in C)
you may give a <em>message handler</em> you can give a <em>message handler</em>
to be called in case of errors. to be called in case of errors.
This function is called with the original error object This function is called with the original error object
and returns a new error object. and returns a new error object.
@ -453,7 +453,7 @@ which is then called a <em>metamethod</em>.
In the previous example, the key is the string "<code>__add</code>" In the previous example, the key is the string "<code>__add</code>"
and the metamethod is the function that performs the addition. and the metamethod is the function that performs the addition.
Unless stated otherwise, Unless stated otherwise,
a metamethod may in fact be any callable value, a metamethod can in fact be any callable value,
which is either a function or a value with a <code>__call</code> metamethod. which is either a function or a value with a <code>__call</code> metamethod.
@ -1379,7 +1379,9 @@ Lua also accepts hexadecimal constants,
which start with <code>0x</code> or <code>0X</code>. which start with <code>0x</code> or <code>0X</code>.
Hexadecimal constants also accept an optional fractional part Hexadecimal constants also accept an optional fractional part
plus an optional binary exponent, 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> <p>
@ -1621,21 +1623,13 @@ Expressions are discussed in <a href="#3.4">&sect;3.4</a>.
<p> <p>
Before the assignment, Before the assignment,
the list of values is <em>adjusted</em> to the length of the list of values is <em>adjusted</em> to the length of
the list of variables. the list of variables (see <a href="#3.4.12">&sect;3.4.12</a>).
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>).
<p> <p>
If a variable is both assigned and read If a variable is both assigned and read
inside a multiple assignment, 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. before the assignment.
Thus the code Thus the code
@ -1731,18 +1725,13 @@ labels in Lua are considered statements too:
<p> <p>
A label is visible in the entire block where it is defined, A label is visible in the entire block where it is defined,
except inside nested functions. except inside nested functions.
A goto may jump to any visible label as long as it does not A goto can jump to any visible label as long as it does not
enter into the scope of a local variable. enter into the scope of a local variable.
A label should not be declared A label should not be declared
where a label with the same name is visible, where a label with the same name is visible,
even if this other label has been declared in an enclosing block. 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> <p>
The <b>break</b> statement terminates the execution of a The <b>break</b> statement terminates the execution of a
<b>while</b>, <b>repeat</b>, or <b>for</b> loop, <b>while</b>, <b>repeat</b>, or <b>for</b> 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>. table constructors are explained in <a href="#3.4.9">&sect;3.4.9</a>.
Vararg expressions, Vararg expressions,
denoted by three dots ('<code>...</code>'), can only be used when 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>. 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>). 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> <p>
Nonetheless, it is always a good practice not to rely on these It is always a good practice not to rely on the
implicit coercions, as they are not always applied; 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 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>). (see <a href="#3.4.4">&sect;3.4.4</a>).
These coercions exist mainly for compatibility and may be removed 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> <p>
If the last field in the list has the form <code>exp</code> 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 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> <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>. scope of a to-be-closed variable is called a <em>tail call</em>.
Lua implements <em>proper tail calls</em> Lua implements <em>proper tail calls</em>
(or <em>proper tail recursion</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. the called function reuses the stack entry of the calling function.
Therefore, there is no limit on the number of nested tail calls that Therefore, there is no limit on the number of nested tail calls that
a program can execute. a program can execute.
@ -2727,22 +2671,16 @@ initialized with the argument values:
</pre><p> </pre><p>
When a Lua function is called, When a Lua function is called,
it adjusts its list of arguments to it adjusts its list of arguments to
the length of its list of parameters, the length of its list of parameters (see <a href="#3.4.12">&sect;3.4.12</a>),
unless the function is a <em>vararg function</em>, unless the function is a <em>variadic function</em>,
which is indicated by three dots ('<code>...</code>') which is indicated by three dots ('<code>...</code>')
at the end of its parameter list. 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 instead, it collects all extra arguments and supplies them
to the function through a <em>vararg expression</em>, to the function through a <em>vararg expression</em>,
which is also written as three dots. which is also written as three dots.
The value of this expression is a list of all actual extra arguments, The value of this expression is a list of all actual extra arguments,
similar to a function with multiple results. similar to a function with multiple results (see <a href="#3.4.12">&sect;3.4.12</a>).
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).
<p> <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> <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 The scope of a local variable begins at the first statement after
its declaration and lasts until the last non-void statement its declaration and lasts until the last non-void statement
of the innermost block that includes the declaration. of the innermost block that includes the declaration.
(<em>Void statements</em> are labels and empty statements.)
Consider the following example: Consider the following example:
<pre> <pre>
@ -3071,7 +3126,7 @@ In general,
Lua's garbage collection can free or move internal memory Lua's garbage collection can free or move internal memory
and then invalidate pointers to internal strings. and then invalidate pointers to internal strings.
To allow a safe use of these pointers, 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. is valid while the string value at that index is not removed from the stack.
(It can be moved to another index, though.) (It can be moved to another index, though.)
When the index is a pseudo-index (referring to an upvalue), 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); return realloc(ptr, nsize);
} }
</pre><p> </pre><p>
Note that Standard&nbsp;C ensures Note that ISO&nbsp;C ensures
that <code>free(NULL)</code> has no effect and that that <code>free(NULL)</code> has no effect and that
<code>realloc(NULL,size)</code> is equivalent to <code>malloc(size)</code>. <code>realloc(NULL,size)</code> is equivalent to <code>malloc(size)</code>.
@ -3785,8 +3840,36 @@ when called through this function.
<p> <p>
(Exceptionally, this function was introduced in release 5.4.3. (This function was introduced in release&nbsp;5.4.3.)
It is not present in previous 5.4 releases.)
<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, and pushes a key&ndash;value pair from the table at the given index,
the "next" pair after the given key. the "next" pair after the given key.
If there are no more elements in the table, 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> <p>
@ -4985,6 +5068,7 @@ Also returns&nbsp;0 if any of the indices are not valid.
<p> <p>
Similar to <a href="#lua_gettable"><code>lua_gettable</code></a>, but does a raw access Similar to <a href="#lua_gettable"><code>lua_gettable</code></a>, but does a raw access
(i.e., without metamethods). (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> <p>
Similar to <a href="#lua_settable"><code>lua_settable</code></a>, but does a raw assignment Similar to <a href="#lua_settable"><code>lua_settable</code></a>, but does a raw assignment
(i.e., without metamethods). (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> <pre>int lua_resetthread (lua_State *L);</pre>
<p> <p>
Resets a thread, cleaning its call stack and closing all pending This function is deprecated;
to-be-closed variables. it is equivalent to <a href="#lua_closethread"><code>lua_closethread</code></a> with
Returns a status code: <code>from</code> being <code>NULL</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.
@ -5492,7 +5571,7 @@ otherwise, returns <code>NULL</code>.
<hr><h3><a name="lua_toclose"><code>lua_toclose</code></a></h3><p> <hr><h3><a name="lua_toclose"><code>lua_toclose</code></a></h3><p>
<span class="apii">[-0, +0, <em>m</em>]</span> <span class="apii">[-0, +0, <em>v</em>]</span>
<pre>void lua_toclose (lua_State *L, int index);</pre> <pre>void lua_toclose (lua_State *L, int index);</pre>
<p> <p>
@ -5512,6 +5591,11 @@ by any other function in the API except <a href="#lua_settop"><code>lua_settop</
unless previously deactivated by <a href="#lua_closeslot"><code>lua_closeslot</code></a>. unless previously deactivated by <a href="#lua_closeslot"><code>lua_closeslot</code></a>.
<p>
This function raises an error if the value at the given slot
neither has a <code>__close</code> metamethod nor is a false value.
<p> <p>
This function should not be called for an index This function should not be called for an index
that is equal to or below an active to-be-closed slot. that is equal to or below an active to-be-closed slot.
@ -5585,6 +5669,12 @@ after its last character (as in&nbsp;C),
but can contain other zeros in its body. but can contain other zeros in its body.
<p>
This function can raise memory errors only
when converting a number to a string
(as then it may create a new string).
@ -6033,7 +6123,7 @@ the number of parameters of the function
</li> </li>
<li><b><code>isvararg</code>: </b> <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). (always true for C&nbsp;functions).
</li> </li>
@ -6773,7 +6863,7 @@ Equivalent to the sequence
<pre>void luaL_buffsub (luaL_Buffer *B, int n);</pre> <pre>void luaL_buffsub (luaL_Buffer *B, int n);</pre>
<p> <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>). (see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>).
The buffer must have at least that many bytes. The buffer must have at least that many bytes.
@ -6968,8 +7058,8 @@ It is defined as the following macro:
<pre> <pre>
(luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0)) (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))
</pre><p> </pre><p>
It returns <a href="#pdf-LUA_OK"><code>LUA_OK</code></a> if there are no errors, It returns&nbsp;0 (<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>). or 1 in case of errors.
@ -6986,8 +7076,8 @@ It is defined as the following macro:
<pre> <pre>
(luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0)) (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))
</pre><p> </pre><p>
It returns <a href="#pdf-LUA_OK"><code>LUA_OK</code></a> if there are no errors, It returns&nbsp;0 (<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>). or 1 in case of errors.
@ -7294,7 +7384,7 @@ with <code>tname</code> in the registry.
<p> <p>
Creates a new Lua state. Creates a new Lua state.
It calls <a href="#lua_newstate"><code>lua_newstate</code></a> with an 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>) 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. that print messages to the standard error output.
@ -7685,9 +7775,7 @@ to start the traceback.
<hr><h3><a name="luaL_typeerror"><code>luaL_typeerror</code></a></h3><p> <hr><h3><a name="luaL_typeerror"><code>luaL_typeerror</code></a></h3><p>
<span class="apii">[-0, +0, <em>v</em>]</span> <span class="apii">[-0, +0, <em>v</em>]</span>
<pre>const char *luaL_typeerror (lua_State *L, <pre>int luaL_typeerror (lua_State *L, int arg, const char *tname);</pre>
int arg,
const char *tname);</pre>
<p> <p>
Raises a type error for the argument <code>arg</code> Raises a type error for the argument <code>arg</code>
@ -8708,6 +8796,8 @@ When you require a module <code>modname</code> and
This variable is only a reference to the real table; This variable is only a reference to the real table;
assignments to this variable do not change the assignments to this variable do not change the
table used by <a href="#pdf-require"><code>require</code></a>. 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 +8835,7 @@ including if necessary a path and an extension.
<p> <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 As such, it is only available on some platforms
(Windows, Linux, Mac OS X, Solaris, BSD, (Windows, Linux, Mac OS X, Solaris, BSD,
plus other Unix systems that support the <code>dlfcn</code> standard). plus other Unix systems that support the <code>dlfcn</code> standard).
@ -8799,6 +8889,8 @@ A table to store loaders for specific modules
This variable is only a reference to the real table; This variable is only a reference to the real table;
assignments to this variable do not change the assignments to this variable do not change the
table used by <a href="#pdf-require"><code>require</code></a>. 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 +9403,7 @@ according to the format string <code>fmt</code> (see <a href="#6.4.2">&sect;6.4.
<p> <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. with the given format.
The format string cannot have the variable-length options 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>). '<code>s</code>' or '<code>z</code>' (see <a href="#6.4.2">&sect;6.4.2</a>).
@ -10091,9 +10183,9 @@ Returns the arc sine of <code>x</code> (in radians).
<p> <p>
Returns the arc tangent of <code>y/x</code> (in radians), 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. quadrant of the result.
It also handles correctly the case of <code>x</code> being zero. It also handles correctly the case of <code>x</code> being zero.
@ -10953,7 +11045,7 @@ The default value for <code>code</code> is <b>true</b>.
<p> <p>
If the optional second argument <code>close</code> is true, 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>).
@ -11195,13 +11287,13 @@ The returned table can contain all the fields returned by <a href="#lua_getinfo"
with the string <code>what</code> describing which fields to fill in. with the string <code>what</code> describing which fields to fill in.
The default for <code>what</code> is to get all information available, The default for <code>what</code> is to get all information available,
except the table of valid lines. except the table of valid lines.
If present, The option '<code>f</code>'
the option '<code>f</code>'
adds a field named <code>func</code> with the function itself. adds a field named <code>func</code> with the function itself.
If present, The option '<code>L</code>' adds a field named <code>activelines</code>
the option '<code>L</code>' with the table of valid lines,
adds a field named <code>activelines</code> with the table of provided the function is a Lua function.
valid lines. If the function has no debug information,
the table is empty.
<p> <p>
@ -11503,12 +11595,18 @@ The options are:
<li><b><code>-i</code>: </b> enter interactive mode after running <em>script</em>;</li> <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 <li><b><code>-l <em>mod</em></code>: </b> "require" <em>mod</em> and assign the
result to global <em>mod</em>;</li> 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>-v</code>: </b> print version information;</li>
<li><b><code>-E</code>: </b> ignore environment variables;</li> <li><b><code>-E</code>: </b> ignore environment variables;</li>
<li><b><code>-W</code>: </b> turn warnings on;</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> stop handling options;</li>
<li><b><code>-</code>: </b> execute <code>stdin</code> as a file and stop handling options.</li> <li><b><code>-</code>: </b> execute <code>stdin</code> as a file and stop handling options.</li>
</ul><p> </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>. After handling its options, <code>lua</code> runs the given <em>script</em>.
When called without arguments, When called without arguments,
<code>lua</code> behaves as <code>lua -v -i</code> <code>lua</code> behaves as <code>lua -v -i</code>
@ -11532,6 +11630,10 @@ Lua does not consult any environment variables.
In particular, In particular,
the values of <a href="#pdf-package.path"><code>package.path</code></a> and <a href="#pdf-package.cpath"><code>package.cpath</code></a> the values of <a href="#pdf-package.path"><code>package.path</code></a> and <a href="#pdf-package.cpath"><code>package.cpath</code></a>
are set with the default paths defined in <code>luaconf.h</code>. are set with the default paths defined in <code>luaconf.h</code>.
To signal to the libraries that this option is on,
the stand-alone interpreter sets the field
<code>"LUA_NOENV"</code> in the registry to a true value.
Other libraries may consult this field for the same purpose.
<p> <p>
@ -11582,7 +11684,7 @@ If there is a script,
the script is called with arguments the script is called with arguments
<code>arg[1]</code>, &middot;&middot;&middot;, <code>arg[#arg]</code>. <code>arg[1]</code>, &middot;&middot;&middot;, <code>arg[#arg]</code>.
Like all chunks in Lua, Like all chunks in Lua,
the script is compiled as a vararg function. the script is compiled as a variadic function.
<p> <p>
@ -11946,13 +12048,12 @@ and LiteralString, see <a href="#3.1">&sect;3.1</a>.)
<P CLASS="footer"> <P CLASS="footer">
Last update: Last update:
Thu Jan 13 11:33:16 UTC 2022 Thu Jun 13 22:15:52 UTC 2024
</P> </P>
<!-- <!--
Last change: revised for Lua 5.4.4 Last change: revised for Lua 5.4.7
--> -->
</body></html> </body></html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -29,7 +29,7 @@ tt, kbd, code {
<BODY> <BODY>
<H1> <H1>
<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> <A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
Welcome to Lua 5.4 Welcome to Lua 5.4
</H1> </H1>
@ -49,29 +49,31 @@ Welcome to Lua 5.4
<P> <P>
Lua is a powerful, efficient, lightweight, embeddable scripting language Lua is a powerful, efficient, lightweight, embeddable scripting language
developed by a developed by a
<A HREF="http://www.lua.org/authors.html">team</A> <A HREF="https://www.lua.org/authors.html">team</A>
at at
<A HREF="http://www.puc-rio.br/">PUC-Rio</A>, <A HREF="https://www.puc-rio.br/">PUC-Rio</A>,
the Pontifical Catholic University of Rio de Janeiro in Brazil. the Pontifical Catholic University of Rio de Janeiro in Brazil.
Lua is Lua is
<A HREF="#license">free software</A> <A HREF="#license">free software</A>
used in used in
<A HREF="http://www.lua.org/uses.html">many products and projects</A> <A HREF="https://www.lua.org/uses.html">many products and projects</A>
around the world. around the world.
<P> <P>
Lua's Lua's
<A HREF="http://www.lua.org/">official web site</A> <A HREF="https://www.lua.org/">official website</A>
provides complete information provides complete information
about Lua, about Lua,
including including
an an
<A HREF="http://www.lua.org/about.html">executive summary</A> <A HREF="https://www.lua.org/about.html">executive summary</A>,
tips on
<A HREF="https://www.lua.org/start.html">getting started</A>,
and and
updated updated
<A HREF="http://www.lua.org/docs.html">documentation</A>, <A HREF="https://www.lua.org/docs.html">documentation</A>,
especially the especially the
<A HREF="http://www.lua.org/manual/5.4/">reference manual</A>, <A HREF="https://www.lua.org/manual/5.4/">reference manual</A>,
which may differ slightly from the which may differ slightly from the
<A HREF="contents.html">local copy</A> <A HREF="contents.html">local copy</A>
distributed in this package. distributed in this package.
@ -79,7 +81,7 @@ distributed in this package.
<H2><A NAME="install">Installing Lua</A></H2> <H2><A NAME="install">Installing Lua</A></H2>
<P> <P>
Lua is distributed in Lua is distributed in
<A HREF="http://www.lua.org/ftp/">source</A> <A HREF="https://www.lua.org/ftp/">source</A>
form. form.
You need to build it before using it. You need to build it before using it.
Building Lua should be straightforward Building Lua should be straightforward
@ -88,7 +90,7 @@ Lua is implemented in pure ANSI C and compiles unmodified in all known
platforms that have an ANSI C compiler. platforms that have an ANSI C compiler.
Lua also compiles unmodified as C++. Lua also compiles unmodified as C++.
The instructions given below for building Lua are for Unix-like platforms, The instructions given below for building Lua are for Unix-like platforms,
such as Linux and Mac OS X. such as Linux and macOS.
See also See also
<A HREF="#other">instructions for other systems</A> <A HREF="#other">instructions for other systems</A>
and and
@ -97,10 +99,7 @@ and
<P> <P>
If you don't have the time or the inclination to compile Lua yourself, If you don't have the time or the inclination to compile Lua yourself,
get a binary from get a binary from
<A HREF="http://lua-users.org/wiki/LuaBinaries">LuaBinaries</A>. <A HREF="https://luabinaries.sourceforge.net">LuaBinaries</A>.
Try also
<A HREF="http://luadist.org/">LuaDist</A>,
a multi-platform distribution of Lua that includes batteries.
<H3>Building Lua</H3> <H3>Building Lua</H3>
<P> <P>
@ -110,7 +109,7 @@ Here are the details.
<OL> <OL>
<LI> <LI>
Open a terminal window and move to Open a terminal window and move to
the top-level directory, which is named <TT>lua-5.4.4</TT>. the top-level directory, which is named <TT>lua-5.4.7</TT>.
The <TT>Makefile</TT> there controls both the build process and the installation process. The <TT>Makefile</TT> there controls both the build process and the installation process.
<P> <P>
<LI> <LI>
@ -121,7 +120,7 @@ The <TT>Makefile</TT> there controls both the build process and the installation
The platforms currently supported are: The platforms currently supported are:
<P> <P>
<P CLASS="display"> <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>
<P> <P>
If your platform is listed, just do "<KBD>make xxx</KBD>", where xxx If your platform is listed, just do "<KBD>make xxx</KBD>", where xxx
@ -214,8 +213,8 @@ then try "<KBD>make linux-readline MYLIBS=-ltermcap</KBD>".
record the changes you've made. record the changes you've made.
<P> <P>
On the other hand, if you need to customize some Lua features, you'll need On the other hand, if you need to customize some Lua features,
to edit <TT>src/luaconf.h</TT> before building and installing Lua. edit <TT>src/luaconf.h</TT> before building and installing Lua.
The edited file will be the one installed, and The edited file will be the one installed, and
it will be used by any Lua clients that you build, to ensure consistency. it will be used by any Lua clients that you build, to ensure consistency.
Further customization is available to experts by editing the Lua sources. Further customization is available to experts by editing the Lua sources.
@ -244,7 +243,7 @@ compiler:
</DL> </DL>
<P> <P>
To use Lua as a library in your own programs, you'll need to know how to To use Lua as a library in your own programs, you need to know how to
create and use libraries with your compiler. Moreover, to dynamically load create and use libraries with your compiler. Moreover, to dynamically load
C libraries for Lua, you'll need to know how to create dynamic libraries C libraries for Lua, you'll need to know how to create dynamic libraries
and you'll need to make sure that the Lua API functions are accessible to and you'll need to make sure that the Lua API functions are accessible to
@ -287,11 +286,11 @@ lists the
<H2><A NAME="license">License</A></H2> <H2><A NAME="license">License</A></H2>
<P> <P>
<A HREF="http://www.opensource.org/docs/definition.php"> <A HREF="https://opensource.org/osd">
<IMG SRC="osi-certified-72x60.png" ALIGN="right" ALT="[osi certified]" STYLE="padding-left: 30px ;"> <IMG SRC="OSIApproved_100X125.png" ALIGN="right" ALT="[Open Source Initiative Approved License]" STYLE="padding-left: 1em" WIDTH=50>
</A> </A>
Lua is free software distributed under the terms of the Lua is free software distributed under the terms of the
<A HREF="http://www.opensource.org/licenses/mit-license.html">MIT license</A> <A HREF="https://opensource.org/license/mit">MIT license</A>
reproduced below; reproduced below;
it may be used for any purpose, including commercial purposes, it may be used for any purpose, including commercial purposes,
at absolutely no cost without having to ask us. at absolutely no cost without having to ask us.
@ -299,11 +298,11 @@ at absolutely no cost without having to ask us.
The only requirement is that if you do use Lua, The only requirement is that if you do use Lua,
then you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation. then you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation.
For details, see For details, see the
<A HREF="http://www.lua.org/license.html">this</A>. <A HREF="https://www.lua.org/license.html">license page</A>.
<BLOCKQUOTE STYLE="padding-bottom: 0em"> <BLOCKQUOTE STYLE="padding-bottom: 0em">
Copyright &copy; 1994&ndash;2022 Lua.org, PUC-Rio. Copyright &copy; 1994&ndash;2024 Lua.org, PUC-Rio.
<P> <P>
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
@ -330,10 +329,10 @@ THE SOFTWARE.
<P CLASS="footer"> <P CLASS="footer">
Last update: Last update:
Mon Jan 3 09:54:18 UTC 2022 Wed May 8 21:56:16 UTC 2024
</P> </P>
<!-- <!--
Last change: revised for Lua 5.4.4 Last change: revised for Lua 5.4.7
--> -->
</BODY> </BODY>

View File

@ -30,7 +30,7 @@ CMCFLAGS=
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE ======= # == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
PLATS= guess aix bsd c89 freebsd generic linux linux-readline macosx mingw posix solaris PLATS= guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
LUA_A= liblua.a LUA_A= liblua.a
CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o
@ -117,6 +117,9 @@ FreeBSD NetBSD OpenBSD freebsd:
generic: $(ALL) generic: $(ALL)
ios:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_IOS"
Linux linux: linux-noreadline Linux linux: linux-noreadline
linux-noreadline: linux-noreadline:

View File

@ -60,27 +60,28 @@ const char lua_ident[] =
static TValue *index2value (lua_State *L, int idx) { static TValue *index2value (lua_State *L, int idx) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (idx > 0) { if (idx > 0) {
StkId o = ci->func + idx; StkId o = ci->func.p + idx;
api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index"); api_check(L, idx <= ci->top.p - (ci->func.p + 1), "unacceptable index");
if (o >= L->top) return &G(L)->nilvalue; if (o >= L->top.p) return &G(L)->nilvalue;
else return s2v(o); else return s2v(o);
} }
else if (!ispseudo(idx)) { /* negative index */ else if (!ispseudo(idx)) { /* negative index */
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
return s2v(L->top + idx); "invalid index");
return s2v(L->top.p + idx);
} }
else if (idx == LUA_REGISTRYINDEX) else if (idx == LUA_REGISTRYINDEX)
return &G(L)->l_registry; return &G(L)->l_registry;
else { /* upvalues */ else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx; idx = LUA_REGISTRYINDEX - idx;
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
if (ttisCclosure(s2v(ci->func))) { /* C closure? */ if (ttisCclosure(s2v(ci->func.p))) { /* C closure? */
CClosure *func = clCvalue(s2v(ci->func)); CClosure *func = clCvalue(s2v(ci->func.p));
return (idx <= func->nupvalues) ? &func->upvalue[idx-1] return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
: &G(L)->nilvalue; : &G(L)->nilvalue;
} }
else { /* light C function or Lua function (through a hook)?) */ 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 */ 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) { l_sinline StkId index2stack (lua_State *L, int idx) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (idx > 0) { if (idx > 0) {
StkId o = ci->func + idx; StkId o = ci->func.p + idx;
api_check(L, o < L->top, "invalid index"); api_check(L, o < L->top.p, "invalid index");
return o; return o;
} }
else { /* non-positive index */ else { /* non-positive index */
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
"invalid index");
api_check(L, !ispseudo(idx), "invalid index"); api_check(L, !ispseudo(idx), "invalid index");
return L->top + idx; return L->top.p + idx;
} }
} }
@ -112,17 +114,12 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
lua_lock(L); lua_lock(L);
ci = L->ci; ci = L->ci;
api_check(L, n >= 0, "negative 'n'"); api_check(L, n >= 0, "negative 'n'");
if (L->stack_last - L->top > n) /* stack large enough? */ if (L->stack_last.p - L->top.p > n) /* stack large enough? */
res = 1; /* yes; check is OK */ res = 1; /* yes; check is OK */
else { /* no; need to grow stack */ else /* need to grow stack */
int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; res = luaD_growstack(L, n, 0);
if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */ if (res && ci->top.p < L->top.p + n)
res = 0; /* no */ ci->top.p = L->top.p + n; /* adjust frame top */
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 */
lua_unlock(L); lua_unlock(L);
return res; return res;
} }
@ -134,11 +131,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
lua_lock(to); lua_lock(to);
api_checknelems(from, n); api_checknelems(from, n);
api_check(from, G(from) == G(to), "moving among independent states"); api_check(from, G(from) == G(to), "moving among independent states");
api_check(from, to->ci->top - to->top >= n, "stack overflow"); api_check(from, to->ci->top.p - to->top.p >= n, "stack overflow");
from->top -= n; from->top.p -= n;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
setobjs2s(to, to->top, from->top + i); setobjs2s(to, to->top.p, from->top.p + i);
to->top++; /* stack already checked by previous 'api_check' */ to->top.p++; /* stack already checked by previous 'api_check' */
} }
lua_unlock(to); 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) { LUA_API int lua_absindex (lua_State *L, int idx) {
return (idx > 0 || ispseudo(idx)) return (idx > 0 || ispseudo(idx))
? idx ? idx
: cast_int(L->top - L->ci->func) + idx; : cast_int(L->top.p - L->ci->func.p) + idx;
} }
LUA_API int lua_gettop (lua_State *L) { LUA_API int lua_gettop (lua_State *L) {
return cast_int(L->top - (L->ci->func + 1)); return cast_int(L->top.p - (L->ci->func.p + 1));
} }
@ -187,24 +184,24 @@ LUA_API void lua_settop (lua_State *L, int idx) {
ptrdiff_t diff; /* difference for new top */ ptrdiff_t diff; /* difference for new top */
lua_lock(L); lua_lock(L);
ci = L->ci; ci = L->ci;
func = ci->func; func = ci->func.p;
if (idx >= 0) { if (idx >= 0) {
api_check(L, idx <= ci->top - (func + 1), "new top too large"); api_check(L, idx <= ci->top.p - (func + 1), "new top too large");
diff = ((func + 1) + idx) - L->top; diff = ((func + 1) + idx) - L->top.p;
for (; diff > 0; diff--) for (; diff > 0; diff--)
setnilvalue(s2v(L->top++)); /* clear new slots */ setnilvalue(s2v(L->top.p++)); /* clear new slots */
} }
else { else {
api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); api_check(L, -(idx+1) <= (L->top.p - (func + 1)), "invalid new top");
diff = idx + 1; /* will "subtract" index (as it is negative) */ diff = idx + 1; /* will "subtract" index (as it is negative) */
} }
api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot"); api_check(L, L->tbclist.p < L->top.p, "previous pop of an unclosed slot");
newtop = L->top + diff; newtop = L->top.p + diff;
if (diff < 0 && L->tbclist >= newtop) { if (diff < 0 && L->tbclist.p >= newtop) {
lua_assert(hastocloseCfunc(ci->nresults)); lua_assert(hastocloseCfunc(ci->nresults));
luaF_close(L, newtop, CLOSEKTOP, 0); newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
} }
L->top = newtop; /* correct top only after closing any upvalue */ L->top.p = newtop; /* correct top only after closing any upvalue */
lua_unlock(L); lua_unlock(L);
} }
@ -213,10 +210,9 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
StkId level; StkId level;
lua_lock(L); lua_lock(L);
level = index2stack(L, idx); level = index2stack(L, idx);
api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level, api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level,
"no variable to close at given level"); "no variable to close at given level");
luaF_close(L, level, CLOSEKTOP, 0); level = luaF_close(L, level, CLOSEKTOP, 0);
level = index2stack(L, idx); /* stack may be moved */
setnilvalue(s2v(level)); setnilvalue(s2v(level));
lua_unlock(L); 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) { LUA_API void lua_rotate (lua_State *L, int idx, int n) {
StkId p, t, m; StkId p, t, m;
lua_lock(L); lua_lock(L);
t = L->top - 1; /* end of stack segment being rotated */ t = L->top.p - 1; /* end of stack segment being rotated */
p = index2stack(L, idx); /* start of segment */ p = index2stack(L, idx); /* start of segment */
api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'"); api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */ m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
@ -264,7 +260,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
api_check(L, isvalid(L, to), "invalid index"); api_check(L, isvalid(L, to), "invalid index");
setobj(L, to, fr); setobj(L, to, fr);
if (isupvalue(toidx)) /* function upvalue? */ if (isupvalue(toidx)) /* function upvalue? */
luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr); luaC_barrier(L, clCvalue(s2v(L->ci->func.p)), fr);
/* LUA_REGISTRYINDEX does not need gc barrier /* LUA_REGISTRYINDEX does not need gc barrier
(collector revisits it before finishing collection) */ (collector revisits it before finishing collection) */
lua_unlock(L); lua_unlock(L);
@ -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_API void lua_pushvalue (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
setobj2s(L, L->top, index2value(L, idx)); setobj2s(L, L->top.p, index2value(L, idx));
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -342,12 +338,12 @@ LUA_API void lua_arith (lua_State *L, int op) {
api_checknelems(L, 2); /* all other operations expect two operands */ api_checknelems(L, 2); /* all other operations expect two operands */
else { /* for unary operations, add fake 2nd operand */ else { /* for unary operations, add fake 2nd operand */
api_checknelems(L, 1); api_checknelems(L, 1);
setobjs2s(L, L->top, L->top - 1); setobjs2s(L, L->top.p, L->top.p - 1);
api_incr_top(L); api_incr_top(L);
} }
/* first operand at top - 2, second at top - 1; result go to top - 2 */ /* first operand at top - 2, second at top - 1; result go to top - 2 */
luaO_arith(L, op, s2v(L->top - 2), s2v(L->top - 1), L->top - 2); luaO_arith(L, op, s2v(L->top.p - 2), s2v(L->top.p - 1), L->top.p - 2);
L->top--; /* remove second operand */ L->top.p--; /* remove second operand */
lua_unlock(L); 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) { LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
size_t sz = luaO_str2num(s, s2v(L->top)); size_t sz = luaO_str2num(s, s2v(L->top.p));
if (sz != 0) if (sz != 0)
api_incr_top(L); api_incr_top(L);
return sz; return sz;
@ -421,9 +417,9 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
o = index2value(L, idx); /* previous call may reallocate the stack */ o = index2value(L, idx); /* previous call may reallocate the stack */
} }
if (len != NULL) if (len != NULL)
*len = vslen(o); *len = tsslen(tsvalue(o));
lua_unlock(L); lua_unlock(L);
return svalue(o); return getstr(tsvalue(o));
} }
@ -500,7 +496,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
LUA_API void lua_pushnil (lua_State *L) { LUA_API void lua_pushnil (lua_State *L) {
lua_lock(L); lua_lock(L);
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -508,7 +504,7 @@ LUA_API void lua_pushnil (lua_State *L) {
LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
lua_lock(L); lua_lock(L);
setfltvalue(s2v(L->top), n); setfltvalue(s2v(L->top.p), n);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -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_API void lua_pushinteger (lua_State *L, lua_Integer n) {
lua_lock(L); lua_lock(L);
setivalue(s2v(L->top), n); setivalue(s2v(L->top.p), n);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -531,7 +527,7 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts; TString *ts;
lua_lock(L); lua_lock(L);
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
setsvalue2s(L, L->top, ts); setsvalue2s(L, L->top.p, ts);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L); luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
@ -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_API const char *lua_pushstring (lua_State *L, const char *s) {
lua_lock(L); lua_lock(L);
if (s == NULL) if (s == NULL)
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
else { else {
TString *ts; TString *ts;
ts = luaS_new(L, s); ts = luaS_new(L, s);
setsvalue2s(L, L->top, ts); setsvalue2s(L, L->top.p, ts);
s = getstr(ts); /* internal copy's address */ s = getstr(ts); /* internal copy's address */
} }
api_incr_top(L); api_incr_top(L);
@ -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_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
lua_lock(L); lua_lock(L);
if (n == 0) { if (n == 0) {
setfvalue(s2v(L->top), fn); setfvalue(s2v(L->top.p), fn);
api_incr_top(L); api_incr_top(L);
} }
else { else {
@ -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"); api_check(L, n <= MAXUPVAL, "upvalue index too large");
cl = luaF_newCclosure(L, n); cl = luaF_newCclosure(L, n);
cl->f = fn; cl->f = fn;
L->top -= n; L->top.p -= n;
while (n--) { while (n--) {
setobj2n(L, &cl->upvalue[n], s2v(L->top + n)); setobj2n(L, &cl->upvalue[n], s2v(L->top.p + n));
/* does not need barrier because closure is white */ /* does not need barrier because closure is white */
lua_assert(iswhite(cl)); lua_assert(iswhite(cl));
} }
setclCvalue(L, s2v(L->top), cl); setclCvalue(L, s2v(L->top.p), cl);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L); luaC_checkGC(L);
} }
@ -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_API void lua_pushboolean (lua_State *L, int b) {
lua_lock(L); lua_lock(L);
if (b) if (b)
setbtvalue(s2v(L->top)); setbtvalue(s2v(L->top.p));
else else
setbfvalue(s2v(L->top)); setbfvalue(s2v(L->top.p));
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -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_API void lua_pushlightuserdata (lua_State *L, void *p) {
lua_lock(L); lua_lock(L);
setpvalue(s2v(L->top), p); setpvalue(s2v(L->top.p), p);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -627,7 +623,7 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
LUA_API int lua_pushthread (lua_State *L) { LUA_API int lua_pushthread (lua_State *L) {
lua_lock(L); lua_lock(L);
setthvalue(L, s2v(L->top), L); setthvalue(L, s2v(L->top.p), L);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return (G(L)->mainthread == L); return (G(L)->mainthread == L);
@ -644,16 +640,16 @@ l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot; const TValue *slot;
TString *str = luaS_new(L, k); TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) { if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
setobj2s(L, L->top, slot); setobj2s(L, L->top.p, slot);
api_incr_top(L); api_incr_top(L);
} }
else { else {
setsvalue2s(L, L->top, str); setsvalue2s(L, L->top.p, str);
api_incr_top(L); api_incr_top(L);
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot); luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
} }
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
@ -680,13 +676,13 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
TValue *t; TValue *t;
lua_lock(L); lua_lock(L);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastget(L, t, s2v(L->top - 1), slot, luaH_get)) { if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) {
setobj2s(L, L->top - 1, slot); setobj2s(L, L->top.p - 1, slot);
} }
else else
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot); luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
@ -702,27 +698,27 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L); lua_lock(L);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) { if (luaV_fastgeti(L, t, n, slot)) {
setobj2s(L, L->top, slot); setobj2s(L, L->top.p, slot);
} }
else { else {
TValue aux; TValue aux;
setivalue(&aux, n); setivalue(&aux, n);
luaV_finishget(L, t, &aux, L->top, slot); luaV_finishget(L, t, &aux, L->top.p, slot);
} }
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
l_sinline int finishrawget (lua_State *L, const TValue *val) { l_sinline int finishrawget (lua_State *L, const TValue *val) {
if (isempty(val)) /* avoid copying empty items to the stack */ if (isempty(val)) /* avoid copying empty items to the stack */
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
else else
setobj2s(L, L->top, val); setobj2s(L, L->top.p, val);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
@ -739,8 +735,8 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = gettable(L, idx); t = gettable(L, idx);
val = luaH_get(t, s2v(L->top - 1)); val = luaH_get(t, s2v(L->top.p - 1));
L->top--; /* remove key */ L->top.p--; /* remove key */
return finishrawget(L, val); return finishrawget(L, val);
} }
@ -767,7 +763,7 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t; Table *t;
lua_lock(L); lua_lock(L);
t = luaH_new(L); t = luaH_new(L);
sethvalue2s(L, L->top, t); sethvalue2s(L, L->top.p, t);
api_incr_top(L); api_incr_top(L);
if (narray > 0 || nrec > 0) if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec); luaH_resize(L, t, narray, nrec);
@ -794,7 +790,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
break; break;
} }
if (mt != NULL) { if (mt != NULL) {
sethvalue2s(L, L->top, mt); sethvalue2s(L, L->top.p, mt);
api_incr_top(L); api_incr_top(L);
res = 1; res = 1;
} }
@ -810,12 +806,12 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
o = index2value(L, idx); o = index2value(L, idx);
api_check(L, ttisfulluserdata(o), "full userdata expected"); api_check(L, ttisfulluserdata(o), "full userdata expected");
if (n <= 0 || n > uvalue(o)->nuvalue) { if (n <= 0 || n > uvalue(o)->nuvalue) {
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
t = LUA_TNONE; t = LUA_TNONE;
} }
else { else {
setobj2s(L, L->top, &uvalue(o)->uv[n - 1].uv); setobj2s(L, L->top.p, &uvalue(o)->uv[n - 1].uv);
t = ttype(s2v(L->top)); t = ttype(s2v(L->top.p));
} }
api_incr_top(L); api_incr_top(L);
lua_unlock(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); TString *str = luaS_new(L, k);
api_checknelems(L, 1); api_checknelems(L, 1);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) { if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1)); luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
L->top--; /* pop value */ L->top.p--; /* pop value */
} }
else { else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ setsvalue2s(L, L->top.p, str); /* push 'str' (to make it a TValue) */
api_incr_top(L); api_incr_top(L);
luaV_finishset(L, t, s2v(L->top - 1), s2v(L->top - 2), slot); luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), slot);
L->top -= 2; /* pop value and key */ L->top.p -= 2; /* pop value and key */
} }
lua_unlock(L); /* lock done by caller */ lua_unlock(L); /* lock done by caller */
} }
@ -862,12 +858,12 @@ LUA_API void lua_settable (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 2); api_checknelems(L, 2);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastget(L, t, s2v(L->top - 2), slot, luaH_get)) { if (luaV_fastget(L, t, s2v(L->top.p - 2), slot, luaH_get)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1)); luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
} }
else else
luaV_finishset(L, t, s2v(L->top - 2), s2v(L->top - 1), slot); luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), slot);
L->top -= 2; /* pop index and value */ L->top.p -= 2; /* pop index and value */
lua_unlock(L); lua_unlock(L);
} }
@ -885,14 +881,14 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
api_checknelems(L, 1); api_checknelems(L, 1);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) { if (luaV_fastgeti(L, t, n, slot)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1)); luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
} }
else { else {
TValue aux; TValue aux;
setivalue(&aux, n); setivalue(&aux, n);
luaV_finishset(L, t, &aux, s2v(L->top - 1), slot); luaV_finishset(L, t, &aux, s2v(L->top.p - 1), slot);
} }
L->top--; /* pop value */ L->top.p--; /* pop value */
lua_unlock(L); lua_unlock(L);
} }
@ -902,16 +898,16 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
lua_lock(L); lua_lock(L);
api_checknelems(L, n); api_checknelems(L, n);
t = gettable(L, idx); t = gettable(L, idx);
luaH_set(L, t, key, s2v(L->top - 1)); luaH_set(L, t, key, s2v(L->top.p - 1));
invalidateTMcache(t); invalidateTMcache(t);
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1)); luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
L->top -= n; L->top.p -= n;
lua_unlock(L); lua_unlock(L);
} }
LUA_API void lua_rawset (lua_State *L, int idx) { LUA_API void lua_rawset (lua_State *L, int idx) {
aux_rawset(L, idx, s2v(L->top - 2), 2); aux_rawset(L, idx, s2v(L->top.p - 2), 2);
} }
@ -927,9 +923,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = gettable(L, idx); t = gettable(L, idx);
luaH_setint(L, t, n, s2v(L->top - 1)); luaH_setint(L, t, n, s2v(L->top.p - 1));
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1)); luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
L->top--; L->top.p--;
lua_unlock(L); lua_unlock(L);
} }
@ -940,11 +936,11 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
obj = index2value(L, objindex); obj = index2value(L, objindex);
if (ttisnil(s2v(L->top - 1))) if (ttisnil(s2v(L->top.p - 1)))
mt = NULL; mt = NULL;
else { else {
api_check(L, ttistable(s2v(L->top - 1)), "table expected"); api_check(L, ttistable(s2v(L->top.p - 1)), "table expected");
mt = hvalue(s2v(L->top - 1)); mt = hvalue(s2v(L->top.p - 1));
} }
switch (ttype(obj)) { switch (ttype(obj)) {
case LUA_TTABLE: { case LUA_TTABLE: {
@ -968,7 +964,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
break; break;
} }
} }
L->top--; L->top.p--;
lua_unlock(L); lua_unlock(L);
return 1; return 1;
} }
@ -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))) if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue)))
res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */ res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */
else { else {
setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top - 1)); setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top.p - 1));
luaC_barrierback(L, gcvalue(o), s2v(L->top - 1)); luaC_barrierback(L, gcvalue(o), s2v(L->top.p - 1));
res = 1; res = 1;
} }
L->top--; L->top.p--;
lua_unlock(L); lua_unlock(L);
return res; return res;
} }
@ -1000,7 +996,8 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
#define checkresults(L,na,nr) \ #define checkresults(L,na,nr) \
api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \ api_check(L, (nr) == LUA_MULTRET \
|| (L->ci->top.p - L->top.p >= (nr) - (na)), \
"results from function overflow current stack size") "results from function overflow current stack size")
@ -1013,7 +1010,7 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
api_checknelems(L, nargs+1); api_checknelems(L, nargs+1);
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults); checkresults(L, nargs, nresults);
func = L->top - (nargs+1); func = L->top.p - (nargs+1);
if (k != NULL && yieldable(L)) { /* need to prepare continuation? */ if (k != NULL && yieldable(L)) { /* need to prepare continuation? */
L->ci->u.c.k = k; /* save continuation */ L->ci->u.c.k = k; /* save continuation */
L->ci->u.c.ctx = ctx; /* save context */ L->ci->u.c.ctx = ctx; /* save context */
@ -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"); api_check(L, ttisfunction(s2v(o)), "error handler must be a function");
func = savestack(L, o); func = savestack(L, o);
} }
c.func = L->top - (nargs+1); /* function to be called */ c.func = L->top.p - (nargs+1); /* function to be called */
if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */ if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */
c.nresults = nresults; /* do a 'conventional' protected call */ c.nresults = nresults; /* do a 'conventional' protected call */
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
@ -1096,12 +1093,12 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
luaZ_init(L, &z, reader, data); luaZ_init(L, &z, reader, data);
status = luaD_protectedparser(L, &z, chunkname, mode); status = luaD_protectedparser(L, &z, chunkname, mode);
if (status == LUA_OK) { /* no errors? */ if (status == LUA_OK) { /* no errors? */
LClosure *f = clLvalue(s2v(L->top - 1)); /* get newly created function */ LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */
if (f->nupvalues >= 1) { /* does it have an upvalue? */ if (f->nupvalues >= 1) { /* does it have an upvalue? */
/* get global table from registry */ /* get global table from registry */
const TValue *gt = getGtable(L); const TValue *gt = getGtable(L);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
setobj(L, f->upvals[0]->v, gt); setobj(L, f->upvals[0]->v.p, gt);
luaC_barrier(L, f->upvals[0], gt); luaC_barrier(L, f->upvals[0], gt);
} }
} }
@ -1115,7 +1112,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
TValue *o; TValue *o;
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
o = s2v(L->top - 1); o = s2v(L->top.p - 1);
if (isLfunction(o)) if (isLfunction(o))
status = luaU_dump(L, getproto(o), writer, data, strip); status = luaU_dump(L, getproto(o), writer, data, strip);
else else
@ -1241,7 +1238,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
LUA_API int lua_error (lua_State *L) { LUA_API int lua_error (lua_State *L) {
TValue *errobj; TValue *errobj;
lua_lock(L); lua_lock(L);
errobj = s2v(L->top - 1); errobj = s2v(L->top.p - 1);
api_checknelems(L, 1); api_checknelems(L, 1);
/* error object is the memory error message? */ /* error object is the memory error message? */
if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg)) if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
@ -1259,12 +1256,12 @@ LUA_API int lua_next (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = gettable(L, idx); t = gettable(L, idx);
more = luaH_next(L, t, L->top - 1); more = luaH_next(L, t, L->top.p - 1);
if (more) { if (more) {
api_incr_top(L); api_incr_top(L);
} }
else /* no more elements */ else /* no more elements */
L->top -= 1; /* remove key */ L->top.p -= 1; /* remove key */
lua_unlock(L); lua_unlock(L);
return more; return more;
} }
@ -1276,7 +1273,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
o = index2stack(L, idx); o = index2stack(L, idx);
nresults = L->ci->nresults; nresults = L->ci->nresults;
api_check(L, L->tbclist < o, "given index below or equal a marked one"); api_check(L, L->tbclist.p < o, "given index below or equal a marked one");
luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */ luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
if (!hastocloseCfunc(nresults)) /* function not marked yet? */ if (!hastocloseCfunc(nresults)) /* function not marked yet? */
L->ci->nresults = codeNresults(nresults); /* mark it */ L->ci->nresults = codeNresults(nresults); /* mark it */
@ -1291,7 +1288,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
if (n > 0) if (n > 0)
luaV_concat(L, n); luaV_concat(L, n);
else { /* nothing to concatenate */ else { /* nothing to concatenate */
setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); /* push empty string */ setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */
api_incr_top(L); api_incr_top(L);
} }
luaC_checkGC(L); luaC_checkGC(L);
@ -1303,7 +1300,7 @@ LUA_API void lua_len (lua_State *L, int idx) {
TValue *t; TValue *t;
lua_lock(L); lua_lock(L);
t = index2value(L, idx); t = index2value(L, idx);
luaV_objlen(L, L->top, t); luaV_objlen(L, L->top.p, t);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -1348,7 +1345,7 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
lua_lock(L); lua_lock(L);
api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value"); api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value");
u = luaS_newudata(L, size, nuvalue); u = luaS_newudata(L, size, nuvalue);
setuvalue(L, s2v(L->top), u); setuvalue(L, s2v(L->top.p), u);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L); luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
@ -1374,7 +1371,7 @@ static const char *aux_upvalue (TValue *fi, int n, TValue **val,
Proto *p = f->p; Proto *p = f->p;
if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues))) if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues)))
return NULL; /* 'n' not in [1, p->sizeupvalues] */ return NULL; /* 'n' not in [1, p->sizeupvalues] */
*val = f->upvals[n-1]->v; *val = f->upvals[n-1]->v.p;
if (owner) *owner = obj2gco(f->upvals[n - 1]); if (owner) *owner = obj2gco(f->upvals[n - 1]);
name = p->upvalues[n-1].name; name = p->upvalues[n-1].name;
return (name == NULL) ? "(no name)" : getstr(name); return (name == NULL) ? "(no name)" : getstr(name);
@ -1390,7 +1387,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
lua_lock(L); lua_lock(L);
name = aux_upvalue(index2value(L, funcindex), n, &val, NULL); name = aux_upvalue(index2value(L, funcindex), n, &val, NULL);
if (name) { if (name) {
setobj2s(L, L->top, val); setobj2s(L, L->top.p, val);
api_incr_top(L); api_incr_top(L);
} }
lua_unlock(L); lua_unlock(L);
@ -1408,8 +1405,8 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
api_checknelems(L, 1); api_checknelems(L, 1);
name = aux_upvalue(fi, n, &val, &owner); name = aux_upvalue(fi, n, &val, &owner);
if (name) { if (name) {
L->top--; L->top.p--;
setobj(L, val, s2v(L->top)); setobj(L, val, s2v(L->top.p));
luaC_barrier(L, owner, val); luaC_barrier(L, owner, val);
} }
lua_unlock(L); lua_unlock(L);

View File

@ -12,23 +12,26 @@
#include "lstate.h" #include "lstate.h"
/* Increments 'L->top', checking for stack overflows */ /* Increments 'L->top.p', checking for stack overflows */
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ #define api_incr_top(L) {L->top.p++; \
"stack overflow");} api_check(L, L->top.p <= L->ci->top.p, \
"stack overflow");}
/* /*
** If a call returns too many multiple returns, the callee may not have ** If a call returns too many multiple returns, the callee may not have
** stack space to accommodate all results. In this case, this macro ** stack space to accommodate all results. In this case, this macro
** increases its stack space ('L->ci->top'). ** increases its stack space ('L->ci->top.p').
*/ */
#define adjustresults(L,nres) \ #define adjustresults(L,nres) \
{ if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } { if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
L->ci->top.p = L->top.p; }
/* Ensure the stack has at least 'n' elements */ /* Ensure the stack has at least 'n' elements */
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ #define api_checknelems(L,n) \
"not enough elements in the stack") api_check(L, (n) < (L->top.p - L->ci->func.p), \
"not enough elements in the stack")
/* /*

View File

@ -80,6 +80,7 @@ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
int top = lua_gettop(L); int top = lua_gettop(L);
lua_getinfo(L, "f", ar); /* push function */ lua_getinfo(L, "f", ar); /* push function */
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
luaL_checkstack(L, 6, "not enough stack"); /* slots for 'findfield' */
if (findfield(L, top + 1, 2)) { if (findfield(L, top + 1, 2)) {
const char *name = lua_tostring(L, -1); const char *name = lua_tostring(L, -1);
if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */ if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */
@ -249,11 +250,13 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
return 1; return 1;
} }
else { else {
const char *msg;
luaL_pushfail(L); luaL_pushfail(L);
msg = (en != 0) ? strerror(en) : "(no extra info)";
if (fname) if (fname)
lua_pushfstring(L, "%s: %s", fname, strerror(en)); lua_pushfstring(L, "%s: %s", fname, msg);
else else
lua_pushstring(L, strerror(en)); lua_pushstring(L, msg);
lua_pushinteger(L, en); lua_pushinteger(L, en);
return 3; return 3;
} }
@ -526,13 +529,14 @@ static void newbox (lua_State *L) {
/* /*
** Compute new size for buffer 'B', enough to accommodate extra 'sz' ** Compute new size for buffer 'B', enough to accommodate extra 'sz'
** bytes. ** bytes. (The test for "not big enough" also gets the case when the
** computation of 'newsize' overflows.)
*/ */
static size_t newbuffsize (luaL_Buffer *B, size_t sz) { static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
size_t newsize = B->size * 2; /* double buffer size */ size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */
if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */ if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */
return luaL_error(B->L, "buffer too large"); return luaL_error(B->L, "buffer too large");
if (newsize < B->n + sz) /* double is not big enough? */ if (newsize < B->n + sz) /* not big enough? */
newsize = B->n + sz; newsize = B->n + sz;
return newsize; return newsize;
} }
@ -611,7 +615,7 @@ LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
** box (if existent) is not on the top of the stack. So, instead of ** box (if existent) is not on the top of the stack. So, instead of
** calling 'luaL_addlstring', it replicates the code using -2 as the ** calling 'luaL_addlstring', it replicates the code using -2 as the
** last argument to 'prepbuffsize', signaling that the box is (or will ** last argument to 'prepbuffsize', signaling that the box is (or will
** be) bellow the string being added to the buffer. (Box creation can ** be) below the string being added to the buffer. (Box creation can
** trigger an emergency GC, so we should not remove the string from the ** trigger an emergency GC, so we should not remove the string from the
** stack before we have the space guaranteed.) ** stack before we have the space guaranteed.)
*/ */
@ -731,25 +735,29 @@ static const char *getF (lua_State *L, void *ud, size_t *size) {
static int errfile (lua_State *L, const char *what, int fnameindex) { static int errfile (lua_State *L, const char *what, int fnameindex) {
const char *serr = strerror(errno); int err = errno;
const char *filename = lua_tostring(L, fnameindex) + 1; const char *filename = lua_tostring(L, fnameindex) + 1;
lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); if (err != 0)
lua_pushfstring(L, "cannot %s %s: %s", what, filename, strerror(err));
else
lua_pushfstring(L, "cannot %s %s", what, filename);
lua_remove(L, fnameindex); lua_remove(L, fnameindex);
return LUA_ERRFILE; return LUA_ERRFILE;
} }
static int skipBOM (LoadF *lf) { /*
const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ ** Skip an optional BOM at the start of a stream. If there is an
int c; ** incomplete BOM (the first character is correct but the rest is
lf->n = 0; ** not), returns the first character anyway to force an error
do { ** (as no chunk can start with 0xEF).
c = getc(lf->f); */
if (c == EOF || c != *(const unsigned char *)p++) return c; static int skipBOM (FILE *f) {
lf->buff[lf->n++] = c; /* to be read by the parser */ int c = getc(f); /* read first character */
} while (*p != '\0'); if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */
lf->n = 0; /* prefix matched; discard it */ return getc(f); /* ignore BOM and return next char */
return getc(lf->f); /* return next character */ else /* no (valid) BOM */
return c; /* return first character */
} }
@ -760,13 +768,13 @@ static int skipBOM (LoadF *lf) {
** first "valid" character of the file (after the optional BOM and ** first "valid" character of the file (after the optional BOM and
** a first-line comment). ** a first-line comment).
*/ */
static int skipcomment (LoadF *lf, int *cp) { static int skipcomment (FILE *f, int *cp) {
int c = *cp = skipBOM(lf); int c = *cp = skipBOM(f);
if (c == '#') { /* first line is a comment (Unix exec. file)? */ if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */ do { /* skip first line */
c = getc(lf->f); c = getc(f);
} while (c != EOF && c != '\n'); } while (c != EOF && c != '\n');
*cp = getc(lf->f); /* skip end-of-line, if present */ *cp = getc(f); /* next character after comment, if present */
return 1; /* there was a comment */ return 1; /* there was a comment */
} }
else return 0; /* no comment */ else return 0; /* no comment */
@ -785,18 +793,25 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
} }
else { else {
lua_pushfstring(L, "@%s", filename); lua_pushfstring(L, "@%s", filename);
errno = 0;
lf.f = fopen(filename, "r"); lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex); if (lf.f == NULL) return errfile(L, "open", fnameindex);
} }
if (skipcomment(&lf, &c)) /* read initial portion */ lf.n = 0;
lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ if (skipcomment(lf.f, &c)) /* read initial portion */
if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ if (c == LUA_SIGNATURE[0]) { /* binary file? */
if (lf.f == NULL) return errfile(L, "reopen", fnameindex); lf.n = 0; /* remove possible newline */
skipcomment(&lf, &c); /* re-read initial portion */ if (filename) { /* "real" file? */
errno = 0;
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
skipcomment(lf.f, &c); /* re-read initial portion */
}
} }
if (c != EOF) if (c != EOF)
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
errno = 0;
status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
readstatus = ferror(lf.f); readstatus = ferror(lf.f);
if (filename) fclose(lf.f); /* close file (even in case of errors) */ if (filename) fclose(lf.f); /* close file (even in case of errors) */
@ -927,7 +942,7 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
luaL_checkstack(L, nup, "too many upvalues"); luaL_checkstack(L, nup, "too many upvalues");
for (; l->name != NULL; l++) { /* fill the table with given functions */ for (; l->name != NULL; l++) { /* fill the table with given functions */
if (l->func == NULL) /* place holder? */ if (l->func == NULL) /* placeholder? */
lua_pushboolean(L, 0); lua_pushboolean(L, 0);
else { else {
int i; int i;
@ -1019,9 +1034,14 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
} }
/*
** Standard panic funcion just prints an error message. The test
** with 'lua_type' avoids possible memory errors in 'lua_tostring'.
*/
static int panic (lua_State *L) { static int panic (lua_State *L) {
const char *msg = lua_tostring(L, -1); const char *msg = (lua_type(L, -1) == LUA_TSTRING)
if (msg == NULL) msg = "error object is not a string"; ? lua_tostring(L, -1)
: "error object is not a string";
lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
msg); msg);
return 0; /* return to Lua to abort */ return 0; /* return to Lua to abort */

View File

@ -415,7 +415,7 @@ int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
/* /*
** Format and emit an 'iAsBx' instruction. ** Format and emit an 'iAsBx' instruction.
*/ */
int luaK_codeAsBx (FuncState *fs, OpCode o, int a, int bc) { static int codeAsBx (FuncState *fs, OpCode o, int a, int bc) {
unsigned int b = bc + OFFSET_sBx; unsigned int b = bc + OFFSET_sBx;
lua_assert(getOpMode(o) == iAsBx); lua_assert(getOpMode(o) == iAsBx);
lua_assert(a <= MAXARG_A && b <= MAXARG_Bx); lua_assert(a <= MAXARG_A && b <= MAXARG_Bx);
@ -671,7 +671,7 @@ static int fitsBx (lua_Integer i) {
void luaK_int (FuncState *fs, int reg, lua_Integer i) { void luaK_int (FuncState *fs, int reg, lua_Integer i) {
if (fitsBx(i)) if (fitsBx(i))
luaK_codeAsBx(fs, OP_LOADI, reg, cast_int(i)); codeAsBx(fs, OP_LOADI, reg, cast_int(i));
else else
luaK_codek(fs, reg, luaK_intK(fs, i)); luaK_codek(fs, reg, luaK_intK(fs, i));
} }
@ -680,7 +680,7 @@ void luaK_int (FuncState *fs, int reg, lua_Integer i) {
static void luaK_float (FuncState *fs, int reg, lua_Number f) { static void luaK_float (FuncState *fs, int reg, lua_Number f) {
lua_Integer fi; lua_Integer fi;
if (luaV_flttointeger(f, &fi, F2Ieq) && fitsBx(fi)) if (luaV_flttointeger(f, &fi, F2Ieq) && fitsBx(fi))
luaK_codeAsBx(fs, OP_LOADF, reg, cast_int(fi)); codeAsBx(fs, OP_LOADF, reg, cast_int(fi));
else else
luaK_codek(fs, reg, luaK_numberK(fs, f)); luaK_codek(fs, reg, luaK_numberK(fs, f));
} }
@ -776,7 +776,8 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
break; break;
} }
case VLOCAL: { /* already in a register */ case VLOCAL: { /* already in a register */
e->u.info = e->u.var.ridx; int temp = e->u.var.ridx;
e->u.info = temp; /* (can't do a direct assignment; values overlap) */
e->k = VNONRELOC; /* becomes a non-relocatable value */ e->k = VNONRELOC; /* becomes a non-relocatable value */
break; break;
} }
@ -1025,7 +1026,7 @@ static int luaK_exp2K (FuncState *fs, expdesc *e) {
** in the range of R/K indices). ** in the range of R/K indices).
** Returns 1 iff expression is K. ** Returns 1 iff expression is K.
*/ */
int luaK_exp2RK (FuncState *fs, expdesc *e) { static int exp2RK (FuncState *fs, expdesc *e) {
if (luaK_exp2K(fs, e)) if (luaK_exp2K(fs, e))
return 1; return 1;
else { /* not a constant in the right range: put it in a register */ else { /* not a constant in the right range: put it in a register */
@ -1037,7 +1038,7 @@ int luaK_exp2RK (FuncState *fs, expdesc *e) {
static void codeABRK (FuncState *fs, OpCode o, int a, int b, static void codeABRK (FuncState *fs, OpCode o, int a, int b,
expdesc *ec) { expdesc *ec) {
int k = luaK_exp2RK(fs, ec); int k = exp2RK(fs, ec);
luaK_codeABCk(fs, o, a, b, ec->u.info, k); luaK_codeABCk(fs, o, a, b, ec->u.info, k);
} }
@ -1215,7 +1216,7 @@ static void codenot (FuncState *fs, expdesc *e) {
/* /*
** Check whether expression 'e' is a small literal string ** Check whether expression 'e' is a short literal string
*/ */
static int isKstr (FuncState *fs, expdesc *e) { static int isKstr (FuncState *fs, expdesc *e) {
return (e->k == VK && !hasjumps(e) && e->u.info <= MAXARG_B && return (e->k == VK && !hasjumps(e) && e->u.info <= MAXARG_B &&
@ -1225,7 +1226,7 @@ static int isKstr (FuncState *fs, expdesc *e) {
/* /*
** Check whether expression 'e' is a literal integer. ** Check whether expression 'e' is a literal integer.
*/ */
int luaK_isKint (expdesc *e) { static int isKint (expdesc *e) {
return (e->k == VKINT && !hasjumps(e)); return (e->k == VKINT && !hasjumps(e));
} }
@ -1235,7 +1236,7 @@ int luaK_isKint (expdesc *e) {
** proper range to fit in register C ** proper range to fit in register C
*/ */
static int isCint (expdesc *e) { static int isCint (expdesc *e) {
return luaK_isKint(e) && (l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C)); return isKint(e) && (l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C));
} }
@ -1244,7 +1245,7 @@ static int isCint (expdesc *e) {
** proper range to fit in register sC ** proper range to fit in register sC
*/ */
static int isSCint (expdesc *e) { static int isSCint (expdesc *e) {
return luaK_isKint(e) && fitsC(e->u.ival); return isKint(e) && fitsC(e->u.ival);
} }
@ -1283,15 +1284,17 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */ if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */
luaK_exp2anyreg(fs, t); /* put it in a register */ luaK_exp2anyreg(fs, t); /* put it in a register */
if (t->k == VUPVAL) { if (t->k == VUPVAL) {
t->u.ind.t = t->u.info; /* upvalue index */ int temp = t->u.info; /* upvalue index */
t->u.ind.idx = k->u.info; /* literal string */ lua_assert(isKstr(fs, k));
t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */
t->u.ind.idx = k->u.info; /* literal short string */
t->k = VINDEXUP; t->k = VINDEXUP;
} }
else { else {
/* register index of the table */ /* register index of the table */
t->u.ind.t = (t->k == VLOCAL) ? t->u.var.ridx: t->u.info; t->u.ind.t = (t->k == VLOCAL) ? t->u.var.ridx: t->u.info;
if (isKstr(fs, k)) { if (isKstr(fs, k)) {
t->u.ind.idx = k->u.info; /* literal string */ t->u.ind.idx = k->u.info; /* literal short string */
t->k = VINDEXSTR; t->k = VINDEXSTR;
} }
else if (isCint(k)) { else if (isCint(k)) {
@ -1351,6 +1354,35 @@ static int constfolding (FuncState *fs, int op, expdesc *e1,
} }
/*
** Convert a BinOpr to an OpCode (ORDER OPR - ORDER OP)
*/
l_sinline OpCode binopr2op (BinOpr opr, BinOpr baser, OpCode base) {
lua_assert(baser <= opr &&
((baser == OPR_ADD && opr <= OPR_SHR) ||
(baser == OPR_LT && opr <= OPR_LE)));
return cast(OpCode, (cast_int(opr) - cast_int(baser)) + cast_int(base));
}
/*
** Convert a UnOpr to an OpCode (ORDER OPR - ORDER OP)
*/
l_sinline OpCode unopr2op (UnOpr opr) {
return cast(OpCode, (cast_int(opr) - cast_int(OPR_MINUS)) +
cast_int(OP_UNM));
}
/*
** Convert a BinOpr to a tag method (ORDER OPR - ORDER TM)
*/
l_sinline TMS binopr2TM (BinOpr opr) {
lua_assert(OPR_ADD <= opr && opr <= OPR_SHR);
return cast(TMS, (cast_int(opr) - cast_int(OPR_ADD)) + cast_int(TM_ADD));
}
/* /*
** Emit code for unary expressions that "produce values" ** Emit code for unary expressions that "produce values"
** (everything but 'not'). ** (everything but 'not').
@ -1389,12 +1421,15 @@ static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2,
** Emit code for binary expressions that "produce values" over ** Emit code for binary expressions that "produce values" over
** two registers. ** two registers.
*/ */
static void codebinexpval (FuncState *fs, OpCode op, static void codebinexpval (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) { expdesc *e1, expdesc *e2, int line) {
int v2 = luaK_exp2anyreg(fs, e2); /* both operands are in registers */ OpCode op = binopr2op(opr, OPR_ADD, OP_ADD);
int v2 = luaK_exp2anyreg(fs, e2); /* make sure 'e2' is in a register */
/* 'e1' must be already in a register or it is a constant */
lua_assert((VNIL <= e1->k && e1->k <= VKSTR) ||
e1->k == VNONRELOC || e1->k == VRELOC);
lua_assert(OP_ADD <= op && op <= OP_SHR); lua_assert(OP_ADD <= op && op <= OP_SHR);
finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, binopr2TM(opr));
cast(TMS, (op - OP_ADD) + TM_ADD));
} }
@ -1410,12 +1445,24 @@ static void codebini (FuncState *fs, OpCode op,
} }
/*
** Code binary operators with K operand.
*/
static void codebinK (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
TMS event = binopr2TM(opr);
int v2 = e2->u.info; /* K index */
OpCode op = binopr2op(opr, OPR_ADD, OP_ADDK);
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
}
/* Try to code a binary operator negating its second operand. /* Try to code a binary operator negating its second operand.
** For the metamethod, 2nd operand must keep its original value. ** For the metamethod, 2nd operand must keep its original value.
*/ */
static int finishbinexpneg (FuncState *fs, expdesc *e1, expdesc *e2, static int finishbinexpneg (FuncState *fs, expdesc *e1, expdesc *e2,
OpCode op, int line, TMS event) { OpCode op, int line, TMS event) {
if (!luaK_isKint(e2)) if (!isKint(e2))
return 0; /* not an integer constant */ return 0; /* not an integer constant */
else { else {
lua_Integer i2 = e2->u.ival; lua_Integer i2 = e2->u.ival;
@ -1437,24 +1484,27 @@ static void swapexps (expdesc *e1, expdesc *e2) {
} }
/*
** Code binary operators with no constant operand.
*/
static void codebinNoK (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
if (flip)
swapexps(e1, e2); /* back to original order */
codebinexpval(fs, opr, e1, e2, line); /* use standard operators */
}
/* /*
** Code arithmetic operators ('+', '-', ...). If second operand is a ** Code arithmetic operators ('+', '-', ...). If second operand is a
** constant in the proper range, use variant opcodes with K operands. ** constant in the proper range, use variant opcodes with K operands.
*/ */
static void codearith (FuncState *fs, BinOpr opr, static void codearith (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) { expdesc *e1, expdesc *e2, int flip, int line) {
TMS event = cast(TMS, opr + TM_ADD); if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) /* K operand? */
if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */ codebinK(fs, opr, e1, e2, flip, line);
int v2 = e2->u.info; /* K index */ else /* 'e2' is neither an immediate nor a K operand */
OpCode op = cast(OpCode, opr + OP_ADDK); codebinNoK(fs, opr, e1, e2, flip, line);
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 */
}
} }
@ -1471,35 +1521,27 @@ static void codecommutative (FuncState *fs, BinOpr op,
flip = 1; flip = 1;
} }
if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */ if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */
codebini(fs, cast(OpCode, OP_ADDI), e1, e2, flip, line, TM_ADD); codebini(fs, OP_ADDI, e1, e2, flip, line, TM_ADD);
else else
codearith(fs, op, e1, e2, flip, line); codearith(fs, op, e1, e2, flip, line);
} }
/* /*
** Code bitwise operations; they are all associative, so the function ** Code bitwise operations; they are all commutative, so the function
** tries to put an integer constant as the 2nd operand (a K operand). ** tries to put an integer constant as the 2nd operand (a K operand).
*/ */
static void codebitwise (FuncState *fs, BinOpr opr, static void codebitwise (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) { expdesc *e1, expdesc *e2, int line) {
int flip = 0; int flip = 0;
int v2; if (e1->k == VKINT) {
OpCode op;
if (e1->k == VKINT && luaK_exp2RK(fs, e1)) {
swapexps(e1, e2); /* 'e2' will be the constant operand */ swapexps(e1, e2); /* 'e2' will be the constant operand */
flip = 1; flip = 1;
} }
else if (!(e2->k == VKINT && luaK_exp2RK(fs, e2))) { /* no constants? */ if (e2->k == VKINT && luaK_exp2K(fs, e2)) /* K operand? */
op = cast(OpCode, opr + OP_ADD); codebinK(fs, opr, e1, e2, flip, line);
codebinexpval(fs, op, e1, e2, line); /* all-register opcodes */ else /* no constants */
return; codebinNoK(fs, opr, e1, e2, flip, line);
}
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));
} }
@ -1507,25 +1549,27 @@ static void codebitwise (FuncState *fs, BinOpr opr,
** Emit code for order comparisons. When using an immediate operand, ** Emit code for order comparisons. When using an immediate operand,
** 'isfloat' tells whether the original value was a float. ** 'isfloat' tells whether the original value was a float.
*/ */
static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
int r1, r2; int r1, r2;
int im; int im;
int isfloat = 0; int isfloat = 0;
OpCode op;
if (isSCnumber(e2, &im, &isfloat)) { if (isSCnumber(e2, &im, &isfloat)) {
/* use immediate operand */ /* use immediate operand */
r1 = luaK_exp2anyreg(fs, e1); r1 = luaK_exp2anyreg(fs, e1);
r2 = im; r2 = im;
op = cast(OpCode, (op - OP_LT) + OP_LTI); op = binopr2op(opr, OPR_LT, OP_LTI);
} }
else if (isSCnumber(e1, &im, &isfloat)) { else if (isSCnumber(e1, &im, &isfloat)) {
/* transform (A < B) to (B > A) and (A <= B) to (B >= A) */ /* transform (A < B) to (B > A) and (A <= B) to (B >= A) */
r1 = luaK_exp2anyreg(fs, e2); r1 = luaK_exp2anyreg(fs, e2);
r2 = im; r2 = im;
op = (op == OP_LT) ? OP_GTI : OP_GEI; op = binopr2op(opr, OPR_LT, OP_GTI);
} }
else { /* regular case, compare two registers */ else { /* regular case, compare two registers */
r1 = luaK_exp2anyreg(fs, e1); r1 = luaK_exp2anyreg(fs, e1);
r2 = luaK_exp2anyreg(fs, e2); r2 = luaK_exp2anyreg(fs, e2);
op = binopr2op(opr, OPR_LT, OP_LT);
} }
freeexps(fs, e1, e2); freeexps(fs, e1, e2);
e1->u.info = condjump(fs, op, r1, r2, isfloat, 1); e1->u.info = condjump(fs, op, r1, r2, isfloat, 1);
@ -1551,7 +1595,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
op = OP_EQI; op = OP_EQI;
r2 = im; /* immediate operand */ r2 = im; /* immediate operand */
} }
else if (luaK_exp2RK(fs, e2)) { /* 1st expression is constant? */ else if (exp2RK(fs, e2)) { /* 2nd expression is constant? */
op = OP_EQK; op = OP_EQK;
r2 = e2->u.info; /* constant index */ r2 = e2->u.info; /* constant index */
} }
@ -1568,16 +1612,16 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
/* /*
** Apply prefix operation 'op' to expression 'e'. ** Apply prefix operation 'op' to expression 'e'.
*/ */
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { void luaK_prefix (FuncState *fs, UnOpr opr, expdesc *e, int line) {
static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
luaK_dischargevars(fs, e); luaK_dischargevars(fs, e);
switch (op) { switch (opr) {
case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */ case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */
if (constfolding(fs, op + LUA_OPUNM, e, &ef)) if (constfolding(fs, opr + LUA_OPUNM, e, &ef))
break; break;
/* else */ /* FALLTHROUGH */ /* else */ /* FALLTHROUGH */
case OPR_LEN: case OPR_LEN:
codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); codeunexpval(fs, unopr2op(opr), e, line);
break; break;
case OPR_NOT: codenot(fs, e); break; case OPR_NOT: codenot(fs, e); break;
default: lua_assert(0); default: lua_assert(0);
@ -1611,12 +1655,13 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
case OPR_SHL: case OPR_SHR: { case OPR_SHL: case OPR_SHR: {
if (!tonumeral(v, NULL)) if (!tonumeral(v, NULL))
luaK_exp2anyreg(fs, v); luaK_exp2anyreg(fs, v);
/* else keep numeral, which may be folded with 2nd operand */ /* else keep numeral, which may be folded or used as an immediate
operand */
break; break;
} }
case OPR_EQ: case OPR_NE: { case OPR_EQ: case OPR_NE: {
if (!tonumeral(v, NULL)) if (!tonumeral(v, NULL))
luaK_exp2RK(fs, v); exp2RK(fs, v);
/* else keep numeral, which may be an immediate operand */ /* else keep numeral, which may be an immediate operand */
break; break;
} }
@ -1706,30 +1751,27 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
/* coded as (r1 >> -I) */; /* coded as (r1 >> -I) */;
} }
else /* regular case (two registers) */ else /* regular case (two registers) */
codebinexpval(fs, OP_SHL, e1, e2, line); codebinexpval(fs, opr, e1, e2, line);
break; break;
} }
case OPR_SHR: { case OPR_SHR: {
if (isSCint(e2)) if (isSCint(e2))
codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */ codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */
else /* regular case (two registers) */ else /* regular case (two registers) */
codebinexpval(fs, OP_SHR, e1, e2, line); codebinexpval(fs, opr, e1, e2, line);
break; break;
} }
case OPR_EQ: case OPR_NE: { case OPR_EQ: case OPR_NE: {
codeeq(fs, opr, e1, e2); codeeq(fs, opr, e1, e2);
break; break;
} }
case OPR_LT: case OPR_LE: {
OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
codeorder(fs, op, e1, e2);
break;
}
case OPR_GT: case OPR_GE: { case OPR_GT: case OPR_GE: {
/* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */ /* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */
OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
swapexps(e1, e2); swapexps(e1, e2);
codeorder(fs, op, e1, e2); opr = cast(BinOpr, (opr - OPR_GT) + OPR_LT);
} /* FALLTHROUGH */
case OPR_LT: case OPR_LE: {
codeorder(fs, opr, e1, e2);
break; break;
} }
default: lua_assert(0); default: lua_assert(0);

View File

@ -61,10 +61,8 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
LUAI_FUNC int luaK_code (FuncState *fs, Instruction i); LUAI_FUNC int luaK_code (FuncState *fs, Instruction i);
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx);
LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
int B, int C, int k); int B, int C, int k);
LUAI_FUNC int luaK_isKint (expdesc *e);
LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v); LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
LUAI_FUNC void luaK_fixline (FuncState *fs, int line); LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
@ -76,7 +74,6 @@ LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);

View File

@ -76,7 +76,7 @@ static int luaB_auxwrap (lua_State *L) {
if (l_unlikely(r < 0)) { /* error? */ if (l_unlikely(r < 0)) { /* error? */
int stat = lua_status(co); int stat = lua_status(co);
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
stat = lua_resetthread(co); /* close its tbc variables */ stat = lua_closethread(co, L); /* close its tbc variables */
lua_assert(stat != LUA_OK); lua_assert(stat != LUA_OK);
lua_xmove(co, L, 1); /* move error message to the caller */ 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); int status = auxstatus(L, co);
switch (status) { switch (status) {
case COS_DEAD: case COS_YIELD: { case COS_DEAD: case COS_YIELD: {
status = lua_resetthread(co); status = lua_closethread(co, L);
if (status == LUA_OK) { if (status == LUA_OK) {
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
return 1; return 1;

View File

@ -31,7 +31,7 @@
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) #define LuaClosure(f) ((f) != NULL && (f)->c.tt == LUA_VLCL)
static const char *funcnamefromcall (lua_State *L, CallInfo *ci, static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
@ -182,10 +182,10 @@ static const char *upvalname (const Proto *p, int uv) {
static const char *findvararg (CallInfo *ci, int n, StkId *pos) { static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
if (clLvalue(s2v(ci->func))->p->is_vararg) { if (clLvalue(s2v(ci->func.p))->p->is_vararg) {
int nextra = ci->u.l.nextraargs; int nextra = ci->u.l.nextraargs;
if (n >= -nextra) { /* 'n' is negative */ if (n >= -nextra) { /* 'n' is negative */
*pos = ci->func - nextra - (n + 1); *pos = ci->func.p - nextra - (n + 1);
return "(vararg)"; /* generic name for any vararg */ return "(vararg)"; /* generic name for any vararg */
} }
} }
@ -194,7 +194,7 @@ static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) { const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
StkId base = ci->func + 1; StkId base = ci->func.p + 1;
const char *name = NULL; const char *name = NULL;
if (isLua(ci)) { if (isLua(ci)) {
if (n < 0) /* access to vararg values? */ if (n < 0) /* access to vararg values? */
@ -203,7 +203,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
} }
if (name == NULL) { /* no 'standard' name? */ if (name == NULL) { /* no 'standard' name? */
StkId limit = (ci == L->ci) ? L->top : ci->next->func; StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */ if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
/* generic name for any valid slot */ /* generic name for any valid slot */
name = isLua(ci) ? "(temporary)" : "(C temporary)"; name = isLua(ci) ? "(temporary)" : "(C temporary)";
@ -221,16 +221,16 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
const char *name; const char *name;
lua_lock(L); lua_lock(L);
if (ar == NULL) { /* information about non-active function? */ if (ar == NULL) { /* information about non-active function? */
if (!isLfunction(s2v(L->top - 1))) /* not a Lua function? */ if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */
name = NULL; name = NULL;
else /* consider live variables at function start (parameters) */ else /* consider live variables at function start (parameters) */
name = luaF_getlocalname(clLvalue(s2v(L->top - 1))->p, n, 0); name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
} }
else { /* active function; get information through 'ar' */ else { /* active function; get information through 'ar' */
StkId pos = NULL; /* to avoid warnings */ StkId pos = NULL; /* to avoid warnings */
name = luaG_findlocal(L, ar->i_ci, n, &pos); name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) { if (name) {
setobjs2s(L, L->top, pos); setobjs2s(L, L->top.p, pos);
api_incr_top(L); api_incr_top(L);
} }
} }
@ -245,8 +245,8 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
lua_lock(L); lua_lock(L);
name = luaG_findlocal(L, ar->i_ci, n, &pos); name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) { if (name) {
setobjs2s(L, pos, L->top - 1); setobjs2s(L, pos, L->top.p - 1);
L->top--; /* pop value */ L->top.p--; /* pop value */
} }
lua_unlock(L); lua_unlock(L);
return name; return name;
@ -254,7 +254,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
static void funcinfo (lua_Debug *ar, Closure *cl) { static void funcinfo (lua_Debug *ar, Closure *cl) {
if (noLuaClosure(cl)) { if (!LuaClosure(cl)) {
ar->source = "=[C]"; ar->source = "=[C]";
ar->srclen = LL("=[C]"); ar->srclen = LL("=[C]");
ar->linedefined = -1; ar->linedefined = -1;
@ -288,29 +288,31 @@ static int nextline (const Proto *p, int currentline, int pc) {
static void collectvalidlines (lua_State *L, Closure *f) { static void collectvalidlines (lua_State *L, Closure *f) {
if (noLuaClosure(f)) { if (!LuaClosure(f)) {
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
api_incr_top(L); api_incr_top(L);
} }
else { else {
int i;
TValue v;
const Proto *p = f->l.p; const Proto *p = f->l.p;
int currentline = p->linedefined; int currentline = p->linedefined;
Table *t = luaH_new(L); /* new table to store active lines */ Table *t = luaH_new(L); /* new table to store active lines */
sethvalue2s(L, L->top, t); /* push it on stack */ sethvalue2s(L, L->top.p, t); /* push it on stack */
api_incr_top(L); api_incr_top(L);
setbtvalue(&v); /* boolean 'true' to be the value of all indices */ if (p->lineinfo != NULL) { /* proto with debug information? */
if (!p->is_vararg) /* regular function? */ int i;
i = 0; /* consider all instructions */ TValue v;
else { /* vararg function */ setbtvalue(&v); /* boolean 'true' to be the value of all indices */
lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); if (!p->is_vararg) /* regular function? */
currentline = nextline(p, currentline, 0); i = 0; /* consider all instructions */
i = 1; /* skip first instruction (OP_VARARGPREP) */ else { /* vararg function */
} lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
for (; i < p->sizelineinfo; i++) { /* for each instruction */ currentline = nextline(p, currentline, 0);
currentline = nextline(p, currentline, i); /* get its line */ i = 1; /* skip first instruction (OP_VARARGPREP) */
luaH_setint(L, t, currentline, &v); /* table[line] = true */ }
for (; i < p->sizelineinfo; i++) { /* for each instruction */
currentline = nextline(p, currentline, i); /* get its line */
luaH_setint(L, t, currentline, &v); /* table[line] = true */
}
} }
} }
} }
@ -339,7 +341,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
} }
case 'u': { case 'u': {
ar->nups = (f == NULL) ? 0 : f->c.nupvalues; ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
if (noLuaClosure(f)) { if (!LuaClosure(f)) {
ar->isvararg = 1; ar->isvararg = 1;
ar->nparams = 0; ar->nparams = 0;
} }
@ -388,20 +390,20 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
lua_lock(L); lua_lock(L);
if (*what == '>') { if (*what == '>') {
ci = NULL; ci = NULL;
func = s2v(L->top - 1); func = s2v(L->top.p - 1);
api_check(L, ttisfunction(func), "function expected"); api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */ what++; /* skip the '>' */
L->top--; /* pop function */ L->top.p--; /* pop function */
} }
else { else {
ci = ar->i_ci; ci = ar->i_ci;
func = s2v(ci->func); func = s2v(ci->func.p);
lua_assert(ttisfunction(func)); lua_assert(ttisfunction(func));
} }
cl = ttisclosure(func) ? clvalue(func) : NULL; cl = ttisclosure(func) ? clvalue(func) : NULL;
status = auxgetinfo(L, what, ar, cl, ci); status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) { if (strchr(what, 'f')) {
setobj2s(L, L->top, func); setobj2s(L, L->top.p, func);
api_incr_top(L); api_incr_top(L);
} }
if (strchr(what, 'L')) if (strchr(what, 'L'))
@ -417,40 +419,6 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
** ======================================================= ** =======================================================
*/ */
static const char *getobjname (const Proto *p, int lastpc, int reg,
const char **name);
/*
** Find a "name" for the constant 'c'.
*/
static void kname (const Proto *p, int c, const char **name) {
TValue *kvalue = &p->k[c];
*name = (ttisstring(kvalue)) ? svalue(kvalue) : "?";
}
/*
** Find a "name" for the register 'c'.
*/
static void rname (const Proto *p, int pc, int c, const char **name) {
const char *what = getobjname(p, pc, c, name); /* search for 'c' */
if (!(what && *what == 'c')) /* did not find a constant name? */
*name = "?";
}
/*
** Find a "name" for a 'C' value in an RK instruction.
*/
static void rkname (const Proto *p, int pc, Instruction i, const char **name) {
int c = GETARG_C(i); /* key index */
if (GETARG_k(i)) /* is 'c' a constant? */
kname(p, c, name);
else /* 'c' is a register */
rname(p, pc, c, name);
}
static int filterpc (int pc, int jmptarget) { static int filterpc (int pc, int jmptarget) {
if (pc < jmptarget) /* is code conditional (inside a jump)? */ if (pc < jmptarget) /* is code conditional (inside a jump)? */
@ -509,28 +477,29 @@ static int findsetreg (const Proto *p, int lastpc, int reg) {
/* /*
** Check whether table being indexed by instruction 'i' is the ** Find a "name" for the constant 'c'.
** environment '_ENV'
*/ */
static const char *gxf (const Proto *p, int pc, Instruction i, int isup) { static const char *kname (const Proto *p, int index, const char **name) {
int t = GETARG_B(i); /* table index */ TValue *kvalue = &p->k[index];
const char *name; /* name of indexed variable */ if (ttisstring(kvalue)) {
if (isup) /* is an upvalue? */ *name = getstr(tsvalue(kvalue));
name = upvalname(p, t); return "constant";
else }
getobjname(p, pc, t, &name); else {
return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field"; *name = "?";
return NULL;
}
} }
static const char *getobjname (const Proto *p, int lastpc, int reg, static const char *basicgetobjname (const Proto *p, int *ppc, int reg,
const char **name) { const char **name) {
int pc; int pc = *ppc;
*name = luaF_getlocalname(p, reg + 1, lastpc); *name = luaF_getlocalname(p, reg + 1, pc);
if (*name) /* is a local? */ if (*name) /* is a local? */
return "local"; return "local";
/* else try symbolic execution */ /* else try symbolic execution */
pc = findsetreg(p, lastpc, reg); *ppc = pc = findsetreg(p, pc, reg);
if (pc != -1) { /* could find instruction? */ if (pc != -1) { /* could find instruction? */
Instruction i = p->code[pc]; Instruction i = p->code[pc];
OpCode op = GET_OPCODE(i); OpCode op = GET_OPCODE(i);
@ -538,18 +507,80 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
case OP_MOVE: { case OP_MOVE: {
int b = GETARG_B(i); /* move from 'b' to 'a' */ int b = GETARG_B(i); /* move from 'b' to 'a' */
if (b < GETARG_A(i)) if (b < GETARG_A(i))
return getobjname(p, pc, b, name); /* get name for 'b' */ return basicgetobjname(p, ppc, b, name); /* get name for 'b' */
break; break;
} }
case OP_GETUPVAL: {
*name = upvalname(p, GETARG_B(i));
return "upvalue";
}
case OP_LOADK: return kname(p, GETARG_Bx(i), name);
case OP_LOADKX: return kname(p, GETARG_Ax(p->code[pc + 1]), name);
default: break;
}
}
return NULL; /* could not find reasonable name */
}
/*
** Find a "name" for the register 'c'.
*/
static void rname (const Proto *p, int pc, int c, const char **name) {
const char *what = basicgetobjname(p, &pc, c, name); /* search for 'c' */
if (!(what && *what == 'c')) /* did not find a constant name? */
*name = "?";
}
/*
** Find a "name" for a 'C' value in an RK instruction.
*/
static void rkname (const Proto *p, int pc, Instruction i, const char **name) {
int c = GETARG_C(i); /* key index */
if (GETARG_k(i)) /* is 'c' a constant? */
kname(p, c, name);
else /* 'c' is a register */
rname(p, pc, c, name);
}
/*
** Check whether table being indexed by instruction 'i' is the
** environment '_ENV'
*/
static const char *isEnv (const Proto *p, int pc, Instruction i, int isup) {
int t = GETARG_B(i); /* table index */
const char *name; /* name of indexed variable */
if (isup) /* is 't' an upvalue? */
name = upvalname(p, t);
else /* 't' is a register */
basicgetobjname(p, &pc, t, &name);
return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field";
}
/*
** Extend 'basicgetobjname' to handle table accesses
*/
static const char *getobjname (const Proto *p, int lastpc, int reg,
const char **name) {
const char *kind = basicgetobjname(p, &lastpc, reg, name);
if (kind != NULL)
return kind;
else if (lastpc != -1) { /* could find instruction? */
Instruction i = p->code[lastpc];
OpCode op = GET_OPCODE(i);
switch (op) {
case OP_GETTABUP: { case OP_GETTABUP: {
int k = GETARG_C(i); /* key index */ int k = GETARG_C(i); /* key index */
kname(p, k, name); kname(p, k, name);
return gxf(p, pc, i, 1); return isEnv(p, lastpc, i, 1);
} }
case OP_GETTABLE: { case OP_GETTABLE: {
int k = GETARG_C(i); /* key index */ int k = GETARG_C(i); /* key index */
rname(p, pc, k, name); rname(p, lastpc, k, name);
return gxf(p, pc, i, 0); return isEnv(p, lastpc, i, 0);
} }
case OP_GETI: { case OP_GETI: {
*name = "integer index"; *name = "integer index";
@ -558,24 +589,10 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
case OP_GETFIELD: { case OP_GETFIELD: {
int k = GETARG_C(i); /* key index */ int k = GETARG_C(i); /* key index */
kname(p, k, name); kname(p, k, name);
return gxf(p, pc, i, 0); return isEnv(p, lastpc, i, 0);
}
case OP_GETUPVAL: {
*name = upvalname(p, GETARG_B(i));
return "upvalue";
}
case OP_LOADK:
case OP_LOADKX: {
int b = (op == OP_LOADK) ? GETARG_Bx(i)
: GETARG_Ax(p->code[pc + 1]);
if (ttisstring(&p->k[b])) {
*name = svalue(&p->k[b]);
return "constant";
}
break;
} }
case OP_SELF: { case OP_SELF: {
rkname(p, pc, i, name); rkname(p, lastpc, i, name);
return "method"; return "method";
} }
default: break; /* go through to return NULL */ default: break; /* go through to return NULL */
@ -627,7 +644,7 @@ static const char *funcnamefromcode (lua_State *L, const Proto *p,
default: default:
return NULL; /* cannot find a reasonable name */ return NULL; /* cannot find a reasonable name */
} }
*name = getstr(G(L)->tmname[tm]) + 2; *name = getshrstr(G(L)->tmname[tm]) + 2;
return "metamethod"; return "metamethod";
} }
@ -656,18 +673,19 @@ static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
/* /*
** Check whether pointer 'o' points to some value in the stack ** Check whether pointer 'o' points to some value in the stack frame of
** frame of the current function. Because 'o' may not point to a ** the current function and, if so, returns its index. Because 'o' may
** value in this stack, we cannot compare it with the region ** not point to a value in this stack, we cannot compare it with the
** boundaries (undefined behaviour in ISO C). ** region boundaries (undefined behavior in ISO C).
*/ */
static int isinstack (CallInfo *ci, const TValue *o) { static int instack (CallInfo *ci, const TValue *o) {
StkId pos; int pos;
for (pos = ci->func + 1; pos < ci->top; pos++) { StkId base = ci->func.p + 1;
if (o == s2v(pos)) for (pos = 0; base + pos < ci->top.p; pos++) {
return 1; if (o == s2v(base + pos))
return pos;
} }
return 0; /* not found */ return -1; /* not found */
} }
@ -681,7 +699,7 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
LClosure *c = ci_func(ci); LClosure *c = ci_func(ci);
int i; int i;
for (i = 0; i < c->nupvalues; i++) { for (i = 0; i < c->nupvalues; i++) {
if (c->upvals[i]->v == o) { if (c->upvals[i]->v.p == o) {
*name = upvalname(c->p, i); *name = upvalname(c->p, i);
return "upvalue"; return "upvalue";
} }
@ -708,9 +726,11 @@ static const char *varinfo (lua_State *L, const TValue *o) {
const char *kind = NULL; const char *kind = NULL;
if (isLua(ci)) { if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
if (!kind && isinstack(ci, o)) /* no? try a register */ if (!kind) { /* not an upvalue? */
kind = getobjname(ci_func(ci)->p, currentpc(ci), int reg = instack(ci, o); /* try a register */
cast_int(cast(StkId, o) - (ci->func + 1)), &name); if (reg >= 0) /* is 'o' a register? */
kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name);
}
} }
return formatvarinfo(L, kind, name); return formatvarinfo(L, kind, name);
} }
@ -807,10 +827,10 @@ l_noret luaG_errormsg (lua_State *L) {
if (L->errfunc != 0) { /* is there an error handling function? */ if (L->errfunc != 0) { /* is there an error handling function? */
StkId errfunc = restorestack(L, L->errfunc); StkId errfunc = restorestack(L, L->errfunc);
lua_assert(ttisfunction(s2v(errfunc))); lua_assert(ttisfunction(s2v(errfunc)));
setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */
setobjs2s(L, L->top - 1, errfunc); /* push function */ setobjs2s(L, L->top.p - 1, errfunc); /* push function */
L->top++; /* assume EXTRA_STACK */ L->top.p++; /* assume EXTRA_STACK */
luaD_callnoyield(L, L->top - 2, 1); /* call it */ luaD_callnoyield(L, L->top.p - 2, 1); /* call it */
} }
luaD_throw(L, LUA_ERRRUN); luaD_throw(L, LUA_ERRRUN);
} }
@ -824,8 +844,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
va_start(argp, fmt); va_start(argp, fmt);
msg = luaO_pushvfstring(L, fmt, argp); /* format message */ msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp); va_end(argp);
if (isLua(ci)) /* if Lua function, add source:line information */ if (isLua(ci)) { /* if Lua function, add source:line information */
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci)); luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
L->top.p--;
}
luaG_errormsg(L); luaG_errormsg(L);
} }
@ -842,7 +865,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
if (p->lineinfo == NULL) /* no debug information? */ if (p->lineinfo == NULL) /* no debug information? */
return 0; return 0;
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */ if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
int delta = 0; /* line diference */ int delta = 0; /* line difference */
int pc = oldpc; int pc = oldpc;
for (;;) { for (;;) {
int lineinfo = p->lineinfo[++pc]; int lineinfo = p->lineinfo[++pc];
@ -859,6 +882,28 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
} }
/*
** Traces Lua calls. If code is running the first instruction of a function,
** and function is not vararg, and it is not coming from an yield,
** calls 'luaD_hookcall'. (Vararg functions will call 'luaD_hookcall'
** after adjusting its variable arguments; otherwise, they could call
** a line/count hook before the call hook. Functions coming from
** an yield already called 'luaD_hookcall' before yielding.)
*/
int luaG_tracecall (lua_State *L) {
CallInfo *ci = L->ci;
Proto *p = ci_func(ci)->p;
ci->u.l.trap = 1; /* ensure hooks will be checked */
if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */
if (p->is_vararg)
return 0; /* hooks will start at VARARGPREP instruction */
else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yieded? */
luaD_hookcall(L, ci); /* check 'call' hook */
}
return 1; /* keep 'trap' on */
}
/* /*
** Traces the execution of a Lua function. Called before the execution ** Traces the execution of a Lua function. Called before the execution
** of each opcode, when debug is on. 'L->oldpc' stores the last ** of each opcode, when debug is on. 'L->oldpc' stores the last
@ -869,7 +914,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc' ** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
** at most causes an extra call to a line hook.) ** at most causes an extra call to a line hook.)
** This function is not "Protected" when called, so it should correct ** This function is not "Protected" when called, so it should correct
** 'L->top' before calling anything that can run the GC. ** 'L->top.p' before calling anything that can run the GC.
*/ */
int luaG_traceexec (lua_State *L, const Instruction *pc) { int luaG_traceexec (lua_State *L, const Instruction *pc) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
@ -882,17 +927,17 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
} }
pc++; /* reference is always next instruction */ pc++; /* reference is always next instruction */
ci->u.l.savedpc = pc; /* save 'pc' */ ci->u.l.savedpc = pc; /* save 'pc' */
counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); counthook = (mask & LUA_MASKCOUNT) && (--L->hookcount == 0);
if (counthook) if (counthook)
resethookcount(L); /* reset count */ resethookcount(L); /* reset count */
else if (!(mask & LUA_MASKLINE)) else if (!(mask & LUA_MASKLINE))
return 1; /* no line hook and count != 0; nothing to be done now */ return 1; /* no line hook and count != 0; nothing to be done now */
if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ if (ci->callstatus & CIST_HOOKYIELD) { /* hook yielded last time? */
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
return 1; /* do not call hook again (VM yielded, so it did not move) */ return 1; /* do not call hook again (VM yielded, so it did not move) */
} }
if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */ if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
L->top = ci->top; /* correct top */ L->top.p = ci->top.p; /* correct top */
if (counthook) if (counthook)
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */ luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
if (mask & LUA_MASKLINE) { if (mask & LUA_MASKLINE) {
@ -909,7 +954,6 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
if (L->status == LUA_YIELD) { /* did hook yield? */ if (L->status == LUA_YIELD) { /* did hook yield? */
if (counthook) if (counthook)
L->hookcount = 1; /* undo decrement to zero */ L->hookcount = 1; /* undo decrement to zero */
ci->u.l.savedpc--; /* undo increment (resume will increment it again) */
ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
luaD_throw(L, LUA_YIELD); luaD_throw(L, LUA_YIELD);
} }

View File

@ -15,7 +15,7 @@
/* Active Lua function (given call info) */ /* Active Lua function (given call info) */
#define ci_func(ci) (clLvalue(s2v((ci)->func))) #define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
#define resethookcount(L) (L->hookcount = L->basehookcount) #define resethookcount(L) (L->hookcount = L->basehookcount)
@ -58,6 +58,7 @@ LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
TString *src, int line); TString *src, int line);
LUAI_FUNC l_noret luaG_errormsg (lua_State *L); LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc); LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
LUAI_FUNC int luaG_tracecall (lua_State *L);
#endif #endif

239
3rdparty/lua/src/ldo.c vendored
View File

@ -104,11 +104,11 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
} }
default: { default: {
lua_assert(errorstatus(errcode)); /* real error */ lua_assert(errorstatus(errcode)); /* real error */
setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */
break; break;
} }
} }
L->top = oldtop + 1; L->top.p = oldtop + 1;
} }
@ -121,7 +121,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
global_State *g = G(L); global_State *g = G(L);
errcode = luaE_resetthread(L, errcode); /* close all upvalues */ errcode = luaE_resetthread(L, errcode); /* close all upvalues */
if (g->mainthread->errorJmp) { /* main thread has a handler? */ if (g->mainthread->errorJmp) { /* main thread has a handler? */
setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ setobjs2s(L, g->mainthread->top.p++, L->top.p - 1); /* copy error obj. */
luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ luaD_throw(g->mainthread, errcode); /* re-throw in main thread */
} }
else { /* no handler at all; abort */ else { /* no handler at all; abort */
@ -157,16 +157,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
** Stack reallocation ** Stack reallocation
** =================================================================== ** ===================================================================
*/ */
static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
/*
** Change all pointers to the stack into offsets.
*/
static void relstack (lua_State *L) {
CallInfo *ci; CallInfo *ci;
UpVal *up; UpVal *up;
L->top = (L->top - oldstack) + newstack; L->top.offset = savestack(L, L->top.p);
L->tbclist = (L->tbclist - oldstack) + newstack; L->tbclist.offset = savestack(L, L->tbclist.p);
for (up = L->openupval; up != NULL; up = up->u.open.next) for (up = L->openupval; up != NULL; up = up->u.open.next)
up->v = s2v((uplevel(up) - oldstack) + newstack); up->v.offset = savestack(L, uplevel(up));
for (ci = L->ci; ci != NULL; ci = ci->previous) { for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top = (ci->top - oldstack) + newstack; ci->top.offset = savestack(L, ci->top.p);
ci->func = (ci->func - oldstack) + newstack; 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.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.p = s2v(restorestack(L, up->v.offset));
for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top.p = restorestack(L, ci->top.offset);
ci->func.p = restorestack(L, ci->func.offset);
if (isLua(ci)) if (isLua(ci))
ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */ ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
} }
@ -176,44 +198,45 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
/* some space for error handling */ /* some space for error handling */
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) #define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
/* /*
** Reallocate the stack to a new size, correcting all pointers into ** Reallocate the stack to a new size, correcting all pointers into it.
** it. (There are pointers to a stack from its upvalues, from its list ** In ISO C, any pointer use after the pointer has been deallocated is
** of call infos, plus a few individual pointers.) The reallocation is ** undefined behavior. So, before the reallocation, all pointers are
** done in two steps (allocation + free) because the correction must be ** changed to offsets, and after the reallocation they are changed back
** done while both addresses (the old stack and the new one) are valid. ** to pointers. As during the reallocation the pointers are invalid, the
** (In ISO C, any pointer use after the pointer has been deallocated is ** reallocation cannot run emergency collections.
** undefined behavior.) **
** In case of allocation error, raise an error or return false according ** In case of allocation error, raise an error or return false according
** to 'raiseerror'. ** to 'raiseerror'.
*/ */
int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
int oldsize = stacksize(L); int oldsize = stacksize(L);
int i; int i;
StkId newstack = luaM_reallocvector(L, NULL, 0, StkId newstack;
newsize + EXTRA_STACK, StackValue); int oldgcstop = G(L)->gcstopem;
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
relstack(L); /* change pointers to offsets */
G(L)->gcstopem = 1; /* stop emergency collection */
newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
newsize + EXTRA_STACK, StackValue);
G(L)->gcstopem = oldgcstop; /* restore emergency collection */
if (l_unlikely(newstack == NULL)) { /* reallocation failed? */ if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
correctstack(L); /* change offsets back to pointers */
if (raiseerror) if (raiseerror)
luaM_error(L); luaM_error(L);
else return 0; /* do not raise an error */ else return 0; /* do not raise an error */
} }
/* number of elements to be copied to the new stack */ L->stack.p = newstack;
i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK; correctstack(L); /* change offsets back to pointers */
memcpy(newstack, L->stack, i * sizeof(StackValue)); L->stack_last.p = L->stack.p + newsize;
for (; i < newsize + EXTRA_STACK; i++) for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
setnilvalue(s2v(newstack + i)); /* erase new segment */ setnilvalue(s2v(newstack + i)); /* erase new segment */
correctstack(L, L->stack, newstack);
luaM_freearray(L, L->stack, oldsize + EXTRA_STACK);
L->stack = newstack;
L->stack_last = L->stack + newsize;
return 1; return 1;
} }
/* /*
** Try to grow the stack by at least 'n' elements. when 'raiseerror' ** Try to grow the stack by at least 'n' elements. When 'raiseerror'
** is true, raises any error; otherwise, return 0 in case of errors. ** is true, raises any error; otherwise, return 0 in case of errors.
*/ */
int luaD_growstack (lua_State *L, int n, int raiseerror) { int luaD_growstack (lua_State *L, int n, int raiseerror) {
@ -227,35 +250,38 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) {
luaD_throw(L, LUA_ERRERR); /* error inside message handler */ luaD_throw(L, LUA_ERRERR); /* error inside message handler */
return 0; /* if not 'raiseerror', just signal it */ return 0; /* if not 'raiseerror', just signal it */
} }
else { else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */
int newsize = 2 * size; /* tentative new size */ int newsize = 2 * size; /* tentative new size */
int needed = cast_int(L->top - L->stack) + n; int needed = cast_int(L->top.p - L->stack.p) + n;
if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */ if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */
newsize = LUAI_MAXSTACK; newsize = LUAI_MAXSTACK;
if (newsize < needed) /* but must respect what was asked for */ if (newsize < needed) /* but must respect what was asked for */
newsize = needed; newsize = needed;
if (l_likely(newsize <= LUAI_MAXSTACK)) if (l_likely(newsize <= LUAI_MAXSTACK))
return luaD_reallocstack(L, newsize, raiseerror); return luaD_reallocstack(L, newsize, raiseerror);
else { /* stack overflow */
/* add extra size to be able to handle the error message */
luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
if (raiseerror)
luaG_runerror(L, "stack overflow");
return 0;
}
} }
/* else stack overflow */
/* add extra size to be able to handle the error message */
luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
if (raiseerror)
luaG_runerror(L, "stack overflow");
return 0;
} }
/*
** Compute how much of the stack is being used, by computing the
** maximum top of all call frames in the stack and the current top.
*/
static int stackinuse (lua_State *L) { static int stackinuse (lua_State *L) {
CallInfo *ci; CallInfo *ci;
int res; int res;
StkId lim = L->top; StkId lim = L->top.p;
for (ci = L->ci; ci != NULL; ci = ci->previous) { for (ci = L->ci; ci != NULL; ci = ci->previous) {
if (lim < ci->top) lim = ci->top; if (lim < ci->top.p) lim = ci->top.p;
} }
lua_assert(lim <= L->stack_last); lua_assert(lim <= L->stack_last.p + EXTRA_STACK);
res = cast_int(lim - L->stack) + 1; /* part of stack in use */ res = cast_int(lim - L->stack.p) + 1; /* part of stack in use */
if (res < LUA_MINSTACK) if (res < LUA_MINSTACK)
res = LUA_MINSTACK; /* ensure a minimum size */ res = LUA_MINSTACK; /* ensure a minimum size */
return res; return res;
@ -273,17 +299,13 @@ static int stackinuse (lua_State *L) {
*/ */
void luaD_shrinkstack (lua_State *L) { void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L); int inuse = stackinuse(L);
int nsize = inuse * 2; /* proposed new size */ int max = (inuse > LUAI_MAXSTACK / 3) ? LUAI_MAXSTACK : inuse * 3;
int max = inuse * 3; /* maximum "reasonable" size */
if (max > LUAI_MAXSTACK) {
max = LUAI_MAXSTACK; /* respect stack limit */
if (nsize > LUAI_MAXSTACK)
nsize = LUAI_MAXSTACK;
}
/* if thread is currently not handling a stack overflow and its /* if thread is currently not handling a stack overflow and its
size is larger than maximum "reasonable" size, shrink it */ size is larger than maximum "reasonable" size, shrink it */
if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) {
int nsize = (inuse > LUAI_MAXSTACK / 2) ? LUAI_MAXSTACK : inuse * 2;
luaD_reallocstack(L, nsize, 0); /* ok if that fails */ luaD_reallocstack(L, nsize, 0); /* ok if that fails */
}
else /* don't change stack */ else /* don't change stack */
condmovestack(L,{},{}); /* (change only for debugging) */ condmovestack(L,{},{}); /* (change only for debugging) */
luaE_shrinkCI(L); /* shrink CI list */ luaE_shrinkCI(L); /* shrink CI list */
@ -292,7 +314,7 @@ void luaD_shrinkstack (lua_State *L) {
void luaD_inctop (lua_State *L) { void luaD_inctop (lua_State *L) {
luaD_checkstack(L, 1); luaD_checkstack(L, 1);
L->top++; L->top.p++;
} }
/* }================================================================== */ /* }================================================================== */
@ -309,8 +331,8 @@ void luaD_hook (lua_State *L, int event, int line,
if (hook && L->allowhook) { /* make sure there is a hook */ if (hook && L->allowhook) { /* make sure there is a hook */
int mask = CIST_HOOKED; int mask = CIST_HOOKED;
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top); /* preserve original 'top' */ ptrdiff_t top = savestack(L, L->top.p); /* preserve original 'top' */
ptrdiff_t ci_top = savestack(L, ci->top); /* idem for 'ci->top' */ ptrdiff_t ci_top = savestack(L, ci->top.p); /* idem for 'ci->top' */
lua_Debug ar; lua_Debug ar;
ar.event = event; ar.event = event;
ar.currentline = line; ar.currentline = line;
@ -320,11 +342,11 @@ void luaD_hook (lua_State *L, int event, int line,
ci->u2.transferinfo.ftransfer = ftransfer; ci->u2.transferinfo.ftransfer = ftransfer;
ci->u2.transferinfo.ntransfer = ntransfer; ci->u2.transferinfo.ntransfer = ntransfer;
} }
if (isLua(ci) && L->top < ci->top) if (isLua(ci) && L->top.p < ci->top.p)
L->top = ci->top; /* protect entire activation register */ L->top.p = ci->top.p; /* protect entire activation register */
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
if (ci->top < L->top + LUA_MINSTACK) if (ci->top.p < L->top.p + LUA_MINSTACK)
ci->top = L->top + LUA_MINSTACK; ci->top.p = L->top.p + LUA_MINSTACK;
L->allowhook = 0; /* cannot call hooks inside a hook */ L->allowhook = 0; /* cannot call hooks inside a hook */
ci->callstatus |= mask; ci->callstatus |= mask;
lua_unlock(L); lua_unlock(L);
@ -332,8 +354,8 @@ void luaD_hook (lua_State *L, int event, int line,
lua_lock(L); lua_lock(L);
lua_assert(!L->allowhook); lua_assert(!L->allowhook);
L->allowhook = 1; L->allowhook = 1;
ci->top = restorestack(L, ci_top); ci->top.p = restorestack(L, ci_top);
L->top = restorestack(L, top); L->top.p = restorestack(L, top);
ci->callstatus &= ~mask; ci->callstatus &= ~mask;
} }
} }
@ -364,7 +386,7 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) {
*/ */
static void rethook (lua_State *L, CallInfo *ci, int nres) { static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (L->hookmask & LUA_MASKRET) { /* is return hook on? */ if (L->hookmask & LUA_MASKRET) { /* is return hook on? */
StkId firstres = L->top - nres; /* index of first result */ StkId firstres = L->top.p - nres; /* index of first result */
int delta = 0; /* correction for vararg functions */ int delta = 0; /* correction for vararg functions */
int ftransfer; int ftransfer;
if (isLua(ci)) { if (isLua(ci)) {
@ -372,10 +394,10 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (p->is_vararg) if (p->is_vararg)
delta = ci->u.l.nextraargs + p->numparams + 1; delta = ci->u.l.nextraargs + p->numparams + 1;
} }
ci->func += delta; /* if vararg, back to virtual 'func' */ ci->func.p += delta; /* if vararg, back to virtual 'func' */
ftransfer = cast(unsigned short, firstres - ci->func); ftransfer = cast(unsigned short, firstres - ci->func.p);
luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */ luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */
ci->func -= delta; ci->func.p -= delta;
} }
if (isLua(ci = ci->previous)) if (isLua(ci = ci->previous))
L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */ L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */
@ -387,16 +409,16 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
** stack, below original 'func', so that 'luaD_precall' can call it. Raise ** stack, below original 'func', so that 'luaD_precall' can call it. Raise
** an error if there is no '__call' metafield. ** an error if there is no '__call' metafield.
*/ */
StkId luaD_tryfuncTM (lua_State *L, StkId func) { static StkId tryfuncTM (lua_State *L, StkId func) {
const TValue *tm; const TValue *tm;
StkId p; StkId p;
checkstackGCp(L, 1, func); /* space for metamethod */ checkstackGCp(L, 1, func); /* space for metamethod */
tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */ tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */
if (l_unlikely(ttisnil(tm))) if (l_unlikely(ttisnil(tm)))
luaG_callerror(L, s2v(func)); /* nothing to call */ luaG_callerror(L, s2v(func)); /* nothing to call */
for (p = L->top; p > func; p--) /* open space for metamethod */ for (p = L->top.p; p > func; p--) /* open space for metamethod */
setobjs2s(L, p, p-1); setobjs2s(L, p, p-1);
L->top++; /* stack space pre-allocated by the caller */ L->top.p++; /* stack space pre-allocated by the caller */
setobj2s(L, func, tm); /* metamethod is the new function to be called */ setobj2s(L, func, tm); /* metamethod is the new function to be called */
return func; return func;
} }
@ -413,28 +435,29 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
int i; int i;
switch (wanted) { /* handle typical cases separately */ switch (wanted) { /* handle typical cases separately */
case 0: /* no values needed */ case 0: /* no values needed */
L->top = res; L->top.p = res;
return; return;
case 1: /* one value needed */ case 1: /* one value needed */
if (nres == 0) /* no results? */ if (nres == 0) /* no results? */
setnilvalue(s2v(res)); /* adjust with nil */ setnilvalue(s2v(res)); /* adjust with nil */
else /* at least one result */ else /* at least one result */
setobjs2s(L, res, L->top - nres); /* move it to proper place */ setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
L->top = res + 1; L->top.p = res + 1;
return; return;
case LUA_MULTRET: case LUA_MULTRET:
wanted = nres; /* we want all results */ wanted = nres; /* we want all results */
break; break;
default: /* two/more results and/or to-be-closed variables */ default: /* two/more results and/or to-be-closed variables */
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
ptrdiff_t savedres = savestack(L, res);
L->ci->callstatus |= CIST_CLSRET; /* in case of yields */ L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
L->ci->u2.nres = nres; L->ci->u2.nres = nres;
luaF_close(L, res, CLOSEKTOP, 1); res = luaF_close(L, res, CLOSEKTOP, 1);
L->ci->callstatus &= ~CIST_CLSRET; L->ci->callstatus &= ~CIST_CLSRET;
if (L->hookmask) /* if needed, call hook after '__close's */ if (L->hookmask) { /* if needed, call hook after '__close's */
ptrdiff_t savedres = savestack(L, res);
rethook(L, L->ci, nres); rethook(L, L->ci, nres);
res = restorestack(L, savedres); /* close and hook can move stack */ res = restorestack(L, savedres); /* hook can move stack */
}
wanted = decodeNresults(wanted); wanted = decodeNresults(wanted);
if (wanted == LUA_MULTRET) if (wanted == LUA_MULTRET)
wanted = nres; /* we want all results */ wanted = nres; /* we want all results */
@ -442,14 +465,14 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
break; break;
} }
/* generic case */ /* generic case */
firstresult = L->top - nres; /* index of first result */ firstresult = L->top.p - nres; /* index of first result */
if (nres > wanted) /* extra results? */ if (nres > wanted) /* extra results? */
nres = wanted; /* don't need them */ nres = wanted; /* don't need them */
for (i = 0; i < nres; i++) /* move all results to correct place */ for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstresult + i); setobjs2s(L, res + i, firstresult + i);
for (; i < wanted; i++) /* complete wanted number of results */ for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(s2v(res + i)); setnilvalue(s2v(res + i));
L->top = res + wanted; /* top points after the last result */ L->top.p = res + wanted; /* top points after the last result */
} }
@ -464,7 +487,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted))) if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
rethook(L, ci, nres); rethook(L, ci, nres);
/* move results to proper place */ /* move results to proper place */
moveresults(L, ci->func, nres, wanted); moveresults(L, ci->func.p, nres, wanted);
/* function cannot be in any of these cases when returning */ /* function cannot be in any of these cases when returning */
lua_assert(!(ci->callstatus & lua_assert(!(ci->callstatus &
(CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET))); (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
@ -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, l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,
int mask, StkId top) { int mask, StkId top) {
CallInfo *ci = L->ci = next_ci(L); /* new frame */ CallInfo *ci = L->ci = next_ci(L); /* new frame */
ci->func = func; ci->func.p = func;
ci->nresults = nret; ci->nresults = nret;
ci->callstatus = mask; ci->callstatus = mask;
ci->top = top; ci->top.p = top;
return ci; return ci;
} }
@ -496,10 +519,10 @@ l_sinline int precallC (lua_State *L, StkId func, int nresults,
CallInfo *ci; CallInfo *ci;
checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
L->ci = ci = prepCallInfo(L, func, nresults, CIST_C, L->ci = ci = prepCallInfo(L, func, nresults, CIST_C,
L->top + LUA_MINSTACK); L->top.p + LUA_MINSTACK);
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top.p <= L->stack_last.p);
if (l_unlikely(L->hookmask & LUA_MASKCALL)) { if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
int narg = cast_int(L->top - func) - 1; int narg = cast_int(L->top.p - func) - 1;
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg); luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
} }
lua_unlock(L); lua_unlock(L);
@ -531,21 +554,21 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int nfixparams = p->numparams; int nfixparams = p->numparams;
int i; int i;
checkstackGCp(L, fsize - delta, func); 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 */ for (i = 0; i < narg1; i++) /* move down function and arguments */
setobjs2s(L, ci->func + i, func + i); setobjs2s(L, ci->func.p + i, func + i);
func = ci->func; /* moved-down function */ func = ci->func.p; /* moved-down function */
for (; narg1 <= nfixparams; narg1++) for (; narg1 <= nfixparams; narg1++)
setnilvalue(s2v(func + narg1)); /* complete missing arguments */ setnilvalue(s2v(func + narg1)); /* complete missing arguments */
ci->top = func + 1 + fsize; /* top for new function */ ci->top.p = func + 1 + fsize; /* top for new function */
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top.p <= L->stack_last.p);
ci->u.l.savedpc = p->code; /* starting point */ ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus |= CIST_TAIL; ci->callstatus |= CIST_TAIL;
L->top = func + narg1; /* set top */ L->top.p = func + narg1; /* set top */
return -1; return -1;
} }
default: { /* not a function */ default: { /* not a function */
func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ func = tryfuncTM(L, func); /* try to get '__call' metamethod */
/* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */ /* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */
narg1++; narg1++;
goto retry; /* try again */ goto retry; /* try again */
@ -574,19 +597,19 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
case LUA_VLCL: { /* Lua function */ case LUA_VLCL: { /* Lua function */
CallInfo *ci; CallInfo *ci;
Proto *p = clLvalue(s2v(func))->p; Proto *p = clLvalue(s2v(func))->p;
int narg = cast_int(L->top - func) - 1; /* number of real arguments */ int narg = cast_int(L->top.p - func) - 1; /* number of real arguments */
int nfixparams = p->numparams; int nfixparams = p->numparams;
int fsize = p->maxstacksize; /* frame size */ int fsize = p->maxstacksize; /* frame size */
checkstackGCp(L, fsize, func); checkstackGCp(L, fsize, func);
L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize); L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize);
ci->u.l.savedpc = p->code; /* starting point */ ci->u.l.savedpc = p->code; /* starting point */
for (; narg < nfixparams; narg++) for (; narg < nfixparams; narg++)
setnilvalue(s2v(L->top++)); /* complete missing arguments */ setnilvalue(s2v(L->top.p++)); /* complete missing arguments */
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top.p <= L->stack_last.p);
return ci; return ci;
} }
default: { /* not a function */ default: { /* not a function */
func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ func = tryfuncTM(L, func); /* try to get '__call' metamethod */
/* return luaD_precall(L, func, nresults); */ /* return luaD_precall(L, func, nresults); */
goto retry; /* try again with metamethod */ goto retry; /* try again with metamethod */
} }
@ -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 ** Call a function (C or Lua) through C. 'inc' can be 1 (increment
** number of recursive invocations in the C stack) or nyci (the same ** number of recursive invocations in the C stack) or nyci (the same
** plus increment number of non-yieldable calls). ** plus increment number of non-yieldable calls).
** This function can be called with some use of EXTRA_STACK, so it should
** check the stack before doing anything else. 'luaD_precall' already
** does that.
*/ */
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; CallInfo *ci;
L->nCcalls += inc; L->nCcalls += inc;
if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) {
checkstackp(L, 0, func); /* free any use of EXTRA_STACK */
luaE_checkcstack(L); luaE_checkcstack(L);
}
if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */ if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */
ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */
luaV_execute(L, ci); /* call it */ luaV_execute(L, ci); /* call it */
@ -651,8 +679,7 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
else { /* error */ else { /* error */
StkId func = restorestack(L, ci->u2.funcidx); StkId func = restorestack(L, ci->u2.funcidx);
L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */ L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */
luaF_close(L, func, status, 1); /* can yield or raise an error */ func = luaF_close(L, func, status, 1); /* can yield or raise an error */
func = restorestack(L, ci->u2.funcidx); /* stack may be moved */
luaD_seterrorobj(L, status, func); luaD_seterrorobj(L, status, func);
luaD_shrinkstack(L); /* restore stack size in case of overflow */ luaD_shrinkstack(L); /* restore stack size in case of overflow */
setcistrecst(ci, LUA_OK); /* clear original status */ setcistrecst(ci, LUA_OK); /* clear original status */
@ -740,8 +767,8 @@ static CallInfo *findpcall (lua_State *L) {
** coroutine error handler and should not kill the coroutine.) ** coroutine error handler and should not kill the coroutine.)
*/ */
static int resume_error (lua_State *L, const char *msg, int narg) { static int resume_error (lua_State *L, const char *msg, int narg) {
L->top -= narg; /* remove args from the stack */ L->top.p -= narg; /* remove args from the stack */
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ setsvalue2s(L, L->top.p, luaS_new(L, msg)); /* push error message */
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return LUA_ERRRUN; return LUA_ERRRUN;
@ -757,7 +784,7 @@ static int resume_error (lua_State *L, const char *msg, int narg) {
*/ */
static void resume (lua_State *L, void *ud) { static void resume (lua_State *L, void *ud) {
int n = *(cast(int*, ud)); /* number of arguments */ int n = *(cast(int*, ud)); /* number of arguments */
StkId firstArg = L->top - n; /* first argument */ StkId firstArg = L->top.p - n; /* first argument */
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (L->status == LUA_OK) /* starting a coroutine? */ if (L->status == LUA_OK) /* starting a coroutine? */
ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */ ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */
@ -765,7 +792,11 @@ static void resume (lua_State *L, void *ud) {
lua_assert(L->status == LUA_YIELD); lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */ L->status = LUA_OK; /* mark that it is running (again) */
if (isLua(ci)) { /* yielded inside a hook? */ if (isLua(ci)) { /* yielded inside a hook? */
L->top = firstArg; /* discard arguments */ /* undo increment made by 'luaG_traceexec': instruction was not
executed yet */
lua_assert(ci->callstatus & CIST_HOOKYIELD);
ci->u.l.savedpc--;
L->top.p = firstArg; /* discard arguments */
luaV_execute(L, ci); /* just continue running Lua code */ luaV_execute(L, ci); /* just continue running Lua code */
} }
else { /* 'common' yield */ else { /* 'common' yield */
@ -808,7 +839,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->status == LUA_OK) { /* may be starting a coroutine */
if (L->ci != &L->base_ci) /* not in base level? */ if (L->ci != &L->base_ci) /* not in base level? */
return resume_error(L, "cannot resume non-suspended coroutine", nargs); return resume_error(L, "cannot resume non-suspended coroutine", nargs);
else if (L->top - (L->ci->func + 1) == nargs) /* no function? */ else if (L->top.p - (L->ci->func.p + 1) == nargs) /* no function? */
return resume_error(L, "cannot resume dead coroutine", nargs); return resume_error(L, "cannot resume dead coroutine", nargs);
} }
else if (L->status != LUA_YIELD) /* ended with errors? */ else if (L->status != LUA_YIELD) /* ended with errors? */
@ -826,11 +857,11 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
lua_assert(status == L->status); /* normal end or yield */ lua_assert(status == L->status); /* normal end or yield */
else { /* unrecoverable error */ else { /* unrecoverable error */
L->status = cast_byte(status); /* mark thread as 'dead' */ L->status = cast_byte(status); /* mark thread as 'dead' */
luaD_seterrorobj(L, status, L->top); /* push error message */ luaD_seterrorobj(L, status, L->top.p); /* push error message */
L->ci->top = L->top; L->ci->top.p = L->top.p;
} }
*nresults = (status == LUA_YIELD) ? L->ci->u2.nyield *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield
: cast_int(L->top - (L->ci->func + 1)); : cast_int(L->top.p - (L->ci->func.p + 1));
lua_unlock(L); lua_unlock(L);
return status; return status;
} }
@ -985,7 +1016,7 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
p.dyd.gt.arr = NULL; p.dyd.gt.size = 0; p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
p.dyd.label.arr = NULL; p.dyd.label.size = 0; p.dyd.label.arr = NULL; p.dyd.label.size = 0;
luaZ_initbuffer(L, &p.buff); luaZ_initbuffer(L, &p.buff);
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); status = luaD_pcall(L, f_parser, &p, savestack(L, L->top.p), L->errfunc);
luaZ_freebuffer(L, &p.buff); luaZ_freebuffer(L, &p.buff);
luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);

View File

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

View File

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

View File

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

View File

@ -29,10 +29,10 @@
#define MAXUPVAL 255 #define MAXUPVAL 255
#define upisopen(up) ((up)->v != &(up)->u.value) #define upisopen(up) ((up)->v.p != &(up)->u.value)
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v)) #define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p))
/* /*
@ -54,7 +54,7 @@ LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level); LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy); LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy);
LUAI_FUNC void luaF_unlinkupval (UpVal *uv); LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,

124
3rdparty/lua/src/lgc.c vendored
View File

@ -252,12 +252,13 @@ void luaC_fix (lua_State *L, GCObject *o) {
/* /*
** create a new collectable object (with given type and size) and link ** create a new collectable object (with given type, size, and offset)
** it to 'allgc' list. ** and link it to 'allgc' list.
*/ */
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
global_State *g = G(L); global_State *g = G(L);
GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz)); char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
GCObject *o = cast(GCObject *, p + offset);
o->marked = luaC_white(g); o->marked = luaC_white(g);
o->tt = tt; o->tt = tt;
o->next = g->allgc; o->next = g->allgc;
@ -265,6 +266,11 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return o; return o;
} }
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return luaC_newobjdt(L, tt, sz, 0);
}
/* }====================================================== */ /* }====================================================== */
@ -301,7 +307,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
set2gray(uv); /* open upvalues are kept gray */ set2gray(uv); /* open upvalues are kept gray */
else else
set2black(uv); /* closed upvalues are visited here */ set2black(uv); /* closed upvalues are visited here */
markvalue(g, uv->v); /* mark its content */ markvalue(g, uv->v.p); /* mark its content */
break; break;
} }
case LUA_VUSERDATA: { case LUA_VUSERDATA: {
@ -376,7 +382,7 @@ static int remarkupvals (global_State *g) {
work++; work++;
if (!iswhite(uv)) { /* upvalue already visited? */ if (!iswhite(uv)) { /* upvalue already visited? */
lua_assert(upisopen(uv) && isgray(uv)); lua_assert(upisopen(uv) && isgray(uv));
markvalue(g, uv->v); /* mark its value */ markvalue(g, uv->v.p); /* mark its value */
} }
} }
} }
@ -536,10 +542,12 @@ static void traversestrongtable (global_State *g, Table *h) {
static lu_mem traversetable (global_State *g, Table *h) { static lu_mem traversetable (global_State *g, Table *h) {
const char *weakkey, *weakvalue; const char *weakkey, *weakvalue;
const TValue *mode = gfasttm(g, h->metatable, TM_MODE); const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
TString *smode;
markobjectN(g, h->metatable); markobjectN(g, h->metatable);
if (mode && ttisstring(mode) && /* is there a weak mode? */ if (mode && ttisshrstring(mode) && /* is there a weak mode? */
(cast_void(weakkey = strchr(svalue(mode), 'k')), (cast_void(smode = tsvalue(mode)),
cast_void(weakvalue = strchr(svalue(mode), 'v')), cast_void(weakkey = strchr(getshrstr(smode), 'k')),
cast_void(weakvalue = strchr(getshrstr(smode), 'v')),
(weakkey || weakvalue))) { /* is really weak? */ (weakkey || weakvalue))) { /* is really weak? */
if (!weakkey) /* strong keys? */ if (!weakkey) /* strong keys? */
traverseweakvalue(g, h); traverseweakvalue(g, h);
@ -620,19 +628,21 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
*/ */
static int traversethread (global_State *g, lua_State *th) { static int traversethread (global_State *g, lua_State *th) {
UpVal *uv; UpVal *uv;
StkId o = th->stack; StkId o = th->stack.p;
if (isold(th) || g->gcstate == GCSpropagate) if (isold(th) || g->gcstate == GCSpropagate)
linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
if (o == NULL) if (o == NULL)
return 1; /* stack not completely built yet */ return 1; /* stack not completely built yet */
lua_assert(g->gcstate == GCSatomic || lua_assert(g->gcstate == GCSatomic ||
th->openupval == NULL || isintwups(th)); th->openupval == NULL || isintwups(th));
for (; o < th->top; o++) /* mark live elements in the stack */ for (; o < th->top.p; o++) /* mark live elements in the stack */
markvalue(g, s2v(o)); markvalue(g, s2v(o));
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next) for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
markobject(g, uv); /* open upvalues cannot be collected */ markobject(g, uv); /* open upvalues cannot be collected */
if (g->gcstate == GCSatomic) { /* final traversal? */ if (g->gcstate == GCSatomic) { /* final traversal? */
for (; o < th->stack_last + EXTRA_STACK; o++) if (!g->gcemergency)
luaD_shrinkstack(th); /* do not change stack in emergency cycle */
for (o = th->top.p; o < th->stack_last.p + EXTRA_STACK; o++)
setnilvalue(s2v(o)); /* clear dead stack slice */ setnilvalue(s2v(o)); /* clear dead stack slice */
/* 'remarkupvals' may have removed thread from 'twups' list */ /* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) { if (!isintwups(th) && th->openupval != NULL) {
@ -640,8 +650,6 @@ static int traversethread (global_State *g, lua_State *th) {
g->twups = th; g->twups = th;
} }
} }
else if (!g->gcemergency)
luaD_shrinkstack(th); /* do not change stack in emergency cycle */
return 1 + stacksize(th); return 1 + stacksize(th);
} }
@ -892,7 +900,7 @@ static GCObject *udata2finalize (global_State *g) {
static void dothecall (lua_State *L, void *ud) { static void dothecall (lua_State *L, void *ud) {
UNUSED(ud); UNUSED(ud);
luaD_callnoyield(L, L->top - 2, 0); luaD_callnoyield(L, L->top.p - 2, 0);
} }
@ -909,16 +917,16 @@ static void GCTM (lua_State *L) {
int oldgcstp = g->gcstp; int oldgcstp = g->gcstp;
g->gcstp |= GCSTPGC; /* avoid GC steps */ g->gcstp |= GCSTPGC; /* avoid GC steps */
L->allowhook = 0; /* stop debug hooks during GC metamethod */ L->allowhook = 0; /* stop debug hooks during GC metamethod */
setobj2s(L, L->top++, tm); /* push finalizer... */ setobj2s(L, L->top.p++, tm); /* push finalizer... */
setobj2s(L, L->top++, &v); /* ... and its argument */ setobj2s(L, L->top.p++, &v); /* ... and its argument */
L->ci->callstatus |= CIST_FIN; /* will run a finalizer */ L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0);
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */ L->allowhook = oldah; /* restore hooks */
g->gcstp = oldgcstp; /* restore state */ g->gcstp = oldgcstp; /* restore state */
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */ if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
luaE_warnerror(L, "__gc"); luaE_warnerror(L, "__gc");
L->top--; /* pops error object */ L->top.p--; /* pops error object */
} }
} }
} }
@ -1041,7 +1049,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);
}
/* /*
@ -1285,6 +1311,15 @@ static void atomic2gen (lua_State *L, global_State *g) {
} }
/*
** Set debt for the next minor collection, which will happen when
** memory grows 'genminormul'%.
*/
static void setminordebt (global_State *g) {
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
}
/* /*
** Enter generational mode. Must go until the end of an atomic cycle ** Enter generational mode. Must go until the end of an atomic cycle
** to ensure that all objects are correctly marked and weak tables ** to ensure that all objects are correctly marked and weak tables
@ -1297,6 +1332,7 @@ static lu_mem entergen (lua_State *L, global_State *g) {
luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
numobjs = atomic(L); /* propagates all and then do the atomic stuff */ numobjs = atomic(L); /* propagates all and then do the atomic stuff */
atomic2gen(L, g); atomic2gen(L, g);
setminordebt(g); /* set debt assuming next cycle will be minor */
return numobjs; return numobjs;
} }
@ -1342,15 +1378,6 @@ static lu_mem fullgen (lua_State *L, global_State *g) {
} }
/*
** Set debt for the next minor collection, which will happen when
** memory grows 'genminormul'%.
*/
static void setminordebt (global_State *g) {
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
}
/* /*
** Does a major collection after last collection was a "bad collection". ** Does a major collection after last collection was a "bad collection".
** **
@ -1384,7 +1411,7 @@ static void stepgenfull (lua_State *L, global_State *g) {
setminordebt(g); setminordebt(g);
} }
else { /* another bad collection; stay in incremental mode */ else { /* another bad collection; stay in incremental mode */
g->GCestimate = gettotalbytes(g); /* first estimate */; g->GCestimate = gettotalbytes(g); /* first estimate */
entersweep(L); entersweep(L);
luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */
setpause(g); setpause(g);
@ -1422,8 +1449,8 @@ static void genstep (lua_State *L, global_State *g) {
lu_mem numobjs = fullgen(L, g); /* do a major collection */ lu_mem numobjs = fullgen(L, g); /* do a major collection */
if (gettotalbytes(g) < majorbase + (majorinc / 2)) { if (gettotalbytes(g) < majorbase + (majorinc / 2)) {
/* collected at least half of memory growth since last major /* collected at least half of memory growth since last major
collection; keep doing minor collections */ collection; keep doing minor collections. */
setminordebt(g); lua_assert(g->lastatomic == 0);
} }
else { /* bad collection */ else { /* bad collection */
g->lastatomic = numobjs; /* signal that last collection was bad */ g->lastatomic = numobjs; /* signal that last collection was bad */
@ -1449,26 +1476,6 @@ static void genstep (lua_State *L, global_State *g) {
*/ */
/*
** Set the "time" to wait before starting a new GC cycle; cycle will
** start when memory use hits the threshold of ('estimate' * pause /
** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
** because Lua cannot even start with less than PAUSEADJ bytes).
*/
static void setpause (global_State *g) {
l_mem threshold, debt;
int pause = getgcparam(g->gcpause);
l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
lua_assert(estimate > 0);
threshold = (pause < MAX_LMEM / estimate) /* overflow? */
? estimate * pause /* no overflow */
: MAX_LMEM; /* overflow; truncate to maximum */
debt = gettotalbytes(g) - threshold;
if (debt > 0) debt = 0;
luaE_setdebt(g, debt);
}
/* /*
** Enter first sweep phase. ** Enter first sweep phase.
** The call to 'sweeptolive' makes the pointer point to an object ** The call to 'sweeptolive' makes the pointer point to an object
@ -1599,7 +1606,7 @@ static lu_mem singlestep (lua_State *L) {
case GCSenteratomic: { case GCSenteratomic: {
work = atomic(L); /* work is what was traversed by 'atomic' */ work = atomic(L); /* work is what was traversed by 'atomic' */
entersweep(L); entersweep(L);
g->GCestimate = gettotalbytes(g); /* first estimate */; g->GCestimate = gettotalbytes(g); /* first estimate */
break; break;
} }
case GCSswpallgc: { /* sweep "regular" objects */ case GCSswpallgc: { /* sweep "regular" objects */
@ -1676,12 +1683,15 @@ static void incstep (lua_State *L, global_State *g) {
} }
/* /*
** performs a basic GC step if collector is running ** Performs a basic GC step if collector is running. (If collector is
** not running, set a reasonable debt to avoid it being called at
** every single check.)
*/ */
void luaC_step (lua_State *L) { void luaC_step (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
lua_assert(!g->gcemergency); if (!gcrunning(g)) /* not running? */
if (gcrunning(g)) { /* running? */ luaE_setdebt(g, -2000);
else {
if(isdecGCmodegen(g)) if(isdecGCmodegen(g))
genstep(L, g); genstep(L, g);
else else
@ -1702,6 +1712,8 @@ static void fullinc (lua_State *L, global_State *g) {
entersweep(L); /* sweep everything to turn them back to white */ entersweep(L); /* sweep everything to turn them back to white */
/* finish any pending sweep phase to start a new cycle */ /* finish any pending sweep phase to start a new cycle */
luaC_runtilstate(L, bitmask(GCSpause)); luaC_runtilstate(L, bitmask(GCSpause));
luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
g->gcstate = GCSenteratomic; /* go straight to atomic phase */
luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */
/* estimate must be correct after a full GC cycle */ /* estimate must be correct after a full GC cycle */
lua_assert(g->GCestimate == gettotalbytes(g)); lua_assert(g->GCestimate == gettotalbytes(g));

View File

@ -172,24 +172,27 @@
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0) #define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
#define luaC_barrier(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
#define luaC_barrierback(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrierback_(L,p) : cast_void(0))
#define luaC_objbarrier(L,p,o) ( \ #define luaC_objbarrier(L,p,o) ( \
(isblack(p) && iswhite(o)) ? \ (isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
#define luaC_barrier(L,p,v) ( \
iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0))
#define luaC_objbarrierback(L,p,o) ( \
(isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0))
#define luaC_barrierback(L,p,v) ( \
iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0))
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L); LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L);
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz,
size_t offset);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);

View File

@ -245,8 +245,8 @@ static int f_gc (lua_State *L) {
*/ */
static int io_fclose (lua_State *L) { static int io_fclose (lua_State *L) {
LStream *p = tolstream(L); LStream *p = tolstream(L);
int res = fclose(p->f); errno = 0;
return luaL_fileresult(L, (res == 0), NULL); return luaL_fileresult(L, (fclose(p->f) == 0), NULL);
} }
@ -272,6 +272,7 @@ static int io_open (lua_State *L) {
LStream *p = newfile(L); LStream *p = newfile(L);
const char *md = mode; /* to traverse/check mode */ const char *md = mode; /* to traverse/check mode */
luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); luaL_argcheck(L, l_checkmode(md), 2, "invalid mode");
errno = 0;
p->f = fopen(filename, mode); p->f = fopen(filename, mode);
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
} }
@ -292,6 +293,7 @@ static int io_popen (lua_State *L) {
const char *mode = luaL_optstring(L, 2, "r"); const char *mode = luaL_optstring(L, 2, "r");
LStream *p = newprefile(L); LStream *p = newprefile(L);
luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode"); luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode");
errno = 0;
p->f = l_popen(L, filename, mode); p->f = l_popen(L, filename, mode);
p->closef = &io_pclose; p->closef = &io_pclose;
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
@ -300,6 +302,7 @@ static int io_popen (lua_State *L) {
static int io_tmpfile (lua_State *L) { static int io_tmpfile (lua_State *L) {
LStream *p = newfile(L); LStream *p = newfile(L);
errno = 0;
p->f = tmpfile(); p->f = tmpfile();
return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
} }
@ -567,6 +570,7 @@ static int g_read (lua_State *L, FILE *f, int first) {
int nargs = lua_gettop(L) - 1; int nargs = lua_gettop(L) - 1;
int n, success; int n, success;
clearerr(f); clearerr(f);
errno = 0;
if (nargs == 0) { /* no arguments? */ if (nargs == 0) { /* no arguments? */
success = read_line(L, f, 1); success = read_line(L, f, 1);
n = first + 1; /* to return 1 result */ n = first + 1; /* to return 1 result */
@ -660,6 +664,7 @@ static int io_readline (lua_State *L) {
static int g_write (lua_State *L, FILE *f, int arg) { static int g_write (lua_State *L, FILE *f, int arg) {
int nargs = lua_gettop(L) - arg; int nargs = lua_gettop(L) - arg;
int status = 1; int status = 1;
errno = 0;
for (; nargs--; arg++) { for (; nargs--; arg++) {
if (lua_type(L, arg) == LUA_TNUMBER) { if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */ /* optimization: could be done exactly as for strings */
@ -678,7 +683,8 @@ static int g_write (lua_State *L, FILE *f, int arg) {
} }
if (l_likely(status)) if (l_likely(status))
return 1; /* file handle already on stack top */ return 1; /* file handle already on stack top */
else return luaL_fileresult(L, status, NULL); else
return luaL_fileresult(L, status, NULL);
} }
@ -703,6 +709,7 @@ static int f_seek (lua_State *L) {
l_seeknum offset = (l_seeknum)p3; l_seeknum offset = (l_seeknum)p3;
luaL_argcheck(L, (lua_Integer)offset == p3, 3, luaL_argcheck(L, (lua_Integer)offset == p3, 3,
"not an integer in proper range"); "not an integer in proper range");
errno = 0;
op = l_fseek(f, offset, mode[op]); op = l_fseek(f, offset, mode[op]);
if (l_unlikely(op)) if (l_unlikely(op))
return luaL_fileresult(L, 0, NULL); /* error */ return luaL_fileresult(L, 0, NULL); /* error */
@ -719,19 +726,25 @@ static int f_setvbuf (lua_State *L) {
FILE *f = tofile(L); FILE *f = tofile(L);
int op = luaL_checkoption(L, 2, NULL, modenames); int op = luaL_checkoption(L, 2, NULL, modenames);
lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
int res = setvbuf(f, NULL, mode[op], (size_t)sz); int res;
errno = 0;
res = setvbuf(f, NULL, mode[op], (size_t)sz);
return luaL_fileresult(L, res == 0, NULL); return luaL_fileresult(L, res == 0, NULL);
} }
static int io_flush (lua_State *L) { static int io_flush (lua_State *L) {
return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); FILE *f = getiofile(L, IO_OUTPUT);
errno = 0;
return luaL_fileresult(L, fflush(f) == 0, NULL);
} }
static int f_flush (lua_State *L) { static int f_flush (lua_State *L) {
return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); FILE *f = tofile(L);
errno = 0;
return luaL_fileresult(L, fflush(f) == 0, NULL);
} }
@ -773,7 +786,7 @@ static const luaL_Reg meth[] = {
** metamethods for file handles ** metamethods for file handles
*/ */
static const luaL_Reg metameth[] = { static const luaL_Reg metameth[] = {
{"__index", NULL}, /* place holder */ {"__index", NULL}, /* placeholder */
{"__gc", f_gc}, {"__gc", f_gc},
{"__close", f_gc}, {"__close", f_gc},
{"__tostring", f_tostring}, {"__tostring", f_tostring},

View File

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

View File

@ -71,11 +71,24 @@ typedef signed char ls_byte;
/* /*
** conversion of pointer to unsigned integer: ** conversion of pointer to unsigned integer: this is for hashing only;
** this is for hashing only; there is no problem if the integer ** there is no problem if the integer cannot hold the whole pointer
** cannot hold the whole pointer value ** 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))

View File

@ -249,6 +249,15 @@ static int math_type (lua_State *L) {
** =================================================================== ** ===================================================================
*/ */
/*
** This code uses lots of shifts. ANSI C does not allow shifts greater
** than or equal to the width of the type being shifted, so some shifts
** are written in convoluted ways to match that restriction. For
** preprocessor tests, it assumes a width of 32 bits, so the maximum
** shift there is 31 bits.
*/
/* number of binary digits in the mantissa of a float */ /* number of binary digits in the mantissa of a float */
#define FIGS l_floatatt(MANT_DIG) #define FIGS l_floatatt(MANT_DIG)
@ -267,20 +276,23 @@ static int math_type (lua_State *L) {
/* try to find an integer type with at least 64 bits */ /* try to find an integer type with at least 64 bits */
#if (ULONG_MAX >> 31 >> 31) >= 3 #if ((ULONG_MAX >> 31) >> 31) >= 3
/* 'long' has at least 64 bits */ /* 'long' has at least 64 bits */
#define Rand64 unsigned long #define Rand64 unsigned long
#define SRand64 long
#elif !defined(LUA_USE_C89) && defined(LLONG_MAX) #elif !defined(LUA_USE_C89) && defined(LLONG_MAX)
/* there is a 'long long' type (which must have at least 64 bits) */ /* there is a 'long long' type (which must have at least 64 bits) */
#define Rand64 unsigned long long #define Rand64 unsigned long long
#define SRand64 long long
#elif (LUA_MAXUNSIGNED >> 31 >> 31) >= 3 #elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
/* 'lua_Integer' has at least 64 bits */ /* 'lua_Unsigned' has at least 64 bits */
#define Rand64 lua_Unsigned #define Rand64 lua_Unsigned
#define SRand64 lua_Integer
#endif #endif
@ -319,23 +331,30 @@ static Rand64 nextrand (Rand64 *state) {
} }
/* must take care to not shift stuff by more than 63 slots */
/* /*
** Convert bits from a random integer into a float in the ** Convert bits from a random integer into a float in the
** interval [0,1), getting the higher FIG bits from the ** interval [0,1), getting the higher FIG bits from the
** random unsigned integer and converting that to a float. ** random unsigned integer and converting that to a float.
** Some old Microsoft compilers cannot cast an unsigned long
** to a floating-point number, so we use a signed long as an
** intermediary. When lua_Number is float or double, the shift ensures
** that 'sx' is non negative; in that case, a good compiler will remove
** the correction.
*/ */
/* must throw out the extra (64 - FIGS) bits */ /* must throw out the extra (64 - FIGS) bits */
#define shift64_FIG (64 - FIGS) #define shift64_FIG (64 - FIGS)
/* to scale to [0, 1), multiply by scaleFIG = 2^(-FIGS) */ /* 2^(-FIGS) == 2^-1 / 2^(FIGS-1) */
#define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1))) #define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1)))
static lua_Number I2d (Rand64 x) { static lua_Number I2d (Rand64 x) {
return (lua_Number)(trim64(x) >> shift64_FIG) * scaleFIG; SRand64 sx = (SRand64)(trim64(x) >> shift64_FIG);
lua_Number res = (lua_Number)(sx) * scaleFIG;
if (sx < 0)
res += l_mathop(1.0); /* correct the two's complement if negative */
lua_assert(0 <= res && res < 1);
return res;
} }
/* convert a 'Rand64' to a 'lua_Unsigned' */ /* convert a 'Rand64' to a 'lua_Unsigned' */
@ -471,8 +490,6 @@ static lua_Number I2d (Rand64 x) {
#else /* 32 < FIGS <= 64 */ #else /* 32 < FIGS <= 64 */
/* must take care to not shift stuff by more than 31 slots */
/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */ /* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
#define scaleFIG \ #define scaleFIG \
(l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33))) (l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33)))
@ -500,12 +517,12 @@ static lua_Number I2d (Rand64 x) {
/* convert a 'Rand64' to a 'lua_Unsigned' */ /* convert a 'Rand64' to a 'lua_Unsigned' */
static lua_Unsigned I2UInt (Rand64 x) { static lua_Unsigned I2UInt (Rand64 x) {
return ((lua_Unsigned)trim32(x.h) << 31 << 1) | (lua_Unsigned)trim32(x.l); return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l);
} }
/* convert a 'lua_Unsigned' to a 'Rand64' */ /* convert a 'lua_Unsigned' to a 'Rand64' */
static Rand64 Int2I (lua_Unsigned n) { static Rand64 Int2I (lua_Unsigned n) {
return packI((lu_int32)(n >> 31 >> 1), (lu_int32)n); return packI((lu_int32)((n >> 31) >> 1), (lu_int32)n);
} }
#endif /* } */ #endif /* } */

View File

@ -22,25 +22,6 @@
#include "lstate.h" #include "lstate.h"
#if defined(EMERGENCYGCTESTS)
/*
** First allocation will fail whenever not building initial state.
** (This fail will trigger 'tryagain' and a full GC cycle at every
** allocation.)
*/
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
if (completestate(g) && ns > 0) /* frees never fail */
return NULL; /* fail */
else /* normal allocation */
return (*g->frealloc)(g->ud, block, os, ns);
}
#else
#define firsttry(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
#endif
/* /*
** About the realloc function: ** About the realloc function:
@ -60,6 +41,43 @@ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
*/ */
/*
** Macro to call the allocation function.
*/
#define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
/*
** When an allocation fails, it will try again after an emergency
** collection, except when it cannot run a collection. The GC should
** not be called while the state is not fully built, as the collector
** is not yet fully initialized. Also, it should not be called when
** 'gcstopem' is true, because then the interpreter is in the middle of
** a collection step.
*/
#define cantryagain(g) (completestate(g) && !g->gcstopem)
#if defined(EMERGENCYGCTESTS)
/*
** First allocation will fail except when freeing a block (frees never
** fail) and when it cannot try again; this fail will trigger 'tryagain'
** and a full GC cycle at every allocation.
*/
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
if (ns > 0 && cantryagain(g))
return NULL; /* fail */
else /* normal allocation */
return callfrealloc(g, block, os, ns);
}
#else
#define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns)
#endif
/* /*
@ -132,7 +150,7 @@ l_noret luaM_toobig (lua_State *L) {
void luaM_free_ (lua_State *L, void *block, size_t osize) { void luaM_free_ (lua_State *L, void *block, size_t osize) {
global_State *g = G(L); global_State *g = G(L);
lua_assert((osize == 0) == (block == NULL)); lua_assert((osize == 0) == (block == NULL));
(*g->frealloc)(g->ud, block, osize, 0); callfrealloc(g, block, osize, 0);
g->GCdebt -= osize; g->GCdebt -= osize;
} }
@ -140,19 +158,15 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
/* /*
** In case of allocation fail, this function will do an emergency ** In case of allocation fail, this function will do an emergency
** collection to free some memory and then try the allocation again. ** collection to free some memory and then try the allocation again.
** The GC should not be called while state is not fully built, as the
** collector is not yet fully initialized. Also, it should not be called
** when 'gcstopem' is true, because then the interpreter is in the
** middle of a collection step.
*/ */
static void *tryagain (lua_State *L, void *block, static void *tryagain (lua_State *L, void *block,
size_t osize, size_t nsize) { size_t osize, size_t nsize) {
global_State *g = G(L); global_State *g = G(L);
if (completestate(g) && !g->gcstopem) { if (cantryagain(g)) {
luaC_fullgc(L, 1); /* try to free some memory... */ luaC_fullgc(L, 1); /* try to free some memory... */
return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ return callfrealloc(g, block, osize, nsize); /* try again */
} }
else return NULL; /* cannot free any memory without a full state */ else return NULL; /* cannot run an emergency collection */
} }

View File

@ -24,15 +24,6 @@
#include "lualib.h" #include "lualib.h"
/*
** LUA_IGMARK is a mark to ignore all before it when building the
** luaopen_ function name.
*/
#if !defined (LUA_IGMARK)
#define LUA_IGMARK "-"
#endif
/* /*
** LUA_CSUBSEP is the character that replaces dots in submodule names ** LUA_CSUBSEP is the character that replaces dots in submodule names
** when searching for a C loader. ** when searching for a C loader.
@ -708,8 +699,13 @@ static const luaL_Reg ll_funcs[] = {
static void createsearcherstable (lua_State *L) { static void createsearcherstable (lua_State *L) {
static const lua_CFunction searchers[] = static const lua_CFunction searchers[] = {
{searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; searcher_preload,
searcher_Lua,
searcher_C,
searcher_Croot,
NULL
};
int i; int i;
/* create 'searchers' table */ /* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);

View File

@ -62,7 +62,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
case LUA_OPBOR: return intop(|, v1, v2); case LUA_OPBOR: return intop(|, v1, v2);
case LUA_OPBXOR: return intop(^, v1, v2); case LUA_OPBXOR: return intop(^, v1, v2);
case LUA_OPSHL: return luaV_shiftl(v1, v2); case LUA_OPSHL: return luaV_shiftl(v1, v2);
case LUA_OPSHR: return luaV_shiftl(v1, -v2); case LUA_OPSHR: return luaV_shiftr(v1, v2);
case LUA_OPUNM: return intop(-, 0, v1); case LUA_OPUNM: return intop(-, 0, v1);
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
default: lua_assert(0); return 0; default: lua_assert(0); return 0;
@ -386,29 +386,39 @@ void luaO_tostring (lua_State *L, TValue *obj) {
** =================================================================== ** ===================================================================
*/ */
/* size for buffer space used by 'luaO_pushvfstring' */ /*
#define BUFVFS 200 ** Size for buffer space used by 'luaO_pushvfstring'. It should be
** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages,
** so that 'luaG_addinfo' can work directly on the buffer.
*/
#define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95)
/* buffer used by 'luaO_pushvfstring' */ /* buffer used by 'luaO_pushvfstring' */
typedef struct BuffFS { typedef struct BuffFS {
lua_State *L; lua_State *L;
int pushed; /* number of string pieces already on the stack */ int pushed; /* true if there is a part of the result on the stack */
int blen; /* length of partial string in 'space' */ int blen; /* length of partial string in 'space' */
char space[BUFVFS]; /* holds last part of the result */ char space[BUFVFS]; /* holds last part of the result */
} BuffFS; } BuffFS;
/* /*
** Push given string to the stack, as part of the buffer, and ** Push given string to the stack, as part of the result, and
** join the partial strings in the stack into one. ** join it to previous partial result if there is one.
** It may call 'luaV_concat' while using one slot from EXTRA_STACK.
** This call cannot invoke metamethods, as both operands must be
** strings. It can, however, raise an error if the result is too
** long. In that case, 'luaV_concat' frees the extra slot before
** raising the error.
*/ */
static void pushstr (BuffFS *buff, const char *str, size_t l) { static void pushstr (BuffFS *buff, const char *str, size_t lstr) {
lua_State *L = buff->L; lua_State *L = buff->L;
setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); setsvalue2s(L, L->top.p, luaS_newlstr(L, str, lstr));
L->top++; /* may use one extra slot */ L->top.p++; /* may use one slot from EXTRA_STACK */
buff->pushed++; if (!buff->pushed) /* no previous string on the stack? */
luaV_concat(L, buff->pushed); /* join partial results into one */ buff->pushed = 1; /* now there is one */
buff->pushed = 1; else /* join previous string with new one */
luaV_concat(L, 2);
} }
@ -454,7 +464,7 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
/* /*
** Add a number to the buffer. ** Add a numeral to the buffer.
*/ */
static void addnum2buff (BuffFS *buff, TValue *num) { static void addnum2buff (BuffFS *buff, TValue *num) {
char *numbuff = getbuff(buff, MAXNUMBER2STR); char *numbuff = getbuff(buff, MAXNUMBER2STR);
@ -532,7 +542,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */ addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
clearbuff(&buff); /* empty buffer into the stack */ clearbuff(&buff); /* empty buffer into the stack */
lua_assert(buff.pushed == 1); lua_assert(buff.pushed == 1);
return svalue(s2v(L->top - 1)); return getstr(tsvalue(s2v(L->top.p - 1)));
} }

View File

@ -52,6 +52,8 @@ typedef union Value {
lua_CFunction f; /* light C functions */ lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */ lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */ lua_Number n; /* float numbers */
/* not used, but may avoid warnings for uninitialized value */
lu_byte ub;
} Value; } Value;
@ -155,6 +157,17 @@ typedef union StackValue {
/* index to stack elements */ /* index to stack elements */
typedef StackValue *StkId; typedef StackValue *StkId;
/*
** When reallocating the stack, change all pointers to the stack into
** proper offsets.
*/
typedef union {
StkId p; /* actual pointer */
ptrdiff_t offset; /* used while the stack is being reallocated */
} StkIdRel;
/* convert a 'StackValue' to a 'TValue' */ /* convert a 'StackValue' to a 'TValue' */
#define s2v(o) (&(o)->val) #define s2v(o) (&(o)->val)
@ -373,7 +386,7 @@ typedef struct GCObject {
typedef struct TString { typedef struct TString {
CommonHeader; CommonHeader;
lu_byte extra; /* reserved words for short strings; "has hash" for longs */ lu_byte extra; /* reserved words for short strings; "has hash" for longs */
lu_byte shrlen; /* length for short strings */ lu_byte shrlen; /* length for short strings, 0xFF for long strings */
unsigned int hash; unsigned int hash;
union { union {
size_t lnglen; /* length for long strings */ size_t lnglen; /* length for long strings */
@ -385,19 +398,17 @@ typedef struct TString {
/* /*
** Get the actual string (array of bytes) from a 'TString'. ** Get the actual string (array of bytes) from a 'TString'. (Generic
** version and specialized versions for long and short strings.)
*/ */
#define getstr(ts) ((ts)->contents) #define getstr(ts) ((ts)->contents)
#define getlngstr(ts) check_exp((ts)->shrlen == 0xFF, (ts)->contents)
#define getshrstr(ts) check_exp((ts)->shrlen != 0xFF, (ts)->contents)
/* get the actual string (array of bytes) from a Lua value */
#define svalue(o) getstr(tsvalue(o))
/* get string length from 'TString *s' */ /* get string length from 'TString *s' */
#define tsslen(s) ((s)->tt == LUA_VSHRSTR ? (s)->shrlen : (s)->u.lnglen) #define tsslen(s) \
((s)->shrlen != 0xFF ? (s)->shrlen : (s)->u.lnglen)
/* get string length from 'TValue *o' */
#define vslen(o) tsslen(tsvalue(o))
/* }================================================================== */ /* }================================================================== */
@ -615,8 +626,10 @@ typedef struct Proto {
*/ */
typedef struct UpVal { typedef struct UpVal {
CommonHeader; CommonHeader;
lu_byte tbc; /* true if it represents a to-be-closed variable */ union {
TValue *v; /* points to stack or to its own value */ TValue *p; /* points to stack or to its own value */
ptrdiff_t offset; /* used while the stack is being reallocated */
} v;
union { union {
struct { /* (when open) */ struct { /* (when open) */
struct UpVal *next; /* linked list */ struct UpVal *next; /* linked list */

View File

@ -21,7 +21,7 @@ iABC C(8) | B(8) |k| A(8) | Op(7) |
iABx Bx(17) | A(8) | Op(7) | iABx Bx(17) | A(8) | Op(7) |
iAsBx sBx (signed)(17) | A(8) | Op(7) | iAsBx sBx (signed)(17) | A(8) | Op(7) |
iAx Ax(25) | Op(7) | iAx Ax(25) | Op(7) |
isJ sJ(25) | Op(7) | isJ sJ (signed)(25) | Op(7) |
A signed argument is represented in excess K: the represented value is A signed argument is represented in excess K: the represented value is
the written unsigned value minus K, where K is half the maximum for the the written unsigned value minus K, where K is half the maximum for the
@ -210,15 +210,15 @@ OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */
OP_GETUPVAL,/* A B R[A] := UpValue[B] */ OP_GETUPVAL,/* A B R[A] := UpValue[B] */
OP_SETUPVAL,/* A B UpValue[B] := R[A] */ OP_SETUPVAL,/* A B UpValue[B] := R[A] */
OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:string] */ OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:shortstring] */
OP_GETTABLE,/* A B C R[A] := R[B][R[C]] */ OP_GETTABLE,/* A B C R[A] := R[B][R[C]] */
OP_GETI,/* A B C R[A] := R[B][C] */ OP_GETI,/* A B C R[A] := R[B][C] */
OP_GETFIELD,/* A B C R[A] := R[B][K[C]:string] */ OP_GETFIELD,/* A B C R[A] := R[B][K[C]:shortstring] */
OP_SETTABUP,/* A B C UpValue[A][K[B]:string] := RK(C) */ OP_SETTABUP,/* A B C UpValue[A][K[B]:shortstring] := RK(C) */
OP_SETTABLE,/* A B C R[A][R[B]] := RK(C) */ OP_SETTABLE,/* A B C R[A][R[B]] := RK(C) */
OP_SETI,/* A B C R[A][B] := RK(C) */ OP_SETI,/* A B C R[A][B] := RK(C) */
OP_SETFIELD,/* A B C R[A][K[B]:string] := RK(C) */ OP_SETFIELD,/* A B C R[A][K[B]:shortstring] := RK(C) */
OP_NEWTABLE,/* A B C k R[A] := {} */ OP_NEWTABLE,/* A B C k R[A] := {} */

View File

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

View File

@ -468,6 +468,7 @@ static void singlevar (LexState *ls, expdesc *var) {
expdesc key; expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k != VVOID); /* this one must exist */ lua_assert(var->k != VVOID); /* this one must exist */
luaK_exp2anyregup(fs, var); /* but could be a constant */
codestring(&key, varname); /* key is variable name */ codestring(&key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */ luaK_indexed(fs, var, &key); /* env[varname] */
} }
@ -520,12 +521,12 @@ static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
/* /*
** Solves the goto at index 'g' to given 'label' and removes it ** Solves the goto at index 'g' to given 'label' and removes it
** from the list of pending goto's. ** from the list of pending gotos.
** If it jumps into the scope of some variable, raises an error. ** If it jumps into the scope of some variable, raises an error.
*/ */
static void solvegoto (LexState *ls, int g, Labeldesc *label) { static void solvegoto (LexState *ls, int g, Labeldesc *label) {
int i; int i;
Labellist *gl = &ls->dyd->gt; /* list of goto's */ Labellist *gl = &ls->dyd->gt; /* list of gotos */
Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */ Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */
lua_assert(eqstr(gt->name, label->name)); lua_assert(eqstr(gt->name, label->name));
if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */ if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */
@ -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 ** Solves forward jumps. Check whether new label 'lb' matches any
** pending gotos in current block and solves them. Return true ** pending gotos in current block and solves them. Return true
** if any of the goto's need to close upvalues. ** if any of the gotos need to close upvalues.
*/ */
static int solvegotos (LexState *ls, Labeldesc *lb) { static int solvegotos (LexState *ls, Labeldesc *lb) {
Labellist *gl = &ls->dyd->gt; Labellist *gl = &ls->dyd->gt;
@ -600,7 +601,7 @@ static int solvegotos (LexState *ls, Labeldesc *lb) {
/* /*
** Create a new label with the given 'name' at the given 'line'. ** Create a new label with the given 'name' at the given 'line'.
** 'last' tells whether label is the last non-op statement in its ** 'last' tells whether label is the last non-op statement in its
** block. Solves all pending goto's to this new label and adds ** block. Solves all pending gotos to this new label and adds
** a close instruction if necessary. ** a close instruction if necessary.
** Returns true iff it added a close instruction. ** Returns true iff it added a close instruction.
*/ */
@ -673,19 +674,19 @@ static void leaveblock (FuncState *fs) {
LexState *ls = fs->ls; LexState *ls = fs->ls;
int hasclose = 0; int hasclose = 0;
int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */ int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */
if (bl->isloop) /* fix pending breaks? */ removevars(fs, bl->nactvar); /* remove block locals */
lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */
if (bl->isloop) /* has to fix pending breaks? */
hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0); hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
if (!hasclose && bl->previous && bl->upval) if (!hasclose && bl->previous && bl->upval) /* still need a 'close'? */
luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0); luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0);
fs->bl = bl->previous;
removevars(fs, bl->nactvar);
lua_assert(bl->nactvar == fs->nactvar);
fs->freereg = stklevel; /* free registers */ fs->freereg = stklevel; /* free registers */
ls->dyd->label.n = bl->firstlabel; /* remove local labels */ ls->dyd->label.n = bl->firstlabel; /* remove local labels */
if (bl->previous) /* inner block? */ fs->bl = bl->previous; /* current block now is previous one */
movegotosout(fs, bl); /* update pending gotos to outer block */ if (bl->previous) /* was it a nested block? */
movegotosout(fs, bl); /* update pending gotos to enclosing block */
else { else {
if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ if (bl->firstgoto < ls->dyd->gt.n) /* still pending gotos? */
undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
} }
} }
@ -1021,10 +1022,11 @@ static int explist (LexState *ls, expdesc *v) {
} }
static void funcargs (LexState *ls, expdesc *f, int line) { static void funcargs (LexState *ls, expdesc *f) {
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
expdesc args; expdesc args;
int base, nparams; int base, nparams;
int line = ls->linenumber;
switch (ls->t.token) { switch (ls->t.token) {
case '(': { /* funcargs -> '(' [ explist ] ')' */ case '(': { /* funcargs -> '(' [ explist ] ')' */
luaX_next(ls); luaX_next(ls);
@ -1062,8 +1064,8 @@ static void funcargs (LexState *ls, expdesc *f, int line) {
} }
init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
luaK_fixline(fs, line); luaK_fixline(fs, line);
fs->freereg = base+1; /* call remove function and arguments and leaves fs->freereg = base+1; /* call removes function and arguments and leaves
(unless changed) one result */ one result (unless changed later) */
} }
@ -1102,7 +1104,6 @@ static void suffixedexp (LexState *ls, expdesc *v) {
/* suffixedexp -> /* suffixedexp ->
primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
int line = ls->linenumber;
primaryexp(ls, v); primaryexp(ls, v);
for (;;) { for (;;) {
switch (ls->t.token) { switch (ls->t.token) {
@ -1122,12 +1123,12 @@ static void suffixedexp (LexState *ls, expdesc *v) {
luaX_next(ls); luaX_next(ls);
codename(ls, &key); codename(ls, &key);
luaK_self(fs, v, &key); luaK_self(fs, v, &key);
funcargs(ls, v, line); funcargs(ls, v);
break; break;
} }
case '(': case TK_STRING: case '{': { /* funcargs */ case '(': case TK_STRING: case '{': { /* funcargs */
luaK_exp2nextreg(fs, v); luaK_exp2nextreg(fs, v);
funcargs(ls, v, line); funcargs(ls, v);
break; break;
} }
default: return; default: return;
@ -1943,10 +1944,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
LexState lexstate; LexState lexstate;
FuncState funcstate; FuncState funcstate;
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
setclLvalue2s(L, L->top, cl); /* anchor it (to avoid being collected) */ setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */
luaD_inctop(L); luaD_inctop(L);
lexstate.h = luaH_new(L); /* create table for scanner */ lexstate.h = luaH_new(L); /* create table for scanner */
sethvalue2s(L, L->top, lexstate.h); /* anchor it */ sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */
luaD_inctop(L); luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L); funcstate.f = cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p); luaC_objbarrier(L, cl, cl->p);
@ -1960,7 +1961,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
/* all scopes should be correctly finished */ /* all scopes should be correctly finished */
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
L->top--; /* remove scanner's table */ L->top.p--; /* remove scanner's table */
return cl; /* closure is on the stack, too */ return cl; /* closure is on the stack, too */
} }

View File

@ -119,7 +119,7 @@ CallInfo *luaE_extendCI (lua_State *L) {
/* /*
** free all CallInfo structures not in use by a thread ** free all CallInfo structures not in use by a thread
*/ */
void luaE_freeCI (lua_State *L) { static void freeCI (lua_State *L) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
CallInfo *next = ci->next; CallInfo *next = ci->next;
ci->next = NULL; ci->next = NULL;
@ -180,33 +180,33 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) {
static void stack_init (lua_State *L1, lua_State *L) { static void stack_init (lua_State *L1, lua_State *L) {
int i; CallInfo *ci; int i; CallInfo *ci;
/* initialize stack array */ /* initialize stack array */
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue); L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
L1->tbclist = L1->stack; L1->tbclist.p = L1->stack.p;
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
setnilvalue(s2v(L1->stack + i)); /* erase new stack */ setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */
L1->top = L1->stack; L1->top.p = L1->stack.p;
L1->stack_last = L1->stack + BASIC_STACK_SIZE; L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
/* initialize first ci */ /* initialize first ci */
ci = &L1->base_ci; ci = &L1->base_ci;
ci->next = ci->previous = NULL; ci->next = ci->previous = NULL;
ci->callstatus = CIST_C; ci->callstatus = CIST_C;
ci->func = L1->top; ci->func.p = L1->top.p;
ci->u.c.k = NULL; ci->u.c.k = NULL;
ci->nresults = 0; ci->nresults = 0;
setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */ setnilvalue(s2v(L1->top.p)); /* 'function' entry for this 'ci' */
L1->top++; L1->top.p++;
ci->top = L1->top + LUA_MINSTACK; ci->top.p = L1->top.p + LUA_MINSTACK;
L1->ci = ci; L1->ci = ci;
} }
static void freestack (lua_State *L) { static void freestack (lua_State *L) {
if (L->stack == NULL) if (L->stack.p == NULL)
return; /* stack not completely built yet */ return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */ L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L); freeCI(L);
lua_assert(L->nci == 0); lua_assert(L->nci == 0);
luaM_freearray(L, L->stack, stacksize(L) + EXTRA_STACK); /* free stack */ luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */
} }
@ -248,7 +248,7 @@ static void f_luaopen (lua_State *L, void *ud) {
*/ */
static void preinit_thread (lua_State *L, global_State *g) { static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g; G(L) = g;
L->stack = NULL; L->stack.p = NULL;
L->ci = NULL; L->ci = NULL;
L->nci = 0; L->nci = 0;
L->twups = L; /* thread has no upvalues */ L->twups = L; /* thread has no upvalues */
@ -284,20 +284,16 @@ static void close_state (lua_State *L) {
LUA_API lua_State *lua_newthread (lua_State *L) { LUA_API lua_State *lua_newthread (lua_State *L) {
global_State *g; global_State *g = G(L);
GCObject *o;
lua_State *L1; lua_State *L1;
lua_lock(L); lua_lock(L);
g = G(L);
luaC_checkGC(L); luaC_checkGC(L);
/* create new thread */ /* create new thread */
L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l));
L1->marked = luaC_white(g); L1 = gco2th(o);
L1->tt = LUA_VTHREAD;
/* link it on list 'allgc' */
L1->next = g->allgc;
g->allgc = obj2gco(L1);
/* anchor it on L stack */ /* anchor it on L stack */
setthvalue2s(L, L->top, L1); setthvalue2s(L, L->top.p, L1);
api_incr_top(L); api_incr_top(L);
preinit_thread(L1, g); preinit_thread(L1, g);
L1->hookmask = L->hookmask; L1->hookmask = L->hookmask;
@ -316,7 +312,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
void luaE_freethread (lua_State *L, lua_State *L1) { void luaE_freethread (lua_State *L, lua_State *L1) {
LX *l = fromstate(L1); LX *l = fromstate(L1);
luaF_closeupval(L1, L1->stack); /* close all upvalues */ luaF_closeupval(L1, L1->stack.p); /* close all upvalues */
lua_assert(L1->openupval == NULL); lua_assert(L1->openupval == NULL);
luai_userstatefree(L, L1); luai_userstatefree(L, L1);
freestack(L1); freestack(L1);
@ -326,32 +322,41 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
int luaE_resetthread (lua_State *L, int status) { int luaE_resetthread (lua_State *L, int status) {
CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */ CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */ setnilvalue(s2v(L->stack.p)); /* 'function' entry for basic 'ci' */
ci->func = L->stack; ci->func.p = L->stack.p;
ci->callstatus = CIST_C; ci->callstatus = CIST_C;
if (status == LUA_YIELD) if (status == LUA_YIELD)
status = LUA_OK; status = LUA_OK;
L->status = LUA_OK; /* so it can run __close metamethods */ L->status = LUA_OK; /* so it can run __close metamethods */
status = luaD_closeprotected(L, 1, status); status = luaD_closeprotected(L, 1, status);
if (status != LUA_OK) /* errors? */ if (status != LUA_OK) /* errors? */
luaD_seterrorobj(L, status, L->stack + 1); luaD_seterrorobj(L, status, L->stack.p + 1);
else else
L->top = L->stack + 1; L->top.p = L->stack.p + 1;
ci->top = L->top + LUA_MINSTACK; ci->top.p = L->top.p + LUA_MINSTACK;
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0); luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0);
return status; return status;
} }
LUA_API int lua_resetthread (lua_State *L) { LUA_API int lua_closethread (lua_State *L, lua_State *from) {
int status; int status;
lua_lock(L); lua_lock(L);
L->nCcalls = (from) ? getCcalls(from) : 0;
status = luaE_resetthread(L, L->status); status = luaE_resetthread(L, L->status);
lua_unlock(L); lua_unlock(L);
return status; return status;
} }
/*
** Deprecated! Use 'lua_closethread' instead.
*/
LUA_API int lua_resetthread (lua_State *L) {
return lua_closethread(L, NULL);
}
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i; int i;
lua_State *L; lua_State *L;
@ -426,9 +431,9 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
** Generate a warning from an error message ** Generate a warning from an error message
*/ */
void luaE_warnerror (lua_State *L, const char *where) { void luaE_warnerror (lua_State *L, const char *where) {
TValue *errobj = s2v(L->top - 1); /* error object */ TValue *errobj = s2v(L->top.p - 1); /* error object */
const char *msg = (ttisstring(errobj)) const char *msg = (ttisstring(errobj))
? svalue(errobj) ? getstr(tsvalue(errobj))
: "error object is not a string"; : "error object is not a string";
/* produce warning "error in %s (%s)" (where, msg) */ /* produce warning "error in %s (%s)" (where, msg) */
luaE_warning(L, "error in ", 1); luaE_warning(L, "error in ", 1);

View File

@ -9,6 +9,11 @@
#include "lua.h" #include "lua.h"
/* Some header files included here need this definition */
typedef struct CallInfo CallInfo;
#include "lobject.h" #include "lobject.h"
#include "ltm.h" #include "ltm.h"
#include "lzio.h" #include "lzio.h"
@ -139,7 +144,7 @@ struct lua_longjmp; /* defined in ldo.c */
#define BASIC_STACK_SIZE (2*LUA_MINSTACK) #define BASIC_STACK_SIZE (2*LUA_MINSTACK)
#define stacksize(th) cast_int((th)->stack_last - (th)->stack) #define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p)
/* kinds of Garbage Collection */ /* kinds of Garbage Collection */
@ -169,14 +174,14 @@ typedef struct stringtable {
** - field 'transferinfo' is used only during call/returnhooks, ** - field 'transferinfo' is used only during call/returnhooks,
** before the function starts or after it ends. ** before the function starts or after it ends.
*/ */
typedef struct CallInfo { struct CallInfo {
StkId func; /* function index in the stack */ StkIdRel func; /* function index in the stack */
StkId top; /* top for this function */ StkIdRel top; /* top for this function */
struct CallInfo *previous, *next; /* dynamic call link */ struct CallInfo *previous, *next; /* dynamic call link */
union { union {
struct { /* only for Lua functions */ struct { /* only for Lua functions */
const Instruction *savedpc; const Instruction *savedpc;
volatile l_signalT trap; volatile l_signalT trap; /* function is tracing lines/counts */
int nextraargs; /* # of extra arguments in vararg functions */ int nextraargs; /* # of extra arguments in vararg functions */
} l; } l;
struct { /* only for C functions */ struct { /* only for C functions */
@ -196,7 +201,7 @@ typedef struct CallInfo {
} u2; } u2;
short nresults; /* expected number of results from this function */ short nresults; /* expected number of results from this function */
unsigned short callstatus; unsigned short callstatus;
} CallInfo; };
/* /*
@ -291,7 +296,7 @@ typedef struct global_State {
struct lua_State *mainthread; struct lua_State *mainthread;
TString *memerrmsg; /* message for memory-allocation errors */ TString *memerrmsg; /* message for memory-allocation errors */
TString *tmname[TM_N]; /* array with tag-method names */ TString *tmname[TM_N]; /* array with tag-method names */
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ struct Table *mt[LUA_NUMTYPES]; /* metatables for basic types */
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
lua_WarnFunction warnf; /* warning function */ lua_WarnFunction warnf; /* warning function */
void *ud_warn; /* auxiliary data to 'warnf' */ void *ud_warn; /* auxiliary data to 'warnf' */
@ -306,13 +311,13 @@ struct lua_State {
lu_byte status; lu_byte status;
lu_byte allowhook; lu_byte allowhook;
unsigned short nci; /* number of items in 'ci' list */ unsigned short nci; /* number of items in 'ci' list */
StkId top; /* first free slot in the stack */ StkIdRel top; /* first free slot in the stack */
global_State *l_G; global_State *l_G;
CallInfo *ci; /* call info for current function */ CallInfo *ci; /* call info for current function */
StkId stack_last; /* end of stack (last element + 1) */ StkIdRel stack_last; /* end of stack (last element + 1) */
StkId stack; /* stack base */ StkIdRel stack; /* stack base */
UpVal *openupval; /* list of open upvalues in this stack */ UpVal *openupval; /* list of open upvalues in this stack */
StkId tbclist; /* list of to-be-closed variables */ StkIdRel tbclist; /* list of to-be-closed variables */
GCObject *gclist; GCObject *gclist;
struct lua_State *twups; /* list of threads with open upvalues */ struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */ struct lua_longjmp *errorJmp; /* current error recover point */
@ -391,7 +396,6 @@ union GCUnion {
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
LUAI_FUNC void luaE_freeCI (lua_State *L);
LUAI_FUNC void luaE_shrinkCI (lua_State *L); LUAI_FUNC void luaE_shrinkCI (lua_State *L);
LUAI_FUNC void luaE_checkcstack (lua_State *L); LUAI_FUNC void luaE_checkcstack (lua_State *L);
LUAI_FUNC void luaE_incCstack (lua_State *L); LUAI_FUNC void luaE_incCstack (lua_State *L);

View File

@ -36,7 +36,7 @@ int luaS_eqlngstr (TString *a, TString *b) {
lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR); lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR);
return (a == b) || /* same instance or... */ return (a == b) || /* same instance or... */
((len == b->u.lnglen) && /* equal length and ... */ ((len == b->u.lnglen) && /* equal length and ... */
(memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ (memcmp(getlngstr(a), getlngstr(b), len) == 0)); /* equal contents */
} }
@ -52,7 +52,7 @@ unsigned int luaS_hashlongstr (TString *ts) {
lua_assert(ts->tt == LUA_VLNGSTR); lua_assert(ts->tt == LUA_VLNGSTR);
if (ts->extra == 0) { /* no hash? */ if (ts->extra == 0) { /* no hash? */
size_t len = ts->u.lnglen; size_t len = ts->u.lnglen;
ts->hash = luaS_hash(getstr(ts), len, ts->hash); ts->hash = luaS_hash(getlngstr(ts), len, ts->hash);
ts->extra = 1; /* now it has its hash */ ts->extra = 1; /* now it has its hash */
} }
return ts->hash; return ts->hash;
@ -157,6 +157,7 @@ static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
TString *luaS_createlngstrobj (lua_State *L, size_t l) { TString *luaS_createlngstrobj (lua_State *L, size_t l) {
TString *ts = createstrobj(L, l, LUA_VLNGSTR, G(L)->seed); TString *ts = createstrobj(L, l, LUA_VLNGSTR, G(L)->seed);
ts->u.lnglen = l; ts->u.lnglen = l;
ts->shrlen = 0xFF; /* signals that it is a long string */
return ts; return ts;
} }
@ -193,7 +194,7 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
TString **list = &tb->hash[lmod(h, tb->size)]; TString **list = &tb->hash[lmod(h, tb->size)];
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
for (ts = *list; ts != NULL; ts = ts->u.hnext) { for (ts = *list; ts != NULL; ts = ts->u.hnext) {
if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { if (l == ts->shrlen && (memcmp(str, getshrstr(ts), l * sizeof(char)) == 0)) {
/* found! */ /* found! */
if (isdead(g, ts)) /* dead (but not collected yet)? */ if (isdead(g, ts)) /* dead (but not collected yet)? */
changewhite(ts); /* resurrect it */ changewhite(ts); /* resurrect it */
@ -206,8 +207,8 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */ list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */
} }
ts = createstrobj(L, l, LUA_VSHRSTR, h); ts = createstrobj(L, l, LUA_VSHRSTR, h);
memcpy(getstr(ts), str, l * sizeof(char));
ts->shrlen = cast_byte(l); ts->shrlen = cast_byte(l);
memcpy(getshrstr(ts), str, l * sizeof(char));
ts->u.hnext = *list; ts->u.hnext = *list;
*list = ts; *list = ts;
tb->nuse++; tb->nuse++;
@ -223,10 +224,10 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
return internshrstr(L, str, l); return internshrstr(L, str, l);
else { else {
TString *ts; TString *ts;
if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char))) if (l_unlikely(l * sizeof(char) >= (MAX_SIZE - sizeof(TString))))
luaM_toobig(L); luaM_toobig(L);
ts = luaS_createlngstrobj(L, l); ts = luaS_createlngstrobj(L, l);
memcpy(getstr(ts), str, l * sizeof(char)); memcpy(getlngstr(ts), str, l * sizeof(char));
return ts; return ts;
} }
} }

View File

@ -570,7 +570,7 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
static const char *match (MatchState *ms, const char *s, const char *p) { static const char *match (MatchState *ms, const char *s, const char *p) {
if (l_unlikely(ms->matchdepth-- == 0)) if (l_unlikely(ms->matchdepth-- == 0))
luaL_error(ms->L, "pattern too complex"); luaL_error(ms->L, "pattern too complex");
init: /* using goto's to optimize tail recursion */ init: /* using goto to optimize tail recursion */
if (p != ms->p_end) { /* end of pattern? */ if (p != ms->p_end) { /* end of pattern? */
switch (*p) { switch (*p) {
case '(': { /* start capture */ case '(': { /* start capture */

View File

@ -107,7 +107,7 @@ static const TValue absentkey = {ABSTKEYCONSTANT};
*/ */
static Node *hashint (const Table *t, lua_Integer i) { static Node *hashint (const Table *t, lua_Integer i) {
lua_Unsigned ui = l_castS2U(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)); return hashmod(t, cast_int(ui));
else else
return hashmod(t, ui); return hashmod(t, ui);
@ -252,14 +252,16 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t) {
return t->alimit; /* this is the size */ return t->alimit; /* this is the size */
else { else {
unsigned int size = t->alimit; unsigned int size = t->alimit;
/* compute the smallest power of 2 not smaller than 'n' */ /* compute the smallest power of 2 not smaller than 'size' */
size |= (size >> 1); size |= (size >> 1);
size |= (size >> 2); size |= (size >> 2);
size |= (size >> 4); size |= (size >> 4);
size |= (size >> 8); size |= (size >> 8);
#if (UINT_MAX >> 14) > 3 /* unsigned int has more than 16 bits */
size |= (size >> 16); size |= (size >> 16);
#if (UINT_MAX >> 30) > 3 #if (UINT_MAX >> 30) > 3
size |= (size >> 32); /* unsigned int has more than 32 bits */ size |= (size >> 32); /* unsigned int has more than 32 bits */
#endif
#endif #endif
size++; size++;
lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size); lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size);
@ -488,7 +490,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
luaG_runerror(L, "table overflow"); luaG_runerror(L, "table overflow");
size = twoto(lsize); size = twoto(lsize);
t->node = luaM_newvector(L, size, Node); t->node = luaM_newvector(L, size, Node);
for (i = 0; i < (int)size; i++) { for (i = 0; i < cast_int(size); i++) {
Node *n = gnode(t, i); Node *n = gnode(t, i);
gnext(n) = 0; gnext(n) = 0;
setnilkey(n); setnilkey(n);
@ -660,7 +662,8 @@ static Node *getfreepos (Table *t) {
** put new key in its main position; otherwise (colliding node is in its main ** put new key in its main position; otherwise (colliding node is in its main
** position), new key goes to an empty position. ** position), new key goes to an empty position.
*/ */
void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { static void luaH_newkey (lua_State *L, Table *t, const TValue *key,
TValue *value) {
Node *mp; Node *mp;
TValue aux; TValue aux;
if (l_unlikely(ttisnil(key))) if (l_unlikely(ttisnil(key)))
@ -719,22 +722,36 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
/* /*
** Search function for integers. If integer is inside 'alimit', get it ** Search function for integers. If integer is inside 'alimit', get it
** directly from the array part. Otherwise, if 'alimit' is not equal to ** directly from the array part. Otherwise, if 'alimit' is not
** the real size of the array, key still can be in the array part. In ** the real size of the array, the key still can be in the array part.
** this case, try to avoid a call to 'luaH_realasize' when key is just ** In this case, do the "Xmilia trick" to check whether 'key-1' is
** one more than the limit (so that it can be incremented without ** smaller than the real size.
** changing the real size of the array). ** The trick works as follow: let 'p' be an integer such that
** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'.
** That is, 2^(p+1) is the real size of the array, and 'p' is the highest
** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'.
** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will
** have the 'p' bit cleared. If the key is outside the array, that is,
** 'key-1 >= 2^(p+1)', then 'res' will have some bit on higher than 'p',
** therefore it will be larger or equal to 'alimit', and the check
** will fail. If 'key-1 < 2^(p+1)', then 'res' has no bit on higher than
** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller
** than 2^p, therefore smaller than 'alimit', and the check succeeds.
** As special cases, when 'alimit' is 0 the condition is trivially false,
** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'.
** If key is 0 or negative, 'res' will have its higher bit on, so that
** if cannot be smaller than alimit.
*/ */
const TValue *luaH_getint (Table *t, lua_Integer key) { const TValue *luaH_getint (Table *t, lua_Integer key) {
if (l_castS2U(key) - 1u < t->alimit) /* 'key' in [1, t->alimit]? */ lua_Unsigned alimit = t->alimit;
if (l_castS2U(key) - 1u < alimit) /* 'key' in [1, t->alimit]? */
return &t->array[key - 1]; return &t->array[key - 1];
else if (!limitequalsasize(t) && /* key still may be in the array part? */ else if (!isrealasize(t) && /* key still may be in the array part? */
(l_castS2U(key) == t->alimit + 1 || (((l_castS2U(key) - 1u) & ~(alimit - 1u)) < alimit)) {
l_castS2U(key) - 1u < luaH_realasize(t))) {
t->alimit = cast_uint(key); /* probably '#t' is here now */ t->alimit = cast_uint(key); /* probably '#t' is here now */
return &t->array[key - 1]; return &t->array[key - 1];
} }
else { else { /* key is not in the array part; check the hash */
Node *n = hashint(t, key); Node *n = hashint(t, key);
for (;;) { /* check whether 'key' is somewhere in the chain */ for (;;) { /* check whether 'key' is somewhere in the chain */
if (keyisinteger(n) && keyival(n) == key) if (keyisinteger(n) && keyival(n) == key)
@ -975,6 +992,4 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainpositionTV(t, key); return mainpositionTV(t, key);
} }
int luaH_isdummy (const Table *t) { return isdummy(t); }
#endif #endif

View File

@ -41,8 +41,6 @@ LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key,
TValue *value);
LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key, LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key,
TValue *value); TValue *value);
LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key, LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key,
@ -59,7 +57,6 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t);
#if defined(LUA_DEBUG) #if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
LUAI_FUNC int luaH_isdummy (const Table *t);
#endif #endif

View File

@ -93,7 +93,7 @@ static int tremove (lua_State *L) {
lua_Integer pos = luaL_optinteger(L, 2, size); lua_Integer pos = luaL_optinteger(L, 2, size);
if (pos != size) /* validate 'pos' if given */ if (pos != size) /* validate 'pos' if given */
/* check whether 'pos' is in [1, size + 1] */ /* check whether 'pos' is in [1, size + 1] */
luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1, luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2,
"position out of bounds"); "position out of bounds");
lua_geti(L, 1, pos); /* result = t[pos] */ lua_geti(L, 1, pos); /* result = t[pos] */
for ( ; pos < size; pos++) { for ( ; pos < size; pos++) {

View File

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

View File

@ -115,12 +115,13 @@ static void l_message (const char *pname, const char *msg) {
/* /*
** Check whether 'status' is not OK and, if so, prints the error ** Check whether 'status' is not OK and, if so, prints the error
** message on the top of the stack. It assumes that the error object ** message on the top of the stack.
** is a string, as it was either generated by Lua or by 'msghandler'.
*/ */
static int report (lua_State *L, int status) { static int report (lua_State *L, int status) {
if (status != LUA_OK) { if (status != LUA_OK) {
const char *msg = lua_tostring(L, -1); const char *msg = lua_tostring(L, -1);
if (msg == NULL)
msg = "(error message not a string)";
l_message(progname, msg); l_message(progname, msg);
lua_pop(L, 1); /* remove message */ lua_pop(L, 1); /* remove message */
} }
@ -177,10 +178,11 @@ static void print_version (void) {
** to the script (everything after 'script') go to positive indices; ** to the script (everything after 'script') go to positive indices;
** other arguments (before the script name) go to negative indices. ** other arguments (before the script name) go to negative indices.
** If there is no script name, assume interpreter's name as base. ** If there is no script name, assume interpreter's name as base.
** (If there is no interpreter's name either, 'script' is -1, so
** table sizes are zero.)
*/ */
static void createargtable (lua_State *L, char **argv, int argc, int script) { static void createargtable (lua_State *L, char **argv, int argc, int script) {
int i, narg; int i, narg;
if (script == argc) script = 0; /* no script name? */
narg = argc - (script + 1); /* number of positive indices */ narg = argc - (script + 1); /* number of positive indices */
lua_createtable(L, narg, script + 1); lua_createtable(L, narg, script + 1);
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
@ -209,12 +211,17 @@ static int dostring (lua_State *L, const char *s, const char *name) {
/* /*
** Receives 'globname[=modname]' and runs 'globname = require(modname)'. ** Receives 'globname[=modname]' and runs 'globname = require(modname)'.
** If there is no explicit modname and globname contains a '-', cut
** the suffix after '-' (the "version") to make the global name.
*/ */
static int dolibrary (lua_State *L, char *globname) { static int dolibrary (lua_State *L, char *globname) {
int status; int status;
char *suffix = NULL;
char *modname = strchr(globname, '='); char *modname = strchr(globname, '=');
if (modname == NULL) /* no explicit name? */ if (modname == NULL) { /* no explicit name? */
modname = globname; /* module name is equal to global name */ modname = globname; /* module name is equal to global name */
suffix = strchr(modname, *LUA_IGMARK); /* look for a suffix mark */
}
else { else {
*modname = '\0'; /* global name ends here */ *modname = '\0'; /* global name ends here */
modname++; /* module name starts after the '=' */ modname++; /* module name starts after the '=' */
@ -222,8 +229,11 @@ static int dolibrary (lua_State *L, char *globname) {
lua_getglobal(L, "require"); lua_getglobal(L, "require");
lua_pushstring(L, modname); lua_pushstring(L, modname);
status = docall(L, 1, 1); /* call 'require(modname)' */ status = docall(L, 1, 1); /* call 'require(modname)' */
if (status == LUA_OK) if (status == LUA_OK) {
if (suffix != NULL) /* is there a suffix mark? */
*suffix = '\0'; /* remove suffix from global name */
lua_setglobal(L, globname); /* globname = require(modname) */ lua_setglobal(L, globname); /* globname = require(modname) */
}
return report(L, status); return report(L, status);
} }
@ -268,14 +278,23 @@ static int handle_script (lua_State *L, char **argv) {
/* /*
** Traverses all arguments from 'argv', returning a mask with those ** Traverses all arguments from 'argv', returning a mask with those
** needed before running any Lua code (or an error code if it finds ** needed before running any Lua code or an error code if it finds any
** any invalid argument). 'first' returns the first not-handled argument ** invalid argument. In case of error, 'first' is the index of the bad
** (either the script name or a bad argument in case of error). ** argument. Otherwise, 'first' is -1 if there is no program name,
** 0 if there is no script name, or the index of the script name.
*/ */
static int collectargs (char **argv, int *first) { static int collectargs (char **argv, int *first) {
int args = 0; int args = 0;
int i; int i;
for (i = 1; argv[i] != NULL; i++) { if (argv[0] != NULL) { /* is there a program name? */
if (argv[0][0]) /* not empty? */
progname = argv[0]; /* save it */
}
else { /* no program name */
*first = -1;
return 0;
}
for (i = 1; argv[i] != NULL; i++) { /* handle arguments */
*first = i; *first = i;
if (argv[i][0] != '-') /* not an option? */ if (argv[i][0] != '-') /* not an option? */
return args; /* stop handling options */ return args; /* stop handling options */
@ -316,7 +335,7 @@ static int collectargs (char **argv, int *first) {
return has_error; return has_error;
} }
} }
*first = i; /* no script name */ *first = 0; /* no script name */
return args; return args;
} }
@ -609,8 +628,8 @@ static int pmain (lua_State *L) {
char **argv = (char **)lua_touserdata(L, 2); char **argv = (char **)lua_touserdata(L, 2);
int script; int script;
int args = collectargs(argv, &script); int args = collectargs(argv, &script);
int optlim = (script > 0) ? script : argc; /* first argv not an option */
luaL_checkversion(L); /* check that interpreter has correct version */ luaL_checkversion(L); /* check that interpreter has correct version */
if (argv[0] && argv[0][0]) progname = argv[0];
if (args == has_error) { /* bad arg? */ if (args == has_error) { /* bad arg? */
print_usage(argv[script]); /* 'script' has index of bad arg. */ print_usage(argv[script]); /* 'script' has index of bad arg. */
return 0; return 0;
@ -623,19 +642,21 @@ static int pmain (lua_State *L) {
} }
luaL_openlibs(L); /* open standard libraries */ luaL_openlibs(L); /* open standard libraries */
createargtable(L, argv, argc, script); /* create table 'arg' */ createargtable(L, argv, argc, script); /* create table 'arg' */
lua_gc(L, LUA_GCGEN, 0, 0); /* GC in generational mode */ lua_gc(L, LUA_GCRESTART); /* start GC... */
lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */
if (!(args & has_E)) { /* no option '-E'? */ if (!(args & has_E)) { /* no option '-E'? */
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */ if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
return 0; /* error running LUA_INIT */ return 0; /* error running LUA_INIT */
} }
if (!runargs(L, argv, script)) /* execute arguments -e and -l */ if (!runargs(L, argv, optlim)) /* execute arguments -e and -l */
return 0; /* something failed */ return 0; /* something failed */
if (script < argc && /* execute main script (if there is one) */ if (script > 0) { /* execute main script (if there is one) */
handle_script(L, argv + script) != LUA_OK) if (handle_script(L, argv + script) != LUA_OK)
return 0; return 0; /* interrupt in case of error */
}
if (args & has_i) /* -i option? */ if (args & has_i) /* -i option? */
doREPL(L); /* do read-eval-print loop */ doREPL(L); /* do read-eval-print loop */
else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */ else if (script < 1 && !(args & (has_e | has_v))) { /* no active option? */
if (lua_stdin_is_tty()) { /* running in interactive mode? */ if (lua_stdin_is_tty()) { /* running in interactive mode? */
print_version(); print_version();
doREPL(L); /* do read-eval-print loop */ doREPL(L); /* do read-eval-print loop */
@ -654,6 +675,7 @@ int main (int argc, char **argv) {
l_message(argv[0], "cannot create state: not enough memory"); l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
lua_gc(L, LUA_GCSTOP); /* stop GC while building state */
lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */ lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */
lua_pushinteger(L, argc); /* 1st argument */ lua_pushinteger(L, argc); /* 1st argument */
lua_pushlightuserdata(L, argv); /* 2nd argument */ lua_pushlightuserdata(L, argv); /* 2nd argument */

View File

@ -18,14 +18,14 @@
#define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "4" #define LUA_VERSION_MINOR "4"
#define LUA_VERSION_RELEASE "4" #define LUA_VERSION_RELEASE "7"
#define LUA_VERSION_NUM 504 #define LUA_VERSION_NUM 504
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 4) #define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 7)
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2022 Lua.org, PUC-Rio" #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2024 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@ -131,6 +131,16 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont); typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
/*
** Type used by the debug API to collect debug information
*/
typedef struct lua_Debug lua_Debug;
/*
** Functions to be called by the debugger in specific events
*/
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
/* /*
@ -153,7 +163,8 @@ extern const char lua_ident[];
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L); LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L); LUA_API lua_State *(lua_newthread) (lua_State *L);
LUA_API int (lua_resetthread) (lua_State *L); LUA_API int (lua_closethread) (lua_State *L, lua_State *from);
LUA_API int (lua_resetthread) (lua_State *L); /* Deprecated! */
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
@ -442,12 +453,6 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
#define LUA_MASKLINE (1 << LUA_HOOKLINE) #define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) #define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
typedef struct lua_Debug lua_Debug; /* activation record */
/* Functions to be called by the debugger in specific events */
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
@ -492,7 +497,7 @@ struct lua_Debug {
/****************************************************************************** /******************************************************************************
* Copyright (C) 1994-2022 Lua.org, PUC-Rio. * Copyright (C) 1994-2024 Lua.org, PUC-Rio.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the

View File

@ -121,7 +121,7 @@ static int doargs(int argc, char* argv[])
return i; return i;
} }
#define FUNCTION "(function()end)();" #define FUNCTION "(function()end)();\n"
static const char* reader(lua_State* L, void* ud, size_t* size) static const char* reader(lua_State* L, void* ud, size_t* size)
{ {
@ -138,7 +138,7 @@ static const char* reader(lua_State* L, void* ud, size_t* size)
} }
} }
#define toproto(L,i) getproto(s2v(L->top+(i))) #define toproto(L,i) getproto(s2v(L->top.p+(i)))
static const Proto* combine(lua_State* L, int n) static const Proto* combine(lua_State* L, int n)
{ {
@ -155,8 +155,6 @@ static const Proto* combine(lua_State* L, int n)
f->p[i]=toproto(L,i-n-1); f->p[i]=toproto(L,i-n-1);
if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0; if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
} }
luaM_freearray(L,f->lineinfo,f->sizelineinfo);
f->sizelineinfo=0;
return f; return f;
} }
} }

View File

@ -70,6 +70,12 @@
#endif #endif
#if defined(LUA_USE_IOS)
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN
#endif
/* /*
@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits. @@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits.
*/ */
@ -251,6 +257,15 @@
#endif #endif
/*
** LUA_IGMARK is a mark to ignore all after it when building the
** module name (e.g., used to build the luaopen_ function name).
** Typically, the suffix after the mark is the module version,
** as in "mod-v1.2.so".
*/
#define LUA_IGMARK "-"
/* }================================================================== */ /* }================================================================== */
@ -728,7 +743,7 @@
** CHANGE it if you need a different limit. This limit is arbitrary; ** CHANGE it if you need a different limit. This limit is arbitrary;
** its only purpose is to stop Lua from consuming unlimited stack ** its only purpose is to stop Lua from consuming unlimited stack
** space (and to reserve some numbers for pseudo-indices). ** space (and to reserve some numbers for pseudo-indices).
** (It must fit into max(size_t)/32.) ** (It must fit into max(size_t)/32 and max(int)/2.)
*/ */
#if LUAI_IS32INT #if LUAI_IS32INT
#define LUAI_MAXSTACK 1000000 #define LUAI_MAXSTACK 1000000
@ -747,14 +762,15 @@
/* /*
@@ LUA_IDSIZE gives the maximum size for the description of the source @@ LUA_IDSIZE gives the maximum size for the description of the source
@@ of a function in debug information. ** of a function in debug information.
** CHANGE it if you want a different size. ** CHANGE it if you want a different size.
*/ */
#define LUA_IDSIZE 60 #define LUA_IDSIZE 60
/* /*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. @@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib
** buffer system.
*/ */
#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number))) #define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))

View File

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

View File

@ -21,8 +21,7 @@
/* /*
** Encode major-minor version in one byte, one nibble for each ** Encode major-minor version in one byte, one nibble for each
*/ */
#define MYINT(s) (s[0]-'0') /* assume one-digit numerals */ #define LUAC_VERSION (((LUA_VERSION_NUM / 100) * 16) + LUA_VERSION_NUM % 100)
#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR))
#define LUAC_FORMAT 0 /* this is the official format */ #define LUAC_FORMAT 0 /* this is the official format */

View File

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

309
3rdparty/lua/src/lvm.c vendored
View File

@ -91,8 +91,10 @@ static int l_strton (const TValue *obj, TValue *result) {
lua_assert(obj != result); lua_assert(obj != result);
if (!cvt2num(obj)) /* is object not a string? */ if (!cvt2num(obj)) /* is object not a string? */
return 0; return 0;
else else {
return (luaO_str2num(svalue(obj), result) == vslen(obj) + 1); TString *st = tsvalue(obj);
return (luaO_str2num(getstr(st), result) == tsslen(st) + 1);
}
} }
@ -366,30 +368,32 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
/* /*
** Compare two strings 'ls' x 'rs', returning an integer less-equal- ** Compare two strings 'ts1' x 'ts2', returning an integer less-equal-
** -greater than zero if 'ls' is less-equal-greater than 'rs'. ** -greater than zero if 'ts1' is less-equal-greater than 'ts2'.
** The code is a little tricky because it allows '\0' in the strings ** The code is a little tricky because it allows '\0' in the strings
** and it uses 'strcoll' (to respect locales) for each segments ** and it uses 'strcoll' (to respect locales) for each segment
** of the strings. ** of the strings. Note that segments can compare equal but still
** have different lengths.
*/ */
static int l_strcmp (const TString *ls, const TString *rs) { static int l_strcmp (const TString *ts1, const TString *ts2) {
const char *l = getstr(ls); const char *s1 = getstr(ts1);
size_t ll = tsslen(ls); size_t rl1 = tsslen(ts1); /* real length */
const char *r = getstr(rs); const char *s2 = getstr(ts2);
size_t lr = tsslen(rs); size_t rl2 = tsslen(ts2);
for (;;) { /* for each segment */ for (;;) { /* for each segment */
int temp = strcoll(l, r); int temp = strcoll(s1, s2);
if (temp != 0) /* not equal? */ if (temp != 0) /* not equal? */
return temp; /* done */ return temp; /* done */
else { /* strings are equal up to a '\0' */ else { /* strings are equal up to a '\0' */
size_t len = strlen(l); /* index of first '\0' in both strings */ size_t zl1 = strlen(s1); /* index of first '\0' in 's1' */
if (len == lr) /* 'rs' is finished? */ size_t zl2 = strlen(s2); /* index of first '\0' in 's2' */
return (len == ll) ? 0 : 1; /* check 'ls' */ if (zl2 == rl2) /* 's2' is finished? */
else if (len == ll) /* 'ls' is finished? */ return (zl1 == rl1) ? 0 : 1; /* check 's1' */
return -1; /* 'ls' is less than 'rs' ('rs' is not finished) */ else if (zl1 == rl1) /* 's1' is finished? */
/* both strings longer than 'len'; go on comparing after the '\0' */ return -1; /* 's1' is less than 's2' ('s2' is not finished) */
len++; /* both strings longer than 'zl'; go on comparing after the '\0' */
l += len; ll -= len; r += len; lr -= len; zl1++; zl2++;
s1 += zl1; rl1 -= zl1; s2 += zl2; rl2 -= zl2;
} }
} }
} }
@ -608,8 +612,8 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
if (tm == NULL) /* no TM? */ if (tm == NULL) /* no TM? */
return 0; /* objects are different */ return 0; /* objects are different */
else { else {
luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */ luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */
return !l_isfalse(s2v(L->top)); return !l_isfalse(s2v(L->top.p));
} }
} }
@ -624,8 +628,9 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
static void copy2buff (StkId top, int n, char *buff) { static void copy2buff (StkId top, int n, char *buff) {
size_t tl = 0; /* size already copied */ size_t tl = 0; /* size already copied */
do { do {
size_t l = vslen(s2v(top - n)); /* length of string being copied */ TString *st = tsvalue(s2v(top - n));
memcpy(buff + tl, svalue(s2v(top - n)), l * sizeof(char)); size_t l = tsslen(st); /* length of string being copied */
memcpy(buff + tl, getstr(st), l * sizeof(char));
tl += l; tl += l;
} while (--n > 0); } while (--n > 0);
} }
@ -633,17 +638,17 @@ static void copy2buff (StkId top, int n, char *buff) {
/* /*
** Main operation for concatenation: concat 'total' values in the stack, ** 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) { void luaV_concat (lua_State *L, int total) {
if (total == 1) if (total == 1)
return; /* "all" values already concatenated */ return; /* "all" values already concatenated */
do { do {
StkId top = L->top; StkId top = L->top.p;
int n = 2; /* number of elements handled in this pass (at least 2) */ int n = 2; /* number of elements handled in this pass (at least 2) */
if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) || if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) ||
!tostring(L, s2v(top - 1))) !tostring(L, s2v(top - 1)))
luaT_tryconcatTM(L); luaT_tryconcatTM(L); /* may invalidate 'top' */
else if (isemptystr(s2v(top - 1))) /* second operand is empty? */ else if (isemptystr(s2v(top - 1))) /* second operand is empty? */
cast_void(tostring(L, s2v(top - 2))); /* result is first operand */ cast_void(tostring(L, s2v(top - 2))); /* result is first operand */
else if (isemptystr(s2v(top - 2))) { /* first operand is empty string? */ else if (isemptystr(s2v(top - 2))) { /* first operand is empty string? */
@ -651,13 +656,15 @@ void luaV_concat (lua_State *L, int total) {
} }
else { else {
/* at least two non-empty string values; get as many as possible */ /* at least two non-empty string values; get as many as possible */
size_t tl = vslen(s2v(top - 1)); size_t tl = tsslen(tsvalue(s2v(top - 1)));
TString *ts; TString *ts;
/* collect total length and number of strings */ /* collect total length and number of strings */
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) { for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
size_t l = vslen(s2v(top - n - 1)); size_t l = tsslen(tsvalue(s2v(top - n - 1)));
if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) if (l_unlikely(l >= MAX_SIZE - sizeof(TString) - tl)) {
L->top.p = top - total; /* pop strings to avoid wasting stack */
luaG_runerror(L, "string length overflow"); luaG_runerror(L, "string length overflow");
}
tl += l; tl += l;
} }
if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */ if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
@ -667,12 +674,12 @@ void luaV_concat (lua_State *L, int total) {
} }
else { /* long string; copy strings directly to final result */ else { /* long string; copy strings directly to final result */
ts = luaS_createlngstrobj(L, tl); ts = luaS_createlngstrobj(L, tl);
copy2buff(top, n, getstr(ts)); copy2buff(top, n, getlngstr(ts));
} }
setsvalue2s(L, top - n, ts); /* create result */ setsvalue2s(L, top - n, ts); /* create result */
} }
total -= n-1; /* got 'n' strings to create 1 new */ total -= n - 1; /* got 'n' strings to create one new */
L->top -= n-1; /* popped 'n' strings and pushed one */ L->top.p -= n - 1; /* popped 'n' strings and pushed one */
} while (total > 1); /* repeat until only 1 result left */ } while (total > 1); /* repeat until only 1 result left */
} }
@ -763,12 +770,10 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) {
/* number of bits in an integer */ /* number of bits in an integer */
#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT) #define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT)
/* /*
** Shift left operation. (Shift right just negates 'y'.) ** 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) { lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
if (y < 0) { /* shift right? */ if (y < 0) { /* shift right? */
if (y <= -NBITS) return 0; if (y <= -NBITS) return 0;
@ -808,26 +813,26 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
*/ */
void luaV_finishOp (lua_State *L) { void luaV_finishOp (lua_State *L) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
StkId base = ci->func + 1; StkId base = ci->func.p + 1;
Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */
OpCode op = GET_OPCODE(inst); OpCode op = GET_OPCODE(inst);
switch (op) { /* finish its execution */ switch (op) { /* finish its execution */
case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: { 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; break;
} }
case OP_UNM: case OP_BNOT: case OP_LEN: case OP_UNM: case OP_BNOT: case OP_LEN:
case OP_GETTABUP: case OP_GETTABLE: case OP_GETI: case OP_GETTABUP: case OP_GETTABLE: case OP_GETI:
case OP_GETFIELD: case OP_SELF: { case OP_GETFIELD: case OP_SELF: {
setobjs2s(L, base + GETARG_A(inst), --L->top); setobjs2s(L, base + GETARG_A(inst), --L->top.p);
break; break;
} }
case OP_LT: case OP_LE: case OP_LT: case OP_LE:
case OP_LTI: case OP_LEI: case OP_LTI: case OP_LEI:
case OP_GTI: case OP_GEI: case OP_GTI: case OP_GEI:
case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */ case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */
int res = !l_isfalse(s2v(L->top - 1)); int res = !l_isfalse(s2v(L->top.p - 1));
L->top--; L->top.p--;
#if defined(LUA_COMPAT_LT_LE) #if defined(LUA_COMPAT_LT_LE)
if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
ci->callstatus ^= CIST_LEQ; /* clear mark */ ci->callstatus ^= CIST_LEQ; /* clear mark */
@ -840,11 +845,11 @@ void luaV_finishOp (lua_State *L) {
break; break;
} }
case OP_CONCAT: { 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 a = GETARG_A(inst); /* first element to concatenate */
int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */ int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */
setobjs2s(L, top - 2, top); /* put TM result in proper position */ setobjs2s(L, top - 2, top); /* put TM result in proper position */
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) */ luaV_concat(L, total); /* concat them (may yield again) */
break; break;
} }
@ -856,7 +861,7 @@ void luaV_finishOp (lua_State *L) {
StkId ra = base + GETARG_A(inst); StkId ra = base + GETARG_A(inst);
/* adjust top to signal correct number of returns, in case the /* adjust top to signal correct number of returns, in case the
return is "up to top" ('isIT') */ 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 */ /* repeat instruction to close other vars. and complete the return */
ci->u.l.savedpc--; ci->u.l.savedpc--;
break; break;
@ -898,6 +903,7 @@ void luaV_finishOp (lua_State *L) {
** operation, 'fop' is the float operation. ** operation, 'fop' is the float operation.
*/ */
#define op_arithI(L,iop,fop) { \ #define op_arithI(L,iop,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
int imm = GETARG_sC(i); \ int imm = GETARG_sC(i); \
if (ttisinteger(v1)) { \ if (ttisinteger(v1)) { \
@ -926,6 +932,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over floats and others with register operands. ** Arithmetic operations over floats and others with register operands.
*/ */
#define op_arithf(L,fop) { \ #define op_arithf(L,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \ TValue *v2 = vRC(i); \
op_arithf_aux(L, v1, v2, fop); } op_arithf_aux(L, v1, v2, fop); }
@ -935,6 +942,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations with K operands for floats. ** Arithmetic operations with K operands for floats.
*/ */
#define op_arithfK(L,fop) { \ #define op_arithfK(L,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \ TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
op_arithf_aux(L, v1, v2, fop); } op_arithf_aux(L, v1, v2, fop); }
@ -944,6 +952,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over integers and floats. ** Arithmetic operations over integers and floats.
*/ */
#define op_arith_aux(L,v1,v2,iop,fop) { \ #define op_arith_aux(L,v1,v2,iop,fop) { \
StkId ra = RA(i); \
if (ttisinteger(v1) && ttisinteger(v2)) { \ if (ttisinteger(v1) && ttisinteger(v2)) { \
lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \ lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \
pc++; setivalue(s2v(ra), iop(L, i1, i2)); \ pc++; setivalue(s2v(ra), iop(L, i1, i2)); \
@ -973,6 +982,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with constant operand. ** Bitwise operations with constant operand.
*/ */
#define op_bitwiseK(L,op) { \ #define op_bitwiseK(L,op) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
TValue *v2 = KC(i); \ TValue *v2 = KC(i); \
lua_Integer i1; \ lua_Integer i1; \
@ -986,6 +996,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with register operands. ** Bitwise operations with register operands.
*/ */
#define op_bitwise(L,op) { \ #define op_bitwise(L,op) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \ TValue *v2 = vRC(i); \
lua_Integer i1; lua_Integer i2; \ lua_Integer i1; lua_Integer i2; \
@ -1000,18 +1011,19 @@ void luaV_finishOp (lua_State *L) {
** integers. ** integers.
*/ */
#define op_order(L,opi,opn,other) { \ #define op_order(L,opi,opn,other) { \
int cond; \ StkId ra = RA(i); \
TValue *rb = vRB(i); \ int cond; \
if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \ TValue *rb = vRB(i); \
lua_Integer ia = ivalue(s2v(ra)); \ if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
lua_Integer ib = ivalue(rb); \ lua_Integer ia = ivalue(s2v(ra)); \
cond = opi(ia, ib); \ lua_Integer ib = ivalue(rb); \
} \ cond = opi(ia, ib); \
else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \ } \
cond = opn(s2v(ra), rb); \ else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \
else \ cond = opn(s2v(ra), rb); \
Protect(cond = other(L, s2v(ra), rb)); \ else \
docondjump(); } Protect(cond = other(L, s2v(ra), rb)); \
docondjump(); }
/* /*
@ -1019,20 +1031,21 @@ void luaV_finishOp (lua_State *L) {
** always small enough to have an exact representation as a float.) ** always small enough to have an exact representation as a float.)
*/ */
#define op_orderI(L,opi,opf,inv,tm) { \ #define op_orderI(L,opi,opf,inv,tm) { \
int cond; \ StkId ra = RA(i); \
int im = GETARG_sB(i); \ int cond; \
if (ttisinteger(s2v(ra))) \ int im = GETARG_sB(i); \
cond = opi(ivalue(s2v(ra)), im); \ if (ttisinteger(s2v(ra))) \
else if (ttisfloat(s2v(ra))) { \ cond = opi(ivalue(s2v(ra)), im); \
lua_Number fa = fltvalue(s2v(ra)); \ else if (ttisfloat(s2v(ra))) { \
lua_Number fim = cast_num(im); \ lua_Number fa = fltvalue(s2v(ra)); \
cond = opf(fa, fim); \ lua_Number fim = cast_num(im); \
} \ cond = opf(fa, fim); \
else { \ } \
int isf = GETARG_C(i); \ else { \
Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \ int isf = GETARG_C(i); \
} \ Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \
docondjump(); } } \
docondjump(); }
/* }================================================================== */ /* }================================================================== */
@ -1061,7 +1074,7 @@ void luaV_finishOp (lua_State *L) {
#define updatetrap(ci) (trap = ci->u.l.trap) #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) \ #define updatestack(ci) \
@ -1096,7 +1109,7 @@ void luaV_finishOp (lua_State *L) {
** Whenever code can raise errors, the global 'pc' and the global ** Whenever code can raise errors, the global 'pc' and the global
** 'top' must be correct to report occasional errors. ** '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 +1129,7 @@ void luaV_finishOp (lua_State *L) {
/* 'c' is the limit of live values in the stack */ /* 'c' is the limit of live values in the stack */
#define checkGC(L,c) \ #define checkGC(L,c) \
{ luaC_condGC(L, (savepc(L), L->top = (c)), \ { luaC_condGC(L, (savepc(L), L->top.p = (c)), \
updatetrap(ci)); \ updatetrap(ci)); \
luai_threadyield(L); } luai_threadyield(L); }
@ -1128,7 +1141,6 @@ void luaV_finishOp (lua_State *L) {
updatebase(ci); /* correct stack */ \ updatebase(ci); /* correct stack */ \
} \ } \
i = *(pc++); \ i = *(pc++); \
ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
} }
#define vmdispatch(o) switch(o) #define vmdispatch(o) switch(o)
@ -1148,72 +1160,73 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
startfunc: startfunc:
trap = L->hookmask; trap = L->hookmask;
returning: /* trap already set */ returning: /* trap already set */
cl = clLvalue(s2v(ci->func)); cl = ci_func(ci);
k = cl->p->k; k = cl->p->k;
pc = ci->u.l.savedpc; pc = ci->u.l.savedpc;
if (l_unlikely(trap)) { if (l_unlikely(trap))
if (pc == cl->p->code) { /* first instruction (not resuming)? */ trap = luaG_tracecall(L);
if (cl->p->is_vararg) base = ci->func.p + 1;
trap = 0; /* hooks will start after VARARGPREP instruction */
else /* check 'call' hook */
luaD_hookcall(L, ci);
}
ci->u.l.trap = 1; /* assume trap is on, for now */
}
base = ci->func + 1;
/* main loop of interpreter */ /* main loop of interpreter */
for (;;) { for (;;) {
Instruction i; /* instruction being executed */ Instruction i; /* instruction being executed */
StkId ra; /* instruction's A register */
vmfetch(); vmfetch();
#if 0 #if 0
/* low-level line tracing for debugging Lua */ /* low-level line tracing for debugging Lua */
printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p))); printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
#endif #endif
lua_assert(base == ci->func + 1); lua_assert(base == ci->func.p + 1);
lua_assert(base <= L->top && L->top < L->stack_last); lua_assert(base <= L->top.p && L->top.p <= L->stack_last.p);
/* invalidate top for instructions not expecting it */ /* 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)) { vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) { vmcase(OP_MOVE) {
StkId ra = RA(i);
setobjs2s(L, ra, RB(i)); setobjs2s(L, ra, RB(i));
vmbreak; vmbreak;
} }
vmcase(OP_LOADI) { vmcase(OP_LOADI) {
StkId ra = RA(i);
lua_Integer b = GETARG_sBx(i); lua_Integer b = GETARG_sBx(i);
setivalue(s2v(ra), b); setivalue(s2v(ra), b);
vmbreak; vmbreak;
} }
vmcase(OP_LOADF) { vmcase(OP_LOADF) {
StkId ra = RA(i);
int b = GETARG_sBx(i); int b = GETARG_sBx(i);
setfltvalue(s2v(ra), cast_num(b)); setfltvalue(s2v(ra), cast_num(b));
vmbreak; vmbreak;
} }
vmcase(OP_LOADK) { vmcase(OP_LOADK) {
StkId ra = RA(i);
TValue *rb = k + GETARG_Bx(i); TValue *rb = k + GETARG_Bx(i);
setobj2s(L, ra, rb); setobj2s(L, ra, rb);
vmbreak; vmbreak;
} }
vmcase(OP_LOADKX) { vmcase(OP_LOADKX) {
StkId ra = RA(i);
TValue *rb; TValue *rb;
rb = k + GETARG_Ax(*pc); pc++; rb = k + GETARG_Ax(*pc); pc++;
setobj2s(L, ra, rb); setobj2s(L, ra, rb);
vmbreak; vmbreak;
} }
vmcase(OP_LOADFALSE) { vmcase(OP_LOADFALSE) {
StkId ra = RA(i);
setbfvalue(s2v(ra)); setbfvalue(s2v(ra));
vmbreak; vmbreak;
} }
vmcase(OP_LFALSESKIP) { vmcase(OP_LFALSESKIP) {
StkId ra = RA(i);
setbfvalue(s2v(ra)); setbfvalue(s2v(ra));
pc++; /* skip next instruction */ pc++; /* skip next instruction */
vmbreak; vmbreak;
} }
vmcase(OP_LOADTRUE) { vmcase(OP_LOADTRUE) {
StkId ra = RA(i);
setbtvalue(s2v(ra)); setbtvalue(s2v(ra));
vmbreak; vmbreak;
} }
vmcase(OP_LOADNIL) { vmcase(OP_LOADNIL) {
StkId ra = RA(i);
int b = GETARG_B(i); int b = GETARG_B(i);
do { do {
setnilvalue(s2v(ra++)); setnilvalue(s2v(ra++));
@ -1221,21 +1234,24 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_GETUPVAL) { vmcase(OP_GETUPVAL) {
StkId ra = RA(i);
int b = GETARG_B(i); int b = GETARG_B(i);
setobj2s(L, ra, cl->upvals[b]->v); setobj2s(L, ra, cl->upvals[b]->v.p);
vmbreak; vmbreak;
} }
vmcase(OP_SETUPVAL) { vmcase(OP_SETUPVAL) {
StkId ra = RA(i);
UpVal *uv = cl->upvals[GETARG_B(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)); luaC_barrier(L, uv, s2v(ra));
vmbreak; vmbreak;
} }
vmcase(OP_GETTABUP) { vmcase(OP_GETTABUP) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *upval = cl->upvals[GETARG_B(i)]->v; TValue *upval = cl->upvals[GETARG_B(i)]->v.p;
TValue *rc = KC(i); TValue *rc = KC(i);
TString *key = tsvalue(rc); /* key must be a string */ TString *key = tsvalue(rc); /* key must be a short string */
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
setobj2s(L, ra, slot); setobj2s(L, ra, slot);
} }
@ -1244,6 +1260,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_GETTABLE) { vmcase(OP_GETTABLE) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = vRB(i); TValue *rb = vRB(i);
TValue *rc = vRC(i); TValue *rc = vRC(i);
@ -1258,6 +1275,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_GETI) { vmcase(OP_GETI) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = vRB(i); TValue *rb = vRB(i);
int c = GETARG_C(i); int c = GETARG_C(i);
@ -1272,10 +1290,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_GETFIELD) { vmcase(OP_GETFIELD) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = vRB(i); TValue *rb = vRB(i);
TValue *rc = KC(i); TValue *rc = KC(i);
TString *key = tsvalue(rc); /* key must be a string */ TString *key = tsvalue(rc); /* key must be a short string */
if (luaV_fastget(L, rb, key, slot, luaH_getshortstr)) { if (luaV_fastget(L, rb, key, slot, luaH_getshortstr)) {
setobj2s(L, ra, slot); setobj2s(L, ra, slot);
} }
@ -1285,10 +1304,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
} }
vmcase(OP_SETTABUP) { vmcase(OP_SETTABUP) {
const TValue *slot; 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 *rb = KB(i);
TValue *rc = RKC(i); TValue *rc = RKC(i);
TString *key = tsvalue(rb); /* key must be a string */ TString *key = tsvalue(rb); /* key must be a short string */
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
luaV_finishfastset(L, upval, slot, rc); luaV_finishfastset(L, upval, slot, rc);
} }
@ -1297,6 +1316,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SETTABLE) { vmcase(OP_SETTABLE) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = vRB(i); /* key (table is in 'ra') */ TValue *rb = vRB(i); /* key (table is in 'ra') */
TValue *rc = RKC(i); /* value */ TValue *rc = RKC(i); /* value */
@ -1311,6 +1331,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SETI) { vmcase(OP_SETI) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
int c = GETARG_B(i); int c = GETARG_B(i);
TValue *rc = RKC(i); TValue *rc = RKC(i);
@ -1325,10 +1346,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SETFIELD) { vmcase(OP_SETFIELD) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = KB(i); TValue *rb = KB(i);
TValue *rc = RKC(i); TValue *rc = RKC(i);
TString *key = tsvalue(rb); /* key must be a string */ TString *key = tsvalue(rb); /* key must be a short string */
if (luaV_fastget(L, s2v(ra), key, slot, luaH_getshortstr)) { if (luaV_fastget(L, s2v(ra), key, slot, luaH_getshortstr)) {
luaV_finishfastset(L, s2v(ra), slot, rc); luaV_finishfastset(L, s2v(ra), slot, rc);
} }
@ -1337,6 +1359,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_NEWTABLE) { vmcase(OP_NEWTABLE) {
StkId ra = RA(i);
int b = GETARG_B(i); /* log2(hash size) + 1 */ int b = GETARG_B(i); /* log2(hash size) + 1 */
int c = GETARG_C(i); /* array size */ int c = GETARG_C(i); /* array size */
Table *t; Table *t;
@ -1346,7 +1369,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
if (TESTARG_k(i)) /* non-zero extra argument? */ if (TESTARG_k(i)) /* non-zero extra argument? */
c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */ c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */
pc++; /* skip extra argument */ pc++; /* skip extra argument */
L->top = ra + 1; /* correct top in case of emergency GC */ L->top.p = ra + 1; /* correct top in case of emergency GC */
t = luaH_new(L); /* memory allocation */ t = luaH_new(L); /* memory allocation */
sethvalue2s(L, ra, t); sethvalue2s(L, ra, t);
if (b != 0 || c != 0) if (b != 0 || c != 0)
@ -1355,6 +1378,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SELF) { vmcase(OP_SELF) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = vRB(i); TValue *rb = vRB(i);
TValue *rc = RKC(i); TValue *rc = RKC(i);
@ -1384,6 +1408,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_MODK) { vmcase(OP_MODK) {
savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_mod, luaV_modf); op_arithK(L, luaV_mod, luaV_modf);
vmbreak; vmbreak;
} }
@ -1396,6 +1421,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_IDIVK) { vmcase(OP_IDIVK) {
savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_idiv, luai_numidiv); op_arithK(L, luaV_idiv, luai_numidiv);
vmbreak; vmbreak;
} }
@ -1412,6 +1438,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SHRI) { vmcase(OP_SHRI) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
int ic = GETARG_sC(i); int ic = GETARG_sC(i);
lua_Integer ib; lua_Integer ib;
@ -1421,6 +1448,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SHLI) { vmcase(OP_SHLI) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
int ic = GETARG_sC(i); int ic = GETARG_sC(i);
lua_Integer ib; lua_Integer ib;
@ -1442,6 +1470,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_MOD) { vmcase(OP_MOD) {
savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_mod, luaV_modf); op_arith(L, luaV_mod, luaV_modf);
vmbreak; vmbreak;
} }
@ -1454,6 +1483,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_IDIV) { /* floor division */ vmcase(OP_IDIV) { /* floor division */
savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_idiv, luai_numidiv); op_arith(L, luaV_idiv, luai_numidiv);
vmbreak; vmbreak;
} }
@ -1478,6 +1508,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_MMBIN) { vmcase(OP_MMBIN) {
StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */ Instruction pi = *(pc - 2); /* original arith. expression */
TValue *rb = vRB(i); TValue *rb = vRB(i);
TMS tm = (TMS)GETARG_C(i); TMS tm = (TMS)GETARG_C(i);
@ -1487,6 +1518,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_MMBINI) { vmcase(OP_MMBINI) {
StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */ Instruction pi = *(pc - 2); /* original arith. expression */
int imm = GETARG_sB(i); int imm = GETARG_sB(i);
TMS tm = (TMS)GETARG_C(i); TMS tm = (TMS)GETARG_C(i);
@ -1496,6 +1528,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_MMBINK) { vmcase(OP_MMBINK) {
StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */ Instruction pi = *(pc - 2); /* original arith. expression */
TValue *imm = KB(i); TValue *imm = KB(i);
TMS tm = (TMS)GETARG_C(i); TMS tm = (TMS)GETARG_C(i);
@ -1505,6 +1538,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_UNM) { vmcase(OP_UNM) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
lua_Number nb; lua_Number nb;
if (ttisinteger(rb)) { if (ttisinteger(rb)) {
@ -1519,6 +1553,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_BNOT) { vmcase(OP_BNOT) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
lua_Integer ib; lua_Integer ib;
if (tointegerns(rb, &ib)) { if (tointegerns(rb, &ib)) {
@ -1529,6 +1564,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_NOT) { vmcase(OP_NOT) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
if (l_isfalse(rb)) if (l_isfalse(rb))
setbtvalue(s2v(ra)); setbtvalue(s2v(ra));
@ -1537,21 +1573,25 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_LEN) { vmcase(OP_LEN) {
StkId ra = RA(i);
Protect(luaV_objlen(L, ra, vRB(i))); Protect(luaV_objlen(L, ra, vRB(i)));
vmbreak; vmbreak;
} }
vmcase(OP_CONCAT) { vmcase(OP_CONCAT) {
StkId ra = RA(i);
int n = GETARG_B(i); /* number of elements to concatenate */ 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)); 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; vmbreak;
} }
vmcase(OP_CLOSE) { vmcase(OP_CLOSE) {
StkId ra = RA(i);
Protect(luaF_close(L, ra, LUA_OK, 1)); Protect(luaF_close(L, ra, LUA_OK, 1));
vmbreak; vmbreak;
} }
vmcase(OP_TBC) { vmcase(OP_TBC) {
StkId ra = RA(i);
/* create new to-be-closed upvalue */ /* create new to-be-closed upvalue */
halfProtect(luaF_newtbcupval(L, ra)); halfProtect(luaF_newtbcupval(L, ra));
vmbreak; vmbreak;
@ -1561,6 +1601,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_EQ) { vmcase(OP_EQ) {
StkId ra = RA(i);
int cond; int cond;
TValue *rb = vRB(i); TValue *rb = vRB(i);
Protect(cond = luaV_equalobj(L, s2v(ra), rb)); Protect(cond = luaV_equalobj(L, s2v(ra), rb));
@ -1576,6 +1617,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_EQK) { vmcase(OP_EQK) {
StkId ra = RA(i);
TValue *rb = KB(i); TValue *rb = KB(i);
/* basic types do not use '__eq'; we can use raw equality */ /* basic types do not use '__eq'; we can use raw equality */
int cond = luaV_rawequalobj(s2v(ra), rb); int cond = luaV_rawequalobj(s2v(ra), rb);
@ -1583,6 +1625,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_EQI) { vmcase(OP_EQI) {
StkId ra = RA(i);
int cond; int cond;
int im = GETARG_sB(i); int im = GETARG_sB(i);
if (ttisinteger(s2v(ra))) if (ttisinteger(s2v(ra)))
@ -1611,11 +1654,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_TEST) { vmcase(OP_TEST) {
StkId ra = RA(i);
int cond = !l_isfalse(s2v(ra)); int cond = !l_isfalse(s2v(ra));
docondjump(); docondjump();
vmbreak; vmbreak;
} }
vmcase(OP_TESTSET) { vmcase(OP_TESTSET) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
if (l_isfalse(rb) == GETARG_k(i)) if (l_isfalse(rb) == GETARG_k(i))
pc++; pc++;
@ -1626,11 +1671,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_CALL) { vmcase(OP_CALL) {
StkId ra = RA(i);
CallInfo *newci; CallInfo *newci;
int b = GETARG_B(i); int b = GETARG_B(i);
int nresults = GETARG_C(i) - 1; int nresults = GETARG_C(i) - 1;
if (b != 0) /* fixed number of arguments? */ if (b != 0) /* fixed number of arguments? */
L->top = ra + b; /* top signals number of arguments */ L->top.p = ra + b; /* top signals number of arguments */
/* else previous instruction set top */ /* else previous instruction set top */
savepc(L); /* in case of errors */ savepc(L); /* in case of errors */
if ((newci = luaD_precall(L, ra, nresults)) == NULL) if ((newci = luaD_precall(L, ra, nresults)) == NULL)
@ -1642,54 +1688,57 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_TAILCALL) { vmcase(OP_TAILCALL) {
StkId ra = RA(i);
int b = GETARG_B(i); /* number of arguments + 1 (function) */ int b = GETARG_B(i); /* number of arguments + 1 (function) */
int n; /* number of results when calling a C function */ int n; /* number of results when calling a C function */
int nparams1 = GETARG_C(i); int nparams1 = GETARG_C(i);
/* delta is virtual 'func' - real 'func' (vararg functions) */ /* delta is virtual 'func' - real 'func' (vararg functions) */
int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0; int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
if (b != 0) if (b != 0)
L->top = ra + b; L->top.p = ra + b;
else /* previous instruction set top */ 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 */ savepc(ci); /* several calls here can raise errors */
if (TESTARG_k(i)) { if (TESTARG_k(i)) {
luaF_closeupval(L, base); /* close upvalues from current call */ luaF_closeupval(L, base); /* close upvalues from current call */
lua_assert(L->tbclist < base); /* no pending tbc variables */ lua_assert(L->tbclist.p < base); /* no pending tbc variables */
lua_assert(base == ci->func + 1); lua_assert(base == ci->func.p + 1);
} }
if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */ if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */
goto startfunc; /* execute the callee */ goto startfunc; /* execute the callee */
else { /* C function? */ 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 */ luaD_poscall(L, ci, n); /* finish caller */
updatetrap(ci); /* 'luaD_poscall' can change hooks */ updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret; /* caller returns after the tail call */ goto ret; /* caller returns after the tail call */
} }
} }
vmcase(OP_RETURN) { vmcase(OP_RETURN) {
StkId ra = RA(i);
int n = GETARG_B(i) - 1; /* number of results */ int n = GETARG_B(i) - 1; /* number of results */
int nparams1 = GETARG_C(i); int nparams1 = GETARG_C(i);
if (n < 0) /* not fixed? */ 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); savepc(ci);
if (TESTARG_k(i)) { /* may there be open upvalues? */ if (TESTARG_k(i)) { /* may there be open upvalues? */
ci->u2.nres = n; /* save number of returns */ ci->u2.nres = n; /* save number of returns */
if (L->top < ci->top) if (L->top.p < ci->top.p)
L->top = ci->top; L->top.p = ci->top.p;
luaF_close(L, base, CLOSEKTOP, 1); luaF_close(L, base, CLOSEKTOP, 1);
updatetrap(ci); updatetrap(ci);
updatestack(ci); updatestack(ci);
} }
if (nparams1) /* vararg function? */ if (nparams1) /* vararg function? */
ci->func -= ci->u.l.nextraargs + nparams1; ci->func.p -= ci->u.l.nextraargs + nparams1;
L->top = ra + n; /* set call for 'luaD_poscall' */ L->top.p = ra + n; /* set call for 'luaD_poscall' */
luaD_poscall(L, ci, n); luaD_poscall(L, ci, n);
updatetrap(ci); /* 'luaD_poscall' can change hooks */ updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret; goto ret;
} }
vmcase(OP_RETURN0) { vmcase(OP_RETURN0) {
if (l_unlikely(L->hookmask)) { if (l_unlikely(L->hookmask)) {
L->top = ra; StkId ra = RA(i);
L->top.p = ra;
savepc(ci); savepc(ci);
luaD_poscall(L, ci, 0); /* no hurry... */ luaD_poscall(L, ci, 0); /* no hurry... */
trap = 1; trap = 1;
@ -1697,15 +1746,16 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
else { /* do the 'poscall' here */ else { /* do the 'poscall' here */
int nres; int nres;
L->ci = ci->previous; /* back to caller */ 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--) 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; goto ret;
} }
vmcase(OP_RETURN1) { vmcase(OP_RETURN1) {
if (l_unlikely(L->hookmask)) { if (l_unlikely(L->hookmask)) {
L->top = ra + 1; StkId ra = RA(i);
L->top.p = ra + 1;
savepc(ci); savepc(ci);
luaD_poscall(L, ci, 1); /* no hurry... */ luaD_poscall(L, ci, 1); /* no hurry... */
trap = 1; trap = 1;
@ -1714,12 +1764,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
int nres = ci->nresults; int nres = ci->nresults;
L->ci = ci->previous; /* back to caller */ L->ci = ci->previous; /* back to caller */
if (nres == 0) if (nres == 0)
L->top = base - 1; /* asked for no results */ L->top.p = base - 1; /* asked for no results */
else { else {
StkId ra = RA(i);
setobjs2s(L, base - 1, ra); /* at least this result */ setobjs2s(L, base - 1, ra); /* at least this result */
L->top = base; L->top.p = base;
for (; l_unlikely(nres > 1); nres--) 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 */ ret: /* return from a Lua function */
@ -1731,6 +1782,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
} }
} }
vmcase(OP_FORLOOP) { vmcase(OP_FORLOOP) {
StkId ra = RA(i);
if (ttisinteger(s2v(ra + 2))) { /* integer loop? */ if (ttisinteger(s2v(ra + 2))) { /* integer loop? */
lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1))); lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1)));
if (count > 0) { /* still more iterations? */ if (count > 0) { /* still more iterations? */
@ -1749,12 +1801,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_FORPREP) { vmcase(OP_FORPREP) {
StkId ra = RA(i);
savestate(L, ci); /* in case of errors */ savestate(L, ci); /* in case of errors */
if (forprep(L, ra)) if (forprep(L, ra))
pc += GETARG_Bx(i) + 1; /* skip the loop */ pc += GETARG_Bx(i) + 1; /* skip the loop */
vmbreak; vmbreak;
} }
vmcase(OP_TFORPREP) { vmcase(OP_TFORPREP) {
StkId ra = RA(i);
/* create to-be-closed upvalue (if needed) */ /* create to-be-closed upvalue (if needed) */
halfProtect(luaF_newtbcupval(L, ra + 3)); halfProtect(luaF_newtbcupval(L, ra + 3));
pc += GETARG_Bx(i); pc += GETARG_Bx(i);
@ -1763,7 +1817,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
goto l_tforcall; goto l_tforcall;
} }
vmcase(OP_TFORCALL) { vmcase(OP_TFORCALL) {
l_tforcall: l_tforcall: {
StkId ra = RA(i);
/* 'ra' has the iterator function, 'ra + 1' has the state, /* 'ra' has the iterator function, 'ra + 1' has the state,
'ra + 2' has the control variable, and 'ra + 3' has the 'ra + 2' has the control variable, and 'ra + 3' has the
to-be-closed variable. The call will use the stack after to-be-closed variable. The call will use the stack after
@ -1771,29 +1826,31 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
*/ */
/* push function, state, and control variable */ /* push function, state, and control variable */
memcpy(ra + 4, ra, 3 * sizeof(*ra)); 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 */ ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */
updatestack(ci); /* stack may have changed */ updatestack(ci); /* stack may have changed */
i = *(pc++); /* go to next instruction */ i = *(pc++); /* go to next instruction */
lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i)); lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));
goto l_tforloop; goto l_tforloop;
} }}
vmcase(OP_TFORLOOP) { vmcase(OP_TFORLOOP) {
l_tforloop: l_tforloop: {
StkId ra = RA(i);
if (!ttisnil(s2v(ra + 4))) { /* continue loop? */ if (!ttisnil(s2v(ra + 4))) { /* continue loop? */
setobjs2s(L, ra + 2, ra + 4); /* save control variable */ setobjs2s(L, ra + 2, ra + 4); /* save control variable */
pc -= GETARG_Bx(i); /* jump back */ pc -= GETARG_Bx(i); /* jump back */
} }
vmbreak; vmbreak;
} }}
vmcase(OP_SETLIST) { vmcase(OP_SETLIST) {
StkId ra = RA(i);
int n = GETARG_B(i); int n = GETARG_B(i);
unsigned int last = GETARG_C(i); unsigned int last = GETARG_C(i);
Table *h = hvalue(s2v(ra)); Table *h = hvalue(s2v(ra));
if (n == 0) 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 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; last += n;
if (TESTARG_k(i)) { if (TESTARG_k(i)) {
last += GETARG_Ax(*pc) * (MAXARG_C + 1); last += GETARG_Ax(*pc) * (MAXARG_C + 1);
@ -1810,12 +1867,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_CLOSURE) { vmcase(OP_CLOSURE) {
StkId ra = RA(i);
Proto *p = cl->p->p[GETARG_Bx(i)]; Proto *p = cl->p->p[GETARG_Bx(i)];
halfProtect(pushclosure(L, p, cl->upvals, base, ra)); halfProtect(pushclosure(L, p, cl->upvals, base, ra));
checkGC(L, ra + 1); checkGC(L, ra + 1);
vmbreak; vmbreak;
} }
vmcase(OP_VARARG) { vmcase(OP_VARARG) {
StkId ra = RA(i);
int n = GETARG_C(i) - 1; /* required results */ int n = GETARG_C(i) - 1; /* required results */
Protect(luaT_getvarargs(L, ci, ra, n)); Protect(luaT_getvarargs(L, ci, ra, n));
vmbreak; vmbreak;

View File

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

View File

@ -164,7 +164,7 @@ Clark Cooper
Copyright (c) 2001-2019 Expat maintainers Copyright (c) 2001-2019 Expat maintainers
Lua - a powerful, fast, lightweight, embeddable scripting language Lua - a powerful, fast, lightweight, embeddable scripting language
Copyright (c) 1994-2017 Lua.org, PUC-Rio Copyright (c) 1994-2024 Lua.org, PUC-Rio
LuaFileSystem - File System Library for Lua LuaFileSystem - File System Library for Lua
Copyright (c) 2003-2015 Kepler Project Copyright (c) 2003-2015 Kepler Project