Merge pull request #13 from walterschell/feature/5.4.4

Released 2022-01-26
This commit is contained in:
Walter Schell 2022-01-27 20:26:10 -05:00 committed by GitHub
commit 0ab5db21e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
80 changed files with 625 additions and 343 deletions

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.1) cmake_minimum_required(VERSION 3.1)
project(lua LANGUAGES C VERSION 5.4.3) project(lua LANGUAGES C VERSION 5.4.4)
option(LUA_SUPPORT_DL "Support dynamic loading of compiled modules" OFF) option(LUA_SUPPORT_DL "Support dynamic loading of compiled modules" OFF)
option(LUA_BUILD_AS_CXX "Build lua as C++" OFF) option(LUA_BUILD_AS_CXX "Build lua as C++" OFF)
@ -20,4 +20,4 @@ else()
endif() endif()
add_subdirectory(lua-5.4.3) add_subdirectory(lua-5.4.4)

View File

@ -1,5 +1,5 @@
# Lua # Lua
CMake based build of Lua 5.4.3 CMake based build of Lua 5.4.4
| Build as C | Build as C++ | | Build as C | Build as C++ |
| --: | --: | | --: | --: |
| ![Build Linux](https://github.com/walterschell/Lua/actions/workflows/build-linux.yml/badge.svg?branch=master) | ![Build Linux as C++](https://github.com/walterschell/Lua/actions/workflows/build-emscripten-cxx.yml/badge.svg?branch=master) | | ![Build Linux](https://github.com/walterschell/Lua/actions/workflows/build-linux.yml/badge.svg?branch=master) | ![Build Linux as C++](https://github.com/walterschell/Lua/actions/workflows/build-emscripten-cxx.yml/badge.svg?branch=master) |

View File

@ -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.3 R= $V.4
# Targets start here. # Targets start here.
all: $(PLAT) all: $(PLAT)

View File

@ -1,5 +1,5 @@
This is Lua 5.4.3, released on 15 Mar 2021. This is Lua 5.4.4, released on 13 Jan 2022.
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.

View File

@ -32,7 +32,7 @@ For a complete introduction to Lua programming, see the book
<P> <P>
<SMALL> <SMALL>
Copyright &copy; 2020&ndash;2021 Lua.org, PUC-Rio. Copyright &copy; 2020&ndash;2022 Lua.org, PUC-Rio.
Freely available under the terms of the Freely available under the terms of the
<A HREF="http://www.lua.org/license.html">Lua license</A>. <A HREF="http://www.lua.org/license.html">Lua license</A>.
</SMALL> </SMALL>
@ -664,10 +664,10 @@ Freely available under the terms of the
<P CLASS="footer"> <P CLASS="footer">
Last update: Last update:
Wed Mar 3 13:04:44 UTC 2021 Thu Jan 13 11:32:22 UTC 2022
</P> </P>
<!-- <!--
Last change: revised for Lua 5.4.3 Last change: revised for Lua 5.4.4
--> -->
</BODY> </BODY>

View File

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

@ -19,7 +19,7 @@ by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
<P> <P>
<SMALL> <SMALL>
Copyright &copy; 2020&ndash;2021 Lua.org, PUC-Rio. Copyright &copy; 2020&ndash;2022 Lua.org, PUC-Rio.
Freely available under the terms of the Freely available under the terms of the
<a href="http://www.lua.org/license.html">Lua license</a>. <a href="http://www.lua.org/license.html">Lua license</a>.
</SMALL> </SMALL>
@ -961,11 +961,8 @@ these marks have no effect.
<p> <p>
Finalizers cannot yield. Finalizers cannot yield nor run the garbage collector.
Except for that, they can do anything, Because they can run in unpredictable times,
such as raise errors, create new objects,
or even run the garbage collector.
However, because they can run in unpredictable times,
it is good practice to restrict each finalizer it is good practice to restrict each finalizer
to the minimum necessary to properly release to the minimum necessary to properly release
its associated resource. its associated resource.
@ -1636,8 +1633,10 @@ before the adjustment
<p> <p>
The assignment statement first evaluates all its expressions If a variable is both assigned and read
and only then the assignments are performed. inside a multiple assignment,
Lua ensures all reads get the value of the variable
before the assignment.
Thus the code Thus the code
<pre> <pre>
@ -1661,6 +1660,14 @@ and
cyclically permutes the values of <code>x</code>, <code>y</code>, and <code>z</code>. cyclically permutes the values of <code>x</code>, <code>y</code>, and <code>z</code>.
<p>
Note that this guarantee covers only accesses
syntactically inside the assignment statement.
If a function or a metamethod called during the assignment
changes the value of a variable,
Lua gives no guarantees about the order of that access.
<p> <p>
An assignment to a global name <code>x = val</code> An assignment to a global name <code>x = val</code>
is equivalent to the assignment is equivalent to the assignment
@ -2416,16 +2423,21 @@ character is one byte.)
<p> <p>
The length operator applied on a table The length operator applied on a table
returns a border in that table. returns a border in that table.
A <em>border</em> in a table <code>t</code> is any natural number A <em>border</em> in a table <code>t</code> is any non-negative integer
that satisfies the following condition: that satisfies the following condition:
<pre> <pre>
(border == 0 or t[border] ~= nil) and t[border + 1] == nil (border == 0 or t[border] ~= nil) and
(t[border + 1] == nil or border == math.maxinteger)
</pre><p> </pre><p>
In words, In words,
a border is any (natural) index present in the table a border is any positive integer index present in the table
that is followed by an absent index that is followed by an absent index,
(or zero, when index 1 is absent). plus two limit cases:
zero, when index 1 is absent;
and the maximum value for an integer, when that index is present.
Note that keys that are not positive integers
do not interfere with borders.
<p> <p>
@ -2436,12 +2448,9 @@ The table <code>{10, 20, 30, nil, 50}</code> has two borders (3 and 5),
and therefore it is not a sequence. and therefore it is not a sequence.
(The <b>nil</b> at index 4 is called a <em>hole</em>.) (The <b>nil</b> at index 4 is called a <em>hole</em>.)
The table <code>{nil, 20, 30, nil, nil, 60, nil}</code> The table <code>{nil, 20, 30, nil, nil, 60, nil}</code>
has three borders (0, 3, and 6) and three holes has three borders (0, 3, and 6),
(at indices 1, 4, and 5),
so it is not a sequence, too. so it is not a sequence, too.
The table <code>{}</code> is a sequence with border 0. The table <code>{}</code> is a sequence with border 0.
Note that non-natural keys do not interfere
with whether a table is a sequence.
<p> <p>
@ -2459,7 +2468,7 @@ the memory addresses of its non-numeric keys.)
<p> <p>
The computation of the length of a table The computation of the length of a table
has a guaranteed worst time of <em>O(log n)</em>, has a guaranteed worst time of <em>O(log n)</em>,
where <em>n</em> is the largest natural key in the table. where <em>n</em> is the largest integer key in the table.
<p> <p>
@ -3979,6 +3988,10 @@ For more details about these options,
see <a href="#pdf-collectgarbage"><code>collectgarbage</code></a>. see <a href="#pdf-collectgarbage"><code>collectgarbage</code></a>.
<p>
This function should not be called by a finalizer.
@ -5933,7 +5946,10 @@ information about a function or an activation record.
<a href="#lua_getstack"><code>lua_getstack</code></a> fills only the private part <a href="#lua_getstack"><code>lua_getstack</code></a> fills only the private part
of this structure, for later use. of this structure, for later use.
To fill the other fields of <a href="#lua_Debug"><code>lua_Debug</code></a> with useful information, To fill the other fields of <a href="#lua_Debug"><code>lua_Debug</code></a> with useful information,
you must call <a href="#lua_getinfo"><code>lua_getinfo</code></a>. you must call <a href="#lua_getinfo"><code>lua_getinfo</code></a> with an appropriate parameter.
(Specifically, to get a field,
you must add the letter between parentheses in the field's comment
to the parameter <code>what</code> of <a href="#lua_getinfo"><code>lua_getinfo</code></a>.)
<p> <p>
@ -6110,11 +6126,25 @@ you can write the following code:
<p> <p>
Each character in the string <code>what</code> Each character in the string <code>what</code>
selects some fields of the structure <code>ar</code> to be filled or selects some fields of the structure <code>ar</code> to be filled or
a value to be pushed on the stack: a value to be pushed on the stack.
(These characters are also documented in the declaration of
the structure <a href="#lua_Debug"><code>lua_Debug</code></a>,
between parentheses in the comments following each field.)
<ul> <ul>
<li><b>'<code>n</code>': </b> fills in the field <code>name</code> and <code>namewhat</code>; <li><b>'<code>f</code>': </b>
pushes onto the stack the function that is
running at the given level;
</li>
<li><b>'<code>l</code>': </b> fills in the field <code>currentline</code>;
</li>
<li><b>'<code>n</code>': </b> fills in the fields <code>name</code> and <code>namewhat</code>;
</li>
<li><b>'<code>r</code>': </b> fills in the fields <code>ftransfer</code> and <code>ntransfer</code>;
</li> </li>
<li><b>'<code>S</code>': </b> <li><b>'<code>S</code>': </b>
@ -6122,9 +6152,6 @@ fills in the fields <code>source</code>, <code>short_src</code>,
<code>linedefined</code>, <code>lastlinedefined</code>, and <code>what</code>; <code>linedefined</code>, <code>lastlinedefined</code>, and <code>what</code>;
</li> </li>
<li><b>'<code>l</code>': </b> fills in the field <code>currentline</code>;
</li>
<li><b>'<code>t</code>': </b> fills in the field <code>istailcall</code>; <li><b>'<code>t</code>': </b> fills in the field <code>istailcall</code>;
</li> </li>
@ -6132,25 +6159,13 @@ fills in the fields <code>source</code>, <code>short_src</code>,
<code>nups</code>, <code>nparams</code>, and <code>isvararg</code>; <code>nups</code>, <code>nparams</code>, and <code>isvararg</code>;
</li> </li>
<li><b>'<code>f</code>': </b>
pushes onto the stack the function that is
running at the given level;
</li>
<li><b>'<code>L</code>': </b> <li><b>'<code>L</code>': </b>
pushes onto the stack a table whose indices are the pushes onto the stack a table whose indices are
numbers of the lines that are valid on the function. the lines on the function with some associated code,
(A <em>valid line</em> is a line with some associated code, that is, the lines where you can put a break point.
that is, a line where you can put a break point. (Lines with no code include empty lines and comments.)
Non-valid lines include empty lines and comments.)
<p>
If this option is given together with option '<code>f</code>', If this option is given together with option '<code>f</code>',
its table is pushed after the function. its table is pushed after the function.
<p>
This is the only option that can raise a memory error. This is the only option that can raise a memory error.
</li> </li>
@ -6508,7 +6523,7 @@ Adds the byte <code>c</code> to the buffer <code>B</code>
<hr><h3><a name="luaL_addgsub"><code>luaL_addgsub</code></a></h3><p> <hr><h3><a name="luaL_addgsub"><code>luaL_addgsub</code></a></h3><p>
<span class="apii">[-0, +0, <em>m</em>]</span> <span class="apii">[-?, +?, <em>m</em>]</span>
<pre>const void luaL_addgsub (luaL_Buffer *B, const char *s, <pre>const void luaL_addgsub (luaL_Buffer *B, const char *s,
const char *p, const char *r);</pre> const char *p, const char *r);</pre>
@ -6562,7 +6577,7 @@ to the buffer <code>B</code>
<hr><h3><a name="luaL_addvalue"><code>luaL_addvalue</code></a></h3><p> <hr><h3><a name="luaL_addvalue"><code>luaL_addvalue</code></a></h3><p>
<span class="apii">[-1, +?, <em>m</em>]</span> <span class="apii">[-?, +?, <em>m</em>]</span>
<pre>void luaL_addvalue (luaL_Buffer *B);</pre> <pre>void luaL_addvalue (luaL_Buffer *B);</pre>
<p> <p>
@ -6716,7 +6731,7 @@ Note that any addition to the buffer may invalidate this address.
<hr><h3><a name="luaL_buffinit"><code>luaL_buffinit</code></a></h3><p> <hr><h3><a name="luaL_buffinit"><code>luaL_buffinit</code></a></h3><p>
<span class="apii">[-0, +0, &ndash;]</span> <span class="apii">[-0, +?, &ndash;]</span>
<pre>void luaL_buffinit (lua_State *L, luaL_Buffer *B);</pre> <pre>void luaL_buffinit (lua_State *L, luaL_Buffer *B);</pre>
<p> <p>
@ -6754,7 +6769,7 @@ Equivalent to the sequence
<hr><h3><a name="luaL_buffsub"><code>luaL_buffsub</code></a></h3><p> <hr><h3><a name="luaL_buffsub"><code>luaL_buffsub</code></a></h3><p>
<span class="apii">[-0, +0, &ndash;]</span> <span class="apii">[-?, +?, &ndash;]</span>
<pre>void luaL_buffsub (luaL_Buffer *B, int n);</pre> <pre>void luaL_buffsub (luaL_Buffer *B, int n);</pre>
<p> <p>
@ -7557,6 +7572,11 @@ on top of the library table.
These values are popped from the stack after the registration. These values are popped from the stack after the registration.
<p>
A function with a <code>NULL</code> value represents a placeholder,
which is filled with <b>false</b>.
@ -7919,6 +7939,10 @@ See <a href="#2.5">&sect;2.5</a> for more details about garbage collection
and some of these options. and some of these options.
<p>
This function should not be called by a finalizer.
<p> <p>
@ -7936,7 +7960,7 @@ to its caller.
<p> <p>
<hr><h3><a name="pdf-error"><code>error (message [, level])</code></a></h3> <hr><h3><a name="pdf-error"><code>error (message [, level])</code></a></h3>
Raises an error (see <a href="#2.3">&sect;2.3</a>) with @{message} as the error object. Raises an error (see <a href="#2.3">&sect;2.3</a>) with <code>message</code> as the error object.
This function never returns. This function never returns.
@ -8111,9 +8135,8 @@ use a numerical <b>for</b>.)
<p> <p>
The behavior of <code>next</code> is undefined if, You should not assign any value to a non-existent field in a table
during the traversal, during its traversal.
you assign any value to a non-existent field in the table.
You may however modify existing fields. You may however modify existing fields.
In particular, you may set existing fields to nil. In particular, you may set existing fields to nil.
@ -8159,7 +8182,7 @@ This means that any error inside&nbsp;<code>f</code> is not propagated;
instead, <code>pcall</code> catches the error instead, <code>pcall</code> catches the error
and returns a status code. and returns a status code.
Its first result is the status code (a boolean), Its first result is the status code (a boolean),
which is true if the call succeeds without errors. which is <b>true</b> if the call succeeds without errors.
In such case, <code>pcall</code> also returns all results from the call, In such case, <code>pcall</code> also returns all results from the call,
after this first result. after this first result.
In case of any error, <code>pcall</code> returns <b>false</b> plus the error object. In case of any error, <code>pcall</code> returns <b>false</b> plus the error object.
@ -8439,7 +8462,7 @@ an object with type <code>"thread"</code>.
<p> <p>
Returns true when the coroutine <code>co</code> can yield. Returns <b>true</b> when the coroutine <code>co</code> can yield.
The default for <code>co</code> is the running coroutine. The default for <code>co</code> is the running coroutine.
@ -8483,7 +8506,7 @@ If there is any error,
<p> <p>
Returns the running coroutine plus a boolean, Returns the running coroutine plus a boolean,
true when the running coroutine is the main one. <b>true</b> when the running coroutine is the main one.
@ -9021,7 +9044,7 @@ otherwise, it returns <b>fail</b>.
A third, optional numeric argument <code>init</code> specifies A third, optional numeric argument <code>init</code> specifies
where to start the search; where to start the search;
its default value is&nbsp;1 and can be negative. its default value is&nbsp;1 and can be negative.
A value of <b>true</b> as a fourth, optional argument <code>plain</code> A <b>true</b> as a fourth, optional argument <code>plain</code>
turns off the pattern matching facilities, turns off the pattern matching facilities,
so the function does a plain "find substring" operation, so the function does a plain "find substring" operation,
with no characters in <code>pattern</code> being considered magic. with no characters in <code>pattern</code> being considered magic.
@ -9046,8 +9069,10 @@ following the description given in its first argument,
which must be a string. which must be a string.
The format string follows the same rules as the ISO&nbsp;C function <code>sprintf</code>. The format string follows the same rules as the ISO&nbsp;C function <code>sprintf</code>.
The only differences are that the conversion specifiers and modifiers The only differences are that the conversion specifiers and modifiers
<code>*</code>, <code>h</code>, <code>L</code>, <code>l</code>, and <code>n</code> are not supported <code>F</code>, <code>n</code>, <code>*</code>, <code>h</code>, <code>L</code>, and <code>l</code> are not supported
and that there is an extra specifier, <code>q</code>. and that there is an extra specifier, <code>q</code>.
Both width and precision, when present,
are limited to two digits.
<p> <p>
@ -9071,7 +9096,7 @@ may produce the string:
"a string with \"quotes\" and \ "a string with \"quotes\" and \
new line" new line"
</pre><p> </pre><p>
This specifier does not support modifiers (flags, width, length). This specifier does not support modifiers (flags, width, precision).
<p> <p>
@ -10362,7 +10387,7 @@ or <b>fail</b> if <code>x</code> is not a number.
<p> <p>
Returns a boolean, Returns a boolean,
true if and only if integer <code>m</code> is below integer <code>n</code> when <b>true</b> if and only if integer <code>m</code> is below integer <code>n</code> when
they are compared as unsigned integers. they are compared as unsigned integers.
@ -11924,10 +11949,10 @@ and LiteralString, see <a href="#3.1">&sect;3.1</a>.)
<P CLASS="footer"> <P CLASS="footer">
Last update: Last update:
Mon Mar 15 13:39:42 UTC 2021 Thu Jan 13 11:33:16 UTC 2022
</P> </P>
<!-- <!--
Last change: revised for Lua 5.4.3 Last change: revised for Lua 5.4.4
--> -->
</body></html> </body></html>

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -110,7 +110,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.3</TT>. the top-level directory, which is named <TT>lua-5.4.4</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>
@ -303,7 +303,7 @@ For details, see
<A HREF="http://www.lua.org/license.html">this</A>. <A HREF="http://www.lua.org/license.html">this</A>.
<BLOCKQUOTE STYLE="padding-bottom: 0em"> <BLOCKQUOTE STYLE="padding-bottom: 0em">
Copyright &copy; 1994&ndash;2021 Lua.org, PUC-Rio. Copyright &copy; 1994&ndash;2022 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 +330,10 @@ THE SOFTWARE.
<P CLASS="footer"> <P CLASS="footer">
Last update: Last update:
Wed Mar 3 10:16:26 UTC 2021 Mon Jan 3 09:54:18 UTC 2022
</P> </P>
<!-- <!--
Last change: revised for Lua 5.4.3 Last change: revised for Lua 5.4.4
--> -->
</BODY> </BODY>

