diffu-lua-5.4.3-lua-5.4.4
Makefile
@@ -46,7 +46,7 @@
# Lua version and release.
V= 5.4
-R= $V.3
+R= $V.4
# Targets start here.
all: $(PLAT)
README
@@ -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
further information about Lua, see doc/readme.html.
doc/contents.html
@@ -32,7 +32,7 @@
<P>
<SMALL>
-Copyright © 2020–2021 Lua.org, PUC-Rio.
+Copyright © 2020–2022 Lua.org, PUC-Rio.
Freely available under the terms of the
<A HREF="http://www.lua.org/license.html">Lua license</A>.
</SMALL>
@@ -664,10 +664,10 @@
<P CLASS="footer">
Last update:
-Wed Mar 3 13:04:44 UTC 2021
+Thu Jan 13 11:32:22 UTC 2022
</P>
<!--
-Last change: revised for Lua 5.4.3
+Last change: revised for Lua 5.4.4
-->
</BODY>
doc/manual.html
@@ -19,7 +19,7 @@
<P>
<SMALL>
-Copyright © 2020–2021 Lua.org, PUC-Rio.
+Copyright © 2020–2022 Lua.org, PUC-Rio.
Freely available under the terms of the
<a href="http://www.lua.org/license.html">Lua license</a>.
</SMALL>
@@ -961,11 +961,8 @@
<p>
-Finalizers cannot yield.
-Except for that, they can do anything,
-such as raise errors, create new objects,
-or even run the garbage collector.
-However, because they can run in unpredictable times,
+Finalizers cannot yield nor run the garbage collector.
+Because they can run in unpredictable times,
it is good practice to restrict each finalizer
to the minimum necessary to properly release
its associated resource.
@@ -1636,8 +1633,10 @@
<p>
-The assignment statement first evaluates all its expressions
-and only then the assignments are performed.
+If a variable is both assigned and read
+inside a multiple assignment,
+Lua ensures all reads get the value of the variable
+before the assignment.
Thus the code
<pre>
@@ -1662,6 +1661,14 @@
<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>
An assignment to a global name <code>x = val</code>
is equivalent to the assignment
<code>_ENV.x = val</code> (see <a href="#2.2">§2.2</a>).
@@ -2416,16 +2423,21 @@
<p>
The length operator applied on a 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:
<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>
In words,
-a border is any (natural) index present in the table
-that is followed by an absent index
-(or zero, when index 1 is absent).
+a border is any positive integer index present in the table
+that is followed by an absent index,
+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>
@@ -2436,12 +2448,9 @@
and therefore it is not a sequence.
(The <b>nil</b> at index 4 is called a <em>hole</em>.)
The table <code>{nil, 20, 30, nil, nil, 60, nil}</code>
-has three borders (0, 3, and 6) and three holes
-(at indices 1, 4, and 5),
+has three borders (0, 3, and 6),
so it is not a sequence, too.
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>
@@ -2459,7 +2468,7 @@
<p>
The computation of the length of a table
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>
@@ -3979,6 +3988,10 @@
see <a href="#pdf-collectgarbage"><code>collectgarbage</code></a>.
+<p>
+This function should not be called by a finalizer.
+
+
@@ -5933,7 +5946,10 @@
<a href="#lua_getstack"><code>lua_getstack</code></a> fills only the private part
of this structure, for later use.
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>
@@ -6110,11 +6126,25 @@
<p>
Each character in the string <code>what</code>
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>
-<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><b>'<code>S</code>': </b>
@@ -6122,9 +6152,6 @@
<code>linedefined</code>, <code>lastlinedefined</code>, and <code>what</code>;
</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>
@@ -6132,25 +6159,13 @@
<code>nups</code>, <code>nparams</code>, and <code>isvararg</code>;
</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>
-pushes onto the stack a table whose indices are the
-numbers of the lines that are valid on the function.
-(A <em>valid line</em> is a line with some associated code,
-that is, a line where you can put a break point.
-Non-valid lines include empty lines and comments.)
-
-
-<p>
+pushes onto the stack a table whose indices are
+the lines on the function with some associated code,
+that is, the lines where you can put a break point.
+(Lines with no code include empty lines and comments.)
If this option is given together with option '<code>f</code>',
its table is pushed after the function.
-
-
-<p>
This is the only option that can raise a memory error.
</li>
@@ -6508,7 +6523,7 @@
<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,
const char *p, const char *r);</pre>
@@ -6562,7 +6577,7 @@
<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>
<p>
@@ -6716,7 +6731,7 @@
<hr><h3><a name="luaL_buffinit"><code>luaL_buffinit</code></a></h3><p>
-<span class="apii">[-0, +0, –]</span>
+<span class="apii">[-0, +?, –]</span>
<pre>void luaL_buffinit (lua_State *L, luaL_Buffer *B);</pre>
<p>
@@ -6754,7 +6769,7 @@
<hr><h3><a name="luaL_buffsub"><code>luaL_buffsub</code></a></h3><p>
-<span class="apii">[-0, +0, –]</span>
+<span class="apii">[-?, +?, –]</span>
<pre>void luaL_buffsub (luaL_Buffer *B, int n);</pre>
<p>
@@ -7557,6 +7572,11 @@
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 @@
and some of these options.
+<p>
+This function should not be called by a finalizer.
+
+
<p>
@@ -7936,7 +7960,7 @@
<p>
<hr><h3><a name="pdf-error"><code>error (message [, level])</code></a></h3>
-Raises an error (see <a href="#2.3">§2.3</a>) with @{message} as the error object.
+Raises an error (see <a href="#2.3">§2.3</a>) with <code>message</code> as the error object.
This function never returns.
@@ -8111,9 +8135,8 @@
<p>
-The behavior of <code>next</code> is undefined if,
-during the traversal,
-you assign any value to a non-existent field in the table.
+You should not assign any value to a non-existent field in a table
+during its traversal.
You may however modify existing fields.
In particular, you may set existing fields to nil.
@@ -8159,7 +8182,7 @@
instead, <code>pcall</code> catches the error
and returns a status code.
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,
after this first result.
In case of any error, <code>pcall</code> returns <b>false</b> plus the error object.
@@ -8439,7 +8462,7 @@
<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.
@@ -8483,7 +8506,7 @@
<p>
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 @@
A third, optional numeric argument <code>init</code> specifies
where to start the search;
its default value is 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,
so the function does a plain "find substring" operation,
with no characters in <code>pattern</code> being considered magic.
@@ -9046,8 +9069,10 @@
which must be a string.
The format string follows the same rules as the ISO C function <code>sprintf</code>.
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>.
+Both width and precision, when present,
+are limited to two digits.
<p>
@@ -9071,7 +9096,7 @@
"a string with \"quotes\" and \
new line"
</pre><p>
-This specifier does not support modifiers (flags, width, length).
+This specifier does not support modifiers (flags, width, precision).
<p>
@@ -10362,7 +10387,7 @@
<p>
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.
@@ -11924,10 +11949,10 @@
<P CLASS="footer">
Last update:
-Mon Mar 15 13:39:42 UTC 2021
+Thu Jan 13 11:33:16 UTC 2022
</P>
<!--
-Last change: revised for Lua 5.4.3
+Last change: revised for Lua 5.4.4
-->
</body></html>
doc/readme.html
@@ -110,7 +110,7 @@
<OL>
<LI>
Open a terminal window and move to
-the top-level directory, which is named <TT>lua-5.4.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.
<P>
<LI>
@@ -303,7 +303,7 @@
<A HREF="http://www.lua.org/license.html">this</A>.
<BLOCKQUOTE STYLE="padding-bottom: 0em">
-Copyright © 1994–2021 Lua.org, PUC-Rio.
+Copyright © 1994–2022 Lua.org, PUC-Rio.
<P>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -330,10 +330,10 @@
<P CLASS="footer">
Last update:
-Wed Mar 3 10:16:26 UTC 2021
+Mon Jan 3 09:54:18 UTC 2022
</P>
<!--
-Last change: revised for Lua 5.4.3
+Last change: revised for Lua 5.4.4
-->
</BODY>
src/Makefile
@@ -79,7 +79,7 @@
@echo "PLAT= $(PLAT)"
@echo "CC= $(CC)"
@echo "CFLAGS= $(CFLAGS)"
- @echo "LDFLAGS= $(SYSLDFLAGS)"
+ @echo "LDFLAGS= $(LDFLAGS)"
@echo "LIBS= $(LIBS)"
@echo "AR= $(AR)"
@echo "RANLIB= $(RANLIB)"
src/lapi.c
@@ -53,6 +53,10 @@
#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) {
CallInfo *ci = L->ci;
if (idx > 0) {
@@ -70,22 +74,28 @@
else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx;
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
- if (ttislcf(s2v(ci->func))) /* light C function? */
- return &G(L)->nilvalue; /* it has no upvalues */
- else {
+ if (ttisCclosure(s2v(ci->func))) { /* C closure? */
CClosure *func = clCvalue(s2v(ci->func));
return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
: &G(L)->nilvalue;
}
+ else { /* light C function or Lua function (through a hook)?) */
+ api_check(L, ttislcf(s2v(ci->func)), "caller not a C function");
+ 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;
if (idx > 0) {
StkId o = ci->func + idx;
- api_check(L, o < L->top, "unacceptable index");
+ api_check(L, o < L->top, "invalid index");
return o;
}
else { /* non-positive index */
@@ -218,7 +228,7 @@
** Note that we move(copy) only the value inside the stack.
** (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--) {
TValue temp;
setobj(L, &temp, s2v(from));
@@ -438,7 +448,7 @@
}
-static void *touserdata (const TValue *o) {
+l_sinline void *touserdata (const TValue *o) {
switch (ttype(o)) {
case LUA_TUSERDATA: return getudatamem(uvalue(o));
case LUA_TLIGHTUSERDATA: return pvalue(o);
@@ -630,7 +640,7 @@
*/
-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;
TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
@@ -705,7 +715,7 @@
}
-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 */
setnilvalue(s2v(L->top));
else
@@ -1126,18 +1136,19 @@
LUA_API int lua_gc (lua_State *L, int what, ...) {
va_list argp;
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);
- g = G(L);
va_start(argp, what);
switch (what) {
case LUA_GCSTOP: {
- g->gcrunning = 0;
+ g->gcstp = GCSTPUSR; /* stopped by the user */
break;
}
case LUA_GCRESTART: {
luaE_setdebt(g, 0);
- g->gcrunning = 1;
+ g->gcstp = 0; /* (GCSTPGC must be already zero here) */
break;
}
case LUA_GCCOLLECT: {
@@ -1156,8 +1167,8 @@
case LUA_GCSTEP: {
int data = va_arg(argp, int);
l_mem debt = 1; /* =1 to signal that it did an actual step */
- lu_byte oldrunning = g->gcrunning;
- g->gcrunning = 1; /* allow GC to run */
+ lu_byte oldstp = g->gcstp;
+ g->gcstp = 0; /* allow GC to run (GCSTPGC must be zero here) */
if (data == 0) {
luaE_setdebt(g, 0); /* do a basic step */
luaC_step(L);
@@ -1167,7 +1178,7 @@
luaE_setdebt(g, debt);
luaC_checkGC(L);
}
- g->gcrunning = oldrunning; /* restore previous state */
+ g->gcstp = oldstp; /* restore previous state */
if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */
res = 1; /* signal it */
break;
@@ -1185,7 +1196,7 @@
break;
}
case LUA_GCISRUNNING: {
- res = g->gcrunning;
+ res = gcrunning(g);
break;
}
case LUA_GCGEN: {
src/lauxlib.c
@@ -881,6 +881,7 @@
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 (!lua_isstring(L, -1))
luaL_error(L, "'__tostring' must return a string");
src/lauxlib.h
@@ -102,7 +102,7 @@
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);
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s,
const char *p, const char *r);
@@ -154,6 +154,14 @@
#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 */
#define luaL_pushfail(L) lua_pushnil(L)
src/lbaselib.c
@@ -182,12 +182,20 @@
static int pushmode (lua_State *L, int oldmode) {
- lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
- : "generational");
+ if (oldmode == -1)
+ luaL_pushfail(L); /* invalid call to 'lua_gc' */
+ else
+ lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
+ : "generational");
return 1;
}
+/*
+** 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 const char *const opts[] = {"stop", "restart", "collect",
"count", "step", "setpause", "setstepmul",
@@ -200,12 +208,14 @@
case LUA_GCCOUNT: {
int k = lua_gc(L, o);
int b = lua_gc(L, LUA_GCCOUNTB);
+ checkvalres(k);
lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024));
return 1;
}
case LUA_GCSTEP: {
int step = (int)luaL_optinteger(L, 2, 0);
int res = lua_gc(L, o, step);
+ checkvalres(res);
lua_pushboolean(L, res);
return 1;
}
@@ -213,11 +223,13 @@
case LUA_GCSETSTEPMUL: {
int p = (int)luaL_optinteger(L, 2, 0);
int previous = lua_gc(L, o, p);
+ checkvalres(previous);
lua_pushinteger(L, previous);
return 1;
}
case LUA_GCISRUNNING: {
int res = lua_gc(L, o);
+ checkvalres(res);
lua_pushboolean(L, res);
return 1;
}
@@ -234,10 +246,13 @@
}
default: {
int res = lua_gc(L, o);
+ checkvalres(res);
lua_pushinteger(L, res);
return 1;
}
}
+ luaL_pushfail(L); /* invalid call (inside a finalizer) */
+ return 1;
}
@@ -261,6 +276,11 @@
}
+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) {
luaL_checkany(L, 1);
if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */
@@ -270,7 +290,7 @@
}
else {
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;
}
@@ -280,7 +300,8 @@
** Traversal function for 'ipairs'
*/
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);
return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
}
src/lcode.c
@@ -10,6 +10,7 @@
#include "lprefix.h"
+#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
@@ -580,24 +581,41 @@
/*
** 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) {
- TValue k, o;
- setpvalue(&k, cast_voidp(cast_sizet(n)));
+ TValue o;
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) {
TValue o;
+ lua_Integer ik;
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);
+ }
}
src/lcorolib.c
@@ -78,7 +78,7 @@
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
stat = lua_resetthread(co); /* close its tbc variables */
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 ... */
lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
@@ -179,7 +179,7 @@
}
else {
lua_pushboolean(L, 0);
- lua_xmove(co, L, 1); /* copy error message */
+ lua_xmove(co, L, 1); /* move error message */
return 2;
}
}
src/ldebug.c
@@ -34,8 +34,8 @@
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL)
-static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
- const char **name);
+static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
+ const char **name);
static int currentpc (CallInfo *ci) {
@@ -64,7 +64,7 @@
}
else {
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 ||
(i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc)
@@ -301,7 +301,14 @@
sethvalue2s(L, L->top, t); /* push it on stack */
api_incr_top(L);
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 */
luaH_setint(L, t, currentline, &v); /* table[line] = true */
}
@@ -310,15 +317,9 @@
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
- if (ci == NULL) /* no 'ci'? */
- return NULL; /* no info */
- else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */
- *name = "__gc";
- return "metamethod"; /* report it as such */
- }
- /* calling function is a known Lua function? */
- else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
- return funcnamefromcode(L, ci->previous, name);
+ /* calling function is a known function? */
+ if (ci != NULL && !(ci->callstatus & CIST_TAIL))
+ return funcnamefromcall(L, ci->previous, name);
else return NULL; /* no way to find a name */
}
@@ -590,16 +591,10 @@
** Returns what the name is (e.g., "for iterator", "method",
** "metamethod") and sets '*name' to point to the name.
*/
-static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
- const char **name) {
+static const char *funcnamefromcode (lua_State *L, const Proto *p,
+ int pc, const char **name) {
TMS tm = (TMS)0; /* (initial value avoids warnings) */
- const Proto *p = ci_func(ci)->p; /* calling function */
- int pc = currentpc(ci); /* calling instruction index */
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)) {
case OP_CALL:
case OP_TAILCALL:
@@ -636,6 +631,26 @@
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 *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) {
- const char *name = NULL; /* to avoid warnings */
CallInfo *ci = L->ci;
+ const char *name = NULL; /* to avoid warnings */
const char *kind = NULL;
if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
@@ -685,26 +712,40 @@
kind = getobjname(ci_func(ci)->p, currentpc(ci),
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);
- 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) {
CallInfo *ci = L->ci;
const char *name = NULL; /* to avoid warnings */
- const char *what = (isLua(ci)) ? funcnamefromcode(L, ci, &name) : NULL;
- if (what != NULL) {
- const char *t = luaT_objtypename(L, o);
- luaG_runerror(L, "%s '%s' is not callable (a %s value)", what, name, t);
- }
- else
- luaG_typeerror(L, o, "call");
+ const char *kind = funcnamefromcall(L, ci, &name);
+ const char *extra = kind ? formatvarinfo(L, kind, name) : varinfo(L, o);
+ typeerror(L, o, "call", extra);
}
src/ldo.c
@@ -387,15 +387,18 @@
** stack, below original 'func', so that 'luaD_precall' can call it. Raise
** an error if there is no '__call' metafield.
*/
-void luaD_tryfuncTM (lua_State *L, StkId func) {
- const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL);
+StkId luaD_tryfuncTM (lua_State *L, StkId func) {
+ const TValue *tm;
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)))
luaG_callerror(L, s2v(func)); /* nothing to call */
for (p = L->top; p > func; p--) /* open space for metamethod */
setobjs2s(L, p, p-1);
L->top++; /* stack space pre-allocated by the caller */
setobj2s(L, func, tm); /* metamethod is the new function to be called */
+ return func;
}
@@ -405,7 +408,7 @@
** expressions, multiple results for tail calls/single parameters)
** 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;
int i;
switch (wanted) { /* handle typical cases separately */
@@ -473,27 +476,81 @@
#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
** of the current call info. 'narg1' is the number of arguments plus 1
-** (so that it includes the function itself).
+** (so that it includes the function itself). Return the number of
+** results, if it was a C function, or -1 for a Lua function.
*/
-void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
- Proto *p = clLvalue(s2v(func))->p;
- int fsize = p->maxstacksize; /* frame size */
- int nfixparams = p->numparams;
- int i;
- for (i = 0; i < narg1; i++) /* move down function and arguments */
- setobjs2s(L, ci->func + i, func + i);
- checkstackGC(L, fsize);
- func = ci->func; /* moved-down function */
- for (; narg1 <= nfixparams; narg1++)
- setnilvalue(s2v(func + narg1)); /* complete missing arguments */
- ci->top = func + 1 + fsize; /* top for new function */
- lua_assert(ci->top <= L->stack_last);
- ci->u.l.savedpc = p->code; /* starting point */
- ci->callstatus |= CIST_TAIL;
- L->top = func + narg1; /* set top */
+int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
+ int narg1, int delta) {
+ retry:
+ switch (ttypetag(s2v(func))) {
+ case LUA_VCCL: /* C closure */
+ return precallC(L, func, LUA_MULTRET, clCvalue(s2v(func))->f);
+ case LUA_VLCF: /* light C function */
+ return precallC(L, func, LUA_MULTRET, fvalue(s2v(func)));
+ case LUA_VLCL: { /* Lua function */
+ Proto *p = clLvalue(s2v(func))->p;
+ int fsize = p->maxstacksize; /* frame size */
+ int nfixparams = p->numparams;
+ int i;
+ checkstackGCp(L, fsize - delta, func);
+ ci->func -= delta; /* restore 'func' (if vararg) */
+ for (i = 0; i < narg1; i++) /* move down function and arguments */
+ setobjs2s(L, ci->func + i, func + i);
+ func = ci->func; /* moved-down function */
+ 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 @@
** original function position.
*/
CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
- lua_CFunction f;
retry:
switch (ttypetag(s2v(func))) {
case LUA_VCCL: /* C closure */
- f = clCvalue(s2v(func))->f;
- goto Cfunc;
+ precallC(L, func, nresults, clCvalue(s2v(func))->f);
+ return NULL;
case LUA_VLCF: /* light C function */
- f = fvalue(s2v(func));
- Cfunc: {
- int n; /* number of returns */
- CallInfo *ci;
- checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
- L->ci = ci = next_ci(L);
- ci->nresults = nresults;
- ci->callstatus = CIST_C;
- ci->top = L->top + LUA_MINSTACK;
- ci->func = func;
- lua_assert(ci->top <= L->stack_last);
- if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
- int narg = cast_int(L->top - func) - 1;
- luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
- }
- lua_unlock(L);
- n = (*f)(L); /* do the actual call */
- lua_lock(L);
- api_checknelems(L, n);
- luaD_poscall(L, ci, n);
+ precallC(L, func, nresults, fvalue(s2v(func)));
return NULL;
- }
case LUA_VLCL: { /* Lua function */
CallInfo *ci;
Proto *p = clLvalue(s2v(func))->p;
@@ -542,20 +578,16 @@
int nfixparams = p->numparams;
int fsize = p->maxstacksize; /* frame size */
checkstackGCp(L, fsize, func);
- L->ci = ci = next_ci(L);
- ci->nresults = nresults;
+ L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize);
ci->u.l.savedpc = p->code; /* starting point */
- ci->top = func + 1 + fsize;
- ci->func = func;
- L->ci = ci;
for (; narg < nfixparams; narg++)
setnilvalue(s2v(L->top++)); /* complete missing arguments */
lua_assert(ci->top <= L->stack_last);
return ci;
}
default: { /* not a function */
- checkstackGCp(L, 1, func); /* space for metamethod */
- luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */
+ func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */
+ /* return luaD_precall(L, func, nresults); */
goto retry; /* try again with metamethod */
}
}
@@ -567,7 +599,7 @@
** number of recursive invocations in the C stack) or nyci (the same
** 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;
L->nCcalls += inc;
if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
@@ -728,11 +760,10 @@
StkId firstArg = L->top - n; /* first argument */
CallInfo *ci = L->ci;
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 */
lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */
- luaE_incCstack(L); /* control the C stack */
if (isLua(ci)) { /* yielded inside a hook? */
L->top = firstArg; /* discard arguments */
luaV_execute(L, ci); /* just continue running Lua code */
@@ -783,6 +814,9 @@
else if (L->status != LUA_YIELD) /* ended with errors? */
return resume_error(L, "cannot resume dead coroutine", nargs);
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);
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
status = luaD_rawrunprotected(L, resume, &nargs);
src/ldo.h
@@ -58,11 +58,11 @@
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
int fTransfer, int nTransfer);
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
-LUAI_FUNC 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 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_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_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t oldtop, ptrdiff_t ef);
src/lgc.c
@@ -906,18 +906,18 @@
if (!notm(tm)) { /* is there a finalizer? */
int status;
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 */
- g->gcrunning = 0; /* avoid GC steps */
setobj2s(L, L->top++, tm); /* push finalizer... */
setobj2s(L, L->top++, &v); /* ... and its argument */
L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */
- g->gcrunning = running; /* restore state */
+ g->gcstp = oldgcstp; /* restore state */
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
- luaE_warnerror(L, "__gc metamethod");
+ luaE_warnerror(L, "__gc");
L->top--; /* pops error object */
}
}
@@ -1011,7 +1011,8 @@
void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
global_State *g = G(L);
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 */
else { /* move 'o' to 'finobj' list */
GCObject **p;
@@ -1502,12 +1503,13 @@
*/
void luaC_freeallobjects (lua_State *L) {
global_State *g = G(L);
+ g->gcstp = GCSTPCLS; /* no extra finalizers after here */
luaC_changemode(L, KGC_INC);
separatetobefnz(g, 1); /* separate all objects with finalizers */
lua_assert(g->finobj == NULL);
callallpendingfinalizers(L);
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 */
lua_assert(g->strt.nuse == 0);
}
@@ -1647,6 +1649,7 @@
}
+
/*
** Performs a basic incremental step. The debt and step size are
** converted from bytes to "units of work"; then the function loops
@@ -1678,7 +1681,7 @@
void luaC_step (lua_State *L) {
global_State *g = G(L);
lua_assert(!g->gcemergency);
- if (g->gcrunning) { /* running? */
+ if (gcrunning(g)) { /* running? */
if(isdecGCmodegen(g))
genstep(L, g);
else
src/lgc.h
@@ -148,6 +148,16 @@
*/
#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'
** allows some adjustments to be done only when needed. macro
src/llimits.h
@@ -166,6 +166,20 @@
/*
+** 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;
** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
*/
@@ -347,7 +361,7 @@
#define condchangemem(L,pre,pos) ((void)0)
#else
#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
src/lmathlib.c
@@ -475,7 +475,7 @@
/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
#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
@@ -486,7 +486,7 @@
/*
** 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) {
src/lobject.c
@@ -164,7 +164,7 @@
*/
static lua_Number lua_strx2number (const char *s, char **endptr) {
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 nosigdig = 0; /* number of non-significant digits */
int e = 0; /* exponent correction */
@@ -174,7 +174,7 @@
while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
neg = isneg(&s); /* check sign */
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 */
if (*s == dot) {
if (hasdot) break; /* second dot? stop loop */
@@ -184,14 +184,14 @@
if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */
nosigdig++;
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 */
if (hasdot) e--; /* decimal digit? correct exponent */
}
else break; /* neither a dot nor a digit */
}
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 */
e *= 4; /* each digit multiplies/divides value by 2^4 */
if (*s == 'p' || *s == 'P') { /* exponent part? */
@@ -200,7 +200,7 @@
s++; /* skip 'p' */
neg1 = isneg(&s); /* sign */
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 */
exp1 = exp1 * 10 + *(s++) - '0';
if (neg1) exp1 = -exp1;
src/lobject.h
@@ -68,7 +68,7 @@
#define val_(o) ((o)->value_)
-#define valraw(o) (&val_(o))
+#define valraw(o) (val_(o))
/* raw type tag of a TValue */
@@ -112,7 +112,7 @@
#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) \
{ TValue *io1=(obj1); const TValue *io2=(obj2); \
io1->value_ = io2->value_; settt_(io1, io2->tt_); \
src/lopcodes.h
@@ -190,7 +190,8 @@
/*
-** 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 {
@@ -203,7 +204,7 @@
OP_LOADK,/* A Bx R[A] := K[Bx] */
OP_LOADKX,/* A R[A] := K[extra arg] */
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_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */
OP_GETUPVAL,/* A B R[A] := UpValue[B] */
@@ -254,7 +255,7 @@
OP_SHL,/* A B C R[A] := R[B] << R[C] */
OP_SHR,/* A B C R[A] := R[B] >> R[C] */
-OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] */
+OP_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_MMBINK,/* A B C k call C metamethod over R[A] and K[B] */
@@ -280,7 +281,7 @@
OP_GEI,/* A sB k if ((R[A] >= sB) ~= 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_TAILCALL,/* A B C k return R[A](R[A+1], ... ,R[A+B-1]) */
@@ -315,6 +316,18 @@
/*===========================================================================
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
'top' is set to last_result+1, so next open instruction (OP_CALL,
OP_RETURN*, OP_SETLIST) may use 'top'.
src/lparser.c
@@ -417,6 +417,17 @@
/*
+** 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
** this upvalue into all intermediate functions. If it is a global, set
** 'var' as 'void' as a flag.
@@ -1599,7 +1610,7 @@
line = ls->linenumber;
adjust_assign(ls, 4, explist(ls, &e), &e);
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 */
forbody(ls, base, line, nvars - 4, 1);
}
@@ -1703,11 +1714,9 @@
}
-static void checktoclose (LexState *ls, int level) {
+static void checktoclose (FuncState *fs, int level) {
if (level != -1) { /* is there a to-be-closed variable? */
- FuncState *fs = ls->fs;
- markupval(fs, level + 1);
- fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
+ marktobeclosed(fs);
luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0);
}
}
@@ -1751,7 +1760,7 @@
adjust_assign(ls, nvars, nexps, &e);
adjustlocalvars(ls, nvars);
}
- checktoclose(ls, toclose);
+ checktoclose(fs, toclose);
}
@@ -1776,6 +1785,7 @@
luaX_next(ls); /* skip FUNCTION */
ismethod = funcname(ls, &v);
body(ls, &b, ismethod, line);
+ check_readonly(ls, &v);
luaK_storevar(ls->fs, &v, &b);
luaK_fixline(ls->fs, line); /* definition "happens" in the first line */
}
src/lstate.c
@@ -166,7 +166,7 @@
if (getCcalls(L) == LUAI_MAXCCALLS)
luaG_runerror(L, "C stack overflow");
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 @@
luaS_init(L);
luaT_init(L);
luaX_init(L);
- g->gcrunning = 1; /* allow gc */
+ g->gcstp = 0; /* allow gc */
setnilvalue(&g->nilvalue); /* now state is complete */
luai_userstateopen(L);
}
@@ -269,8 +269,9 @@
static void close_state (lua_State *L) {
global_State *g = G(L);
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 */
+ L->ci = &L->base_ci; /* unwind CallInfo list */
luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */
luaC_freeallobjects(L); /* collect all objects */
luai_userstateclose(L);
@@ -330,13 +331,13 @@
ci->callstatus = CIST_C;
if (status == LUA_YIELD)
status = LUA_OK;
+ L->status = LUA_OK; /* so it can run __close metamethods */
status = luaD_closeprotected(L, 1, status);
if (status != LUA_OK) /* errors? */
luaD_seterrorobj(L, status, L->stack + 1);
else
L->top = L->stack + 1;
ci->top = L->top + LUA_MINSTACK;
- L->status = cast_byte(status);
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
return status;
}
@@ -372,7 +373,7 @@
g->ud_warn = NULL;
g->mainthread = 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.hash = NULL;
setnilvalue(&g->l_registry);
src/lstate.h
@@ -165,7 +165,7 @@
** - field 'nyield' is used only while a function is "doing" an
** yield (from the yield until the next resume);
** - 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,
** before the function starts or after it ends.
*/
@@ -209,7 +209,7 @@
#define CIST_YPCALL (1<<4) /* doing a yieldable protected call */
#define CIST_TAIL (1<<5) /* call was tail called */
#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_CLSRET (1<<9) /* function is closing tbc variables */
/* Bits 10-12 are used for CIST_RECST (see below) */
@@ -263,7 +263,7 @@
lu_byte gcstopem; /* stops emergency collections */
lu_byte genminormul; /* control for minor 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 gcpause; /* size of pause between successive GCs */
lu_byte gcstepmul; /* GC "speed" */
src/lstrlib.c
@@ -1090,13 +1090,31 @@
/* valid flags in a format specification */
-#if !defined(L_FMTFLAGS)
-#define L_FMTFLAGS "-+ #0"
+#if !defined(L_FMTFLAGSF)
+
+/* valid flags for a, A, e, E, f, F, g, and G conversions */
+#define L_FMTFLAGSF "-+#0 "
+
+/* valid flags for o, x, and X conversions */
+#define L_FMTFLAGSX "-#0"
+
+/* valid flags for d and i conversions */
+#define L_FMTFLAGSI "-+0 "
+
+/* valid flags for u conversions */
+#define L_FMTFLAGSU "-0"
+
+/* valid flags for c, p, and s conversions */
+#define L_FMTFLAGSC "-"
+
#endif
/*
-** 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
@@ -1189,25 +1207,53 @@
}
-static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
- const char *p = strfrmt;
- while (*p != '\0' && strchr(L_FMTFLAGS, *p) != NULL) p++; /* skip flags */
- if ((size_t)(p - strfrmt) >= sizeof(L_FMTFLAGS)/sizeof(char))
- luaL_error(L, "invalid format (repeated flags)");
- if (isdigit(uchar(*p))) p++; /* skip width */
- if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
- if (*p == '.') {
- p++;
- if (isdigit(uchar(*p))) p++; /* skip precision */
- if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
+static const char *get2digits (const char *s) {
+ if (isdigit(uchar(*s))) {
+ s++;
+ if (isdigit(uchar(*s))) s++; /* (2 digits at most) */
}
- if (isdigit(uchar(*p)))
- luaL_error(L, "invalid format (width or precision too long)");
+ return s;
+}
+
+
+/*
+** Check whether a conversion specification is valid. When called,
+** first character in 'form' must be '%' and last character must
+** be a valid conversion specifier. 'flags' are the accepted flags;
+** 'precision' signals whether to accept a precision.
+*/
+static void checkformat (lua_State *L, const char *form, const char *flags,
+ int precision) {
+ const char *spec = form + 1; /* skip '%' */
+ spec += strspn(spec, flags); /* skip flags */
+ if (*spec != '0') { /* a width cannot start with '0' */
+ spec = get2digits(spec); /* skip width */
+ if (*spec == '.' && precision) {
+ spec++;
+ spec = get2digits(spec); /* skip precision */
+ }
+ }
+ if (!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++) = '%';
- memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));
- form += (p - strfrmt) + 1;
- *form = '\0';
- return p;
+ memcpy(form, strfrmt, len * sizeof(char));
+ *(form + len) = '\0';
+ return strfrmt + len - 1;
}
@@ -1230,6 +1276,7 @@
size_t sfl;
const char *strfrmt = luaL_checklstring(L, arg, &sfl);
const char *strfrmt_end = strfrmt+sfl;
+ const char *flags;
luaL_Buffer b;
luaL_buffinit(L, &b);
while (strfrmt < strfrmt_end) {
@@ -1239,25 +1286,35 @@
luaL_addchar(&b, *strfrmt++); /* %% */
else { /* format item */
char form[MAX_FORMAT]; /* to store the format ('%...') */
- int maxitem = MAX_ITEM;
- char *buff = luaL_prepbuffsize(&b, maxitem); /* to put formatted item */
- int nb = 0; /* number of bytes in added item */
+ int maxitem = MAX_ITEM; /* maximum length for the result */
+ char *buff = luaL_prepbuffsize(&b, maxitem); /* to put result */
+ int nb = 0; /* number of bytes in result */
if (++arg > top)
return luaL_argerror(L, arg, "no value");
- strfrmt = scanformat(L, strfrmt, form);
+ strfrmt = getformat(L, strfrmt, form);
switch (*strfrmt++) {
case 'c': {
+ checkformat(L, form, L_FMTFLAGSC, 0);
nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg));
break;
}
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);
+ checkformat(L, form, flags, 1);
addlenmod(form, LUA_INTEGER_FRMLEN);
nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n);
break;
}
case 'a': case 'A':
+ checkformat(L, form, L_FMTFLAGSF, 1);
addlenmod(form, LUA_NUMBER_FRMLEN);
nb = lua_number2strx(L, buff, maxitem, form,
luaL_checknumber(L, arg));
@@ -1268,12 +1325,14 @@
/* FALLTHROUGH */
case 'e': case 'E': case 'g': case 'G': {
lua_Number n = luaL_checknumber(L, arg);
+ checkformat(L, form, L_FMTFLAGSF, 1);
addlenmod(form, LUA_NUMBER_FRMLEN);
nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n);
break;
}
case 'p': {
const void *p = lua_topointer(L, arg);
+ checkformat(L, form, L_FMTFLAGSC, 0);
if (p == NULL) { /* avoid calling 'printf' with argument NULL */
p = "(null)"; /* result */
form[strlen(form) - 1] = 's'; /* format it as a string */
@@ -1294,7 +1353,8 @@
luaL_addvalue(&b); /* keep entire string */
else {
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 */
luaL_addvalue(&b); /* keep entire string */
}
@@ -1352,15 +1412,6 @@
} 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
*/
@@ -1435,6 +1486,8 @@
** Read and classify next option. 'size' is filled with option's 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)++);
*size = 0; /* default */
switch (opt) {
@@ -1465,7 +1518,11 @@
case '<': h->islittle = 1; break;
case '>': h->islittle = 0; 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);
}
return Knop;
src/ltable.c
@@ -84,8 +84,6 @@
#define hashstr(t,str) hashpow2(t, (str)->hash)
#define hashboolean(t,p) hashpow2(t, p)
-#define hashint(t,i) hashpow2(t, i)
-
#define hashpointer(t,p) hashmod(t, point2uint(p))
@@ -101,6 +99,20 @@
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.
@@ -134,26 +146,24 @@
/*
** returns the 'main' position of an element in a table (that is,
-** the index of its hash value). The key comes broken (tag in 'ktt'
-** and value in 'vkl') so that we can call it on keys inserted into
-** nodes.
+** the index of its hash value).
*/
-static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
- switch (withvariant(ktt)) {
+static Node *mainpositionTV (const Table *t, const TValue *key) {
+ switch (ttypetag(key)) {
case LUA_VNUMINT: {
- lua_Integer key = ivalueraw(*kvl);
- return hashint(t, key);
+ lua_Integer i = ivalue(key);
+ return hashint(t, i);
}
case LUA_VNUMFLT: {
- lua_Number n = fltvalueraw(*kvl);
+ lua_Number n = fltvalue(key);
return hashmod(t, l_hashfloat(n));
}
case LUA_VSHRSTR: {
- TString *ts = tsvalueraw(*kvl);
+ TString *ts = tsvalue(key);
return hashstr(t, ts);
}
case LUA_VLNGSTR: {
- TString *ts = tsvalueraw(*kvl);
+ TString *ts = tsvalue(key);
return hashpow2(t, luaS_hashlongstr(ts));
}
case LUA_VFALSE:
@@ -161,26 +171,25 @@
case LUA_VTRUE:
return hashboolean(t, 1);
case LUA_VLIGHTUSERDATA: {
- void *p = pvalueraw(*kvl);
+ void *p = pvalue(key);
return hashpointer(t, p);
}
case LUA_VLCF: {
- lua_CFunction f = fvalueraw(*kvl);
+ lua_CFunction f = fvalue(key);
return hashpointer(t, f);
}
default: {
- GCObject *o = gcvalueraw(*kvl);
+ GCObject *o = gcvalue(key);
return hashpointer(t, o);
}
}
}
-/*
-** Returns the main position of an element given as a 'TValue'
-*/
-static Node *mainpositionTV (const Table *t, const TValue *key) {
- return mainposition(t, rawtt(key), valraw(key));
+l_sinline Node *mainpositionfromnode (const Table *t, Node *nd) {
+ TValue key;
+ getnodekey(cast(lua_State *, NULL), &key, nd);
+ return mainpositionTV(t, &key);
}
@@ -679,7 +688,7 @@
return;
}
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? */
/* yes; move colliding node into free position */
while (othern + gnext(othern) != mp) /* find previous */
src/ltablib.c
@@ -59,8 +59,9 @@
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 e = aux_getn(L, 1, TAB_RW);
+ e = luaL_intop(+, e, 1); /* first empty element */
switch (lua_gettop(L)) {
case 2: { /* called with only 2 arguments */
pos = e; /* insert new element at the end */
@@ -147,7 +148,7 @@
lua_geti(L, 1, i);
if (l_unlikely(!lua_isstring(L, -1)))
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);
}
src/lua.c
@@ -89,14 +89,15 @@
lua_writestringerror(
"usage: %s [options] [script [args]]\n"
"Available options are:\n"
- " -e stat execute string 'stat'\n"
- " -i enter interactive mode after executing 'script'\n"
- " -l name require library 'name' into global 'name'\n"
- " -v show version information\n"
- " -E ignore environment variables\n"
- " -W turn warnings on\n"
- " -- stop handling options\n"
- " - stop handling options and execute stdin\n"
+ " -e stat execute string 'stat'\n"
+ " -i enter interactive mode after executing 'script'\n"
+ " -l mod require library 'mod' into global 'mod'\n"
+ " -l g=mod require library 'mod' into global 'g'\n"
+ " -v show version information\n"
+ " -E ignore environment variables\n"
+ " -W turn warnings on\n"
+ " -- stop handling options\n"
+ " - stop handling options and execute stdin\n"
,
progname);
}
@@ -207,16 +208,22 @@
/*
-** Calls 'require(name)' and stores the result in a global variable
-** with the given name.
+** Receives 'globname[=modname]' and runs 'globname = require(modname)'.
*/
-static int dolibrary (lua_State *L, const char *name) {
+static int dolibrary (lua_State *L, char *globname) {
int status;
+ 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_pushstring(L, name);
- status = docall(L, 1, 1); /* call 'require(name)' */
+ lua_pushstring(L, modname);
+ status = docall(L, 1, 1); /* call 'require(modname)' */
if (status == LUA_OK)
- lua_setglobal(L, name); /* global[name] = require return */
+ lua_setglobal(L, globname); /* globname = require(modname) */
return report(L, status);
}
@@ -327,7 +334,7 @@
switch (option) {
case 'e': case 'l': {
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];
lua_assert(extra != NULL);
status = (option == 'e')
src/lua.h
@@ -18,14 +18,14 @@
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "4"
-#define LUA_VERSION_RELEASE "3"
+#define LUA_VERSION_RELEASE "4"
#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_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"
@@ -492,7 +492,7 @@
/******************************************************************************
-* 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
* a copy of this software and associated documentation files (the
src/luac.c
@@ -155,6 +155,7 @@
f->p[i]=toproto(L,i-n-1);
if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
}
+ luaM_freearray(L,f->lineinfo,f->sizelineinfo);
f->sizelineinfo=0;
return f;
}
@@ -600,11 +601,11 @@
if (c==0) printf("all out"); else printf("%d out",c-1);
break;
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);
break;
case OP_RETURN:
- printf("%d %d %d",a,b,c);
+ printf("%d %d %d%s",a,b,c,ISK);
printf(COMMENT);
if (b==0) printf("all out"); else printf("%d out",b-1);
break;
@@ -619,7 +620,7 @@
break;
case OP_FORPREP:
printf("%d %d",a,bx);
- printf(COMMENT "to %d",pc+bx+2);
+ printf(COMMENT "exit to %d",pc+bx+3);
break;
case OP_TFORPREP:
printf("%d %d",a,bx);
src/luaconf.h
@@ -485,7 +485,6 @@
@@ LUA_MAXINTEGER is the maximum 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_UNSIGNEDBITS is the number of bits in a LUA_UNSIGNED.
@@ lua_integer2str converts an integer to a string.
*/
@@ -506,9 +505,6 @@
#define LUA_UNSIGNED unsigned LUAI_UACINT
-#define LUA_UNSIGNEDBITS (sizeof(LUA_UNSIGNED) * CHAR_BIT)
-
-
/* now the variable definitions */
#if LUA_INT_TYPE == LUA_INT_INT /* { int */
src/lutf8lib.c
@@ -224,14 +224,11 @@
static int iter_aux (lua_State *L, int strict) {
size_t len;
const char *s = luaL_checklstring(L, 1, &len);
- lua_Integer n = lua_tointeger(L, 2) - 1;
- if (n < 0) /* first iteration? */
- n = 0; /* start from here */
- else if (n < (lua_Integer)len) {
- n++; /* skip current byte */
- while (iscont(s + n)) n++; /* and its continuations */
+ lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
+ if (n < len) {
+ while (iscont(s + n)) n++; /* skip continuation bytes */
}
- if (n >= (lua_Integer)len)
+ if (n >= len) /* (also handles original 'n' being negative) */
return 0; /* no more codepoints */
else {
utfint code;
src/lvm.c
@@ -406,7 +406,7 @@
** from float to int.)
** 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))
return luai_numlt(cast_num(i), f); /* compare them as floats */
else { /* i < f <=> i < ceil(f) */
@@ -423,7 +423,7 @@
** Check whether integer 'i' is less than or equal to float 'f'.
** 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))
return luai_numle(cast_num(i), f); /* compare them as floats */
else { /* i <= f <=> i <= floor(f) */
@@ -440,7 +440,7 @@
** Check whether float 'f' is less than integer 'i'.
** 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))
return luai_numlt(f, cast_num(i)); /* compare them as floats */
else { /* f < i <=> floor(f) < i */
@@ -457,7 +457,7 @@
** Check whether float 'f' is less than or equal to integer 'i'.
** 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))
return luai_numle(f, cast_num(i)); /* compare them as floats */
else { /* f <= i <=> ceil(f) <= i */
@@ -473,7 +473,7 @@
/*
** 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));
if (ttisinteger(l)) {
lua_Integer li = ivalue(l);
@@ -495,7 +495,7 @@
/*
** 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));
if (ttisinteger(l)) {
lua_Integer li = ivalue(l);
@@ -766,7 +766,8 @@
/*
** 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) {
if (y < 0) { /* shift right? */
@@ -847,10 +848,19 @@
luaV_concat(L, total); /* concat them (may yield again) */
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. */
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: {
/* only these other opcodes can yield */
lua_assert(op == OP_TFORCALL || op == OP_CALL ||
@@ -1099,7 +1109,7 @@
#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.)
*/
#define halfProtect(exp) (savestate(L,ci), (exp))
@@ -1156,8 +1166,10 @@
Instruction i; /* instruction being executed */
StkId ra; /* instruction's A register */
vmfetch();
-// low-level line tracing for debugging Lua
-// printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
+ #if 0
+ /* low-level line tracing for debugging Lua */
+ printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
+ #endif
lua_assert(base == ci->func + 1);
lua_assert(base <= L->top && L->top < L->stack_last);
/* invalidate top for instructions not expecting it */
@@ -1625,13 +1637,13 @@
updatetrap(ci); /* C call; nothing else to be done */
else { /* Lua call: run function in this same C frame */
ci = newci;
- ci->callstatus = 0; /* call re-uses 'luaV_execute' */
goto startfunc;
}
vmbreak;
}
vmcase(OP_TAILCALL) {
int b = GETARG_B(i); /* number of arguments + 1 (function) */
+ int n; /* number of results when calling a C function */
int nparams1 = GETARG_C(i);
/* delta is virtual 'func' - real 'func' (vararg functions) */
int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
@@ -1645,23 +1657,14 @@
lua_assert(L->tbclist < base); /* no pending tbc variables */
lua_assert(base == ci->func + 1);
}
- while (!ttisfunction(s2v(ra))) { /* not a function? */
- luaD_tryfuncTM(L, ra); /* try '__call' metamethod */
- b++; /* there is now one extra argument */
- 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 */
+ if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */
+ goto startfunc; /* execute the callee */
+ else { /* C function? */
ci->func -= delta; /* restore 'func' (if vararg) */
- 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 */
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) {
int n = GETARG_B(i) - 1; /* number of results */
@@ -1670,6 +1673,7 @@
n = cast_int(L->top - ra); /* get what is available */
savepc(ci);
if (TESTARG_k(i)) { /* may there be open upvalues? */
+ ci->u2.nres = n; /* save number of returns */
if (L->top < ci->top)
L->top = ci->top;
luaF_close(L, base, CLOSEKTOP, 1);