View File

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

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 "3" #define LUA_VERSION_RELEASE "4"
#define LUA_VERSION_NUM 504 #define LUA_VERSION_NUM 504
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 0) #define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 4)
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2021 Lua.org, PUC-Rio" #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2022 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"
@ -492,7 +492,7 @@ struct lua_Debug {
/****************************************************************************** /******************************************************************************
* Copyright (C) 1994-2021 Lua.org, PUC-Rio. * Copyright (C) 1994-2022 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

@ -485,7 +485,6 @@
@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. @@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.
@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. @@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.
@@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED. @@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED.
@@ LUA_UNSIGNEDBITS is the number of bits in a LUA_UNSIGNED.
@@ lua_integer2str converts an integer to a string. @@ lua_integer2str converts an integer to a string.
*/ */
@ -506,9 +505,6 @@
#define LUA_UNSIGNED unsigned LUAI_UACINT #define LUA_UNSIGNED unsigned LUAI_UACINT
#define LUA_UNSIGNEDBITS (sizeof(LUA_UNSIGNED) * CHAR_BIT)
/* now the variable definitions */ /* now the variable definitions */
#if LUA_INT_TYPE == LUA_INT_INT /* { int */ #if LUA_INT_TYPE == LUA_INT_INT /* { int */

View File

@ -79,7 +79,7 @@ echo:
@echo "PLAT= $(PLAT)" @echo "PLAT= $(PLAT)"
@echo "CC= $(CC)" @echo "CC= $(CC)"
@echo "CFLAGS= $(CFLAGS)" @echo "CFLAGS= $(CFLAGS)"
@echo "LDFLAGS= $(SYSLDFLAGS)" @echo "LDFLAGS= $(LDFLAGS)"
@echo "LIBS= $(LIBS)" @echo "LIBS= $(LIBS)"
@echo "AR= $(AR)" @echo "AR= $(AR)"
@echo "RANLIB= $(RANLIB)" @echo "RANLIB= $(RANLIB)"

View File

@ -53,6 +53,10 @@ const char lua_ident[] =
#define isupvalue(i) ((i) < LUA_REGISTRYINDEX) #define isupvalue(i) ((i) < LUA_REGISTRYINDEX)
/*
** Convert an acceptable index to a pointer to its respective value.
** Non-valid indices return the special nil value 'G(L)->nilvalue'.
*/
static TValue *index2value (lua_State *L, int idx) { static TValue *index2value (lua_State *L, int idx) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (idx > 0) { if (idx > 0) {
@ -70,22 +74,28 @@ static TValue *index2value (lua_State *L, int idx) {
else { /* upvalues */ else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx; idx = LUA_REGISTRYINDEX - idx;
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
if (ttislcf(s2v(ci->func))) /* light C function? */ if (ttisCclosure(s2v(ci->func))) { /* C closure? */
return &G(L)->nilvalue; /* it has no upvalues */
else {
CClosure *func = clCvalue(s2v(ci->func)); CClosure *func = clCvalue(s2v(ci->func));
return (idx <= func->nupvalues) ? &func->upvalue[idx-1] return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
: &G(L)->nilvalue; : &G(L)->nilvalue;
} }
else { /* light C function or Lua function (through a hook)?) */
api_check(L, ttislcf(s2v(ci->func)), "caller not a C function");
return &G(L)->nilvalue; /* no upvalues */
}
} }
} }
static StkId index2stack (lua_State *L, int idx) {
/*
** Convert a valid actual index (not a pseudo-index) to its address.
*/
l_sinline StkId index2stack (lua_State *L, int idx) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (idx > 0) { if (idx > 0) {
StkId o = ci->func + idx; StkId o = ci->func + idx;
api_check(L, o < L->top, "unacceptable index"); api_check(L, o < L->top, "invalid index");
return o; return o;
} }
else { /* non-positive index */ else { /* non-positive index */
@ -218,7 +228,7 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
** Note that we move(copy) only the value inside the stack. ** Note that we move(copy) only the value inside the stack.
** (We do not move additional fields that may exist.) ** (We do not move additional fields that may exist.)
*/ */
static void reverse (lua_State *L, StkId from, StkId to) { l_sinline void reverse (lua_State *L, StkId from, StkId to) {
for (; from < to; from++, to--) { for (; from < to; from++, to--) {
TValue temp; TValue temp;
setobj(L, &temp, s2v(from)); setobj(L, &temp, s2v(from));
@ -438,7 +448,7 @@ LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) {
} }
static void *touserdata (const TValue *o) { l_sinline void *touserdata (const TValue *o) {
switch (ttype(o)) { switch (ttype(o)) {
case LUA_TUSERDATA: return getudatamem(uvalue(o)); case LUA_TUSERDATA: return getudatamem(uvalue(o));
case LUA_TLIGHTUSERDATA: return pvalue(o); case LUA_TLIGHTUSERDATA: return pvalue(o);
@ -630,7 +640,7 @@ LUA_API int lua_pushthread (lua_State *L) {
*/ */
static int auxgetstr (lua_State *L, const TValue *t, const char *k) { l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot; const TValue *slot;
TString *str = luaS_new(L, k); TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) { if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
@ -705,7 +715,7 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
} }
static int finishrawget (lua_State *L, const TValue *val) { l_sinline int finishrawget (lua_State *L, const TValue *val) {
if (isempty(val)) /* avoid copying empty items to the stack */ if (isempty(val)) /* avoid copying empty items to the stack */
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top));
else else
@ -1126,18 +1136,19 @@ LUA_API int lua_status (lua_State *L) {
LUA_API int lua_gc (lua_State *L, int what, ...) { LUA_API int lua_gc (lua_State *L, int what, ...) {
va_list argp; va_list argp;
int res = 0; int res = 0;
global_State *g; global_State *g = G(L);
if (g->gcstp & GCSTPGC) /* internal stop? */
return -1; /* all options are invalid when stopped */
lua_lock(L); lua_lock(L);
g = G(L);
va_start(argp, what); va_start(argp, what);
switch (what) { switch (what) {
case LUA_GCSTOP: { case LUA_GCSTOP: {
g->gcrunning = 0; g->gcstp = GCSTPUSR; /* stopped by the user */
break; break;
} }
case LUA_GCRESTART: { case LUA_GCRESTART: {
luaE_setdebt(g, 0); luaE_setdebt(g, 0);
g->gcrunning = 1; g->gcstp = 0; /* (GCSTPGC must be already zero here) */
break; break;
} }
case LUA_GCCOLLECT: { case LUA_GCCOLLECT: {
@ -1156,8 +1167,8 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
case LUA_GCSTEP: { case LUA_GCSTEP: {
int data = va_arg(argp, int); int data = va_arg(argp, int);
l_mem debt = 1; /* =1 to signal that it did an actual step */ l_mem debt = 1; /* =1 to signal that it did an actual step */
lu_byte oldrunning = g->gcrunning; lu_byte oldstp = g->gcstp;
g->gcrunning = 1; /* allow GC to run */ g->gcstp = 0; /* allow GC to run (GCSTPGC must be zero here) */
if (data == 0) { if (data == 0) {
luaE_setdebt(g, 0); /* do a basic step */ luaE_setdebt(g, 0); /* do a basic step */
luaC_step(L); luaC_step(L);
@ -1167,7 +1178,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
luaE_setdebt(g, debt); luaE_setdebt(g, debt);
luaC_checkGC(L); luaC_checkGC(L);
} }
g->gcrunning = oldrunning; /* restore previous state */ g->gcstp = oldstp; /* restore previous state */
if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */
res = 1; /* signal it */ res = 1; /* signal it */
break; break;
@ -1185,7 +1196,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
break; break;
} }
case LUA_GCISRUNNING: { case LUA_GCISRUNNING: {
res = g->gcrunning; res = gcrunning(g);
break; break;
} }
case LUA_GCGEN: { case LUA_GCGEN: {

View File

@ -881,6 +881,7 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
idx = lua_absindex(L,idx);
if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */ if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */
if (!lua_isstring(L, -1)) if (!lua_isstring(L, -1))
luaL_error(L, "'__tostring' must return a string"); luaL_error(L, "'__tostring' must return a string");

View File

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

View File

@ -10,6 +10,7 @@
#include "lprefix.h" #include "lprefix.h"
#include <float.h>
#include <limits.h> #include <limits.h>
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
@ -580,24 +581,41 @@ static int stringK (FuncState *fs, TString *s) {
/* /*
** Add an integer to list of constants and return its index. ** Add an integer to list of constants and return its index.
** Integers use userdata as keys to avoid collision with floats with
** same value; conversion to 'void*' is used only for hashing, so there
** are no "precision" problems.
*/ */
static int luaK_intK (FuncState *fs, lua_Integer n) { static int luaK_intK (FuncState *fs, lua_Integer n) {
TValue k, o; TValue o;
setpvalue(&k, cast_voidp(cast_sizet(n)));
setivalue(&o, n); setivalue(&o, n);
return addk(fs, &k, &o); return addk(fs, &o, &o); /* use integer itself as key */
} }
/* /*
** Add a float to list of constants and return its index. ** Add a float to list of constants and return its index. Floats
** with integral values need a different key, to avoid collision
** with actual integers. To that, we add to the number its smaller
** power-of-two fraction that is still significant in its scale.
** For doubles, that would be 1/2^52.
** (This method is not bulletproof: there may be another float
** with that value, and for floats larger than 2^53 the result is
** still an integer. At worst, this only wastes an entry with
** a duplicate.)
*/ */
static int luaK_numberK (FuncState *fs, lua_Number r) { static int luaK_numberK (FuncState *fs, lua_Number r) {
TValue o; TValue o;
lua_Integer ik;
setfltvalue(&o, r); setfltvalue(&o, r);
return addk(fs, &o, &o); /* use number itself as key */ if (!luaV_flttointeger(r, &ik, F2Ieq)) /* not an integral value? */
return addk(fs, &o, &o); /* use number itself as key */
else { /* must build an alternative key */
const int nbm = l_floatatt(MANT_DIG);
const lua_Number q = l_mathop(ldexp)(l_mathop(1.0), -nbm + 1);
const lua_Number k = (ik == 0) ? q : r + r*q; /* new key */
TValue kv;
setfltvalue(&kv, k);
/* result is not an integral value, unless value is too large */
lua_assert(!luaV_flttointeger(k, &ik, F2Ieq) ||
l_mathop(fabs)(r) >= l_mathop(1e6));
return addk(fs, &kv, &o);
}
} }

View File

@ -78,7 +78,7 @@ static int luaB_auxwrap (lua_State *L) {
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_resetthread(co); /* close its tbc variables */
lua_assert(stat != LUA_OK); lua_assert(stat != LUA_OK);
lua_xmove(co, L, 1); /* copy error message */ lua_xmove(co, L, 1); /* move error message to the caller */
} }
if (stat != LUA_ERRMEM && /* not a memory error and ... */ if (stat != LUA_ERRMEM && /* not a memory error and ... */
lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */ lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
@ -179,7 +179,7 @@ static int luaB_close (lua_State *L) {
} }
else { else {
lua_pushboolean(L, 0); lua_pushboolean(L, 0);
lua_xmove(co, L, 1); /* copy error message */ lua_xmove(co, L, 1); /* move error message */
return 2; return 2;
} }
} }

View File

@ -34,8 +34,8 @@
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL)
static const char *funcnamefromcode (lua_State *L, CallInfo *ci, static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
const char **name); const char **name);
static int currentpc (CallInfo *ci) { static int currentpc (CallInfo *ci) {
@ -64,7 +64,7 @@ static int getbaseline (const Proto *f, int pc, int *basepc) {
} }
else { else {
int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */ int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */
/* estimate must be a lower bond of the correct base */ /* estimate must be a lower bound of the correct base */
lua_assert(i < 0 || lua_assert(i < 0 ||
(i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc)); (i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc) while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc)
@ -301,7 +301,14 @@ static void collectvalidlines (lua_State *L, Closure *f) {
sethvalue2s(L, L->top, t); /* push it on stack */ sethvalue2s(L, L->top, t); /* push it on stack */
api_incr_top(L); api_incr_top(L);
setbtvalue(&v); /* boolean 'true' to be the value of all indices */ setbtvalue(&v); /* boolean 'true' to be the value of all indices */
for (i = 0; i < p->sizelineinfo; i++) { /* for all instructions */ if (!p->is_vararg) /* regular function? */
i = 0; /* consider all instructions */
else { /* vararg function */
lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
currentline = nextline(p, currentline, 0);
i = 1; /* skip first instruction (OP_VARARGPREP) */
}
for (; i < p->sizelineinfo; i++) { /* for each instruction */
currentline = nextline(p, currentline, i); /* get its line */ currentline = nextline(p, currentline, i); /* get its line */
luaH_setint(L, t, currentline, &v); /* table[line] = true */ luaH_setint(L, t, currentline, &v); /* table[line] = true */
} }
@ -310,15 +317,9 @@ static void collectvalidlines (lua_State *L, Closure *f) {
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
if (ci == NULL) /* no 'ci'? */ /* calling function is a known function? */
return NULL; /* no info */ if (ci != NULL && !(ci->callstatus & CIST_TAIL))
else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */ return funcnamefromcall(L, ci->previous, name);
*name = "__gc";
return "metamethod"; /* report it as such */
}
/* calling function is a known Lua function? */
else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
return funcnamefromcode(L, ci->previous, name);
else return NULL; /* no way to find a name */ else return NULL; /* no way to find a name */
} }
@ -590,16 +591,10 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
** Returns what the name is (e.g., "for iterator", "method", ** Returns what the name is (e.g., "for iterator", "method",
** "metamethod") and sets '*name' to point to the name. ** "metamethod") and sets '*name' to point to the name.
*/ */
static const char *funcnamefromcode (lua_State *L, CallInfo *ci, static const char *funcnamefromcode (lua_State *L, const Proto *p,
const char **name) { int pc, const char **name) {
TMS tm = (TMS)0; /* (initial value avoids warnings) */ TMS tm = (TMS)0; /* (initial value avoids warnings) */
const Proto *p = ci_func(ci)->p; /* calling function */
int pc = currentpc(ci); /* calling instruction index */
Instruction i = p->code[pc]; /* calling instruction */ Instruction i = p->code[pc]; /* calling instruction */
if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
*name = "?";
return "hook";
}
switch (GET_OPCODE(i)) { switch (GET_OPCODE(i)) {
case OP_CALL: case OP_CALL:
case OP_TAILCALL: case OP_TAILCALL:
@ -636,6 +631,26 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
return "metamethod"; return "metamethod";
} }
/*
** Try to find a name for a function based on how it was called.
*/
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
const char **name) {
if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
*name = "?";
return "hook";
}
else if (ci->callstatus & CIST_FIN) { /* was it called as a finalizer? */
*name = "__gc";
return "metamethod"; /* report it as such */
}
else if (isLua(ci))
return funcnamefromcode(L, ci_func(ci)->p, currentpc(ci), name);
else
return NULL;
}
/* }====================================================== */ /* }====================================================== */
@ -675,9 +690,21 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
} }
static const char *formatvarinfo (lua_State *L, const char *kind,
const char *name) {
if (kind == NULL)
return ""; /* no information */
else
return luaO_pushfstring(L, " (%s '%s')", kind, name);
}
/*
** Build a string with a "description" for the value 'o', such as
** "variable 'x'" or "upvalue 'y'".
*/
static const char *varinfo (lua_State *L, const TValue *o) { static const char *varinfo (lua_State *L, const TValue *o) {
const char *name = NULL; /* to avoid warnings */
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
const char *name = NULL; /* to avoid warnings */
const char *kind = NULL; const char *kind = NULL;
if (isLua(ci)) { if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
@ -685,26 +712,40 @@ static const char *varinfo (lua_State *L, const TValue *o) {
kind = getobjname(ci_func(ci)->p, currentpc(ci), kind = getobjname(ci_func(ci)->p, currentpc(ci),
cast_int(cast(StkId, o) - (ci->func + 1)), &name); cast_int(cast(StkId, o) - (ci->func + 1)), &name);
} }
return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : ""; return formatvarinfo(L, kind, name);
} }
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { /*
** Raise a type error
*/
static l_noret typeerror (lua_State *L, const TValue *o, const char *op,
const char *extra) {
const char *t = luaT_objtypename(L, o); const char *t = luaT_objtypename(L, o);
luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o)); luaG_runerror(L, "attempt to %s a %s value%s", op, t, extra);
} }
/*
** Raise a type error with "standard" information about the faulty
** object 'o' (using 'varinfo').
*/
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
typeerror(L, o, op, varinfo(L, o));
}
/*
** Raise an error for calling a non-callable object. Try to find a name
** for the object based on how it was called ('funcnamefromcall'); if it
** cannot get a name there, try 'varinfo'.
*/
l_noret luaG_callerror (lua_State *L, const TValue *o) { l_noret luaG_callerror (lua_State *L, const TValue *o) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
const char *name = NULL; /* to avoid warnings */ const char *name = NULL; /* to avoid warnings */
const char *what = (isLua(ci)) ? funcnamefromcode(L, ci, &name) : NULL; const char *kind = funcnamefromcall(L, ci, &name);
if (what != NULL) { const char *extra = kind ? formatvarinfo(L, kind, name) : varinfo(L, o);
const char *t = luaT_objtypename(L, o); typeerror(L, o, "call", extra);
luaG_runerror(L, "%s '%s' is not callable (a %s value)", what, name, t);
}
else
luaG_typeerror(L, o, "call");
} }

View File

@ -387,15 +387,18 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
** stack, below original 'func', so that 'luaD_precall' can call it. Raise ** stack, below original 'func', so that 'luaD_precall' can call it. Raise
** an error if there is no '__call' metafield. ** an error if there is no '__call' metafield.
*/ */
void luaD_tryfuncTM (lua_State *L, StkId func) { StkId luaD_tryfuncTM (lua_State *L, StkId func) {
const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); const TValue *tm;
StkId p; StkId p;
checkstackGCp(L, 1, func); /* space for metamethod */
tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */
if (l_unlikely(ttisnil(tm))) if (l_unlikely(ttisnil(tm)))
luaG_callerror(L, s2v(func)); /* nothing to call */ luaG_callerror(L, s2v(func)); /* nothing to call */
for (p = L->top; p > func; p--) /* open space for metamethod */ for (p = L->top; p > func; p--) /* open space for metamethod */
setobjs2s(L, p, p-1); setobjs2s(L, p, p-1);
L->top++; /* stack space pre-allocated by the caller */ L->top++; /* stack space pre-allocated by the caller */
setobj2s(L, func, tm); /* metamethod is the new function to be called */ setobj2s(L, func, tm); /* metamethod is the new function to be called */
return func;
} }
@ -405,7 +408,7 @@ void luaD_tryfuncTM (lua_State *L, StkId func) {
** expressions, multiple results for tail calls/single parameters) ** expressions, multiple results for tail calls/single parameters)
** separated. ** separated.
*/ */
static void moveresults (lua_State *L, StkId res, int nres, int wanted) { l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
StkId firstresult; StkId firstresult;
int i; int i;
switch (wanted) { /* handle typical cases separately */ switch (wanted) { /* handle typical cases separately */
@ -473,27 +476,81 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
#define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L)) #define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L))
l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,
int mask, StkId top) {
CallInfo *ci = L->ci = next_ci(L); /* new frame */
ci->func = func;
ci->nresults = nret;
ci->callstatus = mask;
ci->top = top;
return ci;
}
/*
** precall for C functions
*/
l_sinline int precallC (lua_State *L, StkId func, int nresults,
lua_CFunction f) {
int n; /* number of returns */
CallInfo *ci;
checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
L->ci = ci = prepCallInfo(L, func, nresults, CIST_C,
L->top + LUA_MINSTACK);
lua_assert(ci->top <= L->stack_last);
if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
int narg = cast_int(L->top - func) - 1;
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
}
lua_unlock(L);
n = (*f)(L); /* do the actual call */
lua_lock(L);
api_checknelems(L, n);
luaD_poscall(L, ci, n);
return n;
}
/* /*
** Prepare a function for a tail call, building its call info on top ** Prepare a function for a tail call, building its call info on top
** of the current call info. 'narg1' is the number of arguments plus 1 ** of the current call info. 'narg1' is the number of arguments plus 1
** (so that it includes the function itself). ** (so that it includes the function itself). Return the number of
** results, if it was a C function, or -1 for a Lua function.
*/ */
void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
Proto *p = clLvalue(s2v(func))->p; int narg1, int delta) {
int fsize = p->maxstacksize; /* frame size */ retry:
int nfixparams = p->numparams; switch (ttypetag(s2v(func))) {
int i; case LUA_VCCL: /* C closure */
for (i = 0; i < narg1; i++) /* move down function and arguments */ return precallC(L, func, LUA_MULTRET, clCvalue(s2v(func))->f);
setobjs2s(L, ci->func + i, func + i); case LUA_VLCF: /* light C function */
checkstackGC(L, fsize); return precallC(L, func, LUA_MULTRET, fvalue(s2v(func)));
func = ci->func; /* moved-down function */ case LUA_VLCL: { /* Lua function */
for (; narg1 <= nfixparams; narg1++) Proto *p = clLvalue(s2v(func))->p;
setnilvalue(s2v(func + narg1)); /* complete missing arguments */ int fsize = p->maxstacksize; /* frame size */
ci->top = func + 1 + fsize; /* top for new function */ int nfixparams = p->numparams;
lua_assert(ci->top <= L->stack_last); int i;
ci->u.l.savedpc = p->code; /* starting point */ checkstackGCp(L, fsize - delta, func);
ci->callstatus |= CIST_TAIL; ci->func -= delta; /* restore 'func' (if vararg) */
L->top = func + narg1; /* set top */ for (i = 0; i < narg1; i++) /* move down function and arguments */
setobjs2s(L, ci->func + i, func + i);
func = ci->func; /* moved-down function */
for (; narg1 <= nfixparams; narg1++)
setnilvalue(s2v(func + narg1)); /* complete missing arguments */
ci->top = func + 1 + fsize; /* top for new function */
lua_assert(ci->top <= L->stack_last);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus |= CIST_TAIL;
L->top = func + narg1; /* set top */
return -1;
}
default: { /* not a function */
func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */
/* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */
narg1++;
goto retry; /* try again */
}
}
} }
@ -506,35 +563,14 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
** original function position. ** original function position.
*/ */
CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
lua_CFunction f;
retry: retry:
switch (ttypetag(s2v(func))) { switch (ttypetag(s2v(func))) {
case LUA_VCCL: /* C closure */ case LUA_VCCL: /* C closure */
f = clCvalue(s2v(func))->f; precallC(L, func, nresults, clCvalue(s2v(func))->f);
goto Cfunc; return NULL;
case LUA_VLCF: /* light C function */ case LUA_VLCF: /* light C function */
f = fvalue(s2v(func)); precallC(L, func, nresults, fvalue(s2v(func)));
Cfunc: {
int n; /* number of returns */
CallInfo *ci;
checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
L->ci = ci = next_ci(L);
ci->nresults = nresults;
ci->callstatus = CIST_C;
ci->top = L->top + LUA_MINSTACK;
ci->func = func;
lua_assert(ci->top <= L->stack_last);
if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
int narg = cast_int(L->top - func) - 1;
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
}
lua_unlock(L);
n = (*f)(L); /* do the actual call */
lua_lock(L);
api_checknelems(L, n);
luaD_poscall(L, ci, n);
return NULL; return NULL;
}
case LUA_VLCL: { /* Lua function */ case LUA_VLCL: { /* Lua function */
CallInfo *ci; CallInfo *ci;
Proto *p = clLvalue(s2v(func))->p; Proto *p = clLvalue(s2v(func))->p;
@ -542,20 +578,16 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
int nfixparams = p->numparams; int nfixparams = p->numparams;
int fsize = p->maxstacksize; /* frame size */ int fsize = p->maxstacksize; /* frame size */
checkstackGCp(L, fsize, func); checkstackGCp(L, fsize, func);
L->ci = ci = next_ci(L); L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize);
ci->nresults = nresults;
ci->u.l.savedpc = p->code; /* starting point */ ci->u.l.savedpc = p->code; /* starting point */
ci->top = func + 1 + fsize;
ci->func = func;
L->ci = ci;
for (; narg < nfixparams; narg++) for (; narg < nfixparams; narg++)
setnilvalue(s2v(L->top++)); /* complete missing arguments */ setnilvalue(s2v(L->top++)); /* complete missing arguments */
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top <= L->stack_last);
return ci; return ci;
} }
default: { /* not a function */ default: { /* not a function */
checkstackGCp(L, 1, func); /* space for metamethod */ func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */
luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ /* return luaD_precall(L, func, nresults); */
goto retry; /* try again with metamethod */ goto retry; /* try again with metamethod */
} }
} }
@ -567,7 +599,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
** 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).
*/ */
static void ccall (lua_State *L, StkId func, int nResults, int inc) { l_sinline void ccall (lua_State *L, StkId func, int nResults, int 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))
@ -728,11 +760,10 @@ static void resume (lua_State *L, void *ud) {
StkId firstArg = L->top - n; /* first argument */ StkId firstArg = L->top - n; /* first argument */
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (L->status == LUA_OK) /* starting a coroutine? */ if (L->status == LUA_OK) /* starting a coroutine? */
ccall(L, firstArg - 1, LUA_MULTRET, 1); /* just call its body */ ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */
else { /* resuming from previous yield */ else { /* resuming from previous yield */
lua_assert(L->status == LUA_YIELD); lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */ L->status = LUA_OK; /* mark that it is running (again) */
luaE_incCstack(L); /* control the C stack */
if (isLua(ci)) { /* yielded inside a hook? */ if (isLua(ci)) { /* yielded inside a hook? */
L->top = firstArg; /* discard arguments */ L->top = firstArg; /* discard arguments */
luaV_execute(L, ci); /* just continue running Lua code */ luaV_execute(L, ci); /* just continue running Lua code */
@ -783,6 +814,9 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
else if (L->status != LUA_YIELD) /* ended with errors? */ else if (L->status != LUA_YIELD) /* ended with errors? */
return resume_error(L, "cannot resume dead coroutine", nargs); return resume_error(L, "cannot resume dead coroutine", nargs);
L->nCcalls = (from) ? getCcalls(from) : 0; L->nCcalls = (from) ? getCcalls(from) : 0;
if (getCcalls(L) >= LUAI_MAXCCALLS)
return resume_error(L, "C stack overflow", nargs);
L->nCcalls++;
luai_userstateresume(L, nargs); luai_userstateresume(L, nargs);
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
status = luaD_rawrunprotected(L, resume, &nargs); status = luaD_rawrunprotected(L, resume, &nargs);

View File

@ -58,11 +58,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 void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1, int delta);
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func);
LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status); LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status);
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t oldtop, ptrdiff_t ef); ptrdiff_t oldtop, ptrdiff_t ef);

View File

@ -906,18 +906,18 @@ static void GCTM (lua_State *L) {
if (!notm(tm)) { /* is there a finalizer? */ if (!notm(tm)) { /* is there a finalizer? */
int status; int status;
lu_byte oldah = L->allowhook; lu_byte oldah = L->allowhook;
int running = g->gcrunning; int oldgcstp = g->gcstp;
g->gcstp |= GCSTPGC; /* avoid GC steps */
L->allowhook = 0; /* stop debug hooks during GC metamethod */ L->allowhook = 0; /* stop debug hooks during GC metamethod */
g->gcrunning = 0; /* avoid GC steps */
setobj2s(L, L->top++, tm); /* push finalizer... */ setobj2s(L, L->top++, tm); /* push finalizer... */
setobj2s(L, L->top++, &v); /* ... and its argument */ setobj2s(L, L->top++, &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 - 2), 0);
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */ L->allowhook = oldah; /* restore hooks */
g->gcrunning = running; /* restore state */ g->gcstp = oldgcstp; /* restore state */
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */ if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
luaE_warnerror(L, "__gc metamethod"); luaE_warnerror(L, "__gc");
L->top--; /* pops error object */ L->top--; /* pops error object */
} }
} }
@ -1011,7 +1011,8 @@ static void correctpointers (global_State *g, GCObject *o) {
void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
global_State *g = G(L); global_State *g = G(L);
if (tofinalize(o) || /* obj. is already marked... */ if (tofinalize(o) || /* obj. is already marked... */
gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ gfasttm(g, mt, TM_GC) == NULL || /* or has no finalizer... */
(g->gcstp & GCSTPCLS)) /* or closing state? */
return; /* nothing to be done */ return; /* nothing to be done */
else { /* move 'o' to 'finobj' list */ else { /* move 'o' to 'finobj' list */
GCObject **p; GCObject **p;
@ -1502,12 +1503,13 @@ static void deletelist (lua_State *L, GCObject *p, GCObject *limit) {
*/ */
void luaC_freeallobjects (lua_State *L) { void luaC_freeallobjects (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
g->gcstp = GCSTPCLS; /* no extra finalizers after here */
luaC_changemode(L, KGC_INC); luaC_changemode(L, KGC_INC);
separatetobefnz(g, 1); /* separate all objects with finalizers */ separatetobefnz(g, 1); /* separate all objects with finalizers */
lua_assert(g->finobj == NULL); lua_assert(g->finobj == NULL);
callallpendingfinalizers(L); callallpendingfinalizers(L);
deletelist(L, g->allgc, obj2gco(g->mainthread)); deletelist(L, g->allgc, obj2gco(g->mainthread));
deletelist(L, g->finobj, NULL); lua_assert(g->finobj == NULL); /* no new finalizers */
deletelist(L, g->fixedgc, NULL); /* collect fixed objects */ deletelist(L, g->fixedgc, NULL); /* collect fixed objects */
lua_assert(g->strt.nuse == 0); lua_assert(g->strt.nuse == 0);
} }
@ -1647,6 +1649,7 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
} }
/* /*
** Performs a basic incremental step. The debt and step size are ** Performs a basic incremental step. The debt and step size are
** converted from bytes to "units of work"; then the function loops ** converted from bytes to "units of work"; then the function loops
@ -1678,7 +1681,7 @@ static void incstep (lua_State *L, global_State *g) {
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); lua_assert(!g->gcemergency);
if (g->gcrunning) { /* running? */ if (gcrunning(g)) { /* running? */
if(isdecGCmodegen(g)) if(isdecGCmodegen(g))
genstep(L, g); genstep(L, g);
else else

View File

@ -148,6 +148,16 @@
*/ */
#define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0) #define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0)
/*
** Control when GC is running:
*/
#define GCSTPUSR 1 /* bit true when GC stopped by user */
#define GCSTPGC 2 /* bit true when GC stopped by itself */
#define GCSTPCLS 4 /* bit true when closing Lua state */
#define gcrunning(g) ((g)->gcstp == 0)
/* /*
** Does one step of collection when debt becomes positive. 'pre'/'pos' ** Does one step of collection when debt becomes positive. 'pre'/'pos'
** allows some adjustments to be done only when needed. macro ** allows some adjustments to be done only when needed. macro

View File

@ -165,6 +165,20 @@ typedef LUAI_UACINT l_uacInt;
#endif #endif
/*
** Inline functions
*/
#if !defined(LUA_USE_C89)
#define l_inline inline
#elif defined(__GNUC__)
#define l_inline __inline__
#else
#define l_inline /* empty */
#endif
#define l_sinline static l_inline
/* /*
** type for virtual-machine instructions; ** type for virtual-machine instructions;
** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
@ -347,7 +361,7 @@ typedef l_uint32 Instruction;
#define condchangemem(L,pre,pos) ((void)0) #define condchangemem(L,pre,pos) ((void)0)
#else #else
#define condchangemem(L,pre,pos) \ #define condchangemem(L,pre,pos) \
{ if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } } { if (gcrunning(G(L))) { pre; luaC_fullgc(L, 0); pos; } }
#endif #endif
#endif #endif

View File

@ -475,7 +475,7 @@ static lua_Number I2d (Rand64 x) {
/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */ /* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
#define scaleFIG \ #define scaleFIG \
((lua_Number)1.0 / (UONE << 30) / 8.0 / (UONE << (FIGS - 33))) (l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33)))
/* /*
** use FIGS - 32 bits from lower half, throwing out the other ** use FIGS - 32 bits from lower half, throwing out the other
@ -486,7 +486,7 @@ static lua_Number I2d (Rand64 x) {
/* /*
** higher 32 bits go after those (FIGS - 32) bits: shiftHI = 2^(FIGS - 32) ** higher 32 bits go after those (FIGS - 32) bits: shiftHI = 2^(FIGS - 32)
*/ */
#define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * 2.0) #define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * l_mathop(2.0))
static lua_Number I2d (Rand64 x) { static lua_Number I2d (Rand64 x) {

View File

@ -164,7 +164,7 @@ static int isneg (const char **s) {
*/ */
static lua_Number lua_strx2number (const char *s, char **endptr) { static lua_Number lua_strx2number (const char *s, char **endptr) {
int dot = lua_getlocaledecpoint(); int dot = lua_getlocaledecpoint();
lua_Number r = 0.0; /* result (accumulator) */ lua_Number r = l_mathop(0.0); /* result (accumulator) */
int sigdig = 0; /* number of significant digits */ int sigdig = 0; /* number of significant digits */
int nosigdig = 0; /* number of non-significant digits */ int nosigdig = 0; /* number of non-significant digits */
int e = 0; /* exponent correction */ int e = 0; /* exponent correction */
@ -174,7 +174,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
neg = isneg(&s); /* check sign */ neg = isneg(&s); /* check sign */
if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */
return 0.0; /* invalid format (no '0x') */ return l_mathop(0.0); /* invalid format (no '0x') */
for (s += 2; ; s++) { /* skip '0x' and read numeral */ for (s += 2; ; s++) { /* skip '0x' and read numeral */
if (*s == dot) { if (*s == dot) {
if (hasdot) break; /* second dot? stop loop */ if (hasdot) break; /* second dot? stop loop */
@ -184,14 +184,14 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */ if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */
nosigdig++; nosigdig++;
else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */
r = (r * cast_num(16.0)) + luaO_hexavalue(*s); r = (r * l_mathop(16.0)) + luaO_hexavalue(*s);
else e++; /* too many digits; ignore, but still count for exponent */ else e++; /* too many digits; ignore, but still count for exponent */
if (hasdot) e--; /* decimal digit? correct exponent */ if (hasdot) e--; /* decimal digit? correct exponent */
} }
else break; /* neither a dot nor a digit */ else break; /* neither a dot nor a digit */
} }
if (nosigdig + sigdig == 0) /* no digits? */ if (nosigdig + sigdig == 0) /* no digits? */
return 0.0; /* invalid format */ return l_mathop(0.0); /* invalid format */
*endptr = cast_charp(s); /* valid up to here */ *endptr = cast_charp(s); /* valid up to here */
e *= 4; /* each digit multiplies/divides value by 2^4 */ e *= 4; /* each digit multiplies/divides value by 2^4 */
if (*s == 'p' || *s == 'P') { /* exponent part? */ if (*s == 'p' || *s == 'P') { /* exponent part? */
@ -200,7 +200,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
s++; /* skip 'p' */ s++; /* skip 'p' */
neg1 = isneg(&s); /* sign */ neg1 = isneg(&s); /* sign */
if (!lisdigit(cast_uchar(*s))) if (!lisdigit(cast_uchar(*s)))
return 0.0; /* invalid; must have at least one digit */ return l_mathop(0.0); /* invalid; must have at least one digit */
while (lisdigit(cast_uchar(*s))) /* read exponent */ while (lisdigit(cast_uchar(*s))) /* read exponent */
exp1 = exp1 * 10 + *(s++) - '0'; exp1 = exp1 * 10 + *(s++) - '0';
if (neg1) exp1 = -exp1; if (neg1) exp1 = -exp1;

View File

@ -68,7 +68,7 @@ typedef struct TValue {
#define val_(o) ((o)->value_) #define val_(o) ((o)->value_)
#define valraw(o) (&val_(o)) #define valraw(o) (val_(o))
/* raw type tag of a TValue */ /* raw type tag of a TValue */
@ -112,7 +112,7 @@ typedef struct TValue {
#define settt_(o,t) ((o)->tt_=(t)) #define settt_(o,t) ((o)->tt_=(t))
/* main macro to copy values (from 'obj1' to 'obj2') */ /* main macro to copy values (from 'obj2' to 'obj1') */
#define setobj(L,obj1,obj2) \ #define setobj(L,obj1,obj2) \
{ TValue *io1=(obj1); const TValue *io2=(obj2); \ { TValue *io1=(obj1); const TValue *io2=(obj2); \
io1->value_ = io2->value_; settt_(io1, io2->tt_); \ io1->value_ = io2->value_; settt_(io1, io2->tt_); \

View File

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

View File

@ -416,6 +416,17 @@ static void markupval (FuncState *fs, int level) {
} }
/*
** Mark that current block has a to-be-closed variable.
*/
static void marktobeclosed (FuncState *fs) {
BlockCnt *bl = fs->bl;
bl->upval = 1;
bl->insidetbc = 1;
fs->needclose = 1;
}
/* /*
** Find a variable with the given name 'n'. If it is an upvalue, add ** Find a variable with the given name 'n'. If it is an upvalue, add
** this upvalue into all intermediate functions. If it is a global, set ** this upvalue into all intermediate functions. If it is a global, set
@ -1599,7 +1610,7 @@ static void forlist (LexState *ls, TString *indexname) {
line = ls->linenumber; line = ls->linenumber;
adjust_assign(ls, 4, explist(ls, &e), &e); adjust_assign(ls, 4, explist(ls, &e), &e);
adjustlocalvars(ls, 4); /* control variables */ adjustlocalvars(ls, 4); /* control variables */
markupval(fs, fs->nactvar); /* last control var. must be closed */ marktobeclosed(fs); /* last control var. must be closed */
luaK_checkstack(fs, 3); /* extra space to call generator */ luaK_checkstack(fs, 3); /* extra space to call generator */
forbody(ls, base, line, nvars - 4, 1); forbody(ls, base, line, nvars - 4, 1);
} }
@ -1703,11 +1714,9 @@ static int getlocalattribute (LexState *ls) {
} }
static void checktoclose (LexState *ls, int level) { static void checktoclose (FuncState *fs, int level) {
if (level != -1) { /* is there a to-be-closed variable? */ if (level != -1) { /* is there a to-be-closed variable? */
FuncState *fs = ls->fs; marktobeclosed(fs);
markupval(fs, level + 1);
fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0); luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0);
} }
} }
@ -1751,7 +1760,7 @@ static void localstat (LexState *ls) {
adjust_assign(ls, nvars, nexps, &e); adjust_assign(ls, nvars, nexps, &e);
adjustlocalvars(ls, nvars); adjustlocalvars(ls, nvars);
} }
checktoclose(ls, toclose); checktoclose(fs, toclose);
} }
@ -1776,6 +1785,7 @@ static void funcstat (LexState *ls, int line) {
luaX_next(ls); /* skip FUNCTION */ luaX_next(ls); /* skip FUNCTION */
ismethod = funcname(ls, &v); ismethod = funcname(ls, &v);
body(ls, &b, ismethod, line); body(ls, &b, ismethod, line);
check_readonly(ls, &v);
luaK_storevar(ls->fs, &v, &b); luaK_storevar(ls->fs, &v, &b);
luaK_fixline(ls->fs, line); /* definition "happens" in the first line */ luaK_fixline(ls->fs, line); /* definition "happens" in the first line */
} }

View File

@ -166,7 +166,7 @@ void luaE_checkcstack (lua_State *L) {
if (getCcalls(L) == LUAI_MAXCCALLS) if (getCcalls(L) == LUAI_MAXCCALLS)
luaG_runerror(L, "C stack overflow"); luaG_runerror(L, "C stack overflow");
else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11)) else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ luaD_throw(L, LUA_ERRERR); /* error while handling stack error */
} }
@ -236,7 +236,7 @@ static void f_luaopen (lua_State *L, void *ud) {
luaS_init(L); luaS_init(L);
luaT_init(L); luaT_init(L);
luaX_init(L); luaX_init(L);
g->gcrunning = 1; /* allow gc */ g->gcstp = 0; /* allow gc */
setnilvalue(&g->nilvalue); /* now state is complete */ setnilvalue(&g->nilvalue); /* now state is complete */
luai_userstateopen(L); luai_userstateopen(L);
} }
@ -269,8 +269,9 @@ static void preinit_thread (lua_State *L, global_State *g) {
static void close_state (lua_State *L) { static void close_state (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
if (!completestate(g)) /* closing a partially built state? */ if (!completestate(g)) /* closing a partially built state? */
luaC_freeallobjects(L); /* jucst collect its objects */ luaC_freeallobjects(L); /* just collect its objects */
else { /* closing a fully built state */ else { /* closing a fully built state */
L->ci = &L->base_ci; /* unwind CallInfo list */
luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */ luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */
luaC_freeallobjects(L); /* collect all objects */ luaC_freeallobjects(L); /* collect all objects */
luai_userstateclose(L); luai_userstateclose(L);
@ -330,13 +331,13 @@ int luaE_resetthread (lua_State *L, int status) {
ci->callstatus = CIST_C; ci->callstatus = CIST_C;
if (status == LUA_YIELD) if (status == LUA_YIELD)
status = LUA_OK; status = LUA_OK;
L->status = LUA_OK; /* so it can run __close metamethods */
status = luaD_closeprotected(L, 1, status); status = luaD_closeprotected(L, 1, status);
if (status != LUA_OK) /* errors? */ if (status != LUA_OK) /* errors? */
luaD_seterrorobj(L, status, L->stack + 1); luaD_seterrorobj(L, status, L->stack + 1);
else else
L->top = L->stack + 1; L->top = L->stack + 1;
ci->top = L->top + LUA_MINSTACK; ci->top = L->top + LUA_MINSTACK;
L->status = cast_byte(status);
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0); luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
return status; return status;
} }
@ -372,7 +373,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->ud_warn = NULL; g->ud_warn = NULL;
g->mainthread = L; g->mainthread = L;
g->seed = luai_makeseed(L); g->seed = luai_makeseed(L);
g->gcrunning = 0; /* no GC while building state */ g->gcstp = GCSTPGC; /* no GC while building state */
g->strt.size = g->strt.nuse = 0; g->strt.size = g->strt.nuse = 0;
g->strt.hash = NULL; g->strt.hash = NULL;
setnilvalue(&g->l_registry); setnilvalue(&g->l_registry);

View File

@ -165,7 +165,7 @@ typedef struct stringtable {
** - field 'nyield' is used only while a function is "doing" an ** - field 'nyield' is used only while a function is "doing" an
** yield (from the yield until the next resume); ** yield (from the yield until the next resume);
** - field 'nres' is used only while closing tbc variables when ** - field 'nres' is used only while closing tbc variables when
** returning from a C function; ** returning from a function;
** - field 'transferinfo' is used only during call/returnhooks, ** - field 'transferinfo' is used only during call/returnhooks,
** before the function starts or after it ends. ** before the function starts or after it ends.
*/ */
@ -209,7 +209,7 @@ typedef struct CallInfo {
#define CIST_YPCALL (1<<4) /* doing a yieldable protected call */ #define CIST_YPCALL (1<<4) /* doing a yieldable protected call */
#define CIST_TAIL (1<<5) /* call was tail called */ #define CIST_TAIL (1<<5) /* call was tail called */
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ #define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
#define CIST_FIN (1<<7) /* call is running a finalizer */ #define CIST_FIN (1<<7) /* function "called" a finalizer */
#define CIST_TRAN (1<<8) /* 'ci' has transfer information */ #define CIST_TRAN (1<<8) /* 'ci' has transfer information */
#define CIST_CLSRET (1<<9) /* function is closing tbc variables */ #define CIST_CLSRET (1<<9) /* function is closing tbc variables */
/* Bits 10-12 are used for CIST_RECST (see below) */ /* Bits 10-12 are used for CIST_RECST (see below) */
@ -263,7 +263,7 @@ typedef struct global_State {
lu_byte gcstopem; /* stops emergency collections */ lu_byte gcstopem; /* stops emergency collections */
lu_byte genminormul; /* control for minor generational collections */ lu_byte genminormul; /* control for minor generational collections */
lu_byte genmajormul; /* control for major generational collections */ lu_byte genmajormul; /* control for major generational collections */
lu_byte gcrunning; /* true if GC is running */ lu_byte gcstp; /* control whether GC is running */
lu_byte gcemergency; /* true if this is an emergency collection */ lu_byte gcemergency; /* true if this is an emergency collection */
lu_byte gcpause; /* size of pause between successive GCs */ lu_byte gcpause; /* size of pause between successive GCs */
lu_byte gcstepmul; /* GC "speed" */ lu_byte gcstepmul; /* GC "speed" */

View File

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

View File

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

View File

@ -59,8 +59,9 @@ static void checktab (lua_State *L, int arg, int what) {
static int tinsert (lua_State *L) { static int tinsert (lua_State *L) {
lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */
lua_Integer pos; /* where to insert new element */ lua_Integer pos; /* where to insert new element */
lua_Integer e = aux_getn(L, 1, TAB_RW);
e = luaL_intop(+, e, 1); /* first empty element */
switch (lua_gettop(L)) { switch (lua_gettop(L)) {
case 2: { /* called with only 2 arguments */ case 2: { /* called with only 2 arguments */
pos = e; /* insert new element at the end */ pos = e; /* insert new element at the end */
@ -147,7 +148,7 @@ static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
lua_geti(L, 1, i); lua_geti(L, 1, i);
if (l_unlikely(!lua_isstring(L, -1))) if (l_unlikely(!lua_isstring(L, -1)))
luaL_error(L, "invalid value (%s) at index %I in table for 'concat'", luaL_error(L, "invalid value (%s) at index %I in table for 'concat'",
luaL_typename(L, -1), i); luaL_typename(L, -1), (LUAI_UACINT)i);
luaL_addvalue(b); luaL_addvalue(b);
} }

View File

@ -89,14 +89,15 @@ static void print_usage (const char *badoption) {
lua_writestringerror( lua_writestringerror(
"usage: %s [options] [script [args]]\n" "usage: %s [options] [script [args]]\n"
"Available options are:\n" "Available options are:\n"
" -e stat execute string 'stat'\n" " -e stat execute string 'stat'\n"
" -i enter interactive mode after executing 'script'\n" " -i enter interactive mode after executing 'script'\n"
" -l name require library 'name' into global 'name'\n" " -l mod require library 'mod' into global 'mod'\n"
" -v show version information\n" " -l g=mod require library 'mod' into global 'g'\n"
" -E ignore environment variables\n" " -v show version information\n"
" -W turn warnings on\n" " -E ignore environment variables\n"
" -- stop handling options\n" " -W turn warnings on\n"
" - stop handling options and execute stdin\n" " -- stop handling options\n"
" - stop handling options and execute stdin\n"
, ,
progname); progname);
} }
@ -207,16 +208,22 @@ static int dostring (lua_State *L, const char *s, const char *name) {
/* /*
** Calls 'require(name)' and stores the result in a global variable ** Receives 'globname[=modname]' and runs 'globname = require(modname)'.
** with the given name.
*/ */
static int dolibrary (lua_State *L, const char *name) { static int dolibrary (lua_State *L, char *globname) {
int status; int status;
char *modname = strchr(globname, '=');
if (modname == NULL) /* no explicit name? */
modname = globname; /* module name is equal to global name */
else {
*modname = '\0'; /* global name ends here */
modname++; /* module name starts after the '=' */
}
lua_getglobal(L, "require"); lua_getglobal(L, "require");
lua_pushstring(L, name); lua_pushstring(L, modname);
status = docall(L, 1, 1); /* call 'require(name)' */ status = docall(L, 1, 1); /* call 'require(modname)' */
if (status == LUA_OK) if (status == LUA_OK)
lua_setglobal(L, name); /* global[name] = require return */ lua_setglobal(L, globname); /* globname = require(modname) */
return report(L, status); return report(L, status);
} }
@ -327,7 +334,7 @@ static int runargs (lua_State *L, char **argv, int n) {
switch (option) { switch (option) {
case 'e': case 'l': { case 'e': case 'l': {
int status; int status;
const char *extra = argv[i] + 2; /* both options need an argument */ char *extra = argv[i] + 2; /* both options need an argument */
if (*extra == '\0') extra = argv[++i]; if (*extra == '\0') extra = argv[++i];
lua_assert(extra != NULL); lua_assert(extra != NULL);
status = (option == 'e') status = (option == 'e')

View File

@ -155,6 +155,7 @@ 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; f->sizelineinfo=0;
return f; return f;
} }
@ -600,11 +601,11 @@ static void PrintCode(const Proto* f)
if (c==0) printf("all out"); else printf("%d out",c-1); if (c==0) printf("all out"); else printf("%d out",c-1);
break; break;
case OP_TAILCALL: case OP_TAILCALL:
printf("%d %d %d",a,b,c); printf("%d %d %d%s",a,b,c,ISK);
printf(COMMENT "%d in",b-1); printf(COMMENT "%d in",b-1);
break; break;
case OP_RETURN: case OP_RETURN:
printf("%d %d %d",a,b,c); printf("%d %d %d%s",a,b,c,ISK);
printf(COMMENT); printf(COMMENT);
if (b==0) printf("all out"); else printf("%d out",b-1); if (b==0) printf("all out"); else printf("%d out",b-1);
break; break;
@ -619,7 +620,7 @@ static void PrintCode(const Proto* f)
break; break;
case OP_FORPREP: case OP_FORPREP:
printf("%d %d",a,bx); printf("%d %d",a,bx);
printf(COMMENT "to %d",pc+bx+2); printf(COMMENT "exit to %d",pc+bx+3);
break; break;
case OP_TFORPREP: case OP_TFORPREP:
printf("%d %d",a,bx); printf("%d %d",a,bx);

View File

@ -224,14 +224,11 @@ static int byteoffset (lua_State *L) {
static int iter_aux (lua_State *L, int strict) { static int iter_aux (lua_State *L, int strict) {
size_t len; size_t len;
const char *s = luaL_checklstring(L, 1, &len); const char *s = luaL_checklstring(L, 1, &len);
lua_Integer n = lua_tointeger(L, 2) - 1; lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
if (n < 0) /* first iteration? */ if (n < len) {
n = 0; /* start from here */ while (iscont(s + n)) n++; /* skip continuation bytes */
else if (n < (lua_Integer)len) {
n++; /* skip current byte */
while (iscont(s + n)) n++; /* and its continuations */
} }
if (n >= (lua_Integer)len) if (n >= len) /* (also handles original 'n' being negative) */
return 0; /* no more codepoints */ return 0; /* no more codepoints */
else { else {
utfint code; utfint code;

View File

@ -406,7 +406,7 @@ static int l_strcmp (const TString *ls, const TString *rs) {
** from float to int.) ** from float to int.)
** When 'f' is NaN, comparisons must result in false. ** When 'f' is NaN, comparisons must result in false.
*/ */
static int LTintfloat (lua_Integer i, lua_Number f) { l_sinline int LTintfloat (lua_Integer i, lua_Number f) {
if (l_intfitsf(i)) if (l_intfitsf(i))
return luai_numlt(cast_num(i), f); /* compare them as floats */ return luai_numlt(cast_num(i), f); /* compare them as floats */
else { /* i < f <=> i < ceil(f) */ else { /* i < f <=> i < ceil(f) */
@ -423,7 +423,7 @@ static int LTintfloat (lua_Integer i, lua_Number f) {
** Check whether integer 'i' is less than or equal to float 'f'. ** Check whether integer 'i' is less than or equal to float 'f'.
** See comments on previous function. ** See comments on previous function.
*/ */
static int LEintfloat (lua_Integer i, lua_Number f) { l_sinline int LEintfloat (lua_Integer i, lua_Number f) {
if (l_intfitsf(i)) if (l_intfitsf(i))
return luai_numle(cast_num(i), f); /* compare them as floats */ return luai_numle(cast_num(i), f); /* compare them as floats */
else { /* i <= f <=> i <= floor(f) */ else { /* i <= f <=> i <= floor(f) */
@ -440,7 +440,7 @@ static int LEintfloat (lua_Integer i, lua_Number f) {
** Check whether float 'f' is less than integer 'i'. ** Check whether float 'f' is less than integer 'i'.
** See comments on previous function. ** See comments on previous function.
*/ */
static int LTfloatint (lua_Number f, lua_Integer i) { l_sinline int LTfloatint (lua_Number f, lua_Integer i) {
if (l_intfitsf(i)) if (l_intfitsf(i))
return luai_numlt(f, cast_num(i)); /* compare them as floats */ return luai_numlt(f, cast_num(i)); /* compare them as floats */
else { /* f < i <=> floor(f) < i */ else { /* f < i <=> floor(f) < i */
@ -457,7 +457,7 @@ static int LTfloatint (lua_Number f, lua_Integer i) {
** Check whether float 'f' is less than or equal to integer 'i'. ** Check whether float 'f' is less than or equal to integer 'i'.
** See comments on previous function. ** See comments on previous function.
*/ */
static int LEfloatint (lua_Number f, lua_Integer i) { l_sinline int LEfloatint (lua_Number f, lua_Integer i) {
if (l_intfitsf(i)) if (l_intfitsf(i))
return luai_numle(f, cast_num(i)); /* compare them as floats */ return luai_numle(f, cast_num(i)); /* compare them as floats */
else { /* f <= i <=> ceil(f) <= i */ else { /* f <= i <=> ceil(f) <= i */
@ -473,7 +473,7 @@ static int LEfloatint (lua_Number f, lua_Integer i) {
/* /*
** Return 'l < r', for numbers. ** Return 'l < r', for numbers.
*/ */
static int LTnum (const TValue *l, const TValue *r) { l_sinline int LTnum (const TValue *l, const TValue *r) {
lua_assert(ttisnumber(l) && ttisnumber(r)); lua_assert(ttisnumber(l) && ttisnumber(r));
if (ttisinteger(l)) { if (ttisinteger(l)) {
lua_Integer li = ivalue(l); lua_Integer li = ivalue(l);
@ -495,7 +495,7 @@ static int LTnum (const TValue *l, const TValue *r) {
/* /*
** Return 'l <= r', for numbers. ** Return 'l <= r', for numbers.
*/ */
static int LEnum (const TValue *l, const TValue *r) { l_sinline int LEnum (const TValue *l, const TValue *r) {
lua_assert(ttisnumber(l) && ttisnumber(r)); lua_assert(ttisnumber(l) && ttisnumber(r));
if (ttisinteger(l)) { if (ttisinteger(l)) {
lua_Integer li = ivalue(l); lua_Integer li = ivalue(l);
@ -766,7 +766,8 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) {
/* /*
** Shift left operation. (Shift right just negates 'y'.) ** Shift left operation. (Shift right just negates 'y'.)
*/ */
#define luaV_shiftr(x,y) luaV_shiftl(x,-(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? */
@ -847,10 +848,19 @@ void luaV_finishOp (lua_State *L) {
luaV_concat(L, total); /* concat them (may yield again) */ luaV_concat(L, total); /* concat them (may yield again) */
break; break;
} }
case OP_CLOSE: case OP_RETURN: { /* yielded closing variables */ case OP_CLOSE: { /* yielded closing variables */
ci->u.l.savedpc--; /* repeat instruction to close other vars. */ ci->u.l.savedpc--; /* repeat instruction to close other vars. */
break; break;
} }
case OP_RETURN: { /* yielded closing variables */
StkId ra = base + GETARG_A(inst);
/* adjust top to signal correct number of returns, in case the
return is "up to top" ('isIT') */
L->top = ra + ci->u2.nres;
/* repeat instruction to close other vars. and complete the return */
ci->u.l.savedpc--;
break;
}
default: { default: {
/* only these other opcodes can yield */ /* only these other opcodes can yield */
lua_assert(op == OP_TFORCALL || op == OP_CALL || lua_assert(op == OP_TFORCALL || op == OP_CALL ||
@ -1099,7 +1109,7 @@ void luaV_finishOp (lua_State *L) {
#define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci)) #define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci))
/* /*
** Protect code that can only raise errors. (That is, it cannnot change ** Protect code that can only raise errors. (That is, it cannot change
** the stack or hooks.) ** the stack or hooks.)
*/ */
#define halfProtect(exp) (savestate(L,ci), (exp)) #define halfProtect(exp) (savestate(L,ci), (exp))
@ -1156,8 +1166,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
Instruction i; /* instruction being executed */ Instruction i; /* instruction being executed */
StkId ra; /* instruction's A register */ StkId ra; /* instruction's A register */
vmfetch(); vmfetch();
// low-level line tracing for debugging Lua #if 0
// printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p))); /* low-level line tracing for debugging Lua */
printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
#endif
lua_assert(base == ci->func + 1); lua_assert(base == ci->func + 1);
lua_assert(base <= L->top && L->top < L->stack_last); lua_assert(base <= L->top && L->top < L->stack_last);
/* invalidate top for instructions not expecting it */ /* invalidate top for instructions not expecting it */
@ -1625,13 +1637,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
updatetrap(ci); /* C call; nothing else to be done */ updatetrap(ci); /* C call; nothing else to be done */
else { /* Lua call: run function in this same C frame */ else { /* Lua call: run function in this same C frame */
ci = newci; ci = newci;
ci->callstatus = 0; /* call re-uses 'luaV_execute' */
goto startfunc; goto startfunc;
} }
vmbreak; vmbreak;
} }
vmcase(OP_TAILCALL) { vmcase(OP_TAILCALL) {
int b = GETARG_B(i); /* number of arguments + 1 (function) */ int b = GETARG_B(i); /* number of arguments + 1 (function) */
int 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;
@ -1645,23 +1657,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
lua_assert(L->tbclist < base); /* no pending tbc variables */ lua_assert(L->tbclist < base); /* no pending tbc variables */
lua_assert(base == ci->func + 1); lua_assert(base == ci->func + 1);
} }
while (!ttisfunction(s2v(ra))) { /* not a function? */ if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */
luaD_tryfuncTM(L, ra); /* try '__call' metamethod */ goto startfunc; /* execute the callee */
b++; /* there is now one extra argument */ else { /* C function? */
checkstackGCp(L, 1, ra);
}
if (!ttisLclosure(s2v(ra))) { /* C function? */
luaD_precall(L, ra, LUA_MULTRET); /* call it */
updatetrap(ci);
updatestack(ci); /* stack may have been relocated */
ci->func -= delta; /* restore 'func' (if vararg) */ ci->func -= delta; /* restore 'func' (if vararg) */
luaD_poscall(L, ci, cast_int(L->top - ra)); /* 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 */
} }
ci->func -= delta; /* restore 'func' (if vararg) */
luaD_pretailcall(L, ci, ra, b); /* prepare call frame */
goto startfunc; /* execute the callee */
} }
vmcase(OP_RETURN) { vmcase(OP_RETURN) {
int n = GETARG_B(i) - 1; /* number of results */ int n = GETARG_B(i) - 1; /* number of results */
@ -1670,6 +1673,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
n = cast_int(L->top - ra); /* get what is available */ n = cast_int(L->top - 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 */
if (L->top < ci->top) if (L->top < ci->top)
L->top = ci->top; L->top = ci->top;
luaF_close(L, base, CLOSEKTOP, 1); luaF_close(L, base, CLOSEKTOP, 1);

Binary file not shown.

Binary file not shown.