mirror of
https://github.com/etlegacy/etlegacy-libs.git
synced 2025-02-23 20:01:06 +00:00
libs: updated to Lua 5.4.3
This commit is contained in:
parent
94e77a2195
commit
0547e3d49d
53 changed files with 2153 additions and 1530 deletions
|
@ -46,7 +46,7 @@ TO_MAN= lua.1 luac.1
|
|||
|
||||
# Lua version and release.
|
||||
V= 5.4
|
||||
R= $V.0
|
||||
R= $V.3
|
||||
|
||||
# Targets start here.
|
||||
all: $(PLAT)
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
|
||||
This is Lua 5.4.0, released on 18 Jun 2020.
|
||||
This is Lua 5.4.3, released on 15 Mar 2021.
|
||||
|
||||
For installation instructions, license details, and
|
||||
further information about Lua, see doc/readme.html.
|
||||
|
||||
This is a slightly modified version for ET: Legacy.
|
||||
The src/Makefile file has been adjusted to fit our
|
||||
posix and posix32bit requirements.
|
||||
|
|
|
@ -32,7 +32,7 @@ For a complete introduction to Lua programming, see the book
|
|||
|
||||
<P>
|
||||
<SMALL>
|
||||
Copyright © 2020 Lua.org, PUC-Rio.
|
||||
Copyright © 2020–2021 Lua.org, PUC-Rio.
|
||||
Freely available under the terms of the
|
||||
<A HREF="http://www.lua.org/license.html">Lua license</A>.
|
||||
</SMALL>
|
||||
|
@ -95,6 +95,7 @@ Freely available under the terms of the
|
|||
<UL>
|
||||
<LI><A HREF="manual.html#4.1.1">4.1.1 – Stack Size</A>
|
||||
<LI><A HREF="manual.html#4.1.2">4.1.2 – Valid and Acceptable Indices</A>
|
||||
<LI><A HREF="manual.html#4.1.3">4.1.3 – Pointers to strings</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#4.2">4.2 – C Closures</A>
|
||||
<LI><A HREF="manual.html#4.3">4.3 – Registry</A>
|
||||
|
@ -197,7 +198,6 @@ Freely available under the terms of the
|
|||
<A HREF="manual.html#pdf-debug.getregistry">debug.getregistry</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getupvalue">debug.getupvalue</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getuservalue">debug.getuservalue</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.setcstacklimit">debug.setcstacklimit</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.sethook">debug.sethook</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.setlocal">debug.setlocal</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.setmetatable">debug.setmetatable</A><BR>
|
||||
|
@ -396,6 +396,7 @@ Freely available under the terms of the
|
|||
<A HREF="manual.html#lua_callk">lua_callk</A><BR>
|
||||
<A HREF="manual.html#lua_checkstack">lua_checkstack</A><BR>
|
||||
<A HREF="manual.html#lua_close">lua_close</A><BR>
|
||||
<A HREF="manual.html#lua_closeslot">lua_closeslot</A><BR>
|
||||
<A HREF="manual.html#lua_compare">lua_compare</A><BR>
|
||||
<A HREF="manual.html#lua_concat">lua_concat</A><BR>
|
||||
<A HREF="manual.html#lua_copy">lua_copy</A><BR>
|
||||
|
@ -475,7 +476,6 @@ Freely available under the terms of the
|
|||
<A HREF="manual.html#lua_resume">lua_resume</A><BR>
|
||||
<A HREF="manual.html#lua_rotate">lua_rotate</A><BR>
|
||||
<A HREF="manual.html#lua_setallocf">lua_setallocf</A><BR>
|
||||
<A HREF="manual.html#lua_setcstacklimit">lua_setcstacklimit</A><BR>
|
||||
<A HREF="manual.html#lua_setfield">lua_setfield</A><BR>
|
||||
<A HREF="manual.html#lua_setglobal">lua_setglobal</A><BR>
|
||||
<A HREF="manual.html#lua_sethook">lua_sethook</A><BR>
|
||||
|
@ -664,10 +664,10 @@ Freely available under the terms of the
|
|||
|
||||
<P CLASS="footer">
|
||||
Last update:
|
||||
Sat May 30 08:22:18 -03 2020
|
||||
Wed Mar 3 13:04:44 UTC 2021
|
||||
</P>
|
||||
<!--
|
||||
Last change: revised for Lua 5.4.0 (final)
|
||||
Last change: revised for Lua 5.4.3
|
||||
-->
|
||||
|
||||
</BODY>
|
||||
|
|
|
@ -19,7 +19,7 @@ by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
|
|||
|
||||
<P>
|
||||
<SMALL>
|
||||
Copyright © 2020 Lua.org, PUC-Rio.
|
||||
Copyright © 2020–2021 Lua.org, PUC-Rio.
|
||||
Freely available under the terms of the
|
||||
<a href="http://www.lua.org/license.html">Lua license</a>.
|
||||
</SMALL>
|
||||
|
@ -143,6 +143,11 @@ The type <em>boolean</em> has two values, <b>false</b> and <b>true</b>.
|
|||
Both <b>nil</b> and <b>false</b> make a condition false;
|
||||
they are collectively called <em>false values</em>.
|
||||
Any other value makes a condition true.
|
||||
Despite its name,
|
||||
<b>false</b> is frequently used as an alternative to <b>nil</b>,
|
||||
with the key difference that <b>false</b> behaves
|
||||
like a regular value in a table,
|
||||
while a <b>nil</b> in a table represents an absent key.
|
||||
|
||||
|
||||
<p>
|
||||
|
@ -434,7 +439,7 @@ under certain events.
|
|||
You can change several aspects of the behavior
|
||||
of a value by setting specific fields in its metatable.
|
||||
For instance, when a non-numeric value is the operand of an addition,
|
||||
Lua checks for a function in the field "<code>__add</code>" of the value's metatable.
|
||||
Lua checks for a function in the field <code>__add</code> of the value's metatable.
|
||||
If it finds one,
|
||||
Lua calls this function to perform the addition.
|
||||
|
||||
|
@ -901,7 +906,7 @@ For an object (table or userdata) to be finalized when collected,
|
|||
you must <em>mark</em> it for finalization.
|
||||
|
||||
You mark an object for finalization when you set its metatable
|
||||
and the metatable has a field indexed by the string "<code>__gc</code>".
|
||||
and the metatable has a <code>__gc</code> metamethod.
|
||||
Note that if you set a metatable without a <code>__gc</code> field
|
||||
and later create that field in the metatable,
|
||||
the object will not be marked for finalization.
|
||||
|
@ -1992,16 +1997,8 @@ they are closed in the reverse order that they were declared.
|
|||
If there is any error while running a closing method,
|
||||
that error is handled like an error in the regular code
|
||||
where the variable was defined.
|
||||
However, Lua may call the method one more time.
|
||||
|
||||
|
||||
<p>
|
||||
After an error,
|
||||
the other pending closing methods will still be called.
|
||||
Errors in these methods
|
||||
interrupt the respective method and generate a warning,
|
||||
but are otherwise ignored;
|
||||
the error reported is only the original one.
|
||||
|
||||
|
||||
<p>
|
||||
|
@ -2966,26 +2963,31 @@ When you interact with the Lua API,
|
|||
you are responsible for ensuring consistency.
|
||||
In particular,
|
||||
<em>you are responsible for controlling stack overflow</em>.
|
||||
You can use the function <a href="#lua_checkstack"><code>lua_checkstack</code></a>
|
||||
to ensure that the stack has enough space for pushing new elements.
|
||||
When you call any API function,
|
||||
you must ensure the stack has enough room to accommodate the results.
|
||||
|
||||
|
||||
<p>
|
||||
There is one exception to the above rule:
|
||||
When you call a Lua function
|
||||
without a fixed number of results (see <a href="#lua_call"><code>lua_call</code></a>),
|
||||
Lua ensures that the stack has enough space for all results.
|
||||
However, it does not ensure any extra space.
|
||||
So, before pushing anything on the stack after such a call
|
||||
you should use <a href="#lua_checkstack"><code>lua_checkstack</code></a>.
|
||||
|
||||
|
||||
<p>
|
||||
Whenever Lua calls C,
|
||||
it ensures that the stack has space for
|
||||
at least <a name="pdf-LUA_MINSTACK"><code>LUA_MINSTACK</code></a> extra slots.
|
||||
at least <a name="pdf-LUA_MINSTACK"><code>LUA_MINSTACK</code></a> extra elements;
|
||||
that is, you can safely push up to <code>LUA_MINSTACK</code> values into it.
|
||||
<code>LUA_MINSTACK</code> is defined as 20,
|
||||
so that usually you do not have to worry about stack space
|
||||
unless your code has loops pushing elements onto the stack.
|
||||
|
||||
|
||||
<p>
|
||||
When you call a Lua function
|
||||
without a fixed number of results (see <a href="#lua_call"><code>lua_call</code></a>),
|
||||
Lua ensures that the stack has enough space for all results,
|
||||
but it does not ensure any extra space.
|
||||
So, before pushing anything in the stack after such a call
|
||||
you should use <a href="#lua_checkstack"><code>lua_checkstack</code></a>.
|
||||
Whenever necessary,
|
||||
you can use the function <a href="#lua_checkstack"><code>lua_checkstack</code></a>
|
||||
to ensure that the stack has enough space for pushing new elements.
|
||||
|
||||
|
||||
|
||||
|
@ -3044,6 +3046,49 @@ which behaves like a nil value.
|
|||
|
||||
|
||||
|
||||
<h3>4.1.3 – <a name="4.1.3">Pointers to strings</a></h3>
|
||||
|
||||
<p>
|
||||
Several functions in the API return pointers (<code>const char*</code>)
|
||||
to Lua strings in the stack.
|
||||
(See <a href="#lua_pushfstring"><code>lua_pushfstring</code></a>, <a href="#lua_pushlstring"><code>lua_pushlstring</code></a>,
|
||||
<a href="#lua_pushstring"><code>lua_pushstring</code></a>, and <a href="#lua_tolstring"><code>lua_tolstring</code></a>.
|
||||
See also <a href="#luaL_checklstring"><code>luaL_checklstring</code></a>, <a href="#luaL_checkstring"><code>luaL_checkstring</code></a>,
|
||||
and <a href="#luaL_tolstring"><code>luaL_tolstring</code></a> in the auxiliary library.)
|
||||
|
||||
|
||||
<p>
|
||||
In general,
|
||||
Lua's garbage collection can free or move internal memory
|
||||
and then invalidate pointers to internal strings.
|
||||
To allow a safe use of these pointers,
|
||||
The API guarantees that any pointer to a string in a stack index
|
||||
is valid while the string value at that index is not removed from the stack.
|
||||
(It can be moved to another index, though.)
|
||||
When the index is a pseudo-index (referring to an upvalue),
|
||||
the pointer is valid while the corresponding call is active and
|
||||
the corresponding upvalue is not modified.
|
||||
|
||||
|
||||
<p>
|
||||
Some functions in the debug interface
|
||||
also return pointers to strings,
|
||||
namely <a href="#lua_getlocal"><code>lua_getlocal</code></a>, <a href="#lua_getupvalue"><code>lua_getupvalue</code></a>,
|
||||
<a href="#lua_setlocal"><code>lua_setlocal</code></a>, and <a href="#lua_setupvalue"><code>lua_setupvalue</code></a>.
|
||||
For these functions, the pointer is guaranteed to
|
||||
be valid while the caller function is active and
|
||||
the given closure (if one was given) is in the stack.
|
||||
|
||||
|
||||
<p>
|
||||
Except for these guarantees,
|
||||
the garbage collector is free to invalidate
|
||||
any pointer to internal strings.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>4.2 – <a name="4.2">C Closures</a></h2>
|
||||
|
@ -3239,7 +3284,7 @@ Therefore, if a C function <code>foo</code> calls an API function
|
|||
and this API function yields
|
||||
(directly or indirectly by calling another function that yields),
|
||||
Lua cannot return to <code>foo</code> any more,
|
||||
because the <code>longjmp</code> removes its frame from the C stack.
|
||||
because the <code>longjmp</code> removes its frame from the C stack.
|
||||
|
||||
|
||||
<p>
|
||||
|
@ -3269,7 +3314,7 @@ After the thread resumes,
|
|||
it eventually will finish running the callee function.
|
||||
However,
|
||||
the callee function cannot return to the original function,
|
||||
because its frame in the C stack was destroyed by the yield.
|
||||
because its frame in the C stack was destroyed by the yield.
|
||||
Instead, Lua calls a <em>continuation function</em>,
|
||||
which was given as an argument to the callee function.
|
||||
As the name implies,
|
||||
|
@ -3389,7 +3434,7 @@ depending on the situation;
|
|||
an interrogation mark '<code>?</code>' means that
|
||||
we cannot know how many elements the function pops/pushes
|
||||
by looking only at its arguments.
|
||||
(For instance, they may depend on what is on the stack.)
|
||||
(For instance, they may depend on what is in the stack.)
|
||||
The third field, <code>x</code>,
|
||||
tells whether the function may raise errors:
|
||||
'<code>-</code>' means the function never raises any error;
|
||||
|
@ -3408,7 +3453,7 @@ and therefore may raise any errors.
|
|||
<p>
|
||||
Converts the acceptable index <code>idx</code>
|
||||
into an equivalent absolute index
|
||||
(that is, one that does not depend on the stack top).
|
||||
(that is, one that does not depend on the stack size).
|
||||
|
||||
|
||||
|
||||
|
@ -3678,7 +3723,7 @@ of numeric arguments and returns their average and their sum:
|
|||
<pre>int lua_checkstack (lua_State *L, int n);</pre>
|
||||
|
||||
<p>
|
||||
Ensures that the stack has space for at least <code>n</code> extra slots,
|
||||
Ensures that the stack has space for at least <code>n</code> extra elements,
|
||||
that is, that you can safely push up to <code>n</code> values into it.
|
||||
It returns false if it cannot fulfill the request,
|
||||
either because it would cause the stack
|
||||
|
@ -3686,7 +3731,7 @@ to be greater than a fixed maximum size
|
|||
(typically at least several thousand elements) or
|
||||
because it cannot allocate memory for the extra space.
|
||||
This function never shrinks the stack;
|
||||
if the stack already has space for the extra slots,
|
||||
if the stack already has space for the extra elements,
|
||||
it is left unchanged.
|
||||
|
||||
|
||||
|
@ -3715,6 +3760,29 @@ will probably need to close states as soon as they are not needed.
|
|||
|
||||
|
||||
|
||||
<hr><h3><a name="lua_closeslot"><code>lua_closeslot</code></a></h3><p>
|
||||
<span class="apii">[-0, +0, <em>e</em>]</span>
|
||||
<pre>void lua_closeslot (lua_State *L, int index);</pre>
|
||||
|
||||
<p>
|
||||
Close the to-be-closed slot at the given index and set its value to <b>nil</b>.
|
||||
The index must be the last index previously marked to be closed
|
||||
(see <a href="#lua_toclose"><code>lua_toclose</code></a>) that is still active (that is, not closed yet).
|
||||
|
||||
|
||||
<p>
|
||||
A <code>__close</code> metamethod cannot yield
|
||||
when called through this function.
|
||||
|
||||
|
||||
<p>
|
||||
(Exceptionally, this function was introduced in release 5.4.3.
|
||||
It is not present in previous 5.4 releases.)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<hr><h3><a name="lua_compare"><code>lua_compare</code></a></h3><p>
|
||||
<span class="apii">[-0, +0, <em>e</em>]</span>
|
||||
<pre>int lua_compare (lua_State *L, int index1, int index2, int op);</pre>
|
||||
|
@ -4443,6 +4511,10 @@ plus an associated block of raw memory with <code>size</code> bytes.
|
|||
|
||||
<p>
|
||||
The function returns the address of the block of memory.
|
||||
Lua ensures that this address is valid as long as
|
||||
the corresponding userdata is alive (see <a href="#2.5">§2.5</a>).
|
||||
Moreover, if the userdata is marked for finalization (see <a href="#2.5.3">§2.5.3</a>),
|
||||
its address is valid at least until the call to its finalizer.
|
||||
|
||||
|
||||
|
||||
|
@ -4600,11 +4672,12 @@ except that it allows the called function to yield (see <a href="#4.5">§4.5
|
|||
|
||||
|
||||
<hr><h3><a name="lua_pop"><code>lua_pop</code></a></h3><p>
|
||||
<span class="apii">[-n, +0, –]</span>
|
||||
<span class="apii">[-n, +0, <em>e</em>]</span>
|
||||
<pre>void lua_pop (lua_State *L, int n);</pre>
|
||||
|
||||
<p>
|
||||
Pops <code>n</code> elements from the stack.
|
||||
It is implemented as a macro over <a href="#lua_settop"><code>lua_settop</code></a>.
|
||||
|
||||
|
||||
|
||||
|
@ -4688,7 +4761,7 @@ This function is equivalent to <a href="#lua_pushcclosure"><code>lua_pushcclosur
|
|||
|
||||
<p>
|
||||
Pushes onto the stack a formatted string
|
||||
and returns a pointer to this string.
|
||||
and returns a pointer to this string (see <a href="#4.1.3">§4.1.3</a>).
|
||||
It is similar to the ISO C function <code>sprintf</code>,
|
||||
but has two important differences.
|
||||
First,
|
||||
|
@ -4788,7 +4861,7 @@ including embedded zeros.
|
|||
|
||||
|
||||
<p>
|
||||
Returns a pointer to the internal copy of the string.
|
||||
Returns a pointer to the internal copy of the string (see <a href="#4.1.3">§4.1.3</a>).
|
||||
|
||||
|
||||
|
||||
|
@ -4829,7 +4902,7 @@ the function returns.
|
|||
|
||||
|
||||
<p>
|
||||
Returns a pointer to the internal copy of the string.
|
||||
Returns a pointer to the internal copy of the string (see <a href="#4.1.3">§4.1.3</a>).
|
||||
|
||||
|
||||
<p>
|
||||
|
@ -5083,10 +5156,12 @@ and then pops the top element.
|
|||
Resets a thread, cleaning its call stack and closing all pending
|
||||
to-be-closed variables.
|
||||
Returns a status code:
|
||||
<a href="#pdf-LUA_OK"><code>LUA_OK</code></a> for no errors in closing methods,
|
||||
<a href="#pdf-LUA_OK"><code>LUA_OK</code></a> for no errors in the thread
|
||||
(either the original error that stopped the thread or
|
||||
errors in closing methods),
|
||||
or an error status otherwise.
|
||||
In case of error,
|
||||
leaves the error object on the top of the stack,
|
||||
leaves the error object on the top of the stack.
|
||||
|
||||
|
||||
|
||||
|
@ -5273,7 +5348,7 @@ for the "newindex" event (see <a href="#2.4">§2.4</a>).
|
|||
|
||||
|
||||
<hr><h3><a name="lua_settop"><code>lua_settop</code></a></h3><p>
|
||||
<span class="apii">[-?, +?, –]</span>
|
||||
<span class="apii">[-?, +?, <em>e</em>]</span>
|
||||
<pre>void lua_settop (lua_State *L, int index);</pre>
|
||||
|
||||
<p>
|
||||
|
@ -5284,6 +5359,11 @@ then the new elements are filled with <b>nil</b>.
|
|||
If <code>index</code> is 0, then all stack elements are removed.
|
||||
|
||||
|
||||
<p>
|
||||
This function can run arbitrary code when removing an index
|
||||
marked as to-be-closed from the stack.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -5399,33 +5479,37 @@ otherwise, returns <code>NULL</code>.
|
|||
|
||||
|
||||
<hr><h3><a name="lua_toclose"><code>lua_toclose</code></a></h3><p>
|
||||
<span class="apii">[-0, +0, <em>v</em>]</span>
|
||||
<span class="apii">[-0, +0, <em>m</em>]</span>
|
||||
<pre>void lua_toclose (lua_State *L, int index);</pre>
|
||||
|
||||
<p>
|
||||
Marks the given index in the stack as a
|
||||
to-be-closed "variable" (see <a href="#3.3.8">§3.3.8</a>).
|
||||
to-be-closed slot (see <a href="#3.3.8">§3.3.8</a>).
|
||||
Like a to-be-closed variable in Lua,
|
||||
the value at that index in the stack will be closed
|
||||
the value at that slot in the stack will be closed
|
||||
when it goes out of scope.
|
||||
Here, in the context of a C function,
|
||||
to go out of scope means that the running function returns to Lua,
|
||||
there is an error,
|
||||
or the index is removed from the stack through
|
||||
<a href="#lua_settop"><code>lua_settop</code></a> or <a href="#lua_pop"><code>lua_pop</code></a>.
|
||||
An index marked as to-be-closed should not be removed from the stack
|
||||
by any other function in the API except <a href="#lua_settop"><code>lua_settop</code></a> or <a href="#lua_pop"><code>lua_pop</code></a>.
|
||||
or there is an error,
|
||||
or the slot is removed from the stack through
|
||||
<a href="#lua_settop"><code>lua_settop</code></a> or <a href="#lua_pop"><code>lua_pop</code></a>,
|
||||
or there is a call to <a href="#lua_closeslot"><code>lua_closeslot</code></a>.
|
||||
A slot marked as to-be-closed should not be removed from the stack
|
||||
by any other function in the API except <a href="#lua_settop"><code>lua_settop</code></a> or <a href="#lua_pop"><code>lua_pop</code></a>,
|
||||
unless previously deactivated by <a href="#lua_closeslot"><code>lua_closeslot</code></a>.
|
||||
|
||||
|
||||
<p>
|
||||
This function should not be called for an index
|
||||
that is equal to or below an active to-be-closed index.
|
||||
that is equal to or below an active to-be-closed slot.
|
||||
|
||||
|
||||
<p>
|
||||
This function can raise an out-of-memory error.
|
||||
In that case, the value in the given index is immediately closed,
|
||||
as if it was already marked.
|
||||
Note that, both in case of errors and of a regular return,
|
||||
by the time the <code>__close</code> metamethod runs,
|
||||
the C stack was already unwound,
|
||||
so that any automatic C variable declared in the calling function
|
||||
(e.g., a buffer) will be out of scope.
|
||||
|
||||
|
||||
|
||||
|
@ -5482,18 +5566,12 @@ when <code>lua_tolstring</code> is applied to keys during a table traversal.)
|
|||
|
||||
<p>
|
||||
<code>lua_tolstring</code> returns a pointer
|
||||
to a string inside the Lua state.
|
||||
to a string inside the Lua state (see <a href="#4.1.3">§4.1.3</a>).
|
||||
This string always has a zero ('<code>\0</code>')
|
||||
after its last character (as in C),
|
||||
but can contain other zeros in its body.
|
||||
|
||||
|
||||
<p>
|
||||
Because Lua has garbage collection,
|
||||
there is no guarantee that the pointer returned by <code>lua_tolstring</code>
|
||||
will be valid after the corresponding Lua value is removed from the stack.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -5944,7 +6022,7 @@ true if the function is a vararg function
|
|||
</li>
|
||||
|
||||
<li><b><code>ftransfer</code>: </b>
|
||||
the index on the stack of the first value being "transferred",
|
||||
the index in the stack of the first value being "transferred",
|
||||
that is, parameters in a call or return values in a return.
|
||||
(The other values are in consecutive indices.)
|
||||
Using this index, you can access and modify these values
|
||||
|
@ -6141,7 +6219,7 @@ an identification of the <em>activation record</em>
|
|||
of the function executing at a given level.
|
||||
Level 0 is the current running function,
|
||||
whereas level <em>n+1</em> is the function that has called level <em>n</em>
|
||||
(except for tail calls, which do not count on the stack).
|
||||
(except for tail calls, which do not count in the stack).
|
||||
When called with a level greater than the stack depth,
|
||||
<a href="#lua_getstack"><code>lua_getstack</code></a> returns 0;
|
||||
otherwise it returns 1.
|
||||
|
@ -6218,24 +6296,6 @@ calling <a href="#lua_yield"><code>lua_yield</code></a> with <code>nresults</cod
|
|||
|
||||
|
||||
|
||||
<hr><h3><a name="lua_setcstacklimit"><code>lua_setcstacklimit</code></a></h3><p>
|
||||
<span class="apii">[-0, +0, –]</span>
|
||||
<pre>int (lua_setcstacklimit) (lua_State *L, unsigned int limit);</pre>
|
||||
|
||||
<p>
|
||||
Sets a new limit for the C stack.
|
||||
This limit controls how deeply nested calls can go in Lua,
|
||||
with the intent of avoiding a stack overflow.
|
||||
Returns the old limit in case of success,
|
||||
or zero in case of error.
|
||||
For more details about this function,
|
||||
see <a href="#pdf-debug.setcstacklimit"><code>debug.setcstacklimit</code></a>,
|
||||
its equivalent in the standard library.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<hr><h3><a name="lua_sethook"><code>lua_sethook</code></a></h3><p>
|
||||
<span class="apii">[-0, +0, –]</span>
|
||||
<pre>void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);</pre>
|
||||
|
@ -6259,8 +6319,7 @@ For each event, the hook is called as explained below:
|
|||
<ul>
|
||||
|
||||
<li><b>The call hook: </b> is called when the interpreter calls a function.
|
||||
The hook is called just after Lua enters the new function,
|
||||
before the function gets its arguments.
|
||||
The hook is called just after Lua enters the new function.
|
||||
</li>
|
||||
|
||||
<li><b>The return hook: </b> is called when the interpreter returns from a function.
|
||||
|
@ -7573,7 +7632,7 @@ it returns <code>NULL</code> instead of raising an error.
|
|||
Converts any Lua value at the given index to a C string
|
||||
in a reasonable format.
|
||||
The resulting string is pushed onto the stack and also
|
||||
returned by the function.
|
||||
returned by the function (see <a href="#4.1.3">§4.1.3</a>).
|
||||
If <code>len</code> is not <code>NULL</code>,
|
||||
the function also sets <code>*len</code> with the string length.
|
||||
|
||||
|
@ -8001,9 +8060,11 @@ The default is "<code>bt</code>".
|
|||
|
||||
|
||||
<p>
|
||||
Lua does not check the consistency of binary chunks.
|
||||
Maliciously crafted binary chunks can crash
|
||||
the interpreter.
|
||||
It is safe to load malformed binary chunks;
|
||||
<code>load</code> signals an appropriate error.
|
||||
However,
|
||||
Lua does not check the consistency of the code inside binary chunks;
|
||||
running maliciously crafted bytecode can crash the interpreter.
|
||||
|
||||
|
||||
|
||||
|
@ -8351,7 +8412,9 @@ that is,
|
|||
closes all its pending to-be-closed variables
|
||||
and puts the coroutine in a dead state.
|
||||
The given coroutine must be dead or suspended.
|
||||
In case of error closing some variable,
|
||||
In case of error
|
||||
(either the original error that stopped the coroutine or
|
||||
errors in closing methods),
|
||||
returns <b>false</b> plus the error object;
|
||||
otherwise returns <b>true</b>.
|
||||
|
||||
|
@ -8665,6 +8728,18 @@ As such, it is only available on some platforms
|
|||
plus other Unix systems that support the <code>dlfcn</code> standard).
|
||||
|
||||
|
||||
<p>
|
||||
This function is inherently insecure,
|
||||
as it allows Lua to call any function in any readable dynamic
|
||||
library in the system.
|
||||
(Lua calls any function assuming the function
|
||||
has a proper prototype and respects a proper protocol
|
||||
(see <a href="#lua_CFunction"><code>lua_CFunction</code></a>).
|
||||
Therefore,
|
||||
calling an arbitrary function in an arbitrary dynamic library
|
||||
more often than not results in an access violation.)
|
||||
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
|
@ -9901,23 +9976,23 @@ from <code>list[1]</code> to <code>list[#list]</code>.
|
|||
If <code>comp</code> is given,
|
||||
then it must be a function that receives two list elements
|
||||
and returns true when the first element must come
|
||||
before the second in the final order
|
||||
(so that, after the sort,
|
||||
<code>i < j</code> implies <code>not comp(list[j],list[i])</code>).
|
||||
before the second in the final order,
|
||||
so that, after the sort,
|
||||
<code>i <= j</code> implies <code>not comp(list[j],list[i])</code>.
|
||||
If <code>comp</code> is not given,
|
||||
then the standard Lua operator <code><</code> is used instead.
|
||||
|
||||
|
||||
<p>
|
||||
Note that the <code>comp</code> function must define
|
||||
a strict partial order over the elements in the list;
|
||||
that is, it must be asymmetric and transitive.
|
||||
Otherwise, no valid sort may be possible.
|
||||
The <code>comp</code> function must define a consistent order;
|
||||
more formally, the function must define a strict weak order.
|
||||
(A weak order is similar to a total order,
|
||||
but it can equate different elements for comparison purposes.)
|
||||
|
||||
|
||||
<p>
|
||||
The sort algorithm is not stable:
|
||||
elements considered equal by the given order
|
||||
Different elements considered equal by the given order
|
||||
may have their relative positions changed by the sort.
|
||||
|
||||
|
||||
|
@ -11084,7 +11159,7 @@ which means the function running at level <code>f</code> of the call stack
|
|||
of the given thread:
|
||||
level 0 is the current function (<code>getinfo</code> itself);
|
||||
level 1 is the function that called <code>getinfo</code>
|
||||
(except for tail calls, which do not count on the stack);
|
||||
(except for tail calls, which do not count in the stack);
|
||||
and so on.
|
||||
If <code>f</code> is a number greater than the number of active functions,
|
||||
then <code>getinfo</code> returns <b>fail</b>.
|
||||
|
@ -11218,43 +11293,6 @@ to the userdata <code>u</code> plus a boolean,
|
|||
|
||||
|
||||
|
||||
<p>
|
||||
<hr><h3><a name="pdf-debug.setcstacklimit"><code>debug.setcstacklimit (limit)</code></a></h3>
|
||||
|
||||
|
||||
<p>
|
||||
Sets a new limit for the C stack.
|
||||
This limit controls how deeply nested calls can go in Lua,
|
||||
with the intent of avoiding a stack overflow.
|
||||
A limit too small restricts recursive calls pointlessly;
|
||||
a limit too large exposes the interpreter to stack-overflow crashes.
|
||||
Unfortunately, there is no way to know a priori
|
||||
the maximum safe limit for a platform.
|
||||
|
||||
|
||||
<p>
|
||||
Each call made from Lua code counts one unit.
|
||||
Other operations (e.g., calls made from C to Lua or resuming a coroutine)
|
||||
may have a higher cost.
|
||||
|
||||
|
||||
<p>
|
||||
This function has the following restrictions:
|
||||
|
||||
<ul>
|
||||
<li>It can only be called from the main coroutine (thread);</li>
|
||||
<li>It cannot be called while handling a stack-overflow error;</li>
|
||||
<li><code>limit</code> must be less than 40000;</li>
|
||||
<li><code>limit</code> cannot be less than the amount of C stack in use.</li>
|
||||
</ul><p>
|
||||
If a call does not respect some restriction,
|
||||
it returns a false value.
|
||||
Otherwise,
|
||||
the call returns the old limit.
|
||||
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
<hr><h3><a name="pdf-debug.sethook"><code>debug.sethook ([thread,] hook, mask [, count])</code></a></h3>
|
||||
|
||||
|
@ -11886,10 +11924,10 @@ and LiteralString, see <a href="#3.1">§3.1</a>.)
|
|||
|
||||
<P CLASS="footer">
|
||||
Last update:
|
||||
Thu Jun 18 16:10:16 UTC 2020
|
||||
Mon Mar 15 13:39:42 UTC 2021
|
||||
</P>
|
||||
<!--
|
||||
Last change: revised for Lua 5.4.0 (final)
|
||||
Last change: revised for Lua 5.4.3
|
||||
-->
|
||||
|
||||
</body></html>
|
||||
|
|
|
@ -110,7 +110,7 @@ Here are the details.
|
|||
<OL>
|
||||
<LI>
|
||||
Open a terminal window and move to
|
||||
the top-level directory, which is named <TT>lua-5.4.0</TT>.
|
||||
the top-level directory, which is named <TT>lua-5.4.3</TT>.
|
||||
The <TT>Makefile</TT> there controls both the build process and the installation process.
|
||||
<P>
|
||||
<LI>
|
||||
|
@ -303,7 +303,7 @@ For details, see
|
|||
<A HREF="http://www.lua.org/license.html">this</A>.
|
||||
|
||||
<BLOCKQUOTE STYLE="padding-bottom: 0em">
|
||||
Copyright © 1994–2020 Lua.org, PUC-Rio.
|
||||
Copyright © 1994–2021 Lua.org, PUC-Rio.
|
||||
|
||||
<P>
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
@ -330,10 +330,10 @@ THE SOFTWARE.
|
|||
|
||||
<P CLASS="footer">
|
||||
Last update:
|
||||
Fri May 1 19:33:31 UTC 2020
|
||||
Wed Mar 3 10:16:26 UTC 2021
|
||||
</P>
|
||||
<!--
|
||||
Last change: revised for Lua 5.4.0 (final)
|
||||
Last change: revised for Lua 5.4.3
|
||||
-->
|
||||
|
||||
</BODY>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
PLAT= guess
|
||||
|
||||
CC= gcc -std=gnu99
|
||||
CFLAGS= -O2 -Wall -Wextra $(SYSCFLAGS) $(MYCFLAGS)
|
||||
CFLAGS= -O2 -Wall -Wextra -DLUA_COMPAT_5_3 $(SYSCFLAGS) $(MYCFLAGS)
|
||||
LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS)
|
||||
LIBS= -lm $(SYSLIBS) $(MYLIBS)
|
||||
|
||||
|
@ -26,11 +26,11 @@ MYLIBS=
|
|||
MYOBJS=
|
||||
|
||||
# Special flags for compiler modules; -Os reduces code size.
|
||||
CMCFLAGS= -Os
|
||||
CMCFLAGS=
|
||||
|
||||
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
|
||||
|
||||
PLATS= guess aix bsd c89 freebsd generic linux linux-readline macosx mingw posix posix32bit solaris
|
||||
PLATS= guess aix bsd c89 freebsd generic linux linux-readline macosx mingw posix solaris
|
||||
|
||||
LUA_A= liblua.a
|
||||
CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o
|
||||
|
@ -67,7 +67,7 @@ $(LUAC_T): $(LUAC_O) $(LUA_A)
|
|||
$(CC) -o $@ $(LDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS)
|
||||
|
||||
test:
|
||||
./lua -v
|
||||
./$(LUA_T) -v
|
||||
|
||||
clean:
|
||||
$(RM) $(ALL_T) $(ALL_O)
|
||||
|
@ -108,6 +108,8 @@ c89:
|
|||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_C89" CC="gcc -std=c89"
|
||||
@echo ''
|
||||
@echo '*** C89 does not guarantee 64-bit integers for Lua.'
|
||||
@echo '*** Make sure to compile all external Lua libraries'
|
||||
@echo '*** with LUA_USE_C89 to ensure consistency'
|
||||
@echo ''
|
||||
|
||||
FreeBSD NetBSD OpenBSD freebsd:
|
||||
|
@ -133,10 +135,7 @@ mingw:
|
|||
$(MAKE) "LUAC_T=luac.exe" luac.exe
|
||||
|
||||
posix:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -fPIC -DLUA_USE_DLOPEN" SYSLIBS="-ldl"
|
||||
|
||||
posix32bit:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-m32 -DLUA_USE_POSIX -fPIC -DLUA_USE_DLOPEN" SYSLDFLAGS="-m32" SYSLIBS="-ldl"
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX"
|
||||
|
||||
SunOS solaris:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN -D_REENTRANT" SYSLIBS="-ldl"
|
||||
|
|
110
lua/src/lapi.c
110
lua/src/lapi.c
|
@ -39,7 +39,7 @@ const char lua_ident[] =
|
|||
|
||||
|
||||
/*
|
||||
** Test for a valid index.
|
||||
** Test for a valid index (one that is not the 'nilvalue').
|
||||
** '!ttisnil(o)' implies 'o != &G(L)->nilvalue', so it is not needed.
|
||||
** However, it covers the most common cases in a faster way.
|
||||
*/
|
||||
|
@ -74,7 +74,8 @@ static TValue *index2value (lua_State *L, int idx) {
|
|||
return &G(L)->nilvalue; /* it has no upvalues */
|
||||
else {
|
||||
CClosure *func = clCvalue(s2v(ci->func));
|
||||
return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : &G(L)->nilvalue;
|
||||
return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
|
||||
: &G(L)->nilvalue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -97,8 +98,9 @@ static StkId index2stack (lua_State *L, int idx) {
|
|||
|
||||
LUA_API int lua_checkstack (lua_State *L, int n) {
|
||||
int res;
|
||||
CallInfo *ci = L->ci;
|
||||
CallInfo *ci;
|
||||
lua_lock(L);
|
||||
ci = L->ci;
|
||||
api_check(L, n >= 0, "negative 'n'");
|
||||
if (L->stack_last - L->top > n) /* stack large enough? */
|
||||
res = 1; /* yes; check is OK */
|
||||
|
@ -170,10 +172,12 @@ LUA_API int lua_gettop (lua_State *L) {
|
|||
|
||||
|
||||
LUA_API void lua_settop (lua_State *L, int idx) {
|
||||
CallInfo *ci = L->ci;
|
||||
StkId func = ci->func;
|
||||
CallInfo *ci;
|
||||
StkId func, newtop;
|
||||
ptrdiff_t diff; /* difference for new top */
|
||||
lua_lock(L);
|
||||
ci = L->ci;
|
||||
func = ci->func;
|
||||
if (idx >= 0) {
|
||||
api_check(L, idx <= ci->top - (func + 1), "new top too large");
|
||||
diff = ((func + 1) + idx) - L->top;
|
||||
|
@ -184,9 +188,26 @@ LUA_API void lua_settop (lua_State *L, int idx) {
|
|||
api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
|
||||
diff = idx + 1; /* will "subtract" index (as it is negative) */
|
||||
}
|
||||
if (diff < 0 && hastocloseCfunc(ci->nresults))
|
||||
luaF_close(L, L->top + diff, LUA_OK);
|
||||
L->top += diff; /* correct top only after closing any upvalue */
|
||||
api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot");
|
||||
newtop = L->top + diff;
|
||||
if (diff < 0 && L->tbclist >= newtop) {
|
||||
lua_assert(hastocloseCfunc(ci->nresults));
|
||||
luaF_close(L, newtop, CLOSEKTOP, 0);
|
||||
}
|
||||
L->top = newtop; /* correct top only after closing any upvalue */
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
||||
|
||||
LUA_API void lua_closeslot (lua_State *L, int idx) {
|
||||
StkId level;
|
||||
lua_lock(L);
|
||||
level = index2stack(L, idx);
|
||||
api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level,
|
||||
"no variable to close at given level");
|
||||
luaF_close(L, level, CLOSEKTOP, 0);
|
||||
level = index2stack(L, idx); /* stack may be moved */
|
||||
setnilvalue(s2v(level));
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
||||
|
@ -376,20 +397,22 @@ LUA_API int lua_toboolean (lua_State *L, int idx) {
|
|||
|
||||
|
||||
LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
|
||||
TValue *o = index2value(L, idx);
|
||||
TValue *o;
|
||||
lua_lock(L);
|
||||
o = index2value(L, idx);
|
||||
if (!ttisstring(o)) {
|
||||
if (!cvt2str(o)) { /* not convertible? */
|
||||
if (len != NULL) *len = 0;
|
||||
lua_unlock(L);
|
||||
return NULL;
|
||||
}
|
||||
lua_lock(L); /* 'luaO_tostring' may create a new string */
|
||||
luaO_tostring(L, o);
|
||||
luaC_checkGC(L);
|
||||
o = index2value(L, idx); /* previous call may reallocate the stack */
|
||||
lua_unlock(L);
|
||||
}
|
||||
if (len != NULL)
|
||||
*len = vslen(o);
|
||||
lua_unlock(L);
|
||||
return svalue(o);
|
||||
}
|
||||
|
||||
|
@ -563,6 +586,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
|
|||
while (n--) {
|
||||
setobj2n(L, &cl->upvalue[n], s2v(L->top + n));
|
||||
/* does not need barrier because closure is white */
|
||||
lua_assert(iswhite(cl));
|
||||
}
|
||||
setclCvalue(L, s2v(L->top), cl);
|
||||
api_incr_top(L);
|
||||
|
@ -623,10 +647,21 @@ static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
** Get the global table in the registry. Since all predefined
|
||||
** indices in the registry were inserted right when the registry
|
||||
** was created and never removed, they must always be in the array
|
||||
** part of the registry.
|
||||
*/
|
||||
#define getGtable(L) \
|
||||
(&hvalue(&G(L)->l_registry)->array[LUA_RIDX_GLOBALS - 1])
|
||||
|
||||
|
||||
LUA_API int lua_getglobal (lua_State *L, const char *name) {
|
||||
Table *reg = hvalue(&G(L)->l_registry);
|
||||
const TValue *G;
|
||||
lua_lock(L);
|
||||
return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
|
||||
G = getGtable(L);
|
||||
return auxgetstr(L, G, name);
|
||||
}
|
||||
|
||||
|
||||
|
@ -804,9 +839,10 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
|
|||
|
||||
|
||||
LUA_API void lua_setglobal (lua_State *L, const char *name) {
|
||||
Table *reg = hvalue(&G(L)->l_registry);
|
||||
const TValue *G;
|
||||
lua_lock(L); /* unlock done in 'auxsetstr' */
|
||||
auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
|
||||
G = getGtable(L);
|
||||
auxsetstr(L, G, name);
|
||||
}
|
||||
|
||||
|
||||
|
@ -853,12 +889,10 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
|
|||
|
||||
static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
|
||||
Table *t;
|
||||
TValue *slot;
|
||||
lua_lock(L);
|
||||
api_checknelems(L, n);
|
||||
t = gettable(L, idx);
|
||||
slot = luaH_set(L, t, key);
|
||||
setobj2t(L, slot, s2v(L->top - 1));
|
||||
luaH_set(L, t, key, s2v(L->top - 1));
|
||||
invalidateTMcache(t);
|
||||
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
|
||||
L->top -= n;
|
||||
|
@ -1055,8 +1089,7 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
|
|||
LClosure *f = clLvalue(s2v(L->top - 1)); /* get newly created function */
|
||||
if (f->nupvalues >= 1) { /* does it have an upvalue? */
|
||||
/* get global table from registry */
|
||||
Table *reg = hvalue(&G(L)->l_registry);
|
||||
const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
|
||||
const TValue *gt = getGtable(L);
|
||||
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
|
||||
setobj(L, f->upvals[0]->v, gt);
|
||||
luaC_barrier(L, f->upvals[0], gt);
|
||||
|
@ -1093,8 +1126,9 @@ LUA_API int lua_status (lua_State *L) {
|
|||
LUA_API int lua_gc (lua_State *L, int what, ...) {
|
||||
va_list argp;
|
||||
int res = 0;
|
||||
global_State *g = G(L);
|
||||
global_State *g;
|
||||
lua_lock(L);
|
||||
g = G(L);
|
||||
va_start(argp, what);
|
||||
switch (what) {
|
||||
case LUA_GCSTOP: {
|
||||
|
@ -1194,9 +1228,15 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
|
|||
|
||||
|
||||
LUA_API int lua_error (lua_State *L) {
|
||||
TValue *errobj;
|
||||
lua_lock(L);
|
||||
errobj = s2v(L->top - 1);
|
||||
api_checknelems(L, 1);
|
||||
luaG_errormsg(L);
|
||||
/* error object is the memory error message? */
|
||||
if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
|
||||
luaM_error(L); /* raise a memory error */
|
||||
else
|
||||
luaG_errormsg(L); /* raise a regular error */
|
||||
/* code unreachable; will unlock when control actually leaves the kernel */
|
||||
return 0; /* to avoid warnings */
|
||||
}
|
||||
|
@ -1225,8 +1265,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
|
|||
lua_lock(L);
|
||||
o = index2stack(L, idx);
|
||||
nresults = L->ci->nresults;
|
||||
api_check(L, L->openupval == NULL || uplevel(L->openupval) <= o,
|
||||
"marked index below or equal new one");
|
||||
api_check(L, L->tbclist < o, "given index below or equal a marked one");
|
||||
luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
|
||||
if (!hastocloseCfunc(nresults)) /* function not marked yet? */
|
||||
L->ci->nresults = codeNresults(nresults); /* mark it */
|
||||
|
@ -1238,14 +1277,12 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
|
|||
LUA_API void lua_concat (lua_State *L, int n) {
|
||||
lua_lock(L);
|
||||
api_checknelems(L, n);
|
||||
if (n >= 2) {
|
||||
if (n > 0)
|
||||
luaV_concat(L, n);
|
||||
}
|
||||
else if (n == 0) { /* push empty string */
|
||||
setsvalue2s(L, L->top, luaS_newlstr(L, "", 0));
|
||||
else { /* nothing to concatenate */
|
||||
setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); /* push empty string */
|
||||
api_incr_top(L);
|
||||
}
|
||||
/* else n == 1; nothing to do */
|
||||
luaC_checkGC(L);
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
@ -1370,13 +1407,16 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
|
|||
|
||||
|
||||
static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) {
|
||||
static const UpVal *const nullup = NULL;
|
||||
LClosure *f;
|
||||
TValue *fi = index2value(L, fidx);
|
||||
api_check(L, ttisLclosure(fi), "Lua function expected");
|
||||
f = clLvalue(fi);
|
||||
api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index");
|
||||
if (pf) *pf = f;
|
||||
if (1 <= n && n <= f->p->sizeupvalues)
|
||||
return &f->upvals[n - 1]; /* get its upvalue pointer */
|
||||
else
|
||||
return (UpVal**)&nullup;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1388,11 +1428,14 @@ LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) {
|
|||
}
|
||||
case LUA_VCCL: { /* C closure */
|
||||
CClosure *f = clCvalue(fi);
|
||||
api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index");
|
||||
if (1 <= n && n <= f->nupvalues)
|
||||
return &f->upvalue[n - 1];
|
||||
}
|
||||
/* else */
|
||||
} /* FALLTHROUGH */
|
||||
case LUA_VLCF:
|
||||
return NULL; /* light C functions have no upvalues */
|
||||
default: {
|
||||
api_check(L, 0, "closure expected");
|
||||
api_check(L, 0, "function expected");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1404,6 +1447,7 @@ LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
|
|||
LClosure *f1;
|
||||
UpVal **up1 = getupvalref(L, fidx1, n1, &f1);
|
||||
UpVal **up2 = getupvalref(L, fidx2, n2, NULL);
|
||||
api_check(L, *up1 != NULL && *up2 != NULL, "invalid upvalue index");
|
||||
*up1 = *up2;
|
||||
luaC_objbarrier(L, f1, *up1);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
|
||||
#define hastocloseCfunc(n) ((n) < LUA_MULTRET)
|
||||
|
||||
/* Map [-1, inf) (range of 'nresults') into (-inf, -2] */
|
||||
#define codeNresults(n) (-(n) - 3)
|
||||
#define decodeNresults(n) (-(n) - 3)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -190,7 +190,7 @@ LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) {
|
|||
}
|
||||
|
||||
|
||||
int luaL_typeerror (lua_State *L, int arg, const char *tname) {
|
||||
LUALIB_API int luaL_typeerror (lua_State *L, int arg, const char *tname) {
|
||||
const char *msg;
|
||||
const char *typearg; /* name for the type of the actual argument */
|
||||
if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING)
|
||||
|
@ -283,10 +283,10 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
|
|||
|
||||
|
||||
LUALIB_API int luaL_execresult (lua_State *L, int stat) {
|
||||
const char *what = "exit"; /* type of termination */
|
||||
if (stat != 0 && errno != 0) /* error with an 'errno'? */
|
||||
return luaL_fileresult(L, 0, NULL);
|
||||
else {
|
||||
const char *what = "exit"; /* type of termination */
|
||||
l_inspectstat(stat, what); /* interpret result */
|
||||
if (*what == 'e' && stat == 0) /* successful termination? */
|
||||
lua_pushboolean(L, 1);
|
||||
|
@ -378,7 +378,7 @@ LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def,
|
|||
** but without 'msg'.)
|
||||
*/
|
||||
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
|
||||
if (!lua_checkstack(L, space)) {
|
||||
if (l_unlikely(!lua_checkstack(L, space))) {
|
||||
if (msg)
|
||||
luaL_error(L, "stack overflow (%s)", msg);
|
||||
else
|
||||
|
@ -388,20 +388,20 @@ LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
|
|||
|
||||
|
||||
LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) {
|
||||
if (lua_type(L, arg) != t)
|
||||
if (l_unlikely(lua_type(L, arg) != t))
|
||||
tag_error(L, arg, t);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_checkany (lua_State *L, int arg) {
|
||||
if (lua_type(L, arg) == LUA_TNONE)
|
||||
if (l_unlikely(lua_type(L, arg) == LUA_TNONE))
|
||||
luaL_argerror(L, arg, "value expected");
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) {
|
||||
const char *s = lua_tolstring(L, arg, len);
|
||||
if (!s) tag_error(L, arg, LUA_TSTRING);
|
||||
if (l_unlikely(!s)) tag_error(L, arg, LUA_TSTRING);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -420,7 +420,7 @@ LUALIB_API const char *luaL_optlstring (lua_State *L, int arg,
|
|||
LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) {
|
||||
int isnum;
|
||||
lua_Number d = lua_tonumberx(L, arg, &isnum);
|
||||
if (!isnum)
|
||||
if (l_unlikely(!isnum))
|
||||
tag_error(L, arg, LUA_TNUMBER);
|
||||
return d;
|
||||
}
|
||||
|
@ -442,7 +442,7 @@ static void interror (lua_State *L, int arg) {
|
|||
LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) {
|
||||
int isnum;
|
||||
lua_Integer d = lua_tointegerx(L, arg, &isnum);
|
||||
if (!isnum) {
|
||||
if (l_unlikely(!isnum)) {
|
||||
interror(L, arg);
|
||||
}
|
||||
return d;
|
||||
|
@ -475,8 +475,10 @@ static void *resizebox (lua_State *L, int idx, size_t newsize) {
|
|||
lua_Alloc allocf = lua_getallocf(L, &ud);
|
||||
UBox *box = (UBox *)lua_touserdata(L, idx);
|
||||
void *temp = allocf(ud, box->box, box->bsize, newsize);
|
||||
if (temp == NULL && newsize > 0) /* allocation error? */
|
||||
luaL_error(L, "not enough memory");
|
||||
if (l_unlikely(temp == NULL && newsize > 0)) { /* allocation error? */
|
||||
lua_pushliteral(L, "not enough memory");
|
||||
lua_error(L); /* raise a memory error */
|
||||
}
|
||||
box->box = temp;
|
||||
box->bsize = newsize;
|
||||
return temp;
|
||||
|
@ -513,13 +515,22 @@ static void newbox (lua_State *L) {
|
|||
#define buffonstack(B) ((B)->b != (B)->init.b)
|
||||
|
||||
|
||||
/*
|
||||
** Whenever buffer is accessed, slot 'idx' must either be a box (which
|
||||
** cannot be NULL) or it is a placeholder for the buffer.
|
||||
*/
|
||||
#define checkbufferlevel(B,idx) \
|
||||
lua_assert(buffonstack(B) ? lua_touserdata(B->L, idx) != NULL \
|
||||
: lua_touserdata(B->L, idx) == (void*)B)
|
||||
|
||||
|
||||
/*
|
||||
** Compute new size for buffer 'B', enough to accommodate extra 'sz'
|
||||
** bytes.
|
||||
*/
|
||||
static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
|
||||
size_t newsize = B->size * 2; /* double buffer size */
|
||||
if (MAX_SIZET - sz < B->n) /* overflow in (B->n + sz)? */
|
||||
if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */
|
||||
return luaL_error(B->L, "buffer too large");
|
||||
if (newsize < B->n + sz) /* double is not big enough? */
|
||||
newsize = B->n + sz;
|
||||
|
@ -529,10 +540,11 @@ static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
|
|||
|
||||
/*
|
||||
** Returns a pointer to a free area with at least 'sz' bytes in buffer
|
||||
** 'B'. 'boxidx' is the relative position in the stack where the
|
||||
** buffer's box is or should be.
|
||||
** 'B'. 'boxidx' is the relative position in the stack where is the
|
||||
** buffer's box or its placeholder.
|
||||
*/
|
||||
static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) {
|
||||
checkbufferlevel(B, boxidx);
|
||||
if (B->size - B->n >= sz) /* enough space? */
|
||||
return B->b + B->n;
|
||||
else {
|
||||
|
@ -543,10 +555,9 @@ static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) {
|
|||
if (buffonstack(B)) /* buffer already has a box? */
|
||||
newbuff = (char *)resizebox(L, boxidx, newsize); /* resize it */
|
||||
else { /* no box yet */
|
||||
lua_pushnil(L); /* reserve slot for final result */
|
||||
lua_remove(L, boxidx); /* remove placeholder */
|
||||
newbox(L); /* create a new box */
|
||||
/* move box (and slot) to its intended position */
|
||||
lua_rotate(L, boxidx - 1, 2);
|
||||
lua_insert(L, boxidx); /* move box to its intended position */
|
||||
lua_toclose(L, boxidx);
|
||||
newbuff = (char *)resizebox(L, boxidx, newsize);
|
||||
memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */
|
||||
|
@ -581,11 +592,11 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
|
|||
|
||||
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
|
||||
lua_State *L = B->L;
|
||||
checkbufferlevel(B, -1);
|
||||
lua_pushlstring(L, B->b, B->n);
|
||||
if (buffonstack(B)) {
|
||||
lua_copy(L, -1, -3); /* move string to reserved slot */
|
||||
lua_pop(L, 2); /* pop string and box (closing the box) */
|
||||
}
|
||||
if (buffonstack(B))
|
||||
lua_closeslot(L, -2); /* close the box */
|
||||
lua_remove(L, -2); /* remove box or placeholder from the stack */
|
||||
}
|
||||
|
||||
|
||||
|
@ -620,6 +631,7 @@ LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
|
|||
B->b = B->init.b;
|
||||
B->n = 0;
|
||||
B->size = LUAL_BUFFERSIZE;
|
||||
lua_pushlightuserdata(L, (void*)B); /* push placeholder */
|
||||
}
|
||||
|
||||
|
||||
|
@ -637,10 +649,14 @@ LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {
|
|||
** =======================================================
|
||||
*/
|
||||
|
||||
/* index of free-list header */
|
||||
#define freelist 0
|
||||
|
||||
/* index of free-list header (after the predefined values) */
|
||||
#define freelist (LUA_RIDX_LAST + 1)
|
||||
|
||||
/*
|
||||
** The previously freed references form a linked list:
|
||||
** t[freelist] is the index of a first free index, or zero if list is
|
||||
** empty; t[t[freelist]] is the index of the second element; etc.
|
||||
*/
|
||||
LUALIB_API int luaL_ref (lua_State *L, int t) {
|
||||
int ref;
|
||||
if (lua_isnil(L, -1)) {
|
||||
|
@ -648,9 +664,16 @@ LUALIB_API int luaL_ref (lua_State *L, int t) {
|
|||
return LUA_REFNIL; /* 'nil' has a unique fixed reference */
|
||||
}
|
||||
t = lua_absindex(L, t);
|
||||
lua_rawgeti(L, t, freelist); /* get first free element */
|
||||
if (lua_rawgeti(L, t, freelist) == LUA_TNIL) { /* first access? */
|
||||
ref = 0; /* list is empty */
|
||||
lua_pushinteger(L, 0); /* initialize as an empty list */
|
||||
lua_rawseti(L, t, freelist); /* ref = t[freelist] = 0 */
|
||||
}
|
||||
else { /* already initialized */
|
||||
lua_assert(lua_isinteger(L, -1));
|
||||
ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */
|
||||
lua_pop(L, 1); /* remove it from stack */
|
||||
}
|
||||
lua_pop(L, 1); /* remove element from stack */
|
||||
if (ref != 0) { /* any free element? */
|
||||
lua_rawgeti(L, t, ref); /* remove it from list */
|
||||
lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */
|
||||
|
@ -666,6 +689,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
|
|||
if (ref >= 0) {
|
||||
t = lua_absindex(L, t);
|
||||
lua_rawgeti(L, t, freelist);
|
||||
lua_assert(lua_isinteger(L, -1));
|
||||
lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */
|
||||
lua_pushinteger(L, ref);
|
||||
lua_rawseti(L, t, freelist); /* t[freelist] = ref */
|
||||
|
@ -849,7 +873,7 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
|
|||
int isnum;
|
||||
lua_len(L, idx);
|
||||
l = lua_tointegerx(L, -1, &isnum);
|
||||
if (!isnum)
|
||||
if (l_unlikely(!isnum))
|
||||
luaL_error(L, "object length is not an integer");
|
||||
lua_pop(L, 1); /* remove object */
|
||||
return l;
|
||||
|
@ -1004,43 +1028,67 @@ static int panic (lua_State *L) {
|
|||
|
||||
|
||||
/*
|
||||
** Emit a warning. '*warnstate' means:
|
||||
** 0 - warning system is off;
|
||||
** 1 - ready to start a new message;
|
||||
** 2 - previous message is to be continued.
|
||||
** Warning functions:
|
||||
** warnfoff: warning system is off
|
||||
** warnfon: ready to start a new message
|
||||
** warnfcont: previous message is to be continued
|
||||
*/
|
||||
static void warnf (void *ud, const char *message, int tocont) {
|
||||
int *warnstate = (int *)ud;
|
||||
if (*warnstate != 2 && !tocont && *message == '@') { /* control message? */
|
||||
if (strcmp(message, "@off") == 0)
|
||||
*warnstate = 0;
|
||||
else if (strcmp(message, "@on") == 0)
|
||||
*warnstate = 1;
|
||||
return;
|
||||
static void warnfoff (void *ud, const char *message, int tocont);
|
||||
static void warnfon (void *ud, const char *message, int tocont);
|
||||
static void warnfcont (void *ud, const char *message, int tocont);
|
||||
|
||||
|
||||
/*
|
||||
** Check whether message is a control message. If so, execute the
|
||||
** control or ignore it if unknown.
|
||||
*/
|
||||
static int checkcontrol (lua_State *L, const char *message, int tocont) {
|
||||
if (tocont || *(message++) != '@') /* not a control message? */
|
||||
return 0;
|
||||
else {
|
||||
if (strcmp(message, "off") == 0)
|
||||
lua_setwarnf(L, warnfoff, L); /* turn warnings off */
|
||||
else if (strcmp(message, "on") == 0)
|
||||
lua_setwarnf(L, warnfon, L); /* turn warnings on */
|
||||
return 1; /* it was a control message */
|
||||
}
|
||||
else if (*warnstate == 0) /* warnings off? */
|
||||
return;
|
||||
if (*warnstate == 1) /* previous message was the last? */
|
||||
lua_writestringerror("%s", "Lua warning: "); /* start a new warning */
|
||||
}
|
||||
|
||||
|
||||
static void warnfoff (void *ud, const char *message, int tocont) {
|
||||
checkcontrol((lua_State *)ud, message, tocont);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Writes the message and handle 'tocont', finishing the message
|
||||
** if needed and setting the next warn function.
|
||||
*/
|
||||
static void warnfcont (void *ud, const char *message, int tocont) {
|
||||
lua_State *L = (lua_State *)ud;
|
||||
lua_writestringerror("%s", message); /* write message */
|
||||
if (tocont) /* not the last part? */
|
||||
*warnstate = 2; /* to be continued */
|
||||
lua_setwarnf(L, warnfcont, L); /* to be continued */
|
||||
else { /* last part */
|
||||
lua_writestringerror("%s", "\n"); /* finish message with end-of-line */
|
||||
*warnstate = 1; /* ready to start a new message */
|
||||
lua_setwarnf(L, warnfon, L); /* next call is a new message */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void warnfon (void *ud, const char *message, int tocont) {
|
||||
if (checkcontrol((lua_State *)ud, message, tocont)) /* control message? */
|
||||
return; /* nothing else to be done */
|
||||
lua_writestringerror("%s", "Lua warning: "); /* start a new warning */
|
||||
warnfcont(ud, message, tocont); /* finish processing */
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API lua_State *luaL_newstate (void) {
|
||||
lua_State *L = lua_newstate(l_alloc, NULL);
|
||||
if (L) {
|
||||
int *warnstate; /* space for warning state */
|
||||
if (l_likely(L)) {
|
||||
lua_atpanic(L, &panic);
|
||||
warnstate = (int *)lua_newuserdatauv(L, sizeof(int), 0);
|
||||
luaL_ref(L, LUA_REGISTRYINDEX); /* make sure it won't be collected */
|
||||
*warnstate = 0; /* default is warnings off */
|
||||
lua_setwarnf(L, warnf, warnstate);
|
||||
lua_setwarnf(L, warnfoff, L); /* default is warnings off */
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "luaconf.h"
|
||||
#include "lua.h"
|
||||
|
||||
|
||||
|
@ -130,10 +131,10 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
|
|||
(luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
|
||||
|
||||
#define luaL_argcheck(L, cond,arg,extramsg) \
|
||||
((void)((cond) || luaL_argerror(L, (arg), (extramsg))))
|
||||
((void)(luai_likely(cond) || luaL_argerror(L, (arg), (extramsg))))
|
||||
|
||||
#define luaL_argexpected(L,cond,arg,tname) \
|
||||
((void)((cond) || luaL_typeerror(L, (arg), (tname))))
|
||||
((void)(luai_likely(cond) || luaL_typeerror(L, (arg), (tname))))
|
||||
|
||||
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
|
||||
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
|
||||
|
@ -157,6 +158,22 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
|
|||
#define luaL_pushfail(L) lua_pushnil(L)
|
||||
|
||||
|
||||
/*
|
||||
** Internal assertions for in-house debugging
|
||||
*/
|
||||
#if !defined(lua_assert)
|
||||
|
||||
#if defined LUAI_ASSERT
|
||||
#include <assert.h>
|
||||
#define lua_assert(c) assert(c)
|
||||
#else
|
||||
#define lua_assert(c) ((void)0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Generic Buffer manipulation
|
||||
|
|
|
@ -138,7 +138,7 @@ static int luaB_setmetatable (lua_State *L) {
|
|||
int t = lua_type(L, 2);
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table");
|
||||
if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL)
|
||||
if (l_unlikely(luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL))
|
||||
return luaL_error(L, "cannot change a protected metatable");
|
||||
lua_settop(L, 2);
|
||||
lua_setmetatable(L, 1);
|
||||
|
@ -182,7 +182,8 @@ static int luaB_rawset (lua_State *L) {
|
|||
|
||||
|
||||
static int pushmode (lua_State *L, int oldmode) {
|
||||
lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" : "generational");
|
||||
lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
|
||||
: "generational");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -299,7 +300,7 @@ static int luaB_ipairs (lua_State *L) {
|
|||
|
||||
|
||||
static int load_aux (lua_State *L, int status, int envidx) {
|
||||
if (status == LUA_OK) {
|
||||
if (l_likely(status == LUA_OK)) {
|
||||
if (envidx != 0) { /* 'env' parameter? */
|
||||
lua_pushvalue(L, envidx); /* environment for loaded function */
|
||||
if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */
|
||||
|
@ -355,7 +356,7 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
|
|||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
else if (!lua_isstring(L, -1))
|
||||
else if (l_unlikely(!lua_isstring(L, -1)))
|
||||
luaL_error(L, "reader function must return a string");
|
||||
lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */
|
||||
return lua_tolstring(L, RESERVEDSLOT, size);
|
||||
|
@ -393,7 +394,7 @@ static int dofilecont (lua_State *L, int d1, lua_KContext d2) {
|
|||
static int luaB_dofile (lua_State *L) {
|
||||
const char *fname = luaL_optstring(L, 1, NULL);
|
||||
lua_settop(L, 1);
|
||||
if (luaL_loadfile(L, fname) != LUA_OK)
|
||||
if (l_unlikely(luaL_loadfile(L, fname) != LUA_OK))
|
||||
return lua_error(L);
|
||||
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
|
||||
return dofilecont(L, 0, 0);
|
||||
|
@ -401,7 +402,7 @@ static int luaB_dofile (lua_State *L) {
|
|||
|
||||
|
||||
static int luaB_assert (lua_State *L) {
|
||||
if (lua_toboolean(L, 1)) /* condition is true? */
|
||||
if (l_likely(lua_toboolean(L, 1))) /* condition is true? */
|
||||
return lua_gettop(L); /* return all arguments */
|
||||
else { /* error */
|
||||
luaL_checkany(L, 1); /* there must be a condition */
|
||||
|
@ -437,7 +438,7 @@ static int luaB_select (lua_State *L) {
|
|||
** ignored).
|
||||
*/
|
||||
static int finishpcall (lua_State *L, int status, lua_KContext extra) {
|
||||
if (status != LUA_OK && status != LUA_YIELD) { /* error? */
|
||||
if (l_unlikely(status != LUA_OK && status != LUA_YIELD)) { /* error? */
|
||||
lua_pushboolean(L, 0); /* first result (false) */
|
||||
lua_pushvalue(L, -2); /* error message */
|
||||
return 2; /* return false, msg */
|
||||
|
|
|
@ -314,15 +314,6 @@ void luaK_patchtohere (FuncState *fs, int list) {
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
** MAXimum number of successive Instructions WiTHout ABSolute line
|
||||
** information.
|
||||
*/
|
||||
#if !defined(MAXIWTHABS)
|
||||
#define MAXIWTHABS 120
|
||||
#endif
|
||||
|
||||
|
||||
/* limit for difference between lines in relative line info. */
|
||||
#define LIMLINEDIFF 0x80
|
||||
|
||||
|
@ -337,13 +328,13 @@ void luaK_patchtohere (FuncState *fs, int list) {
|
|||
static void savelineinfo (FuncState *fs, Proto *f, int line) {
|
||||
int linedif = line - fs->previousline;
|
||||
int pc = fs->pc - 1; /* last instruction coded */
|
||||
if (abs(linedif) >= LIMLINEDIFF || fs->iwthabs++ > MAXIWTHABS) {
|
||||
if (abs(linedif) >= LIMLINEDIFF || fs->iwthabs++ >= MAXIWTHABS) {
|
||||
luaM_growvector(fs->ls->L, f->abslineinfo, fs->nabslineinfo,
|
||||
f->sizeabslineinfo, AbsLineInfo, MAX_INT, "lines");
|
||||
f->abslineinfo[fs->nabslineinfo].pc = pc;
|
||||
f->abslineinfo[fs->nabslineinfo++].line = line;
|
||||
linedif = ABSLINEINFO; /* signal that there is absolute information */
|
||||
fs->iwthabs = 0; /* restart counter */
|
||||
fs->iwthabs = 1; /* restart counter */
|
||||
}
|
||||
luaM_growvector(fs->ls->L, f->lineinfo, pc, f->sizelineinfo, ls_byte,
|
||||
MAX_INT, "opcodes");
|
||||
|
@ -545,11 +536,14 @@ static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) {
|
|||
** and try to reuse constants. Because some values should not be used
|
||||
** as keys (nil cannot be a key, integer keys can collapse with float
|
||||
** keys), the caller must provide a useful 'key' for indexing the cache.
|
||||
** Note that all functions share the same table, so entering or exiting
|
||||
** a function can make some indices wrong.
|
||||
*/
|
||||
static int addk (FuncState *fs, TValue *key, TValue *v) {
|
||||
TValue val;
|
||||
lua_State *L = fs->ls->L;
|
||||
Proto *f = fs->f;
|
||||
TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */
|
||||
const TValue *idx = luaH_get(fs->ls->h, key); /* query scanner table */
|
||||
int k, oldsize;
|
||||
if (ttisinteger(idx)) { /* is there an index there? */
|
||||
k = cast_int(ivalue(idx));
|
||||
|
@ -563,7 +557,8 @@ static int addk (FuncState *fs, TValue *key, TValue *v) {
|
|||
k = fs->nk;
|
||||
/* numerical value does not need GC barrier;
|
||||
table has no metatable, so it does not need to invalidate cache */
|
||||
setivalue(idx, k);
|
||||
setivalue(&val, k);
|
||||
luaH_finishset(L, fs->ls->h, key, idx, &val);
|
||||
luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants");
|
||||
while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
|
||||
setobj(L, &f->k[k], v);
|
||||
|
@ -753,7 +748,7 @@ void luaK_setoneret (FuncState *fs, expdesc *e) {
|
|||
|
||||
|
||||
/*
|
||||
** Ensure that expression 'e' is not a variable (nor a constant).
|
||||
** Ensure that expression 'e' is not a variable (nor a <const>).
|
||||
** (Expression still may have jump lists.)
|
||||
*/
|
||||
void luaK_dischargevars (FuncState *fs, expdesc *e) {
|
||||
|
@ -763,7 +758,7 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
|
|||
break;
|
||||
}
|
||||
case VLOCAL: { /* already in a register */
|
||||
e->u.info = e->u.var.sidx;
|
||||
e->u.info = e->u.var.ridx;
|
||||
e->k = VNONRELOC; /* becomes a non-relocatable value */
|
||||
break;
|
||||
}
|
||||
|
@ -805,8 +800,8 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
|
|||
|
||||
|
||||
/*
|
||||
** Ensures expression value is in register 'reg' (and therefore
|
||||
** 'e' will become a non-relocatable expression).
|
||||
** Ensure expression value is in register 'reg', making 'e' a
|
||||
** non-relocatable expression.
|
||||
** (Expression still may have jump lists.)
|
||||
*/
|
||||
static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
|
||||
|
@ -860,7 +855,8 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
|
|||
|
||||
|
||||
/*
|
||||
** Ensures expression value is in any register.
|
||||
** Ensure expression value is in a register, making 'e' a
|
||||
** non-relocatable expression.
|
||||
** (Expression still may have jump lists.)
|
||||
*/
|
||||
static void discharge2anyreg (FuncState *fs, expdesc *e) {
|
||||
|
@ -946,8 +942,11 @@ int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
|
|||
exp2reg(fs, e, e->u.info); /* put final result in it */
|
||||
return e->u.info;
|
||||
}
|
||||
/* else expression has jumps and cannot change its register
|
||||
to hold the jump values, because it is a local variable.
|
||||
Go through to the default case. */
|
||||
}
|
||||
luaK_exp2nextreg(fs, e); /* otherwise, use next available register */
|
||||
luaK_exp2nextreg(fs, e); /* default: use next available register */
|
||||
return e->u.info;
|
||||
}
|
||||
|
||||
|
@ -1032,7 +1031,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
|
|||
switch (var->k) {
|
||||
case VLOCAL: {
|
||||
freeexp(fs, ex);
|
||||
exp2reg(fs, ex, var->u.var.sidx); /* compute 'ex' into proper place */
|
||||
exp2reg(fs, ex, var->u.var.ridx); /* compute 'ex' into proper place */
|
||||
return;
|
||||
}
|
||||
case VUPVAL: {
|
||||
|
@ -1272,7 +1271,7 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
|
|||
}
|
||||
else {
|
||||
/* register index of the table */
|
||||
t->u.ind.t = (t->k == VLOCAL) ? t->u.var.sidx: t->u.info;
|
||||
t->u.ind.t = (t->k == VLOCAL) ? t->u.var.ridx: t->u.info;
|
||||
if (isKstr(fs, k)) {
|
||||
t->u.ind.idx = k->u.info; /* literal string */
|
||||
t->k = VINDEXSTR;
|
||||
|
@ -1299,7 +1298,8 @@ static int validop (int op, TValue *v1, TValue *v2) {
|
|||
case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:
|
||||
case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */
|
||||
lua_Integer i;
|
||||
return (tointegerns(v1, &i) && tointegerns(v2, &i));
|
||||
return (luaV_tointegerns(v1, &i, LUA_FLOORN2I) &&
|
||||
luaV_tointegerns(v2, &i, LUA_FLOORN2I));
|
||||
}
|
||||
case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */
|
||||
return (nvalue(v2) != 0);
|
||||
|
|
|
@ -31,14 +31,14 @@ static lua_State *getco (lua_State *L) {
|
|||
*/
|
||||
static int auxresume (lua_State *L, lua_State *co, int narg) {
|
||||
int status, nres;
|
||||
if (!lua_checkstack(co, narg)) {
|
||||
if (l_unlikely(!lua_checkstack(co, narg))) {
|
||||
lua_pushliteral(L, "too many arguments to resume");
|
||||
return -1; /* error flag */
|
||||
}
|
||||
lua_xmove(L, co, narg);
|
||||
status = lua_resume(co, L, narg, &nres);
|
||||
if (status == LUA_OK || status == LUA_YIELD) {
|
||||
if (!lua_checkstack(L, nres + 1)) {
|
||||
if (l_likely(status == LUA_OK || status == LUA_YIELD)) {
|
||||
if (l_unlikely(!lua_checkstack(L, nres + 1))) {
|
||||
lua_pop(co, nres); /* remove results anyway */
|
||||
lua_pushliteral(L, "too many results to resume");
|
||||
return -1; /* error flag */
|
||||
|
@ -57,7 +57,7 @@ static int luaB_coresume (lua_State *L) {
|
|||
lua_State *co = getco(L);
|
||||
int r;
|
||||
r = auxresume(L, co, lua_gettop(L) - 1);
|
||||
if (r < 0) {
|
||||
if (l_unlikely(r < 0)) {
|
||||
lua_pushboolean(L, 0);
|
||||
lua_insert(L, -2);
|
||||
return 2; /* return false + error message */
|
||||
|
@ -73,11 +73,15 @@ static int luaB_coresume (lua_State *L) {
|
|||
static int luaB_auxwrap (lua_State *L) {
|
||||
lua_State *co = lua_tothread(L, lua_upvalueindex(1));
|
||||
int r = auxresume(L, co, lua_gettop(L));
|
||||
if (r < 0) {
|
||||
if (l_unlikely(r < 0)) { /* error? */
|
||||
int stat = lua_status(co);
|
||||
if (stat != LUA_OK && stat != LUA_YIELD)
|
||||
lua_resetthread(co); /* close variables in case of errors */
|
||||
if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */
|
||||
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 */
|
||||
}
|
||||
if (stat != LUA_ERRMEM && /* not a memory error and ... */
|
||||
lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
|
||||
luaL_where(L, 1); /* add extra info, if available */
|
||||
lua_insert(L, -2);
|
||||
lua_concat(L, 2);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
/*
|
||||
** WARNING: the functions defined here do not necessarily correspond
|
||||
** to the similar functions in the standard C ctype.h. They are
|
||||
** optimized for the specific needs of Lua
|
||||
** optimized for the specific needs of Lua.
|
||||
*/
|
||||
|
||||
#if !defined(LUA_USE_CTYPE)
|
||||
|
@ -61,13 +61,19 @@
|
|||
#define lisprint(c) testprop(c, MASK(PRINTBIT))
|
||||
#define lisxdigit(c) testprop(c, MASK(XDIGITBIT))
|
||||
|
||||
|
||||
/*
|
||||
** this 'ltolower' only works for alphabetic characters
|
||||
** In ASCII, this 'ltolower' is correct for alphabetic characters and
|
||||
** for '.'. That is enough for Lua needs. ('check_exp' ensures that
|
||||
** the character either is an upper-case letter or is unchanged by
|
||||
** the transformation, which holds for lower-case letters and '.'.)
|
||||
*/
|
||||
#define ltolower(c) ((c) | ('A' ^ 'a'))
|
||||
#define ltolower(c) \
|
||||
check_exp(('A' <= (c) && (c) <= 'Z') || (c) == ((c) | ('A' ^ 'a')), \
|
||||
(c) | ('A' ^ 'a'))
|
||||
|
||||
|
||||
/* two more entries for 0 and -1 (EOZ) */
|
||||
/* one entry for each character and for -1 (EOZ) */
|
||||
LUAI_DDEC(const lu_byte luai_ctype_[UCHAR_MAX + 2];)
|
||||
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ static const char *const HOOKKEY = "_HOOKKEY";
|
|||
** checked.
|
||||
*/
|
||||
static void checkstack (lua_State *L, lua_State *L1, int n) {
|
||||
if (L != L1 && !lua_checkstack(L1, n))
|
||||
if (l_unlikely(L != L1 && !lua_checkstack(L1, n)))
|
||||
luaL_error(L, "stack overflow");
|
||||
}
|
||||
|
||||
|
@ -152,6 +152,7 @@ static int db_getinfo (lua_State *L) {
|
|||
lua_State *L1 = getthread(L, &arg);
|
||||
const char *options = luaL_optstring(L, arg+2, "flnSrtu");
|
||||
checkstack(L, L1, 3);
|
||||
luaL_argcheck(L, options[0] != '>', arg + 2, "invalid option '>'");
|
||||
if (lua_isfunction(L, arg + 1)) { /* info about a function? */
|
||||
options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */
|
||||
lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */
|
||||
|
@ -212,7 +213,7 @@ static int db_getlocal (lua_State *L) {
|
|||
lua_Debug ar;
|
||||
const char *name;
|
||||
int level = (int)luaL_checkinteger(L, arg + 1);
|
||||
if (!lua_getstack(L1, level, &ar)) /* out of range? */
|
||||
if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */
|
||||
return luaL_argerror(L, arg+1, "level out of range");
|
||||
checkstack(L, L1, 1);
|
||||
name = lua_getlocal(L1, &ar, nvar);
|
||||
|
@ -237,7 +238,7 @@ static int db_setlocal (lua_State *L) {
|
|||
lua_Debug ar;
|
||||
int level = (int)luaL_checkinteger(L, arg + 1);
|
||||
int nvar = (int)luaL_checkinteger(L, arg + 2);
|
||||
if (!lua_getstack(L1, level, &ar)) /* out of range? */
|
||||
if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */
|
||||
return luaL_argerror(L, arg+1, "level out of range");
|
||||
luaL_checkany(L, arg+3);
|
||||
lua_settop(L, arg+3);
|
||||
|
@ -281,25 +282,33 @@ static int db_setupvalue (lua_State *L) {
|
|||
** Check whether a given upvalue from a given closure exists and
|
||||
** returns its index
|
||||
*/
|
||||
static int checkupval (lua_State *L, int argf, int argnup) {
|
||||
static void *checkupval (lua_State *L, int argf, int argnup, int *pnup) {
|
||||
void *id;
|
||||
int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */
|
||||
luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */
|
||||
luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup,
|
||||
"invalid upvalue index");
|
||||
return nup;
|
||||
id = lua_upvalueid(L, argf, nup);
|
||||
if (pnup) {
|
||||
luaL_argcheck(L, id != NULL, argnup, "invalid upvalue index");
|
||||
*pnup = nup;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
static int db_upvalueid (lua_State *L) {
|
||||
int n = checkupval(L, 1, 2);
|
||||
lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));
|
||||
void *id = checkupval(L, 1, 2, NULL);
|
||||
if (id != NULL)
|
||||
lua_pushlightuserdata(L, id);
|
||||
else
|
||||
luaL_pushfail(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_upvaluejoin (lua_State *L) {
|
||||
int n1 = checkupval(L, 1, 2);
|
||||
int n2 = checkupval(L, 3, 4);
|
||||
int n1, n2;
|
||||
checkupval(L, 1, 2, &n1);
|
||||
checkupval(L, 3, 4, &n2);
|
||||
luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
|
||||
luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
|
||||
lua_upvaluejoin(L, 1, n1, 3, n2);
|
||||
|
@ -369,7 +378,7 @@ static int db_sethook (lua_State *L) {
|
|||
}
|
||||
if (!luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)) {
|
||||
/* table just created; initialize it */
|
||||
lua_pushstring(L, "k");
|
||||
lua_pushliteral(L, "k");
|
||||
lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setmetatable(L, -2); /* metatable(hooktable) = hooktable */
|
||||
|
@ -412,7 +421,7 @@ static int db_debug (lua_State *L) {
|
|||
for (;;) {
|
||||
char buffer[250];
|
||||
lua_writestringerror("%s", "lua_debug> ");
|
||||
if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
|
||||
if (fgets(buffer, sizeof(buffer), stdin) == NULL ||
|
||||
strcmp(buffer, "cont\n") == 0)
|
||||
return 0;
|
||||
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
|
||||
|
@ -440,9 +449,6 @@ static int db_traceback (lua_State *L) {
|
|||
static int db_setcstacklimit (lua_State *L) {
|
||||
int limit = (int)luaL_checkinteger(L, 1);
|
||||
int res = lua_setcstacklimit(L, limit);
|
||||
if (res == 0)
|
||||
lua_pushboolean(L, 0);
|
||||
else
|
||||
lua_pushinteger(L, res);
|
||||
return 1;
|
||||
}
|
||||
|
|
156
lua/src/ldebug.c
156
lua/src/ldebug.c
|
@ -34,10 +34,6 @@
|
|||
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL)
|
||||
|
||||
|
||||
/* Active Lua function (given call info) */
|
||||
#define ci_func(ci) (clLvalue(s2v((ci)->func)))
|
||||
|
||||
|
||||
static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
|
||||
const char **name);
|
||||
|
||||
|
@ -50,10 +46,16 @@ static int currentpc (CallInfo *ci) {
|
|||
|
||||
/*
|
||||
** Get a "base line" to find the line corresponding to an instruction.
|
||||
** For that, search the array of absolute line info for the largest saved
|
||||
** instruction smaller or equal to the wanted instruction. A special
|
||||
** case is when there is no absolute info or the instruction is before
|
||||
** the first absolute one.
|
||||
** Base lines are regularly placed at MAXIWTHABS intervals, so usually
|
||||
** an integer division gets the right place. When the source file has
|
||||
** large sequences of empty/comment lines, it may need extra entries,
|
||||
** so the original estimate needs a correction.
|
||||
** If the original estimate is -1, the initial 'if' ensures that the
|
||||
** 'while' will run at least once.
|
||||
** The assertion that the estimate is a lower bound for the correct base
|
||||
** is valid as long as the debug info has been generated with the same
|
||||
** value for MAXIWTHABS or smaller. (Previous releases use a little
|
||||
** smaller value.)
|
||||
*/
|
||||
static int getbaseline (const Proto *f, int pc, int *basepc) {
|
||||
if (f->sizeabslineinfo == 0 || pc < f->abslineinfo[0].pc) {
|
||||
|
@ -61,20 +63,12 @@ static int getbaseline (const Proto *f, int pc, int *basepc) {
|
|||
return f->linedefined;
|
||||
}
|
||||
else {
|
||||
unsigned int i;
|
||||
if (pc >= f->abslineinfo[f->sizeabslineinfo - 1].pc)
|
||||
i = f->sizeabslineinfo - 1; /* instruction is after last saved one */
|
||||
else { /* binary search */
|
||||
unsigned int j = f->sizeabslineinfo - 1; /* pc < anchorlines[j] */
|
||||
i = 0; /* abslineinfo[i] <= pc */
|
||||
while (i < j - 1) {
|
||||
unsigned int m = (j + i) / 2;
|
||||
if (pc >= f->abslineinfo[m].pc)
|
||||
i = m;
|
||||
else
|
||||
j = m;
|
||||
}
|
||||
}
|
||||
int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */
|
||||
/* estimate must be a lower bond 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)
|
||||
i++; /* low estimate; adjust it */
|
||||
*basepc = f->abslineinfo[i].pc;
|
||||
return f->abslineinfo[i].line;
|
||||
}
|
||||
|
@ -127,20 +121,18 @@ static void settraps (CallInfo *ci) {
|
|||
/*
|
||||
** This function can be called during a signal, under "reasonable"
|
||||
** assumptions.
|
||||
** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by
|
||||
** 'resethookcount') are for debug only, and it is no problem if they
|
||||
** get arbitrary values (causes at most one wrong hook call). 'hookmask'
|
||||
** is an atomic value. We assume that pointers are atomic too (e.g., gcc
|
||||
** ensures that for all platforms where it runs). Moreover, 'hook' is
|
||||
** always checked before being called (see 'luaD_hook').
|
||||
** Fields 'basehookcount' and 'hookcount' (set by 'resethookcount')
|
||||
** are for debug only, and it is no problem if they get arbitrary
|
||||
** values (causes at most one wrong hook call). 'hookmask' is an atomic
|
||||
** value. We assume that pointers are atomic too (e.g., gcc ensures that
|
||||
** for all platforms where it runs). Moreover, 'hook' is always checked
|
||||
** before being called (see 'luaD_hook').
|
||||
*/
|
||||
LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
|
||||
if (func == NULL || mask == 0) { /* turn off hooks? */
|
||||
mask = 0;
|
||||
func = NULL;
|
||||
}
|
||||
if (isLua(L->ci))
|
||||
L->oldpc = L->ci->u.l.savedpc;
|
||||
L->hook = func;
|
||||
L->basehookcount = count;
|
||||
resethookcount(L);
|
||||
|
@ -192,8 +184,8 @@ static const char *upvalname (const Proto *p, int uv) {
|
|||
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
||||
if (clLvalue(s2v(ci->func))->p->is_vararg) {
|
||||
int nextra = ci->u.l.nextraargs;
|
||||
if (n <= nextra) {
|
||||
*pos = ci->func - nextra + (n - 1);
|
||||
if (n >= -nextra) { /* 'n' is negative */
|
||||
*pos = ci->func - nextra - (n + 1);
|
||||
return "(vararg)"; /* generic name for any vararg */
|
||||
}
|
||||
}
|
||||
|
@ -206,7 +198,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
|
|||
const char *name = NULL;
|
||||
if (isLua(ci)) {
|
||||
if (n < 0) /* access to vararg values? */
|
||||
return findvararg(ci, -n, pos);
|
||||
return findvararg(ci, n, pos);
|
||||
else
|
||||
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
|
||||
}
|
||||
|
@ -309,8 +301,8 @@ static void collectvalidlines (lua_State *L, Closure *f) {
|
|||
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 lines with code */
|
||||
currentline = nextline(p, currentline, i);
|
||||
for (i = 0; i < p->sizelineinfo; i++) { /* for all instructions */
|
||||
currentline = nextline(p, currentline, i); /* get its line */
|
||||
luaH_setint(L, t, currentline, &v); /* table[line] = true */
|
||||
}
|
||||
}
|
||||
|
@ -633,12 +625,10 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
|
|||
case OP_LEN: tm = TM_LEN; break;
|
||||
case OP_CONCAT: tm = TM_CONCAT; break;
|
||||
case OP_EQ: tm = TM_EQ; break;
|
||||
case OP_LT: case OP_LE: case OP_LTI: case OP_LEI:
|
||||
*name = "order"; /* '<=' can call '__lt', etc. */
|
||||
return "metamethod";
|
||||
case OP_CLOSE: case OP_RETURN:
|
||||
*name = "close";
|
||||
return "metamethod";
|
||||
/* no cases for OP_EQI and OP_EQK, as they don't call metamethods */
|
||||
case OP_LT: case OP_LTI: case OP_GTI: tm = TM_LT; break;
|
||||
case OP_LE: case OP_LEI: case OP_GEI: tm = TM_LE; break;
|
||||
case OP_CLOSE: case OP_RETURN: tm = TM_CLOSE; break;
|
||||
default:
|
||||
return NULL; /* cannot find a reasonable name */
|
||||
}
|
||||
|
@ -651,14 +641,18 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
|
|||
|
||||
|
||||
/*
|
||||
** The subtraction of two potentially unrelated pointers is
|
||||
** not ISO C, but it should not crash a program; the subsequent
|
||||
** checks are ISO C and ensure a correct result.
|
||||
** Check whether pointer 'o' points to some value in the stack
|
||||
** frame of the current function. Because 'o' may not point to a
|
||||
** value in this stack, we cannot compare it with the region
|
||||
** boundaries (undefined behaviour in ISO C).
|
||||
*/
|
||||
static int isinstack (CallInfo *ci, const TValue *o) {
|
||||
StkId base = ci->func + 1;
|
||||
ptrdiff_t i = cast(StkId, o) - base;
|
||||
return (0 <= i && i < (ci->top - base) && s2v(base + i) == o);
|
||||
StkId pos;
|
||||
for (pos = ci->func + 1; pos < ci->top; pos++) {
|
||||
if (o == s2v(pos))
|
||||
return 1;
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
|
||||
|
@ -701,6 +695,19 @@ l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
|
|||
}
|
||||
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
l_noret luaG_forerror (lua_State *L, const TValue *o, const char *what) {
|
||||
luaG_runerror(L, "bad 'for' %s (number expected, got %s)",
|
||||
what, luaT_objtypename(L, o));
|
||||
|
@ -726,7 +733,7 @@ l_noret luaG_opinterror (lua_State *L, const TValue *p1,
|
|||
*/
|
||||
l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
|
||||
lua_Integer temp;
|
||||
if (!tointegerns(p1, &temp))
|
||||
if (!luaV_tointegerns(p1, &temp, LUA_FLOORN2I))
|
||||
p2 = p1;
|
||||
luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2));
|
||||
}
|
||||
|
@ -784,20 +791,49 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
|
|||
|
||||
/*
|
||||
** Check whether new instruction 'newpc' is in a different line from
|
||||
** previous instruction 'oldpc'.
|
||||
** previous instruction 'oldpc'. More often than not, 'newpc' is only
|
||||
** one or a few instructions after 'oldpc' (it must be after, see
|
||||
** caller), so try to avoid calling 'luaG_getfuncline'. If they are
|
||||
** too far apart, there is a good chance of a ABSLINEINFO in the way,
|
||||
** so it goes directly to 'luaG_getfuncline'.
|
||||
*/
|
||||
static int changedline (const Proto *p, int oldpc, int newpc) {
|
||||
while (oldpc++ < newpc) {
|
||||
if (p->lineinfo[oldpc] != 0)
|
||||
return (luaG_getfuncline(p, oldpc - 1) != luaG_getfuncline(p, newpc));
|
||||
if (p->lineinfo == NULL) /* no debug information? */
|
||||
return 0;
|
||||
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
|
||||
int delta = 0; /* line diference */
|
||||
int pc = oldpc;
|
||||
for (;;) {
|
||||
int lineinfo = p->lineinfo[++pc];
|
||||
if (lineinfo == ABSLINEINFO)
|
||||
break; /* cannot compute delta; fall through */
|
||||
delta += lineinfo;
|
||||
if (pc == newpc)
|
||||
return (delta != 0); /* delta computed successfully */
|
||||
}
|
||||
return 0; /* no line changes in the way */
|
||||
}
|
||||
/* either instructions are too far apart or there is an absolute line
|
||||
info in the way; compute line difference explicitly */
|
||||
return (luaG_getfuncline(p, oldpc) != luaG_getfuncline(p, newpc));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Traces the execution of a Lua function. Called before the execution
|
||||
** of each opcode, when debug is on. 'L->oldpc' stores the last
|
||||
** instruction traced, to detect line changes. When entering a new
|
||||
** function, 'npci' will be zero and will test as a new line whatever
|
||||
** the value of 'oldpc'. Some exceptional conditions may return to
|
||||
** a function without setting 'oldpc'. In that case, 'oldpc' may be
|
||||
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
|
||||
** at most causes an extra call to a line hook.)
|
||||
** This function is not "Protected" when called, so it should correct
|
||||
** 'L->top' before calling anything that can run the GC.
|
||||
*/
|
||||
int luaG_traceexec (lua_State *L, const Instruction *pc) {
|
||||
CallInfo *ci = L->ci;
|
||||
lu_byte mask = L->hookmask;
|
||||
const Proto *p = ci_func(ci)->p;
|
||||
int counthook;
|
||||
if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */
|
||||
ci->u.l.trap = 0; /* don't need to stop again */
|
||||
|
@ -814,20 +850,20 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
|
|||
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
|
||||
return 1; /* do not call hook again (VM yielded, so it did not move) */
|
||||
}
|
||||
if (!isIT(*(ci->u.l.savedpc - 1)))
|
||||
L->top = ci->top; /* prepare top */
|
||||
if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
|
||||
L->top = ci->top; /* correct top */
|
||||
if (counthook)
|
||||
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
|
||||
if (mask & LUA_MASKLINE) {
|
||||
const Proto *p = ci_func(ci)->p;
|
||||
/* 'L->oldpc' may be invalid; use zero in this case */
|
||||
int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0;
|
||||
int npci = pcRel(pc, p);
|
||||
if (npci == 0 || /* call linehook when enter a new function, */
|
||||
pc <= L->oldpc || /* when jump back (loop), or when */
|
||||
changedline(p, pcRel(L->oldpc, p), npci)) { /* enter new line */
|
||||
if (npci <= oldpc || /* call hook when jump back (loop), */
|
||||
changedline(p, oldpc, npci)) { /* or when enter new line */
|
||||
int newline = luaG_getfuncline(p, npci);
|
||||
luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */
|
||||
}
|
||||
L->oldpc = pc; /* 'pc' of last call to line hook */
|
||||
L->oldpc = npci; /* 'pc' of last call to line hook */
|
||||
}
|
||||
if (L->status == LUA_YIELD) { /* did hook yield? */
|
||||
if (counthook)
|
||||
|
|
|
@ -13,6 +13,11 @@
|
|||
|
||||
#define pcRel(pc, p) (cast_int((pc) - (p)->code) - 1)
|
||||
|
||||
|
||||
/* Active Lua function (given call info) */
|
||||
#define ci_func(ci) (clLvalue(s2v((ci)->func)))
|
||||
|
||||
|
||||
#define resethookcount(L) (L->hookcount = L->basehookcount)
|
||||
|
||||
/*
|
||||
|
@ -21,11 +26,22 @@
|
|||
*/
|
||||
#define ABSLINEINFO (-0x80)
|
||||
|
||||
|
||||
/*
|
||||
** MAXimum number of successive Instructions WiTHout ABSolute line
|
||||
** information. (A power of two allows fast divisions.)
|
||||
*/
|
||||
#if !defined(MAXIWTHABS)
|
||||
#define MAXIWTHABS 128
|
||||
#endif
|
||||
|
||||
|
||||
LUAI_FUNC int luaG_getfuncline (const Proto *f, int pc);
|
||||
LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n,
|
||||
StkId *pos);
|
||||
LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
|
||||
const char *opname);
|
||||
LUAI_FUNC l_noret luaG_callerror (lua_State *L, const TValue *o);
|
||||
LUAI_FUNC l_noret luaG_forerror (lua_State *L, const TValue *o,
|
||||
const char *what);
|
||||
LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1,
|
||||
|
|
481
lua/src/ldo.c
481
lua/src/ldo.c
|
@ -98,11 +98,12 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
|
|||
setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
|
||||
break;
|
||||
}
|
||||
case CLOSEPROTECT: {
|
||||
case LUA_OK: { /* special case only for closing upvalues */
|
||||
setnilvalue(s2v(oldtop)); /* no error message */
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
lua_assert(errorstatus(errcode)); /* real error */
|
||||
setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
|
||||
break;
|
||||
}
|
||||
|
@ -118,17 +119,13 @@ l_noret luaD_throw (lua_State *L, int errcode) {
|
|||
}
|
||||
else { /* thread has no error handler */
|
||||
global_State *g = G(L);
|
||||
errcode = luaF_close(L, L->stack, errcode); /* close all upvalues */
|
||||
L->status = cast_byte(errcode); /* mark it as dead */
|
||||
errcode = luaE_resetthread(L, errcode); /* close all upvalues */
|
||||
if (g->mainthread->errorJmp) { /* main thread has a handler? */
|
||||
setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */
|
||||
luaD_throw(g->mainthread, errcode); /* re-throw in main thread */
|
||||
}
|
||||
else { /* no handler at all; abort */
|
||||
if (g->panic) { /* panic function? */
|
||||
luaD_seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */
|
||||
if (L->ci->top < L->top)
|
||||
L->ci->top = L->top; /* pushing msg. can break this invariant */
|
||||
lua_unlock(L);
|
||||
g->panic(L); /* call panic function (last chance to jump out) */
|
||||
}
|
||||
|
@ -139,8 +136,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
|
|||
|
||||
|
||||
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
|
||||
global_State *g = G(L);
|
||||
l_uint32 oldnCcalls = g->Cstacklimit - (L->nCcalls + L->nci);
|
||||
l_uint32 oldnCcalls = L->nCcalls;
|
||||
struct lua_longjmp lj;
|
||||
lj.status = LUA_OK;
|
||||
lj.previous = L->errorJmp; /* chain new error handler */
|
||||
|
@ -149,7 +145,7 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
|
|||
(*f)(L, ud);
|
||||
);
|
||||
L->errorJmp = lj.previous; /* restore old error handler */
|
||||
L->nCcalls = g->Cstacklimit - oldnCcalls - L->nci;
|
||||
L->nCcalls = oldnCcalls;
|
||||
return lj.status;
|
||||
}
|
||||
|
||||
|
@ -164,9 +160,8 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
|
|||
static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
|
||||
CallInfo *ci;
|
||||
UpVal *up;
|
||||
if (oldstack == newstack)
|
||||
return; /* stack address did not change */
|
||||
L->top = (L->top - oldstack) + newstack;
|
||||
L->tbclist = (L->tbclist - oldstack) + newstack;
|
||||
for (up = L->openupval; up != NULL; up = up->u.open.next)
|
||||
up->v = s2v((uplevel(up) - oldstack) + newstack);
|
||||
for (ci = L->ci; ci != NULL; ci = ci->previous) {
|
||||
|
@ -182,22 +177,37 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
|
|||
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
|
||||
|
||||
|
||||
/*
|
||||
** Reallocate the stack to a new size, correcting all pointers into
|
||||
** it. (There are pointers to a stack from its upvalues, from its list
|
||||
** of call infos, plus a few individual pointers.) The reallocation is
|
||||
** done in two steps (allocation + free) because the correction must be
|
||||
** done while both addresses (the old stack and the new one) are valid.
|
||||
** (In ISO C, any pointer use after the pointer has been deallocated is
|
||||
** undefined behavior.)
|
||||
** In case of allocation error, raise an error or return false according
|
||||
** to 'raiseerror'.
|
||||
*/
|
||||
int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
|
||||
int lim = L->stacksize;
|
||||
StkId newstack = luaM_reallocvector(L, L->stack, lim, newsize, StackValue);
|
||||
int oldsize = stacksize(L);
|
||||
int i;
|
||||
StkId newstack = luaM_reallocvector(L, NULL, 0,
|
||||
newsize + EXTRA_STACK, StackValue);
|
||||
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
|
||||
lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK);
|
||||
if (unlikely(newstack == NULL)) { /* reallocation failed? */
|
||||
if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
|
||||
if (raiseerror)
|
||||
luaM_error(L);
|
||||
else return 0; /* do not raise an error */
|
||||
}
|
||||
for (; lim < newsize; lim++)
|
||||
setnilvalue(s2v(newstack + lim)); /* erase new segment */
|
||||
/* number of elements to be copied to the new stack */
|
||||
i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK;
|
||||
memcpy(newstack, L->stack, i * sizeof(StackValue));
|
||||
for (; i < newsize + EXTRA_STACK; i++)
|
||||
setnilvalue(s2v(newstack + i)); /* erase new segment */
|
||||
correctstack(L, L->stack, newstack);
|
||||
luaM_freearray(L, L->stack, oldsize + EXTRA_STACK);
|
||||
L->stack = newstack;
|
||||
L->stacksize = newsize;
|
||||
L->stack_last = L->stack + newsize - EXTRA_STACK;
|
||||
L->stack_last = L->stack + newsize;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -207,52 +217,73 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
|
|||
** is true, raises any error; otherwise, return 0 in case of errors.
|
||||
*/
|
||||
int luaD_growstack (lua_State *L, int n, int raiseerror) {
|
||||
int size = L->stacksize;
|
||||
int newsize = 2 * size; /* tentative new size */
|
||||
if (unlikely(size > LUAI_MAXSTACK)) { /* need more space after extra size? */
|
||||
int size = stacksize(L);
|
||||
if (l_unlikely(size > LUAI_MAXSTACK)) {
|
||||
/* if stack is larger than maximum, thread is already using the
|
||||
extra space reserved for errors, that is, thread is handling
|
||||
a stack error; cannot grow further than that. */
|
||||
lua_assert(stacksize(L) == ERRORSTACKSIZE);
|
||||
if (raiseerror)
|
||||
luaD_throw(L, LUA_ERRERR); /* error inside message handler */
|
||||
else return 0;
|
||||
return 0; /* if not 'raiseerror', just signal it */
|
||||
}
|
||||
else {
|
||||
int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK;
|
||||
int newsize = 2 * size; /* tentative new size */
|
||||
int needed = cast_int(L->top - L->stack) + n;
|
||||
if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */
|
||||
newsize = LUAI_MAXSTACK;
|
||||
if (newsize < needed) /* but must respect what was asked for */
|
||||
newsize = needed;
|
||||
if (unlikely(newsize > LUAI_MAXSTACK)) { /* stack overflow? */
|
||||
if (l_likely(newsize <= LUAI_MAXSTACK))
|
||||
return luaD_reallocstack(L, newsize, raiseerror);
|
||||
else { /* stack overflow */
|
||||
/* add extra size to be able to handle the error message */
|
||||
luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
|
||||
if (raiseerror)
|
||||
luaG_runerror(L, "stack overflow");
|
||||
else return 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} /* else no errors */
|
||||
return luaD_reallocstack(L, newsize, raiseerror);
|
||||
}
|
||||
|
||||
|
||||
static int stackinuse (lua_State *L) {
|
||||
CallInfo *ci;
|
||||
int res;
|
||||
StkId lim = L->top;
|
||||
for (ci = L->ci; ci != NULL; ci = ci->previous) {
|
||||
if (lim < ci->top) lim = ci->top;
|
||||
}
|
||||
lua_assert(lim <= L->stack_last);
|
||||
return cast_int(lim - L->stack) + 1; /* part of stack in use */
|
||||
res = cast_int(lim - L->stack) + 1; /* part of stack in use */
|
||||
if (res < LUA_MINSTACK)
|
||||
res = LUA_MINSTACK; /* ensure a minimum size */
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** If stack size is more than 3 times the current use, reduce that size
|
||||
** to twice the current use. (So, the final stack size is at most 2/3 the
|
||||
** previous size, and half of its entries are empty.)
|
||||
** As a particular case, if stack was handling a stack overflow and now
|
||||
** it is not, 'max' (limited by LUAI_MAXSTACK) will be smaller than
|
||||
** stacksize (equal to ERRORSTACKSIZE in this case), and so the stack
|
||||
** will be reduced to a "regular" size.
|
||||
*/
|
||||
void luaD_shrinkstack (lua_State *L) {
|
||||
int inuse = stackinuse(L);
|
||||
int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
|
||||
if (goodsize > LUAI_MAXSTACK)
|
||||
goodsize = LUAI_MAXSTACK; /* respect stack limit */
|
||||
int nsize = inuse * 2; /* proposed new size */
|
||||
int max = inuse * 3; /* maximum "reasonable" size */
|
||||
if (max > LUAI_MAXSTACK) {
|
||||
max = LUAI_MAXSTACK; /* respect stack limit */
|
||||
if (nsize > LUAI_MAXSTACK)
|
||||
nsize = LUAI_MAXSTACK;
|
||||
}
|
||||
/* if thread is currently not handling a stack overflow and its
|
||||
good size is smaller than current size, shrink its stack */
|
||||
if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) &&
|
||||
goodsize < L->stacksize)
|
||||
luaD_reallocstack(L, goodsize, 0); /* ok if that fails */
|
||||
size is larger than maximum "reasonable" size, shrink it */
|
||||
if (inuse <= LUAI_MAXSTACK && stacksize(L) > max)
|
||||
luaD_reallocstack(L, nsize, 0); /* ok if that fails */
|
||||
else /* don't change stack */
|
||||
condmovestack(L,{},{}); /* (change only for debugging) */
|
||||
luaE_shrinkCI(L); /* shrink CI list */
|
||||
|
@ -278,8 +309,8 @@ void luaD_hook (lua_State *L, int event, int line,
|
|||
if (hook && L->allowhook) { /* make sure there is a hook */
|
||||
int mask = CIST_HOOKED;
|
||||
CallInfo *ci = L->ci;
|
||||
ptrdiff_t top = savestack(L, L->top);
|
||||
ptrdiff_t ci_top = savestack(L, ci->top);
|
||||
ptrdiff_t top = savestack(L, L->top); /* preserve original 'top' */
|
||||
ptrdiff_t ci_top = savestack(L, ci->top); /* idem for 'ci->top' */
|
||||
lua_Debug ar;
|
||||
ar.event = event;
|
||||
ar.currentline = line;
|
||||
|
@ -289,8 +320,10 @@ void luaD_hook (lua_State *L, int event, int line,
|
|||
ci->u2.transferinfo.ftransfer = ftransfer;
|
||||
ci->u2.transferinfo.ntransfer = ntransfer;
|
||||
}
|
||||
if (isLua(ci) && L->top < ci->top)
|
||||
L->top = ci->top; /* protect entire activation register */
|
||||
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
|
||||
if (L->top + LUA_MINSTACK > ci->top)
|
||||
if (ci->top < L->top + LUA_MINSTACK)
|
||||
ci->top = L->top + LUA_MINSTACK;
|
||||
L->allowhook = 0; /* cannot call hooks inside a hook */
|
||||
ci->callstatus |= mask;
|
||||
|
@ -312,51 +345,53 @@ void luaD_hook (lua_State *L, int event, int line,
|
|||
** active.
|
||||
*/
|
||||
void luaD_hookcall (lua_State *L, CallInfo *ci) {
|
||||
int hook = (ci->callstatus & CIST_TAIL) ? LUA_HOOKTAILCALL : LUA_HOOKCALL;
|
||||
Proto *p;
|
||||
if (!(L->hookmask & LUA_MASKCALL)) /* some other hook? */
|
||||
return; /* don't call hook */
|
||||
p = clLvalue(s2v(ci->func))->p;
|
||||
L->top = ci->top; /* prepare top */
|
||||
L->oldpc = 0; /* set 'oldpc' for new function */
|
||||
if (L->hookmask & LUA_MASKCALL) { /* is call hook on? */
|
||||
int event = (ci->callstatus & CIST_TAIL) ? LUA_HOOKTAILCALL
|
||||
: LUA_HOOKCALL;
|
||||
Proto *p = ci_func(ci)->p;
|
||||
ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */
|
||||
luaD_hook(L, hook, -1, 1, p->numparams);
|
||||
luaD_hook(L, event, -1, 1, p->numparams);
|
||||
ci->u.l.savedpc--; /* correct 'pc' */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static StkId rethook (lua_State *L, CallInfo *ci, StkId firstres, int nres) {
|
||||
ptrdiff_t oldtop = savestack(L, L->top); /* hook may change top */
|
||||
int delta = 0;
|
||||
if (isLuacode(ci)) {
|
||||
Proto *p = clLvalue(s2v(ci->func))->p;
|
||||
/*
|
||||
** Executes a return hook for Lua and C functions and sets/corrects
|
||||
** 'oldpc'. (Note that this correction is needed by the line hook, so it
|
||||
** is done even when return hooks are off.)
|
||||
*/
|
||||
static void rethook (lua_State *L, CallInfo *ci, int nres) {
|
||||
if (L->hookmask & LUA_MASKRET) { /* is return hook on? */
|
||||
StkId firstres = L->top - nres; /* index of first result */
|
||||
int delta = 0; /* correction for vararg functions */
|
||||
int ftransfer;
|
||||
if (isLua(ci)) {
|
||||
Proto *p = ci_func(ci)->p;
|
||||
if (p->is_vararg)
|
||||
delta = ci->u.l.nextraargs + p->numparams + 1;
|
||||
if (L->top < ci->top)
|
||||
L->top = ci->top; /* correct top to run hook */
|
||||
}
|
||||
if (L->hookmask & LUA_MASKRET) { /* is return hook on? */
|
||||
int ftransfer;
|
||||
ci->func += delta; /* if vararg, back to virtual 'func' */
|
||||
ftransfer = cast(unsigned short, firstres - ci->func);
|
||||
luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */
|
||||
ci->func -= delta;
|
||||
}
|
||||
if (isLua(ci->previous))
|
||||
L->oldpc = ci->previous->u.l.savedpc; /* update 'oldpc' */
|
||||
return restorestack(L, oldtop);
|
||||
if (isLua(ci = ci->previous))
|
||||
L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Check whether 'func' has a '__call' metafield. If so, put it in the
|
||||
** stack, below original 'func', so that 'luaD_call' can call it. Raise
|
||||
** 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 p;
|
||||
if (unlikely(ttisnil(tm)))
|
||||
luaG_typeerror(L, s2v(func), "call"); /* nothing to call */
|
||||
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 */
|
||||
|
@ -380,27 +415,34 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) {
|
|||
case 1: /* one value needed */
|
||||
if (nres == 0) /* no results? */
|
||||
setnilvalue(s2v(res)); /* adjust with nil */
|
||||
else
|
||||
else /* at least one result */
|
||||
setobjs2s(L, res, L->top - nres); /* move it to proper place */
|
||||
L->top = res + 1;
|
||||
return;
|
||||
case LUA_MULTRET:
|
||||
wanted = nres; /* we want all results */
|
||||
break;
|
||||
default: /* multiple results (or to-be-closed variables) */
|
||||
default: /* two/more results and/or to-be-closed variables */
|
||||
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
|
||||
ptrdiff_t savedres = savestack(L, res);
|
||||
luaF_close(L, res, LUA_OK); /* may change the stack */
|
||||
res = restorestack(L, savedres);
|
||||
wanted = codeNresults(wanted); /* correct value */
|
||||
L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
|
||||
L->ci->u2.nres = nres;
|
||||
luaF_close(L, res, CLOSEKTOP, 1);
|
||||
L->ci->callstatus &= ~CIST_CLSRET;
|
||||
if (L->hookmask) /* if needed, call hook after '__close's */
|
||||
rethook(L, L->ci, nres);
|
||||
res = restorestack(L, savedres); /* close and hook can move stack */
|
||||
wanted = decodeNresults(wanted);
|
||||
if (wanted == LUA_MULTRET)
|
||||
wanted = nres;
|
||||
wanted = nres; /* we want all results */
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* generic case */
|
||||
firstresult = L->top - nres; /* index of first result */
|
||||
/* move all results to correct place */
|
||||
for (i = 0; i < nres && i < wanted; i++)
|
||||
if (nres > wanted) /* extra results? */
|
||||
nres = wanted; /* don't need them */
|
||||
for (i = 0; i < nres; i++) /* move all results to correct place */
|
||||
setobjs2s(L, res + i, firstresult + i);
|
||||
for (; i < wanted; i++) /* complete wanted number of results */
|
||||
setnilvalue(s2v(res + i));
|
||||
|
@ -409,15 +451,21 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) {
|
|||
|
||||
|
||||
/*
|
||||
** Finishes a function call: calls hook if necessary, removes CallInfo,
|
||||
** moves current number of results to proper place.
|
||||
** Finishes a function call: calls hook if necessary, moves current
|
||||
** number of results to proper place, and returns to previous call
|
||||
** info. If function has to close variables, hook must be called after
|
||||
** that.
|
||||
*/
|
||||
void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
|
||||
if (L->hookmask)
|
||||
L->top = rethook(L, ci, L->top - nres, nres);
|
||||
L->ci = ci->previous; /* back to caller */
|
||||
int wanted = ci->nresults;
|
||||
if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
|
||||
rethook(L, ci, nres);
|
||||
/* move results to proper place */
|
||||
moveresults(L, ci->func, nres, ci->nresults);
|
||||
moveresults(L, ci->func, nres, wanted);
|
||||
/* function cannot be in any of these cases when returning */
|
||||
lua_assert(!(ci->callstatus &
|
||||
(CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
|
||||
L->ci = ci->previous; /* back to caller (after closing variables) */
|
||||
}
|
||||
|
||||
|
||||
|
@ -450,12 +498,14 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
|
|||
|
||||
|
||||
/*
|
||||
** Call a function (C or Lua). The function to be called is at *func.
|
||||
** The arguments are on the stack, right after the function.
|
||||
** When returns, all the results are on the stack, starting at the original
|
||||
** function position.
|
||||
** Prepares the call to a function (C or Lua). For C functions, also do
|
||||
** the call. The function to be called is at '*func'. The arguments
|
||||
** are on the stack, right after the function. Returns the CallInfo
|
||||
** to be executed, if it was a Lua function. Otherwise (a C function)
|
||||
** returns NULL, with all the results on the stack, starting at the
|
||||
** original function position.
|
||||
*/
|
||||
void luaD_call (lua_State *L, StkId func, int nresults) {
|
||||
CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
|
||||
lua_CFunction f;
|
||||
retry:
|
||||
switch (ttypetag(s2v(func))) {
|
||||
|
@ -466,15 +516,15 @@ void luaD_call (lua_State *L, StkId func, int nresults) {
|
|||
f = fvalue(s2v(func));
|
||||
Cfunc: {
|
||||
int n; /* number of returns */
|
||||
CallInfo *ci = next_ci(L);
|
||||
checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
|
||||
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;
|
||||
L->ci = ci;
|
||||
lua_assert(ci->top <= L->stack_last);
|
||||
if (L->hookmask & LUA_MASKCALL) {
|
||||
if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
|
||||
int narg = cast_int(L->top - func) - 1;
|
||||
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
|
||||
}
|
||||
|
@ -483,29 +533,28 @@ void luaD_call (lua_State *L, StkId func, int nresults) {
|
|||
lua_lock(L);
|
||||
api_checknelems(L, n);
|
||||
luaD_poscall(L, ci, n);
|
||||
break;
|
||||
return NULL;
|
||||
}
|
||||
case LUA_VLCL: { /* Lua function */
|
||||
CallInfo *ci = next_ci(L);
|
||||
CallInfo *ci;
|
||||
Proto *p = clLvalue(s2v(func))->p;
|
||||
int narg = cast_int(L->top - func) - 1; /* number of real arguments */
|
||||
int nfixparams = p->numparams;
|
||||
int fsize = p->maxstacksize; /* frame size */
|
||||
checkstackp(L, fsize, func);
|
||||
checkstackGCp(L, fsize, func);
|
||||
L->ci = ci = next_ci(L);
|
||||
ci->nresults = nresults;
|
||||
ci->u.l.savedpc = p->code; /* starting point */
|
||||
ci->callstatus = 0;
|
||||
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);
|
||||
luaV_execute(L, ci); /* run the function */
|
||||
break;
|
||||
return ci;
|
||||
}
|
||||
default: { /* not a function */
|
||||
checkstackp(L, 1, func); /* space for metamethod */
|
||||
checkstackGCp(L, 1, func); /* space for metamethod */
|
||||
luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */
|
||||
goto retry; /* try again with metamethod */
|
||||
}
|
||||
|
@ -514,42 +563,108 @@ void luaD_call (lua_State *L, StkId func, int nresults) {
|
|||
|
||||
|
||||
/*
|
||||
** Similar to 'luaD_call', but does not allow yields during the call.
|
||||
** If there is a stack overflow, freeing all CI structures will
|
||||
** force the subsequent call to invoke 'luaE_extendCI', which then
|
||||
** will raise any errors.
|
||||
** Call a function (C or Lua) through C. 'inc' can be 1 (increment
|
||||
** number of recursive invocations in the C stack) or nyci (the same
|
||||
** plus increment number of non-yieldable calls).
|
||||
*/
|
||||
void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
|
||||
incXCcalls(L);
|
||||
if (getCcalls(L) <= CSTACKERR) /* possible stack overflow? */
|
||||
luaE_freeCI(L);
|
||||
luaD_call(L, func, nResults);
|
||||
decXCcalls(L);
|
||||
static void ccall (lua_State *L, StkId func, int nResults, int inc) {
|
||||
CallInfo *ci;
|
||||
L->nCcalls += inc;
|
||||
if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
|
||||
luaE_checkcstack(L);
|
||||
if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */
|
||||
ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */
|
||||
luaV_execute(L, ci); /* call it */
|
||||
}
|
||||
L->nCcalls -= inc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Completes the execution of an interrupted C function, calling its
|
||||
** continuation function.
|
||||
** External interface for 'ccall'
|
||||
*/
|
||||
static void finishCcall (lua_State *L, int status) {
|
||||
CallInfo *ci = L->ci;
|
||||
int n;
|
||||
void luaD_call (lua_State *L, StkId func, int nResults) {
|
||||
ccall(L, func, nResults, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Similar to 'luaD_call', but does not allow yields during the call.
|
||||
*/
|
||||
void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
|
||||
ccall(L, func, nResults, nyci);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Finish the job of 'lua_pcallk' after it was interrupted by an yield.
|
||||
** (The caller, 'finishCcall', does the final call to 'adjustresults'.)
|
||||
** The main job is to complete the 'luaD_pcall' called by 'lua_pcallk'.
|
||||
** If a '__close' method yields here, eventually control will be back
|
||||
** to 'finishCcall' (when that '__close' method finally returns) and
|
||||
** 'finishpcallk' will run again and close any still pending '__close'
|
||||
** methods. Similarly, if a '__close' method errs, 'precover' calls
|
||||
** 'unroll' which calls ''finishCcall' and we are back here again, to
|
||||
** close any pending '__close' methods.
|
||||
** Note that, up to the call to 'luaF_close', the corresponding
|
||||
** 'CallInfo' is not modified, so that this repeated run works like the
|
||||
** first one (except that it has at least one less '__close' to do). In
|
||||
** particular, field CIST_RECST preserves the error status across these
|
||||
** multiple runs, changing only if there is a new error.
|
||||
*/
|
||||
static int finishpcallk (lua_State *L, CallInfo *ci) {
|
||||
int status = getcistrecst(ci); /* get original status */
|
||||
if (l_likely(status == LUA_OK)) /* no error? */
|
||||
status = LUA_YIELD; /* was interrupted by an yield */
|
||||
else { /* error */
|
||||
StkId func = restorestack(L, ci->u2.funcidx);
|
||||
L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */
|
||||
luaF_close(L, func, status, 1); /* can yield or raise an error */
|
||||
func = restorestack(L, ci->u2.funcidx); /* stack may be moved */
|
||||
luaD_seterrorobj(L, status, func);
|
||||
luaD_shrinkstack(L); /* restore stack size in case of overflow */
|
||||
setcistrecst(ci, LUA_OK); /* clear original status */
|
||||
}
|
||||
ci->callstatus &= ~CIST_YPCALL;
|
||||
L->errfunc = ci->u.c.old_errfunc;
|
||||
/* if it is here, there were errors or yields; unlike 'lua_pcallk',
|
||||
do not change status */
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Completes the execution of a C function interrupted by an yield.
|
||||
** The interruption must have happened while the function was either
|
||||
** closing its tbc variables in 'moveresults' or executing
|
||||
** 'lua_callk'/'lua_pcallk'. In the first case, it just redoes
|
||||
** 'luaD_poscall'. In the second case, the call to 'finishpcallk'
|
||||
** finishes the interrupted execution of 'lua_pcallk'. After that, it
|
||||
** calls the continuation of the interrupted function and finally it
|
||||
** completes the job of the 'luaD_call' that called the function. In
|
||||
** the call to 'adjustresults', we do not know the number of results
|
||||
** of the function called by 'lua_callk'/'lua_pcallk', so we are
|
||||
** conservative and use LUA_MULTRET (always adjust).
|
||||
*/
|
||||
static void finishCcall (lua_State *L, CallInfo *ci) {
|
||||
int n; /* actual number of results from C function */
|
||||
if (ci->callstatus & CIST_CLSRET) { /* was returning? */
|
||||
lua_assert(hastocloseCfunc(ci->nresults));
|
||||
n = ci->u2.nres; /* just redo 'luaD_poscall' */
|
||||
/* don't need to reset CIST_CLSRET, as it will be set again anyway */
|
||||
}
|
||||
else {
|
||||
int status = LUA_YIELD; /* default if there were no errors */
|
||||
/* must have a continuation and must be able to call it */
|
||||
lua_assert(ci->u.c.k != NULL && yieldable(L));
|
||||
/* error status can only happen in a protected call */
|
||||
lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD);
|
||||
if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */
|
||||
ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */
|
||||
L->errfunc = ci->u.c.old_errfunc; /* with the same error function */
|
||||
}
|
||||
/* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already
|
||||
handled */
|
||||
adjustresults(L, ci->nresults);
|
||||
if (ci->callstatus & CIST_YPCALL) /* was inside a 'lua_pcallk'? */
|
||||
status = finishpcallk(L, ci); /* finish it */
|
||||
adjustresults(L, LUA_MULTRET); /* finish 'lua_callk' */
|
||||
lua_unlock(L);
|
||||
n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */
|
||||
n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation */
|
||||
lua_lock(L);
|
||||
api_checknelems(L, n);
|
||||
}
|
||||
luaD_poscall(L, ci, n); /* finish 'luaD_call' */
|
||||
}
|
||||
|
||||
|
@ -557,18 +672,14 @@ static void finishCcall (lua_State *L, int status) {
|
|||
/*
|
||||
** Executes "full continuation" (everything in the stack) of a
|
||||
** previously interrupted coroutine until the stack is empty (or another
|
||||
** interruption long-jumps out of the loop). If the coroutine is
|
||||
** recovering from an error, 'ud' points to the error status, which must
|
||||
** be passed to the first continuation function (otherwise the default
|
||||
** status is LUA_YIELD).
|
||||
** interruption long-jumps out of the loop).
|
||||
*/
|
||||
static void unroll (lua_State *L, void *ud) {
|
||||
CallInfo *ci;
|
||||
if (ud != NULL) /* error status? */
|
||||
finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */
|
||||
UNUSED(ud);
|
||||
while ((ci = L->ci) != &L->base_ci) { /* something in the stack */
|
||||
if (!isLua(ci)) /* C function? */
|
||||
finishCcall(L, LUA_YIELD); /* complete its execution */
|
||||
finishCcall(L, ci); /* complete its execution */
|
||||
else { /* Lua function */
|
||||
luaV_finishOp(L); /* finish interrupted instruction */
|
||||
luaV_execute(L, ci); /* execute down to higher C 'boundary' */
|
||||
|
@ -591,28 +702,6 @@ static CallInfo *findpcall (lua_State *L) {
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
** Recovers from an error in a coroutine. Finds a recover point (if
|
||||
** there is one) and completes the execution of the interrupted
|
||||
** 'luaD_pcall'. If there is no recover point, returns zero.
|
||||
*/
|
||||
static int recover (lua_State *L, int status) {
|
||||
StkId oldtop;
|
||||
CallInfo *ci = findpcall(L);
|
||||
if (ci == NULL) return 0; /* no recovery point */
|
||||
/* "finish" luaD_pcall */
|
||||
oldtop = restorestack(L, ci->u2.funcidx);
|
||||
luaF_close(L, oldtop, status); /* may change the stack */
|
||||
oldtop = restorestack(L, ci->u2.funcidx);
|
||||
luaD_seterrorobj(L, status, oldtop);
|
||||
L->ci = ci;
|
||||
L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */
|
||||
luaD_shrinkstack(L);
|
||||
L->errfunc = ci->u.c.old_errfunc;
|
||||
return 1; /* continue running the coroutine */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Signal an error in the call to 'lua_resume', not in the execution
|
||||
** of the coroutine itself. (Such errors should not be handled by any
|
||||
|
@ -638,14 +727,16 @@ static void resume (lua_State *L, void *ud) {
|
|||
int n = *(cast(int*, ud)); /* number of arguments */
|
||||
StkId firstArg = L->top - n; /* first argument */
|
||||
CallInfo *ci = L->ci;
|
||||
if (L->status == LUA_OK) { /* starting a coroutine? */
|
||||
luaD_call(L, firstArg - 1, LUA_MULTRET);
|
||||
}
|
||||
if (L->status == LUA_OK) /* starting a coroutine? */
|
||||
ccall(L, firstArg - 1, LUA_MULTRET, 1); /* 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) */
|
||||
if (isLua(ci)) /* yielded inside a hook? */
|
||||
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 */
|
||||
}
|
||||
else { /* 'common' yield */
|
||||
if (ci->u.c.k != NULL) { /* does it have a continuation function? */
|
||||
lua_unlock(L);
|
||||
|
@ -659,6 +750,26 @@ static void resume (lua_State *L, void *ud) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Unrolls a coroutine in protected mode while there are recoverable
|
||||
** errors, that is, errors inside a protected call. (Any error
|
||||
** interrupts 'unroll', and this loop protects it again so it can
|
||||
** continue.) Stops with a normal end (status == LUA_OK), an yield
|
||||
** (status == LUA_YIELD), or an unprotected error ('findpcall' doesn't
|
||||
** find a recover point).
|
||||
*/
|
||||
static int precover (lua_State *L, int status) {
|
||||
CallInfo *ci;
|
||||
while (errorstatus(status) && (ci = findpcall(L)) != NULL) {
|
||||
L->ci = ci; /* go down to recovery functions */
|
||||
setcistrecst(ci, status); /* status to finish 'pcall' */
|
||||
status = luaD_rawrunprotected(L, unroll, NULL);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
|
||||
int *nresults) {
|
||||
int status;
|
||||
|
@ -671,21 +782,13 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
|
|||
}
|
||||
else if (L->status != LUA_YIELD) /* ended with errors? */
|
||||
return resume_error(L, "cannot resume dead coroutine", nargs);
|
||||
if (from == NULL)
|
||||
L->nCcalls = CSTACKTHREAD;
|
||||
else /* correct 'nCcalls' for this thread */
|
||||
L->nCcalls = getCcalls(from) + from->nci - L->nci - CSTACKCF;
|
||||
if (L->nCcalls <= CSTACKERR)
|
||||
return resume_error(L, "C stack overflow", nargs);
|
||||
L->nCcalls = (from) ? getCcalls(from) : 0;
|
||||
luai_userstateresume(L, nargs);
|
||||
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
|
||||
status = luaD_rawrunprotected(L, resume, &nargs);
|
||||
/* continue running after recoverable errors */
|
||||
while (errorstatus(status) && recover(L, status)) {
|
||||
/* unroll continuation */
|
||||
status = luaD_rawrunprotected(L, unroll, &status);
|
||||
}
|
||||
if (likely(!errorstatus(status)))
|
||||
status = precover(L, status);
|
||||
if (l_likely(!errorstatus(status)))
|
||||
lua_assert(status == L->status); /* normal end or yield */
|
||||
else { /* unrecoverable error */
|
||||
L->status = cast_byte(status); /* mark thread as 'dead' */
|
||||
|
@ -706,26 +809,27 @@ LUA_API int lua_isyieldable (lua_State *L) {
|
|||
|
||||
LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
|
||||
lua_KFunction k) {
|
||||
CallInfo *ci = L->ci;
|
||||
CallInfo *ci;
|
||||
luai_userstateyield(L, nresults);
|
||||
lua_lock(L);
|
||||
ci = L->ci;
|
||||
api_checknelems(L, nresults);
|
||||
if (unlikely(!yieldable(L))) {
|
||||
if (l_unlikely(!yieldable(L))) {
|
||||
if (L != G(L)->mainthread)
|
||||
luaG_runerror(L, "attempt to yield across a C-call boundary");
|
||||
else
|
||||
luaG_runerror(L, "attempt to yield from outside a coroutine");
|
||||
}
|
||||
L->status = LUA_YIELD;
|
||||
ci->u2.nyield = nresults; /* save number of results */
|
||||
if (isLua(ci)) { /* inside a hook? */
|
||||
lua_assert(!isLuacode(ci));
|
||||
api_check(L, nresults == 0, "hooks cannot yield values");
|
||||
api_check(L, k == NULL, "hooks cannot continue after yielding");
|
||||
ci->u2.nyield = 0; /* no results */
|
||||
}
|
||||
else {
|
||||
if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
|
||||
ci->u.c.ctx = ctx; /* save context */
|
||||
ci->u2.nyield = nresults; /* save number of results */
|
||||
luaD_throw(L, LUA_YIELD);
|
||||
}
|
||||
lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */
|
||||
|
@ -734,6 +838,45 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
** Auxiliary structure to call 'luaF_close' in protected mode.
|
||||
*/
|
||||
struct CloseP {
|
||||
StkId level;
|
||||
int status;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Auxiliary function to call 'luaF_close' in protected mode.
|
||||
*/
|
||||
static void closepaux (lua_State *L, void *ud) {
|
||||
struct CloseP *pcl = cast(struct CloseP *, ud);
|
||||
luaF_close(L, pcl->level, pcl->status, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Calls 'luaF_close' in protected mode. Return the original status
|
||||
** or, in case of errors, the new status.
|
||||
*/
|
||||
int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status) {
|
||||
CallInfo *old_ci = L->ci;
|
||||
lu_byte old_allowhooks = L->allowhook;
|
||||
for (;;) { /* keep closing upvalues until no more errors */
|
||||
struct CloseP pcl;
|
||||
pcl.level = restorestack(L, level); pcl.status = status;
|
||||
status = luaD_rawrunprotected(L, &closepaux, &pcl);
|
||||
if (l_likely(status == LUA_OK)) /* no more errors? */
|
||||
return pcl.status;
|
||||
else { /* an error occurred; restore saved state and repeat */
|
||||
L->ci = old_ci;
|
||||
L->allowhook = old_allowhooks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Call the C function 'func' in protected mode, restoring basic
|
||||
** thread information ('allowhook', etc.) and in particular
|
||||
|
@ -747,14 +890,12 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u,
|
|||
ptrdiff_t old_errfunc = L->errfunc;
|
||||
L->errfunc = ef;
|
||||
status = luaD_rawrunprotected(L, func, u);
|
||||
if (unlikely(status != LUA_OK)) { /* an error occurred? */
|
||||
StkId oldtop = restorestack(L, old_top);
|
||||
if (l_unlikely(status != LUA_OK)) { /* an error occurred? */
|
||||
L->ci = old_ci;
|
||||
L->allowhook = old_allowhooks;
|
||||
status = luaF_close(L, oldtop, status);
|
||||
oldtop = restorestack(L, old_top); /* previous call may change stack */
|
||||
luaD_seterrorobj(L, status, oldtop);
|
||||
luaD_shrinkstack(L);
|
||||
status = luaD_closeprotected(L, old_top, status);
|
||||
luaD_seterrorobj(L, status, restorestack(L, old_top));
|
||||
luaD_shrinkstack(L); /* restore stack size in case of overflow */
|
||||
}
|
||||
L->errfunc = old_errfunc;
|
||||
return status;
|
||||
|
|
|
@ -17,11 +17,13 @@
|
|||
** Macro to check stack size and grow stack if needed. Parameters
|
||||
** 'pre'/'pos' allow the macro to preserve a pointer into the
|
||||
** stack across reallocations, doing the work only when needed.
|
||||
** It also allows the running of one GC step when the stack is
|
||||
** reallocated.
|
||||
** 'condmovestack' is used in heavy tests to force a stack reallocation
|
||||
** at every check.
|
||||
*/
|
||||
#define luaD_checkstackaux(L,n,pre,pos) \
|
||||
if (L->stack_last - L->top <= (n)) \
|
||||
if (l_unlikely(L->stack_last - L->top <= (n))) \
|
||||
{ pre; luaD_growstack(L, n, 1); pos; } \
|
||||
else { condmovestack(L,pre,pos); }
|
||||
|
||||
|
@ -35,7 +37,7 @@
|
|||
|
||||
|
||||
/* macro to check stack size, preserving 'p' */
|
||||
#define checkstackp(L,n,p) \
|
||||
#define checkstackGCp(L,n,p) \
|
||||
luaD_checkstackaux(L, n, \
|
||||
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
|
||||
luaC_checkGC(L), /* stack grow uses memory */ \
|
||||
|
@ -44,7 +46,7 @@
|
|||
|
||||
/* macro to check stack size and GC */
|
||||
#define checkstackGC(L,fsize) \
|
||||
luaD_checkstackaux(L, (fsize), (void)0, luaC_checkGC(L))
|
||||
luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0)
|
||||
|
||||
|
||||
/* type of protected functions, to be ran by 'runprotected' */
|
||||
|
@ -57,9 +59,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 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 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);
|
||||
LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres);
|
||||
|
|
173
lua/src/lfunc.c
173
lua/src/lfunc.c
|
@ -53,7 +53,7 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
|
|||
uv->v = &uv->u.value; /* make it closed */
|
||||
setnilvalue(uv->v);
|
||||
cl->upvals[i] = uv;
|
||||
luaC_objbarrier(L, cl, o);
|
||||
luaC_objbarrier(L, cl, uv);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,115 +100,83 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
|
|||
}
|
||||
|
||||
|
||||
static void callclose (lua_State *L, void *ud) {
|
||||
UNUSED(ud);
|
||||
luaD_callnoyield(L, L->top - 3, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Prepare closing method plus its arguments for object 'obj' with
|
||||
** error message 'err'. (This function assumes EXTRA_STACK.)
|
||||
** Call closing method for object 'obj' with error message 'err'. The
|
||||
** boolean 'yy' controls whether the call is yieldable.
|
||||
** (This function assumes EXTRA_STACK.)
|
||||
*/
|
||||
static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) {
|
||||
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
|
||||
StkId top = L->top;
|
||||
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
|
||||
if (ttisnil(tm)) /* no metamethod? */
|
||||
return 0; /* nothing to call */
|
||||
setobj2s(L, top, tm); /* will call metamethod... */
|
||||
setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
|
||||
setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
|
||||
L->top = top + 3; /* add function and arguments */
|
||||
return 1;
|
||||
if (yy)
|
||||
luaD_call(L, top, 0);
|
||||
else
|
||||
luaD_callnoyield(L, top, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Raise an error with message 'msg', inserting the name of the
|
||||
** local variable at position 'level' in the stack.
|
||||
** Check whether object at given level has a close metamethod and raise
|
||||
** an error if not.
|
||||
*/
|
||||
static void varerror (lua_State *L, StkId level, const char *msg) {
|
||||
int idx = cast_int(level - L->ci->func);
|
||||
static void checkclosemth (lua_State *L, StkId level) {
|
||||
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
|
||||
if (ttisnil(tm)) { /* no metamethod? */
|
||||
int idx = cast_int(level - L->ci->func); /* variable index */
|
||||
const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
|
||||
if (vname == NULL) vname = "?";
|
||||
luaG_runerror(L, msg, vname);
|
||||
luaG_runerror(L, "variable '%s' got a non-closable value", vname);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Prepare and call a closing method. If status is OK, code is still
|
||||
** inside the original protected call, and so any error will be handled
|
||||
** there. Otherwise, a previous error already activated the original
|
||||
** protected call, and so the call to the closing method must be
|
||||
** protected here. (A status == CLOSEPROTECT behaves like a previous
|
||||
** error, to also run the closing method in protected mode).
|
||||
** If status is OK, the call to the closing method will be pushed
|
||||
** at the top of the stack. Otherwise, values are pushed after
|
||||
** the 'level' of the upvalue being closed, as everything after
|
||||
** that won't be used again.
|
||||
** Prepare and call a closing method.
|
||||
** If status is CLOSEKTOP, the call to the closing method will be pushed
|
||||
** at the top of the stack. Otherwise, values can be pushed right after
|
||||
** the 'level' of the upvalue being closed, as everything after that
|
||||
** won't be used again.
|
||||
*/
|
||||
static int callclosemth (lua_State *L, StkId level, int status) {
|
||||
static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
|
||||
TValue *uv = s2v(level); /* value being closed */
|
||||
if (likely(status == LUA_OK)) {
|
||||
if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */
|
||||
callclose(L, NULL); /* call closing method */
|
||||
else if (!l_isfalse(uv)) /* non-closable non-false value? */
|
||||
varerror(L, level, "attempt to close non-closable variable '%s'");
|
||||
TValue *errobj;
|
||||
if (status == CLOSEKTOP)
|
||||
errobj = &G(L)->nilvalue; /* error object is nil */
|
||||
else { /* 'luaD_seterrorobj' will set top to level + 2 */
|
||||
errobj = s2v(level + 1); /* error object goes after 'uv' */
|
||||
luaD_seterrorobj(L, status, level + 1); /* set error object */
|
||||
}
|
||||
else { /* must close the object in protected mode */
|
||||
ptrdiff_t oldtop;
|
||||
level++; /* space for error message */
|
||||
oldtop = savestack(L, level + 1); /* top will be after that */
|
||||
luaD_seterrorobj(L, status, level); /* set error message */
|
||||
if (prepclosingmethod(L, uv, s2v(level))) { /* something to call? */
|
||||
int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0);
|
||||
if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */
|
||||
status = newstatus; /* this will be the new error */
|
||||
else {
|
||||
if (newstatus != LUA_OK) /* suppressed error? */
|
||||
luaE_warnerror(L, "__close metamethod");
|
||||
/* leave original error (or nil) on top */
|
||||
L->top = restorestack(L, oldtop);
|
||||
}
|
||||
}
|
||||
/* else no metamethod; ignore this case and keep original error */
|
||||
}
|
||||
return status;
|
||||
callclosemethod(L, uv, errobj, yy);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Try to create a to-be-closed upvalue
|
||||
** (can raise a memory-allocation error)
|
||||
** Maximum value for deltas in 'tbclist', dependent on the type
|
||||
** of delta. (This macro assumes that an 'L' is in scope where it
|
||||
** is used.)
|
||||
*/
|
||||
static void trynewtbcupval (lua_State *L, void *ud) {
|
||||
newupval(L, 1, cast(StkId, ud), &L->openupval);
|
||||
}
|
||||
#define MAXDELTA \
|
||||
((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1)
|
||||
|
||||
|
||||
/*
|
||||
** Create a to-be-closed upvalue. If there is a memory error
|
||||
** when creating the upvalue, the closing method must be called here,
|
||||
** as there is no upvalue to call it later.
|
||||
** Insert a variable in the list of to-be-closed variables.
|
||||
*/
|
||||
void luaF_newtbcupval (lua_State *L, StkId level) {
|
||||
TValue *obj = s2v(level);
|
||||
lua_assert(L->openupval == NULL || uplevel(L->openupval) < level);
|
||||
if (!l_isfalse(obj)) { /* false doesn't need to be closed */
|
||||
int status;
|
||||
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
|
||||
if (ttisnil(tm)) /* no metamethod? */
|
||||
varerror(L, level, "variable '%s' got a non-closable value");
|
||||
status = luaD_rawrunprotected(L, trynewtbcupval, level);
|
||||
if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */
|
||||
lua_assert(status == LUA_ERRMEM);
|
||||
luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */
|
||||
/* next call must succeed, as object is closable */
|
||||
prepclosingmethod(L, s2v(level), s2v(level + 1));
|
||||
callclose(L, NULL); /* call closing method */
|
||||
luaD_throw(L, LUA_ERRMEM); /* throw memory error */
|
||||
}
|
||||
lua_assert(level > L->tbclist);
|
||||
if (l_isfalse(s2v(level)))
|
||||
return; /* false doesn't need to be closed */
|
||||
checkclosemth(L, level); /* value must have a close method */
|
||||
while (cast_uint(level - L->tbclist) > MAXDELTA) {
|
||||
L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */
|
||||
L->tbclist->tbclist.delta = 0;
|
||||
}
|
||||
level->tbclist.delta = cast(unsigned short, level - L->tbclist);
|
||||
L->tbclist = level;
|
||||
}
|
||||
|
||||
|
||||
|
@ -220,25 +188,52 @@ void luaF_unlinkupval (UpVal *uv) {
|
|||
}
|
||||
|
||||
|
||||
int luaF_close (lua_State *L, StkId level, int status) {
|
||||
/*
|
||||
** Close all upvalues up to the given stack level.
|
||||
*/
|
||||
void luaF_closeupval (lua_State *L, StkId level) {
|
||||
UpVal *uv;
|
||||
while ((uv = L->openupval) != NULL && uplevel(uv) >= level) {
|
||||
StkId upl; /* stack index pointed by 'uv' */
|
||||
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
|
||||
TValue *slot = &uv->u.value; /* new position for value */
|
||||
lua_assert(uplevel(uv) < L->top);
|
||||
if (uv->tbc && status != NOCLOSINGMETH) {
|
||||
/* must run closing method, which may change the stack */
|
||||
ptrdiff_t levelrel = savestack(L, level);
|
||||
status = callclosemth(L, uplevel(uv), status);
|
||||
level = restorestack(L, levelrel);
|
||||
}
|
||||
luaF_unlinkupval(uv);
|
||||
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
|
||||
setobj(L, slot, uv->v); /* move value to upvalue slot */
|
||||
uv->v = slot; /* now current value lives here */
|
||||
if (!iswhite(uv))
|
||||
gray2black(uv); /* closed upvalues cannot be gray */
|
||||
if (!iswhite(uv)) { /* neither white nor dead? */
|
||||
nw2black(uv); /* closed upvalues cannot be gray */
|
||||
luaC_barrier(L, uv, slot);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Remove firt element from the tbclist plus its dummy nodes.
|
||||
*/
|
||||
static void poptbclist (lua_State *L) {
|
||||
StkId tbc = L->tbclist;
|
||||
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
|
||||
tbc -= tbc->tbclist.delta;
|
||||
while (tbc > L->stack && tbc->tbclist.delta == 0)
|
||||
tbc -= MAXDELTA; /* remove dummy nodes */
|
||||
L->tbclist = tbc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Close all upvalues and to-be-closed variables up to the given stack
|
||||
** level.
|
||||
*/
|
||||
void luaF_close (lua_State *L, StkId level, int status, int yy) {
|
||||
ptrdiff_t levelrel = savestack(L, level);
|
||||
luaF_closeupval(L, level); /* first, close the upvalues */
|
||||
while (L->tbclist >= level) { /* traverse tbc's down to that level */
|
||||
StkId tbc = L->tbclist; /* get variable index */
|
||||
poptbclist(L); /* remove it from list */
|
||||
prepcallclosemth(L, tbc, status, yy); /* close variable */
|
||||
level = restorestack(L, levelrel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -42,15 +42,9 @@
|
|||
#define MAXMISS 10
|
||||
|
||||
|
||||
/*
|
||||
** Special "status" for 'luaF_close'
|
||||
*/
|
||||
|
||||
/* close upvalues without running their closing methods */
|
||||
#define NOCLOSINGMETH (-1)
|
||||
|
||||
/* close upvalues running all closing methods in protected mode */
|
||||
#define CLOSEPROTECT (-2)
|
||||
/* special status to close upvalues preserving the top of the stack */
|
||||
#define CLOSEKTOP (-1)
|
||||
|
||||
|
||||
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
|
||||
|
@ -59,7 +53,8 @@ LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nupvals);
|
|||
LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
|
||||
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
|
||||
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
|
||||
LUAI_FUNC int luaF_close (lua_State *L, StkId level, int status);
|
||||
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
|
||||
LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy);
|
||||
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
|
||||
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
|
||||
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
|
||||
|
|
498
lua/src/lgc.c
498
lua/src/lgc.c
|
@ -60,16 +60,24 @@
|
|||
#define PAUSEADJ 100
|
||||
|
||||
|
||||
/* mask to erase all color bits (plus gen. related stuff) */
|
||||
#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS | AGEBITS))
|
||||
/* mask with all color bits */
|
||||
#define maskcolors (bitmask(BLACKBIT) | WHITEBITS)
|
||||
|
||||
/* mask with all GC bits */
|
||||
#define maskgcbits (maskcolors | AGEBITS)
|
||||
|
||||
|
||||
/* macro to erase all color bits then sets only the current white bit */
|
||||
/* macro to erase all color bits then set only the current white bit */
|
||||
#define makewhite(g,x) \
|
||||
(x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g)))
|
||||
(x->marked = cast_byte((x->marked & ~maskcolors) | luaC_white(g)))
|
||||
|
||||
#define white2gray(x) resetbits(x->marked, WHITEBITS)
|
||||
#define black2gray(x) resetbit(x->marked, BLACKBIT)
|
||||
/* make an object gray (neither white nor black) */
|
||||
#define set2gray(x) resetbits(x->marked, maskcolors)
|
||||
|
||||
|
||||
/* make an object black (coming from any color) */
|
||||
#define set2black(x) \
|
||||
(x->marked = cast_byte((x->marked & ~WHITEBITS) | bitmask(BLACKBIT)))
|
||||
|
||||
|
||||
#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x)))
|
||||
|
@ -77,16 +85,13 @@
|
|||
#define keyiswhite(n) (keyiscollectable(n) && iswhite(gckey(n)))
|
||||
|
||||
|
||||
#define checkconsistency(obj) \
|
||||
lua_longassert(!iscollectable(obj) || righttt(obj))
|
||||
|
||||
/*
|
||||
** Protected access to objects in values
|
||||
*/
|
||||
#define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL)
|
||||
|
||||
|
||||
#define markvalue(g,o) { checkconsistency(o); \
|
||||
#define markvalue(g,o) { checkliveness(g->mainthread,o); \
|
||||
if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
|
||||
|
||||
#define markkey(g, n) { if keyiswhite(n) reallymarkobject(g,gckey(n)); }
|
||||
|
@ -135,31 +140,38 @@ static GCObject **getgclist (GCObject *o) {
|
|||
|
||||
|
||||
/*
|
||||
** Link a collectable object 'o' with a known type into list pointed by 'p'.
|
||||
** Link a collectable object 'o' with a known type into the list 'p'.
|
||||
** (Must be a macro to access the 'gclist' field in different types.)
|
||||
*/
|
||||
#define linkgclist(o,p) ((o)->gclist = (p), (p) = obj2gco(o))
|
||||
#define linkgclist(o,p) linkgclist_(obj2gco(o), &(o)->gclist, &(p))
|
||||
|
||||
static void linkgclist_ (GCObject *o, GCObject **pnext, GCObject **list) {
|
||||
lua_assert(!isgray(o)); /* cannot be in a gray list */
|
||||
*pnext = *list;
|
||||
*list = o;
|
||||
set2gray(o); /* now it is */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Link a generic collectable object 'o' into list pointed by 'p'.
|
||||
** Link a generic collectable object 'o' into the list 'p'.
|
||||
*/
|
||||
#define linkobjgclist(o,p) (*getgclist(o) = (p), (p) = obj2gco(o))
|
||||
#define linkobjgclist(o,p) linkgclist_(obj2gco(o), getgclist(o), &(p))
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Clear keys for empty entries in tables. If entry is empty
|
||||
** and its key is not marked, mark its entry as dead. This allows the
|
||||
** collection of the key, but keeps its entry in the table (its removal
|
||||
** could break a chain). The main feature of a dead key is that it must
|
||||
** be different from any other value, to do not disturb searches.
|
||||
** Other places never manipulate dead keys, because its associated empty
|
||||
** value is enough to signal that the entry is logically empty.
|
||||
** Clear keys for empty entries in tables. If entry is empty, mark its
|
||||
** entry as dead. This allows the collection of the key, but keeps its
|
||||
** entry in the table: its removal could break a chain and could break
|
||||
** a table traversal. Other places never manipulate dead keys, because
|
||||
** its associated empty value is enough to signal that the entry is
|
||||
** logically empty.
|
||||
*/
|
||||
static void clearkey (Node *n) {
|
||||
lua_assert(isempty(gval(n)));
|
||||
if (keyiswhite(n))
|
||||
setdeadkey(n); /* unused and unmarked key; remove it */
|
||||
if (keyiscollectable(n))
|
||||
setdeadkey(n); /* unused key; remove it */
|
||||
}
|
||||
|
||||
|
||||
|
@ -181,14 +193,17 @@ static int iscleared (global_State *g, const GCObject *o) {
|
|||
|
||||
|
||||
/*
|
||||
** barrier that moves collector forward, that is, mark the white object
|
||||
** 'v' being pointed by the black object 'o'. (If in sweep phase, clear
|
||||
** the black object to white [sweep it] to avoid other barrier calls for
|
||||
** this same object.) In the generational mode, 'v' must also become
|
||||
** old, if 'o' is old; however, it cannot be changed directly to OLD,
|
||||
** because it may still point to non-old objects. So, it is marked as
|
||||
** OLD0. In the next cycle it will become OLD1, and in the next it
|
||||
** will finally become OLD (regular old).
|
||||
** Barrier that moves collector forward, that is, marks the white object
|
||||
** 'v' being pointed by the black object 'o'. In the generational
|
||||
** mode, 'v' must also become old, if 'o' is old; however, it cannot
|
||||
** be changed directly to OLD, because it may still point to non-old
|
||||
** objects. So, it is marked as OLD0. In the next cycle it will become
|
||||
** OLD1, and in the next it will finally become OLD (regular old). By
|
||||
** then, any object it points to will also be old. If called in the
|
||||
** incremental sweep phase, it clears the black object to white (sweep
|
||||
** it) to avoid other barrier calls for this same object. (That cannot
|
||||
** be done is generational mode, as its sweep does not distinguish
|
||||
** whites from deads.)
|
||||
*/
|
||||
void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
|
||||
global_State *g = G(L);
|
||||
|
@ -202,7 +217,8 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
|
|||
}
|
||||
else { /* sweep phase */
|
||||
lua_assert(issweepphase(g));
|
||||
makewhite(g, o); /* mark main obj. as white to avoid other barriers */
|
||||
if (g->gckind == KGC_INC) /* incremental mode? */
|
||||
makewhite(g, o); /* mark 'o' as white to avoid other barriers */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,10 +230,12 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
|
|||
void luaC_barrierback_ (lua_State *L, GCObject *o) {
|
||||
global_State *g = G(L);
|
||||
lua_assert(isblack(o) && !isdead(g, o));
|
||||
lua_assert(g->gckind != KGC_GEN || (isold(o) && getage(o) != G_TOUCHED1));
|
||||
if (getage(o) != G_TOUCHED2) /* not already in gray list? */
|
||||
linkobjgclist(o, g->grayagain); /* link it in 'grayagain' */
|
||||
black2gray(o); /* make object gray (again) */
|
||||
lua_assert((g->gckind == KGC_GEN) == (isold(o) && getage(o) != G_TOUCHED1));
|
||||
if (getage(o) == G_TOUCHED2) /* already in gray list? */
|
||||
set2gray(o); /* make it gray to become touched1 */
|
||||
else /* link it in 'grayagain' and paint it gray */
|
||||
linkobjgclist(o, g->grayagain);
|
||||
if (isold(o)) /* generational mode? */
|
||||
setage(o, G_TOUCHED1); /* touched in current cycle */
|
||||
}
|
||||
|
||||
|
@ -225,7 +243,7 @@ void luaC_barrierback_ (lua_State *L, GCObject *o) {
|
|||
void luaC_fix (lua_State *L, GCObject *o) {
|
||||
global_State *g = G(L);
|
||||
lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */
|
||||
white2gray(o); /* they will be gray forever */
|
||||
set2gray(o); /* they will be gray forever */
|
||||
setage(o, G_OLD); /* and old forever */
|
||||
g->allgc = o->next; /* remove object from 'allgc' list */
|
||||
o->next = g->fixedgc; /* link it to 'fixedgc' list */
|
||||
|
@ -259,24 +277,30 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
|
|||
|
||||
|
||||
/*
|
||||
** Mark an object. Userdata, strings, and closed upvalues are visited
|
||||
** and turned black here. Other objects are marked gray and added
|
||||
** to appropriate list to be visited (and turned black) later. (Open
|
||||
** upvalues are already linked in 'headuv' list. They are kept gray
|
||||
** to avoid barriers, as their values will be revisited by the thread.)
|
||||
** Mark an object. Userdata with no user values, strings, and closed
|
||||
** upvalues are visited and turned black here. Open upvalues are
|
||||
** already indirectly linked through their respective threads in the
|
||||
** 'twups' list, so they don't go to the gray list; nevertheless, they
|
||||
** are kept gray to avoid barriers, as their values will be revisited
|
||||
** by the thread or by 'remarkupvals'. Other objects are added to the
|
||||
** gray list to be visited (and turned black) later. Both userdata and
|
||||
** upvalues can call this function recursively, but this recursion goes
|
||||
** for at most two levels: An upvalue cannot refer to another upvalue
|
||||
** (only closures can), and a userdata's metatable must be a table.
|
||||
*/
|
||||
static void reallymarkobject (global_State *g, GCObject *o) {
|
||||
white2gray(o);
|
||||
switch (o->tt) {
|
||||
case LUA_VSHRSTR:
|
||||
case LUA_VLNGSTR: {
|
||||
gray2black(o);
|
||||
set2black(o); /* nothing to visit */
|
||||
break;
|
||||
}
|
||||
case LUA_VUPVAL: {
|
||||
UpVal *uv = gco2upv(o);
|
||||
if (!upisopen(uv)) /* open upvalues are kept gray */
|
||||
gray2black(o);
|
||||
if (upisopen(uv))
|
||||
set2gray(uv); /* open upvalues are kept gray */
|
||||
else
|
||||
set2black(uv); /* closed upvalues are visited here */
|
||||
markvalue(g, uv->v); /* mark its content */
|
||||
break;
|
||||
}
|
||||
|
@ -284,14 +308,14 @@ static void reallymarkobject (global_State *g, GCObject *o) {
|
|||
Udata *u = gco2u(o);
|
||||
if (u->nuvalue == 0) { /* no user values? */
|
||||
markobjectN(g, u->metatable); /* mark its metatable */
|
||||
gray2black(o); /* nothing else to mark */
|
||||
set2black(u); /* nothing else to mark */
|
||||
break;
|
||||
}
|
||||
/* else... */
|
||||
} /* FALLTHROUGH */
|
||||
case LUA_VLCL: case LUA_VCCL: case LUA_VTABLE:
|
||||
case LUA_VTHREAD: case LUA_VPROTO: {
|
||||
linkobjgclist(o, g->gray);
|
||||
linkobjgclist(o, g->gray); /* to be visited later */
|
||||
break;
|
||||
}
|
||||
default: lua_assert(0); break;
|
||||
|
@ -324,41 +348,54 @@ static lu_mem markbeingfnz (global_State *g) {
|
|||
|
||||
|
||||
/*
|
||||
** Mark all values stored in marked open upvalues from non-marked threads.
|
||||
** (Values from marked threads were already marked when traversing the
|
||||
** thread.) Remove from the list threads that no longer have upvalues and
|
||||
** not-marked threads.
|
||||
** For each non-marked thread, simulates a barrier between each open
|
||||
** upvalue and its value. (If the thread is collected, the value will be
|
||||
** assigned to the upvalue, but then it can be too late for the barrier
|
||||
** to act. The "barrier" does not need to check colors: A non-marked
|
||||
** thread must be young; upvalues cannot be older than their threads; so
|
||||
** any visited upvalue must be young too.) Also removes the thread from
|
||||
** the list, as it was already visited. Removes also threads with no
|
||||
** upvalues, as they have nothing to be checked. (If the thread gets an
|
||||
** upvalue later, it will be linked in the list again.)
|
||||
*/
|
||||
static int remarkupvals (global_State *g) {
|
||||
lua_State *thread;
|
||||
lua_State **p = &g->twups;
|
||||
int work = 0;
|
||||
int work = 0; /* estimate of how much work was done here */
|
||||
while ((thread = *p) != NULL) {
|
||||
work++;
|
||||
lua_assert(!isblack(thread)); /* threads are never black */
|
||||
if (isgray(thread) && thread->openupval != NULL)
|
||||
if (!iswhite(thread) && thread->openupval != NULL)
|
||||
p = &thread->twups; /* keep marked thread with upvalues in the list */
|
||||
else { /* thread is not marked or without upvalues */
|
||||
UpVal *uv;
|
||||
lua_assert(!isold(thread) || thread->openupval == NULL);
|
||||
*p = thread->twups; /* remove thread from the list */
|
||||
thread->twups = thread; /* mark that it is out of list */
|
||||
for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) {
|
||||
lua_assert(getage(uv) <= getage(thread));
|
||||
work++;
|
||||
if (!iswhite(uv)) /* upvalue already visited? */
|
||||
if (!iswhite(uv)) { /* upvalue already visited? */
|
||||
lua_assert(upisopen(uv) && isgray(uv));
|
||||
markvalue(g, uv->v); /* mark its value */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return work;
|
||||
}
|
||||
|
||||
|
||||
static void cleargraylists (global_State *g) {
|
||||
g->gray = g->grayagain = NULL;
|
||||
g->weak = g->allweak = g->ephemeron = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** mark root set and reset all gray lists, to start a new collection
|
||||
*/
|
||||
static void restartcollection (global_State *g) {
|
||||
g->gray = g->grayagain = NULL;
|
||||
g->weak = g->allweak = g->ephemeron = NULL;
|
||||
cleargraylists(g);
|
||||
markobject(g, g->mainthread);
|
||||
markvalue(g, &g->l_registry);
|
||||
markmt(g);
|
||||
|
@ -374,6 +411,26 @@ static void restartcollection (global_State *g) {
|
|||
** =======================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
** Check whether object 'o' should be kept in the 'grayagain' list for
|
||||
** post-processing by 'correctgraylist'. (It could put all old objects
|
||||
** in the list and leave all the work to 'correctgraylist', but it is
|
||||
** more efficient to avoid adding elements that will be removed.) Only
|
||||
** TOUCHED1 objects need to be in the list. TOUCHED2 doesn't need to go
|
||||
** back to a gray list, but then it must become OLD. (That is what
|
||||
** 'correctgraylist' does when it finds a TOUCHED2 object.)
|
||||
*/
|
||||
static void genlink (global_State *g, GCObject *o) {
|
||||
lua_assert(isblack(o));
|
||||
if (getage(o) == G_TOUCHED1) { /* touched in this cycle? */
|
||||
linkobjgclist(o, g->grayagain); /* link it back in 'grayagain' */
|
||||
} /* everything else do not need to be linked back */
|
||||
else if (getage(o) == G_TOUCHED2)
|
||||
changeage(o, G_TOUCHED2, G_OLD); /* advance age */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Traverse a table with weak values and link it to proper list. During
|
||||
** propagate phase, keep it in 'grayagain' list, to be revisited in the
|
||||
|
@ -410,8 +467,9 @@ static void traverseweakvalue (global_State *g, Table *h) {
|
|||
** the atomic phase, if table has any white->white entry, it has to
|
||||
** be revisited during ephemeron convergence (as that key may turn
|
||||
** black). Otherwise, if it has any white key, table has to be cleared
|
||||
** (in the atomic phase). In generational mode, it (like all visited
|
||||
** tables) must be kept in some gray list for post-processing.
|
||||
** (in the atomic phase). In generational mode, some tables
|
||||
** must be kept in some gray list for post-processing; this is done
|
||||
** by 'genlink'.
|
||||
*/
|
||||
static int traverseephemeron (global_State *g, Table *h, int inv) {
|
||||
int marked = 0; /* true if an object is marked in this traversal */
|
||||
|
@ -450,10 +508,8 @@ static int traverseephemeron (global_State *g, Table *h, int inv) {
|
|||
linkgclist(h, g->ephemeron); /* have to propagate again */
|
||||
else if (hasclears) /* table has white keys? */
|
||||
linkgclist(h, g->allweak); /* may have to clean white keys */
|
||||
else if (g->gckind == KGC_GEN)
|
||||
linkgclist(h, g->grayagain); /* keep it in some list */
|
||||
else
|
||||
gray2black(h);
|
||||
genlink(g, obj2gco(h)); /* check whether collector still needs to see it */
|
||||
return marked;
|
||||
}
|
||||
|
||||
|
@ -473,10 +529,7 @@ static void traversestrongtable (global_State *g, Table *h) {
|
|||
markvalue(g, gval(n));
|
||||
}
|
||||
}
|
||||
if (g->gckind == KGC_GEN) {
|
||||
linkgclist(h, g->grayagain); /* keep it in some gray list */
|
||||
black2gray(h);
|
||||
}
|
||||
genlink(g, obj2gco(h));
|
||||
}
|
||||
|
||||
|
||||
|
@ -488,7 +541,6 @@ static lu_mem traversetable (global_State *g, Table *h) {
|
|||
(cast_void(weakkey = strchr(svalue(mode), 'k')),
|
||||
cast_void(weakvalue = strchr(svalue(mode), 'v')),
|
||||
(weakkey || weakvalue))) { /* is really weak? */
|
||||
black2gray(h); /* keep table gray */
|
||||
if (!weakkey) /* strong keys? */
|
||||
traverseweakvalue(g, h);
|
||||
else if (!weakvalue) /* strong values? */
|
||||
|
@ -507,10 +559,7 @@ static int traverseudata (global_State *g, Udata *u) {
|
|||
markobjectN(g, u->metatable); /* mark its metatable */
|
||||
for (i = 0; i < u->nuvalue; i++)
|
||||
markvalue(g, &u->uv[i].uv);
|
||||
if (g->gckind == KGC_GEN) {
|
||||
linkgclist(u, g->grayagain); /* keep it in some gray list */
|
||||
black2gray(u);
|
||||
}
|
||||
genlink(g, obj2gco(u));
|
||||
return 1 + u->nuvalue;
|
||||
}
|
||||
|
||||
|
@ -559,12 +608,21 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
|
|||
|
||||
/*
|
||||
** Traverse a thread, marking the elements in the stack up to its top
|
||||
** and cleaning the rest of the stack in the final traversal.
|
||||
** That ensures that the entire stack have valid (non-dead) objects.
|
||||
** and cleaning the rest of the stack in the final traversal. That
|
||||
** ensures that the entire stack have valid (non-dead) objects.
|
||||
** Threads have no barriers. In gen. mode, old threads must be visited
|
||||
** at every cycle, because they might point to young objects. In inc.
|
||||
** mode, the thread can still be modified before the end of the cycle,
|
||||
** and therefore it must be visited again in the atomic phase. To ensure
|
||||
** these visits, threads must return to a gray list if they are not new
|
||||
** (which can only happen in generational mode) or if the traverse is in
|
||||
** the propagate phase (which can only happen in incremental mode).
|
||||
*/
|
||||
static int traversethread (global_State *g, lua_State *th) {
|
||||
UpVal *uv;
|
||||
StkId o = th->stack;
|
||||
if (isold(th) || g->gcstate == GCSpropagate)
|
||||
linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
|
||||
if (o == NULL)
|
||||
return 1; /* stack not completely built yet */
|
||||
lua_assert(g->gcstate == GCSatomic ||
|
||||
|
@ -574,9 +632,8 @@ static int traversethread (global_State *g, lua_State *th) {
|
|||
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
|
||||
markobject(g, uv); /* open upvalues cannot be collected */
|
||||
if (g->gcstate == GCSatomic) { /* final traversal? */
|
||||
StkId lim = th->stack + th->stacksize; /* real end of stack */
|
||||
for (; o < lim; o++) /* clear not-marked stack slice */
|
||||
setnilvalue(s2v(o));
|
||||
for (; o < th->stack_last + EXTRA_STACK; o++)
|
||||
setnilvalue(s2v(o)); /* clear dead stack slice */
|
||||
/* 'remarkupvals' may have removed thread from 'twups' list */
|
||||
if (!isintwups(th) && th->openupval != NULL) {
|
||||
th->twups = g->twups; /* link it back to the list */
|
||||
|
@ -585,17 +642,16 @@ static int traversethread (global_State *g, lua_State *th) {
|
|||
}
|
||||
else if (!g->gcemergency)
|
||||
luaD_shrinkstack(th); /* do not change stack in emergency cycle */
|
||||
return 1 + th->stacksize;
|
||||
return 1 + stacksize(th);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** traverse one gray object, turning it to black (except for threads,
|
||||
** which are always gray).
|
||||
** traverse one gray object, turning it to black.
|
||||
*/
|
||||
static lu_mem propagatemark (global_State *g) {
|
||||
GCObject *o = g->gray;
|
||||
gray2black(o);
|
||||
nw2black(o);
|
||||
g->gray = *getgclist(o); /* remove from 'gray' list */
|
||||
switch (o->tt) {
|
||||
case LUA_VTABLE: return traversetable(g, gco2t(o));
|
||||
|
@ -603,12 +659,7 @@ static lu_mem propagatemark (global_State *g) {
|
|||
case LUA_VLCL: return traverseLclosure(g, gco2lcl(o));
|
||||
case LUA_VCCL: return traverseCclosure(g, gco2ccl(o));
|
||||
case LUA_VPROTO: return traverseproto(g, gco2p(o));
|
||||
case LUA_VTHREAD: {
|
||||
lua_State *th = gco2th(o);
|
||||
linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
|
||||
black2gray(o);
|
||||
return traversethread(g, th);
|
||||
}
|
||||
case LUA_VTHREAD: return traversethread(g, gco2th(o));
|
||||
default: lua_assert(0); return 0;
|
||||
}
|
||||
}
|
||||
|
@ -638,8 +689,10 @@ static void convergeephemerons (global_State *g) {
|
|||
g->ephemeron = NULL; /* tables may return to this list when traversed */
|
||||
changed = 0;
|
||||
while ((w = next) != NULL) { /* for each ephemeron table */
|
||||
next = gco2t(w)->gclist; /* list is rebuilt during loop */
|
||||
if (traverseephemeron(g, gco2t(w), dir)) { /* marked some value? */
|
||||
Table *h = gco2t(w);
|
||||
next = h->gclist; /* list is rebuilt during loop */
|
||||
nw2black(h); /* out of the list (for now) */
|
||||
if (traverseephemeron(g, h, dir)) { /* marked some value? */
|
||||
propagateall(g); /* propagate changes */
|
||||
changed = 1; /* will have to revisit all ephemeron tables */
|
||||
}
|
||||
|
@ -716,12 +769,16 @@ static void freeobj (lua_State *L, GCObject *o) {
|
|||
case LUA_VUPVAL:
|
||||
freeupval(L, gco2upv(o));
|
||||
break;
|
||||
case LUA_VLCL:
|
||||
luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues));
|
||||
case LUA_VLCL: {
|
||||
LClosure *cl = gco2lcl(o);
|
||||
luaM_freemem(L, cl, sizeLclosure(cl->nupvalues));
|
||||
break;
|
||||
case LUA_VCCL:
|
||||
luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues));
|
||||
}
|
||||
case LUA_VCCL: {
|
||||
CClosure *cl = gco2ccl(o);
|
||||
luaM_freemem(L, cl, sizeCclosure(cl->nupvalues));
|
||||
break;
|
||||
}
|
||||
case LUA_VTABLE:
|
||||
luaH_free(L, gco2t(o));
|
||||
break;
|
||||
|
@ -733,13 +790,17 @@ static void freeobj (lua_State *L, GCObject *o) {
|
|||
luaM_freemem(L, o, sizeudata(u->nuvalue, u->len));
|
||||
break;
|
||||
}
|
||||
case LUA_VSHRSTR:
|
||||
luaS_remove(L, gco2ts(o)); /* remove it from hash table */
|
||||
luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen));
|
||||
case LUA_VSHRSTR: {
|
||||
TString *ts = gco2ts(o);
|
||||
luaS_remove(L, ts); /* remove it from hash table */
|
||||
luaM_freemem(L, ts, sizelstring(ts->shrlen));
|
||||
break;
|
||||
case LUA_VLNGSTR:
|
||||
luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen));
|
||||
}
|
||||
case LUA_VLNGSTR: {
|
||||
TString *ts = gco2ts(o);
|
||||
luaM_freemem(L, ts, sizelstring(ts->u.lnglen));
|
||||
break;
|
||||
}
|
||||
default: lua_assert(0);
|
||||
}
|
||||
}
|
||||
|
@ -766,7 +827,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int countin,
|
|||
freeobj(L, curr); /* erase 'curr' */
|
||||
}
|
||||
else { /* change mark to 'white' */
|
||||
curr->marked = cast_byte((marked & maskcolors) | white);
|
||||
curr->marked = cast_byte((marked & ~maskgcbits) | white);
|
||||
p = &curr->next; /* go to next element */
|
||||
}
|
||||
}
|
||||
|
@ -823,6 +884,8 @@ static GCObject *udata2finalize (global_State *g) {
|
|||
resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */
|
||||
if (issweepphase(g))
|
||||
makewhite(g, o); /* "sweep" object */
|
||||
else if (getage(o) == G_OLD1)
|
||||
g->firstold1 = o; /* it is the first OLD1 object in the list */
|
||||
return o;
|
||||
}
|
||||
|
||||
|
@ -853,7 +916,7 @@ static void GCTM (lua_State *L) {
|
|||
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
|
||||
L->allowhook = oldah; /* restore hooks */
|
||||
g->gcrunning = running; /* restore state */
|
||||
if (unlikely(status != LUA_OK)) { /* error while running __gc? */
|
||||
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
|
||||
luaE_warnerror(L, "__gc metamethod");
|
||||
L->top--; /* pops error object */
|
||||
}
|
||||
|
@ -896,15 +959,15 @@ static GCObject **findlast (GCObject **p) {
|
|||
/*
|
||||
** Move all unreachable objects (or 'all' objects) that need
|
||||
** finalization from list 'finobj' to list 'tobefnz' (to be finalized).
|
||||
** (Note that objects after 'finobjold' cannot be white, so they
|
||||
** don't need to be traversed. In incremental mode, 'finobjold' is NULL,
|
||||
** (Note that objects after 'finobjold1' cannot be white, so they
|
||||
** don't need to be traversed. In incremental mode, 'finobjold1' is NULL,
|
||||
** so the whole list is traversed.)
|
||||
*/
|
||||
static void separatetobefnz (global_State *g, int all) {
|
||||
GCObject *curr;
|
||||
GCObject **p = &g->finobj;
|
||||
GCObject **lastnext = findlast(&g->tobefnz);
|
||||
while ((curr = *p) != g->finobjold) { /* traverse all finalizable objects */
|
||||
while ((curr = *p) != g->finobjold1) { /* traverse all finalizable objects */
|
||||
lua_assert(tofinalize(curr));
|
||||
if (!(iswhite(curr) || all)) /* not being collected? */
|
||||
p = &curr->next; /* don't bother with it */
|
||||
|
@ -920,6 +983,27 @@ static void separatetobefnz (global_State *g, int all) {
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
** If pointer 'p' points to 'o', move it to the next element.
|
||||
*/
|
||||
static void checkpointer (GCObject **p, GCObject *o) {
|
||||
if (o == *p)
|
||||
*p = o->next;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Correct pointers to objects inside 'allgc' list when
|
||||
** object 'o' is being removed from the list.
|
||||
*/
|
||||
static void correctpointers (global_State *g, GCObject *o) {
|
||||
checkpointer(&g->survival, o);
|
||||
checkpointer(&g->old1, o);
|
||||
checkpointer(&g->reallyold, o);
|
||||
checkpointer(&g->firstold1, o);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** if object 'o' has a finalizer, remove it from 'allgc' list (must
|
||||
** search the list to find it) and link it in 'finobj' list.
|
||||
|
@ -936,14 +1020,8 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
|
|||
if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */
|
||||
g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */
|
||||
}
|
||||
else { /* correct pointers into 'allgc' list, if needed */
|
||||
if (o == g->survival)
|
||||
g->survival = o->next;
|
||||
if (o == g->old)
|
||||
g->old = o->next;
|
||||
if (o == g->reallyold)
|
||||
g->reallyold = o->next;
|
||||
}
|
||||
else
|
||||
correctpointers(g, o);
|
||||
/* search for pointer pointing to 'o' */
|
||||
for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ }
|
||||
*p = o->next; /* remove 'o' from 'allgc' list */
|
||||
|
@ -965,24 +1043,31 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
|
|||
static void setpause (global_State *g);
|
||||
|
||||
|
||||
/* mask to erase all color bits, not changing gen-related stuff */
|
||||
#define maskgencolors (~(bitmask(BLACKBIT) | WHITEBITS))
|
||||
|
||||
|
||||
/*
|
||||
** Sweep a list of objects, deleting dead ones and turning
|
||||
** the non dead to old (without changing their colors).
|
||||
** Sweep a list of objects to enter generational mode. Deletes dead
|
||||
** objects and turns the non dead to old. All non-dead threads---which
|
||||
** are now old---must be in a gray list. Everything else is not in a
|
||||
** gray list. Open upvalues are also kept gray.
|
||||
*/
|
||||
static void sweep2old (lua_State *L, GCObject **p) {
|
||||
GCObject *curr;
|
||||
global_State *g = G(L);
|
||||
while ((curr = *p) != NULL) {
|
||||
if (iswhite(curr)) { /* is 'curr' dead? */
|
||||
lua_assert(isdead(G(L), curr));
|
||||
lua_assert(isdead(g, curr));
|
||||
*p = curr->next; /* remove 'curr' from list */
|
||||
freeobj(L, curr); /* erase 'curr' */
|
||||
}
|
||||
else { /* all surviving objects become old */
|
||||
setage(curr, G_OLD);
|
||||
if (curr->tt == LUA_VTHREAD) { /* threads must be watched */
|
||||
lua_State *th = gco2th(curr);
|
||||
linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
|
||||
}
|
||||
else if (curr->tt == LUA_VUPVAL && upisopen(gco2upv(curr)))
|
||||
set2gray(curr); /* open upvalues are always gray */
|
||||
else /* everything else is black */
|
||||
nw2black(curr);
|
||||
p = &curr->next; /* go to next element */
|
||||
}
|
||||
}
|
||||
|
@ -995,9 +1080,13 @@ static void sweep2old (lua_State *L, GCObject **p) {
|
|||
** during the sweep. So, any white object must be dead.) For
|
||||
** non-dead objects, advance their ages and clear the color of
|
||||
** new objects. (Old objects keep their colors.)
|
||||
** The ages of G_TOUCHED1 and G_TOUCHED2 objects cannot be advanced
|
||||
** here, because these old-generation objects are usually not swept
|
||||
** here. They will all be advanced in 'correctgraylist'. That function
|
||||
** will also remove objects turned white here from any gray list.
|
||||
*/
|
||||
static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
|
||||
GCObject *limit) {
|
||||
GCObject *limit, GCObject **pfirstold1) {
|
||||
static const lu_byte nextage[] = {
|
||||
G_SURVIVAL, /* from G_NEW */
|
||||
G_OLD1, /* from G_SURVIVAL */
|
||||
|
@ -1016,9 +1105,15 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
|
|||
freeobj(L, curr); /* erase 'curr' */
|
||||
}
|
||||
else { /* correct mark and age */
|
||||
if (getage(curr) == G_NEW)
|
||||
curr->marked = cast_byte((curr->marked & maskgencolors) | white);
|
||||
if (getage(curr) == G_NEW) { /* new objects go back to white */
|
||||
int marked = curr->marked & ~maskgcbits; /* erase GC bits */
|
||||
curr->marked = cast_byte(marked | G_SURVIVAL | white);
|
||||
}
|
||||
else { /* all other objects will be old, and so keep their color */
|
||||
setage(curr, nextage[getage(curr)]);
|
||||
if (getage(curr) == G_OLD1 && *pfirstold1 == NULL)
|
||||
*pfirstold1 = curr; /* first OLD1 object in the list */
|
||||
}
|
||||
p = &curr->next; /* go to next element */
|
||||
}
|
||||
}
|
||||
|
@ -1028,58 +1123,50 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
|
|||
|
||||
/*
|
||||
** Traverse a list making all its elements white and clearing their
|
||||
** age.
|
||||
** age. In incremental mode, all objects are 'new' all the time,
|
||||
** except for fixed strings (which are always old).
|
||||
*/
|
||||
static void whitelist (global_State *g, GCObject *p) {
|
||||
int white = luaC_white(g);
|
||||
for (; p != NULL; p = p->next)
|
||||
p->marked = cast_byte((p->marked & maskcolors) | white);
|
||||
p->marked = cast_byte((p->marked & ~maskgcbits) | white);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Correct a list of gray objects.
|
||||
** Correct a list of gray objects. Return pointer to where rest of the
|
||||
** list should be linked.
|
||||
** Because this correction is done after sweeping, young objects might
|
||||
** be turned white and still be in the list. They are only removed.
|
||||
** For tables and userdata, advance 'touched1' to 'touched2'; 'touched2'
|
||||
** objects become regular old and are removed from the list.
|
||||
** For threads, just remove white ones from the list.
|
||||
** 'TOUCHED1' objects are advanced to 'TOUCHED2' and remain on the list;
|
||||
** Non-white threads also remain on the list; 'TOUCHED2' objects become
|
||||
** regular old; they and anything else are removed from the list.
|
||||
*/
|
||||
static GCObject **correctgraylist (GCObject **p) {
|
||||
GCObject *curr;
|
||||
while ((curr = *p) != NULL) {
|
||||
switch (curr->tt) {
|
||||
case LUA_VTABLE: case LUA_VUSERDATA: {
|
||||
GCObject **next = getgclist(curr);
|
||||
if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */
|
||||
if (iswhite(curr))
|
||||
goto remove; /* remove all white objects */
|
||||
else if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */
|
||||
lua_assert(isgray(curr));
|
||||
gray2black(curr); /* make it black, for next barrier */
|
||||
nw2black(curr); /* make it black, for next barrier */
|
||||
changeage(curr, G_TOUCHED1, G_TOUCHED2);
|
||||
p = next; /* go to next element */
|
||||
goto remain; /* keep it in the list and go to next element */
|
||||
}
|
||||
else { /* not touched in this cycle */
|
||||
if (!iswhite(curr)) { /* not white? */
|
||||
lua_assert(isold(curr));
|
||||
if (getage(curr) == G_TOUCHED2) /* advance from G_TOUCHED2... */
|
||||
changeage(curr, G_TOUCHED2, G_OLD); /* ... to G_OLD */
|
||||
gray2black(curr); /* make it black */
|
||||
else if (curr->tt == LUA_VTHREAD) {
|
||||
lua_assert(isgray(curr));
|
||||
goto remain; /* keep non-white threads on the list */
|
||||
}
|
||||
/* else, object is white: just remove it from this list */
|
||||
*p = *next; /* remove 'curr' from gray list */
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LUA_VTHREAD: {
|
||||
lua_State *th = gco2th(curr);
|
||||
lua_assert(!isblack(th));
|
||||
if (iswhite(th)) /* new object? */
|
||||
*p = th->gclist; /* remove from gray list */
|
||||
else /* old threads remain gray */
|
||||
p = &th->gclist; /* go to next element */
|
||||
break;
|
||||
}
|
||||
default: lua_assert(0); /* nothing more could be gray here */
|
||||
else { /* everything else is removed */
|
||||
lua_assert(isold(curr)); /* young objects should be white here */
|
||||
if (getage(curr) == G_TOUCHED2) /* advance from TOUCHED2... */
|
||||
changeage(curr, G_TOUCHED2, G_OLD); /* ... to OLD */
|
||||
nw2black(curr); /* make object black (to be removed) */
|
||||
goto remove;
|
||||
}
|
||||
remove: *p = *next; continue;
|
||||
remain: p = next; continue;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
@ -1100,7 +1187,7 @@ static void correctgraylists (global_State *g) {
|
|||
|
||||
|
||||
/*
|
||||
** Mark 'OLD1' objects when starting a new young collection.
|
||||
** Mark black 'OLD1' objects when starting a new young collection.
|
||||
** Gray objects are already in some gray list, and so will be visited
|
||||
** in the atomic step.
|
||||
*/
|
||||
|
@ -1109,13 +1196,12 @@ static void markold (global_State *g, GCObject *from, GCObject *to) {
|
|||
for (p = from; p != to; p = p->next) {
|
||||
if (getage(p) == G_OLD1) {
|
||||
lua_assert(!iswhite(p));
|
||||
if (isblack(p)) {
|
||||
black2gray(p); /* should be '2white', but gray works too */
|
||||
changeage(p, G_OLD1, G_OLD); /* now they are old */
|
||||
if (isblack(p))
|
||||
reallymarkobject(g, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
@ -1131,50 +1217,63 @@ static void finishgencycle (lua_State *L, global_State *g) {
|
|||
|
||||
|
||||
/*
|
||||
** Does a young collection. First, mark 'OLD1' objects. (Only survival
|
||||
** and "recent old" lists can contain 'OLD1' objects. New lists cannot
|
||||
** contain 'OLD1' objects, at most 'OLD0' objects that were already
|
||||
** visited when marked old.) Then does the atomic step. Then,
|
||||
** sweep all lists and advance pointers. Finally, finish the collection.
|
||||
** Does a young collection. First, mark 'OLD1' objects. Then does the
|
||||
** atomic step. Then, sweep all lists and advance pointers. Finally,
|
||||
** finish the collection.
|
||||
*/
|
||||
static void youngcollection (lua_State *L, global_State *g) {
|
||||
GCObject **psurvival; /* to point to first non-dead survival object */
|
||||
GCObject *dummy; /* dummy out parameter to 'sweepgen' */
|
||||
lua_assert(g->gcstate == GCSpropagate);
|
||||
markold(g, g->survival, g->reallyold);
|
||||
if (g->firstold1) { /* are there regular OLD1 objects? */
|
||||
markold(g, g->firstold1, g->reallyold); /* mark them */
|
||||
g->firstold1 = NULL; /* no more OLD1 objects (for now) */
|
||||
}
|
||||
markold(g, g->finobj, g->finobjrold);
|
||||
markold(g, g->tobefnz, NULL);
|
||||
atomic(L);
|
||||
|
||||
/* sweep nursery and get a pointer to its last live element */
|
||||
psurvival = sweepgen(L, g, &g->allgc, g->survival);
|
||||
/* sweep 'survival' and 'old' */
|
||||
sweepgen(L, g, psurvival, g->reallyold);
|
||||
g->reallyold = g->old;
|
||||
g->old = *psurvival; /* 'survival' survivals are old now */
|
||||
g->gcstate = GCSswpallgc;
|
||||
psurvival = sweepgen(L, g, &g->allgc, g->survival, &g->firstold1);
|
||||
/* sweep 'survival' */
|
||||
sweepgen(L, g, psurvival, g->old1, &g->firstold1);
|
||||
g->reallyold = g->old1;
|
||||
g->old1 = *psurvival; /* 'survival' survivals are old now */
|
||||
g->survival = g->allgc; /* all news are survivals */
|
||||
|
||||
/* repeat for 'finobj' lists */
|
||||
psurvival = sweepgen(L, g, &g->finobj, g->finobjsur);
|
||||
/* sweep 'survival' and 'old' */
|
||||
sweepgen(L, g, psurvival, g->finobjrold);
|
||||
g->finobjrold = g->finobjold;
|
||||
g->finobjold = *psurvival; /* 'survival' survivals are old now */
|
||||
dummy = NULL; /* no 'firstold1' optimization for 'finobj' lists */
|
||||
psurvival = sweepgen(L, g, &g->finobj, g->finobjsur, &dummy);
|
||||
/* sweep 'survival' */
|
||||
sweepgen(L, g, psurvival, g->finobjold1, &dummy);
|
||||
g->finobjrold = g->finobjold1;
|
||||
g->finobjold1 = *psurvival; /* 'survival' survivals are old now */
|
||||
g->finobjsur = g->finobj; /* all news are survivals */
|
||||
|
||||
sweepgen(L, g, &g->tobefnz, NULL);
|
||||
|
||||
sweepgen(L, g, &g->tobefnz, NULL, &dummy);
|
||||
finishgencycle(L, g);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Clears all gray lists, sweeps objects, and prepare sublists to enter
|
||||
** generational mode. The sweeps remove dead objects and turn all
|
||||
** surviving objects to old. Threads go back to 'grayagain'; everything
|
||||
** else is turned black (not in any gray list).
|
||||
*/
|
||||
static void atomic2gen (lua_State *L, global_State *g) {
|
||||
cleargraylists(g);
|
||||
/* sweep all elements making them old */
|
||||
g->gcstate = GCSswpallgc;
|
||||
sweep2old(L, &g->allgc);
|
||||
/* everything alive now is old */
|
||||
g->reallyold = g->old = g->survival = g->allgc;
|
||||
g->reallyold = g->old1 = g->survival = g->allgc;
|
||||
g->firstold1 = NULL; /* there are no OLD1 objects anywhere */
|
||||
|
||||
/* repeat for 'finobj' lists */
|
||||
sweep2old(L, &g->finobj);
|
||||
g->finobjrold = g->finobjold = g->finobjsur = g->finobj;
|
||||
g->finobjrold = g->finobjold1 = g->finobjsur = g->finobj;
|
||||
|
||||
sweep2old(L, &g->tobefnz);
|
||||
|
||||
|
@ -1187,8 +1286,9 @@ static void atomic2gen (lua_State *L, global_State *g) {
|
|||
|
||||
/*
|
||||
** Enter generational mode. Must go until the end of an atomic cycle
|
||||
** to ensure that all threads and weak tables are in the gray lists.
|
||||
** Then, turn all objects into old and finishes the collection.
|
||||
** to ensure that all objects are correctly marked and weak tables
|
||||
** are cleared. Then, turn all objects into old and finishes the
|
||||
** collection.
|
||||
*/
|
||||
static lu_mem entergen (lua_State *L, global_State *g) {
|
||||
lu_mem numobjs;
|
||||
|
@ -1207,10 +1307,10 @@ static lu_mem entergen (lua_State *L, global_State *g) {
|
|||
*/
|
||||
static void enterinc (global_State *g) {
|
||||
whitelist(g, g->allgc);
|
||||
g->reallyold = g->old = g->survival = NULL;
|
||||
g->reallyold = g->old1 = g->survival = NULL;
|
||||
whitelist(g, g->finobj);
|
||||
whitelist(g, g->tobefnz);
|
||||
g->finobjrold = g->finobjold = g->finobjsur = NULL;
|
||||
g->finobjrold = g->finobjold1 = g->finobjsur = NULL;
|
||||
g->gcstate = GCSpause;
|
||||
g->gckind = KGC_INC;
|
||||
g->lastatomic = 0;
|
||||
|
@ -1475,52 +1575,64 @@ static int sweepstep (lua_State *L, global_State *g,
|
|||
|
||||
static lu_mem singlestep (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
lu_mem work;
|
||||
lua_assert(!g->gcstopem); /* collector is not reentrant */
|
||||
g->gcstopem = 1; /* no emergency collections while collecting */
|
||||
switch (g->gcstate) {
|
||||
case GCSpause: {
|
||||
restartcollection(g);
|
||||
g->gcstate = GCSpropagate;
|
||||
return 1;
|
||||
work = 1;
|
||||
break;
|
||||
}
|
||||
case GCSpropagate: {
|
||||
if (g->gray == NULL) { /* no more gray objects? */
|
||||
g->gcstate = GCSenteratomic; /* finish propagate phase */
|
||||
return 0;
|
||||
work = 0;
|
||||
}
|
||||
else
|
||||
return propagatemark(g); /* traverse one gray object */
|
||||
work = propagatemark(g); /* traverse one gray object */
|
||||
break;
|
||||
}
|
||||
case GCSenteratomic: {
|
||||
lu_mem work = atomic(L); /* work is what was traversed by 'atomic' */
|
||||
work = atomic(L); /* work is what was traversed by 'atomic' */
|
||||
entersweep(L);
|
||||
g->GCestimate = gettotalbytes(g); /* first estimate */;
|
||||
return work;
|
||||
break;
|
||||
}
|
||||
case GCSswpallgc: { /* sweep "regular" objects */
|
||||
return sweepstep(L, g, GCSswpfinobj, &g->finobj);
|
||||
work = sweepstep(L, g, GCSswpfinobj, &g->finobj);
|
||||
break;
|
||||
}
|
||||
case GCSswpfinobj: { /* sweep objects with finalizers */
|
||||
return sweepstep(L, g, GCSswptobefnz, &g->tobefnz);
|
||||
work = sweepstep(L, g, GCSswptobefnz, &g->tobefnz);
|
||||
break;
|
||||
}
|
||||
case GCSswptobefnz: { /* sweep objects to be finalized */
|
||||
return sweepstep(L, g, GCSswpend, NULL);
|
||||
work = sweepstep(L, g, GCSswpend, NULL);
|
||||
break;
|
||||
}
|
||||
case GCSswpend: { /* finish sweeps */
|
||||
checkSizes(L, g);
|
||||
g->gcstate = GCScallfin;
|
||||
return 0;
|
||||
work = 0;
|
||||
break;
|
||||
}
|
||||
case GCScallfin: { /* call remaining finalizers */
|
||||
if (g->tobefnz && !g->gcemergency) {
|
||||
int n = runafewfinalizers(L, GCFINMAX);
|
||||
return n * GCFINALIZECOST;
|
||||
g->gcstopem = 0; /* ok collections during finalizers */
|
||||
work = runafewfinalizers(L, GCFINMAX) * GCFINALIZECOST;
|
||||
}
|
||||
else { /* emergency mode or no more finalizers */
|
||||
g->gcstate = GCSpause; /* finish collection */
|
||||
return 0;
|
||||
work = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: lua_assert(0); return 0;
|
||||
}
|
||||
g->gcstopem = 0;
|
||||
return work;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -12,16 +12,16 @@
|
|||
#include "lstate.h"
|
||||
|
||||
/*
|
||||
** Collectable objects may have one of three colors: white, which
|
||||
** means the object is not marked; gray, which means the
|
||||
** object is marked, but its references may be not marked; and
|
||||
** black, which means that the object and all its references are marked.
|
||||
** The main invariant of the garbage collector, while marking objects,
|
||||
** is that a black object can never point to a white one. Moreover,
|
||||
** any gray object must be in a "gray list" (gray, grayagain, weak,
|
||||
** allweak, ephemeron) so that it can be visited again before finishing
|
||||
** the collection cycle. These lists have no meaning when the invariant
|
||||
** is not being enforced (e.g., sweep phase).
|
||||
** Collectable objects may have one of three colors: white, which means
|
||||
** the object is not marked; gray, which means the object is marked, but
|
||||
** its references may be not marked; and black, which means that the
|
||||
** object and all its references are marked. The main invariant of the
|
||||
** garbage collector, while marking objects, is that a black object can
|
||||
** never point to a white one. Moreover, any gray object must be in a
|
||||
** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it
|
||||
** can be visited again before finishing the collection cycle. (Open
|
||||
** upvalues are an exception to this rule.) These lists have no meaning
|
||||
** when the invariant is not being enforced (e.g., sweep phase).
|
||||
*/
|
||||
|
||||
|
||||
|
@ -69,14 +69,16 @@
|
|||
|
||||
/*
|
||||
** Layout for bit use in 'marked' field. First three bits are
|
||||
** used for object "age" in generational mode. Last bit is free
|
||||
** to be used by respective objects.
|
||||
** used for object "age" in generational mode. Last bit is used
|
||||
** by tests.
|
||||
*/
|
||||
#define WHITE0BIT 3 /* object is white (type 0) */
|
||||
#define WHITE1BIT 4 /* object is white (type 1) */
|
||||
#define BLACKBIT 5 /* object is black */
|
||||
#define FINALIZEDBIT 6 /* object has been marked for finalization */
|
||||
|
||||
#define TESTBIT 7
|
||||
|
||||
|
||||
|
||||
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
|
||||
|
@ -94,7 +96,8 @@
|
|||
#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked)
|
||||
|
||||
#define changewhite(x) ((x)->marked ^= WHITEBITS)
|
||||
#define gray2black(x) l_setbit((x)->marked, BLACKBIT)
|
||||
#define nw2black(x) \
|
||||
check_exp(!iswhite(x), l_setbit((x)->marked, BLACKBIT))
|
||||
|
||||
#define luaC_white(g) cast_byte((g)->currentwhite & WHITEBITS)
|
||||
|
||||
|
|
|
@ -64,6 +64,12 @@ static int l_checkmode (const char *mode) {
|
|||
#define l_popen(L,c,m) (_popen(c,m))
|
||||
#define l_pclose(L,file) (_pclose(file))
|
||||
|
||||
#if !defined(l_checkmodep)
|
||||
/* Windows accepts "[rw][bt]?" as valid modes */
|
||||
#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && \
|
||||
(m[1] == '\0' || ((m[1] == 'b' || m[1] == 't') && m[2] == '\0')))
|
||||
#endif
|
||||
|
||||
#else /* }{ */
|
||||
|
||||
/* ISO C definitions */
|
||||
|
@ -77,6 +83,12 @@ static int l_checkmode (const char *mode) {
|
|||
|
||||
#endif /* } */
|
||||
|
||||
|
||||
#if !defined(l_checkmodep)
|
||||
/* By default, Lua accepts only "r" or "w" as valid modes */
|
||||
#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && m[1] == '\0')
|
||||
#endif
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
|
@ -174,7 +186,7 @@ static int f_tostring (lua_State *L) {
|
|||
|
||||
static FILE *tofile (lua_State *L) {
|
||||
LStream *p = tolstream(L);
|
||||
if (isclosed(p))
|
||||
if (l_unlikely(isclosed(p)))
|
||||
luaL_error(L, "attempt to use a closed file");
|
||||
lua_assert(p->f);
|
||||
return p->f;
|
||||
|
@ -249,7 +261,7 @@ static LStream *newfile (lua_State *L) {
|
|||
static void opencheck (lua_State *L, const char *fname, const char *mode) {
|
||||
LStream *p = newfile(L);
|
||||
p->f = fopen(fname, mode);
|
||||
if (p->f == NULL)
|
||||
if (l_unlikely(p->f == NULL))
|
||||
luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno));
|
||||
}
|
||||
|
||||
|
@ -279,6 +291,7 @@ static int io_popen (lua_State *L) {
|
|||
const char *filename = luaL_checkstring(L, 1);
|
||||
const char *mode = luaL_optstring(L, 2, "r");
|
||||
LStream *p = newprefile(L);
|
||||
luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode");
|
||||
p->f = l_popen(L, filename, mode);
|
||||
p->closef = &io_pclose;
|
||||
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
|
||||
|
@ -296,7 +309,7 @@ static FILE *getiofile (lua_State *L, const char *findex) {
|
|||
LStream *p;
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, findex);
|
||||
p = (LStream *)lua_touserdata(L, -1);
|
||||
if (isclosed(p))
|
||||
if (l_unlikely(isclosed(p)))
|
||||
luaL_error(L, "default %s file is closed", findex + IOPREF_LEN);
|
||||
return p->f;
|
||||
}
|
||||
|
@ -423,7 +436,7 @@ typedef struct {
|
|||
** Add current char to buffer (if not out of space) and read next one
|
||||
*/
|
||||
static int nextc (RN *rn) {
|
||||
if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */
|
||||
if (l_unlikely(rn->n >= L_MAXLENNUM)) { /* buffer overflow? */
|
||||
rn->buff[0] = '\0'; /* invalidate result */
|
||||
return 0; /* fail */
|
||||
}
|
||||
|
@ -486,8 +499,8 @@ static int read_number (lua_State *L, FILE *f) {
|
|||
ungetc(rn.c, rn.f); /* unread look-ahead char */
|
||||
l_unlockfile(rn.f);
|
||||
rn.buff[rn.n] = '\0'; /* finish string */
|
||||
if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */
|
||||
return 1; /* ok */
|
||||
if (l_likely(lua_stringtonumber(L, rn.buff)))
|
||||
return 1; /* ok, it is a valid number */
|
||||
else { /* invalid format */
|
||||
lua_pushnil(L); /* "result" to be removed */
|
||||
return 0; /* read fails */
|
||||
|
@ -663,7 +676,8 @@ static int g_write (lua_State *L, FILE *f, int arg) {
|
|||
status = status && (fwrite(s, sizeof(char), l, f) == l);
|
||||
}
|
||||
}
|
||||
if (status) return 1; /* file handle already on stack top */
|
||||
if (l_likely(status))
|
||||
return 1; /* file handle already on stack top */
|
||||
else return luaL_fileresult(L, status, NULL);
|
||||
}
|
||||
|
||||
|
@ -690,7 +704,7 @@ static int f_seek (lua_State *L) {
|
|||
luaL_argcheck(L, (lua_Integer)offset == p3, 3,
|
||||
"not an integer in proper range");
|
||||
op = l_fseek(f, offset, mode[op]);
|
||||
if (op)
|
||||
if (l_unlikely(op))
|
||||
return luaL_fileresult(L, 0, NULL); /* error */
|
||||
else {
|
||||
lua_pushinteger(L, (lua_Integer)l_ftell(f));
|
||||
|
|
|
@ -81,7 +81,6 @@ void luaX_init (lua_State *L) {
|
|||
|
||||
const char *luaX_token2str (LexState *ls, int token) {
|
||||
if (token < FIRST_RESERVED) { /* single-byte symbols? */
|
||||
lua_assert(token == cast_uchar(token));
|
||||
if (lisprint(token))
|
||||
return luaO_pushfstring(ls->L, "'%c'", token);
|
||||
else /* control character */
|
||||
|
@ -123,26 +122,29 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
|
|||
|
||||
|
||||
/*
|
||||
** creates a new string and anchors it in scanner's table so that
|
||||
** it will not be collected until the end of the compilation
|
||||
** (by that time it should be anchored somewhere)
|
||||
** Creates a new string and anchors it in scanner's table so that it
|
||||
** will not be collected until the end of the compilation; by that time
|
||||
** it should be anchored somewhere. It also internalizes long strings,
|
||||
** ensuring there is only one copy of each unique string. The table
|
||||
** here is used as a set: the string enters as the key, while its value
|
||||
** is irrelevant. We use the string itself as the value only because it
|
||||
** is a TValue readly available. Later, the code generation can change
|
||||
** this value.
|
||||
*/
|
||||
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
|
||||
lua_State *L = ls->L;
|
||||
TValue *o; /* entry for 'str' */
|
||||
TString *ts = luaS_newlstr(L, str, l); /* create new string */
|
||||
setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */
|
||||
o = luaH_set(L, ls->h, s2v(L->top - 1));
|
||||
if (isempty(o)) { /* not in use yet? */
|
||||
/* boolean value does not need GC barrier;
|
||||
table is not a metatable, so it does not need to invalidate cache */
|
||||
setbtvalue(o); /* t[string] = true */
|
||||
const TValue *o = luaH_getstr(ls->h, ts);
|
||||
if (!ttisnil(o)) /* string already present? */
|
||||
ts = keystrval(nodefromval(o)); /* get saved copy */
|
||||
else { /* not in use yet */
|
||||
TValue *stv = s2v(L->top++); /* reserve stack space for string */
|
||||
setsvalue(L, stv, ts); /* temporarily anchor the string */
|
||||
luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */
|
||||
/* table is not a metatable, so it does not need to invalidate cache */
|
||||
luaC_checkGC(L);
|
||||
}
|
||||
else { /* string already present */
|
||||
ts = keystrval(nodefromval(o)); /* re-use value previously stored */
|
||||
}
|
||||
L->top--; /* remove string from stack */
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
@ -255,9 +257,10 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) {
|
|||
|
||||
|
||||
/*
|
||||
** reads a sequence '[=*[' or ']=*]', leaving the last bracket.
|
||||
** If sequence is well formed, return its number of '='s + 2; otherwise,
|
||||
** return 1 if there is no '='s or 0 otherwise (an unfinished '[==...').
|
||||
** read a sequence '[=*[' or ']=*]', leaving the last bracket. If
|
||||
** sequence is well formed, return its number of '='s + 2; otherwise,
|
||||
** return 1 if it is a single bracket (no '='s and no 2nd bracket);
|
||||
** otherwise (an unfinished '[==...') return 0.
|
||||
*/
|
||||
static size_t skip_sep (LexState *ls) {
|
||||
size_t count = 0;
|
||||
|
@ -482,34 +485,34 @@ static int llex (LexState *ls, SemInfo *seminfo) {
|
|||
}
|
||||
case '=': {
|
||||
next(ls);
|
||||
if (check_next1(ls, '=')) return TK_EQ;
|
||||
if (check_next1(ls, '=')) return TK_EQ; /* '==' */
|
||||
else return '=';
|
||||
}
|
||||
case '<': {
|
||||
next(ls);
|
||||
if (check_next1(ls, '=')) return TK_LE;
|
||||
else if (check_next1(ls, '<')) return TK_SHL;
|
||||
if (check_next1(ls, '=')) return TK_LE; /* '<=' */
|
||||
else if (check_next1(ls, '<')) return TK_SHL; /* '<<' */
|
||||
else return '<';
|
||||
}
|
||||
case '>': {
|
||||
next(ls);
|
||||
if (check_next1(ls, '=')) return TK_GE;
|
||||
else if (check_next1(ls, '>')) return TK_SHR;
|
||||
if (check_next1(ls, '=')) return TK_GE; /* '>=' */
|
||||
else if (check_next1(ls, '>')) return TK_SHR; /* '>>' */
|
||||
else return '>';
|
||||
}
|
||||
case '/': {
|
||||
next(ls);
|
||||
if (check_next1(ls, '/')) return TK_IDIV;
|
||||
if (check_next1(ls, '/')) return TK_IDIV; /* '//' */
|
||||
else return '/';
|
||||
}
|
||||
case '~': {
|
||||
next(ls);
|
||||
if (check_next1(ls, '=')) return TK_NE;
|
||||
if (check_next1(ls, '=')) return TK_NE; /* '~=' */
|
||||
else return '~';
|
||||
}
|
||||
case ':': {
|
||||
next(ls);
|
||||
if (check_next1(ls, ':')) return TK_DBCOLON;
|
||||
if (check_next1(ls, ':')) return TK_DBCOLON; /* '::' */
|
||||
else return ':';
|
||||
}
|
||||
case '"': case '\'': { /* short literal strings */
|
||||
|
@ -548,7 +551,7 @@ static int llex (LexState *ls, SemInfo *seminfo) {
|
|||
return TK_NAME;
|
||||
}
|
||||
}
|
||||
else { /* single-char tokens (+ - / ...) */
|
||||
else { /* single-char tokens ('+', '*', '%', '{', '}', ...) */
|
||||
int c = ls->current;
|
||||
next(ls);
|
||||
return c;
|
||||
|
|
|
@ -7,11 +7,17 @@
|
|||
#ifndef llex_h
|
||||
#define llex_h
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "lobject.h"
|
||||
#include "lzio.h"
|
||||
|
||||
|
||||
#define FIRST_RESERVED 257
|
||||
/*
|
||||
** Single-char tokens (terminal symbols) are represented by their own
|
||||
** numeric code. Other tokens start at the following value.
|
||||
*/
|
||||
#define FIRST_RESERVED (UCHAR_MAX + 1)
|
||||
|
||||
|
||||
#if !defined(LUA_ENV)
|
||||
|
|
|
@ -84,7 +84,15 @@ typedef LUAI_UACNUMBER l_uacNumber;
|
|||
typedef LUAI_UACINT l_uacInt;
|
||||
|
||||
|
||||
/* internal assertions for in-house debugging */
|
||||
/*
|
||||
** Internal assertions for in-house debugging
|
||||
*/
|
||||
#if defined LUAI_ASSERT
|
||||
#undef NDEBUG
|
||||
#include <assert.h>
|
||||
#define lua_assert(c) assert(c)
|
||||
#endif
|
||||
|
||||
#if defined(lua_assert)
|
||||
#define check_exp(c,e) (lua_assert(c), (e))
|
||||
/* to avoid problems with conditions too long */
|
||||
|
@ -141,22 +149,6 @@ typedef LUAI_UACINT l_uacInt;
|
|||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** macros to improve jump prediction (used mainly for error handling)
|
||||
*/
|
||||
#if !defined(likely)
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define likely(x) (__builtin_expect(((x) != 0), 1))
|
||||
#define unlikely(x) (__builtin_expect(((x) != 0), 0))
|
||||
#else
|
||||
#define likely(x) (x)
|
||||
#define unlikely(x) (x)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** non-return type
|
||||
*/
|
||||
|
@ -226,6 +218,17 @@ typedef l_uint32 Instruction;
|
|||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Maximum depth for nested C calls, syntactical nested non-terminals,
|
||||
** and other features implemented through recursion in C. (Value must
|
||||
** fit in a 16-bit unsigned integer. It must also be compatible with
|
||||
** the size of the C stack.)
|
||||
*/
|
||||
#if !defined(LUAI_MAXCCALLS)
|
||||
#define LUAI_MAXCCALLS 200
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** macros that are executed whenever program enters the Lua core
|
||||
** ('lua_lock') and leaves the core ('lua_unlock')
|
||||
|
@ -307,7 +310,8 @@ typedef l_uint32 Instruction;
|
|||
|
||||
/* exponentiation */
|
||||
#if !defined(luai_numpow)
|
||||
#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b))
|
||||
#define luai_numpow(L,a,b) \
|
||||
((void)L, (b == 2) ? (a)*(a) : l_mathop(pow)(a,b))
|
||||
#endif
|
||||
|
||||
/* the others are quite standard operations */
|
||||
|
@ -336,7 +340,7 @@ typedef l_uint32 Instruction;
|
|||
#else
|
||||
/* realloc stack keeping its size */
|
||||
#define condmovestack(L,pre,pos) \
|
||||
{ int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_, 0); pos; }
|
||||
{ int sz_ = stacksize(L); pre; luaD_reallocstack((L), sz_, 0); pos; }
|
||||
#endif
|
||||
|
||||
#if !defined(HARDMEMTESTS)
|
||||
|
|
|
@ -73,7 +73,7 @@ static int math_atan (lua_State *L) {
|
|||
static int math_toint (lua_State *L) {
|
||||
int valid;
|
||||
lua_Integer n = lua_tointegerx(L, 1, &valid);
|
||||
if (valid)
|
||||
if (l_likely(valid))
|
||||
lua_pushinteger(L, n);
|
||||
else {
|
||||
luaL_checkany(L, 1);
|
||||
|
@ -175,7 +175,8 @@ static int math_log (lua_State *L) {
|
|||
lua_Number base = luaL_checknumber(L, 2);
|
||||
#if !defined(LUA_USE_C89)
|
||||
if (base == l_mathop(2.0))
|
||||
res = l_mathop(log2)(x); else
|
||||
res = l_mathop(log2)(x);
|
||||
else
|
||||
#endif
|
||||
if (base == l_mathop(10.0))
|
||||
res = l_mathop(log10)(x);
|
||||
|
|
|
@ -22,14 +22,14 @@
|
|||
#include "lstate.h"
|
||||
|
||||
|
||||
#if defined(HARDMEMTESTS)
|
||||
#if defined(EMERGENCYGCTESTS)
|
||||
/*
|
||||
** First allocation will fail whenever not building initial state
|
||||
** and not shrinking a block. (This fail will trigger 'tryagain' and
|
||||
** a full GC cycle at every allocation.)
|
||||
** First allocation will fail whenever not building initial state.
|
||||
** (This fail will trigger 'tryagain' and a full GC cycle at every
|
||||
** allocation.)
|
||||
*/
|
||||
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
|
||||
if (ttisnil(&g->nilvalue) && ns > os)
|
||||
if (completestate(g) && ns > 0) /* frees never fail */
|
||||
return NULL; /* fail */
|
||||
else /* normal allocation */
|
||||
return (*g->frealloc)(g->ud, block, os, ns);
|
||||
|
@ -83,7 +83,7 @@ void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize,
|
|||
if (nelems + 1 <= size) /* does one extra element still fit? */
|
||||
return block; /* nothing to be done */
|
||||
if (size >= limit / 2) { /* cannot double it? */
|
||||
if (unlikely(size >= limit)) /* cannot grow even a little? */
|
||||
if (l_unlikely(size >= limit)) /* cannot grow even a little? */
|
||||
luaG_runerror(L, "too many %s (limit is %d)", what, limit);
|
||||
size = limit; /* still have at least one free place */
|
||||
}
|
||||
|
@ -138,15 +138,17 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
|
|||
|
||||
|
||||
/*
|
||||
** In case of allocation fail, this function will call the GC to try
|
||||
** to free some memory and then try the allocation again.
|
||||
** (It should not be called when shrinking a block, because then the
|
||||
** interpreter may be in the middle of a collection step.)
|
||||
** In case of allocation fail, this function will do an emergency
|
||||
** collection to free some memory and then try the allocation again.
|
||||
** The GC should not be called while state is not fully built, as the
|
||||
** collector is not yet fully initialized. Also, it should not be called
|
||||
** when 'gcstopem' is true, because then the interpreter is in the
|
||||
** middle of a collection step.
|
||||
*/
|
||||
static void *tryagain (lua_State *L, void *block,
|
||||
size_t osize, size_t nsize) {
|
||||
global_State *g = G(L);
|
||||
if (ttisnil(&g->nilvalue)) { /* is state fully build? */
|
||||
if (completestate(g) && !g->gcstopem) {
|
||||
luaC_fullgc(L, 1); /* try to free some memory... */
|
||||
return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
|
||||
}
|
||||
|
@ -156,16 +158,13 @@ static void *tryagain (lua_State *L, void *block,
|
|||
|
||||
/*
|
||||
** Generic allocation routine.
|
||||
** If allocation fails while shrinking a block, do not try again; the
|
||||
** GC shrinks some blocks and it is not reentrant.
|
||||
*/
|
||||
void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
|
||||
void *newblock;
|
||||
global_State *g = G(L);
|
||||
lua_assert((osize == 0) == (block == NULL));
|
||||
newblock = firsttry(g, block, osize, nsize);
|
||||
if (unlikely(newblock == NULL && nsize > 0)) {
|
||||
if (nsize > osize) /* not shrinking a block? */
|
||||
if (l_unlikely(newblock == NULL && nsize > 0)) {
|
||||
newblock = tryagain(L, block, osize, nsize);
|
||||
if (newblock == NULL) /* still no memory? */
|
||||
return NULL; /* do not update 'GCdebt' */
|
||||
|
@ -179,7 +178,7 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
|
|||
void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize,
|
||||
size_t nsize) {
|
||||
void *newblock = luaM_realloc_(L, block, osize, nsize);
|
||||
if (unlikely(newblock == NULL && nsize > 0)) /* allocation failed? */
|
||||
if (l_unlikely(newblock == NULL && nsize > 0)) /* allocation failed? */
|
||||
luaM_error(L);
|
||||
return newblock;
|
||||
}
|
||||
|
@ -191,7 +190,7 @@ void *luaM_malloc_ (lua_State *L, size_t size, int tag) {
|
|||
else {
|
||||
global_State *g = G(L);
|
||||
void *newblock = firsttry(g, NULL, tag, size);
|
||||
if (unlikely(newblock == NULL)) {
|
||||
if (l_unlikely(newblock == NULL)) {
|
||||
newblock = tryagain(L, NULL, tag, size);
|
||||
if (newblock == NULL)
|
||||
luaM_error(L);
|
||||
|
|
|
@ -132,14 +132,16 @@ static void lsys_unloadlib (void *lib) {
|
|||
|
||||
static void *lsys_load (lua_State *L, const char *path, int seeglb) {
|
||||
void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL));
|
||||
if (lib == NULL) lua_pushstring(L, dlerror());
|
||||
if (l_unlikely(lib == NULL))
|
||||
lua_pushstring(L, dlerror());
|
||||
return lib;
|
||||
}
|
||||
|
||||
|
||||
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
|
||||
lua_CFunction f = cast_func(dlsym(lib, sym));
|
||||
if (f == NULL) lua_pushstring(L, dlerror());
|
||||
if (l_unlikely(f == NULL))
|
||||
lua_pushstring(L, dlerror());
|
||||
return f;
|
||||
}
|
||||
|
||||
|
@ -410,7 +412,7 @@ static int ll_loadlib (lua_State *L) {
|
|||
const char *path = luaL_checkstring(L, 1);
|
||||
const char *init = luaL_checkstring(L, 2);
|
||||
int stat = lookforfunc(L, path, init);
|
||||
if (stat == 0) /* no errors? */
|
||||
if (l_likely(stat == 0)) /* no errors? */
|
||||
return 1; /* return the loaded function */
|
||||
else { /* error; error message is on stack top */
|
||||
luaL_pushfail(L);
|
||||
|
@ -523,14 +525,14 @@ static const char *findfile (lua_State *L, const char *name,
|
|||
const char *path;
|
||||
lua_getfield(L, lua_upvalueindex(1), pname);
|
||||
path = lua_tostring(L, -1);
|
||||
if (path == NULL)
|
||||
if (l_unlikely(path == NULL))
|
||||
luaL_error(L, "'package.%s' must be a string", pname);
|
||||
return searchpath(L, name, path, ".", dirsep);
|
||||
}
|
||||
|
||||
|
||||
static int checkload (lua_State *L, int stat, const char *filename) {
|
||||
if (stat) { /* module loaded successfully? */
|
||||
if (l_likely(stat)) { /* module loaded successfully? */
|
||||
lua_pushstring(L, filename); /* will be 2nd argument to module */
|
||||
return 2; /* return open function and file name */
|
||||
}
|
||||
|
@ -623,13 +625,14 @@ static void findloader (lua_State *L, const char *name) {
|
|||
int i;
|
||||
luaL_Buffer msg; /* to build error message */
|
||||
/* push 'package.searchers' to index 3 in the stack */
|
||||
if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE)
|
||||
if (l_unlikely(lua_getfield(L, lua_upvalueindex(1), "searchers")
|
||||
!= LUA_TTABLE))
|
||||
luaL_error(L, "'package.searchers' must be a table");
|
||||
luaL_buffinit(L, &msg);
|
||||
/* iterate over available searchers to find a loader */
|
||||
for (i = 1; ; i++) {
|
||||
luaL_addstring(&msg, "\n\t"); /* error-message prefix */
|
||||
if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */
|
||||
if (l_unlikely(lua_rawgeti(L, 3, i) == LUA_TNIL)) { /* no more searchers? */
|
||||
lua_pop(L, 1); /* remove nil */
|
||||
luaL_buffsub(&msg, 2); /* remove prefix */
|
||||
luaL_pushresult(&msg); /* create error message */
|
||||
|
|
|
@ -215,37 +215,42 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
|
|||
/* }====================================================== */
|
||||
|
||||
|
||||
/* maximum length of a numeral */
|
||||
/* maximum length of a numeral to be converted to a number */
|
||||
#if !defined (L_MAXLENNUM)
|
||||
#define L_MAXLENNUM 200
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Convert string 's' to a Lua number (put in 'result'). Return NULL on
|
||||
** fail or the address of the ending '\0' on success. ('mode' == 'x')
|
||||
** means a hexadecimal numeral.
|
||||
*/
|
||||
static const char *l_str2dloc (const char *s, lua_Number *result, int mode) {
|
||||
char *endptr;
|
||||
*result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */
|
||||
: lua_str2number(s, &endptr);
|
||||
if (endptr == s) return NULL; /* nothing recognized? */
|
||||
while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */
|
||||
return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */
|
||||
return (*endptr == '\0') ? endptr : NULL; /* OK iff no trailing chars */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Convert string 's' to a Lua number (put in 'result'). Return NULL
|
||||
** on fail or the address of the ending '\0' on success.
|
||||
** 'pmode' points to (and 'mode' contains) special things in the string:
|
||||
** - 'x'/'X' means a hexadecimal numeral
|
||||
** - 'n'/'N' means 'inf' or 'nan' (which should be rejected)
|
||||
** - '.' just optimizes the search for the common case (nothing special)
|
||||
** Convert string 's' to a Lua number (put in 'result') handling the
|
||||
** current locale.
|
||||
** This function accepts both the current locale or a dot as the radix
|
||||
** mark. If the conversion fails, it may mean number has a dot but
|
||||
** locale accepts something else. In that case, the code copies 's'
|
||||
** to a buffer (because 's' is read-only), changes the dot to the
|
||||
** current locale radix mark, and tries to convert again.
|
||||
** The variable 'mode' checks for special characters in the string:
|
||||
** - 'n' means 'inf' or 'nan' (which should be rejected)
|
||||
** - 'x' means a hexadecimal numeral
|
||||
** - '.' just optimizes the search for the common case (no special chars)
|
||||
*/
|
||||
static const char *l_str2d (const char *s, lua_Number *result) {
|
||||
const char *endptr;
|
||||
const char *pmode = strpbrk(s, ".xXnN");
|
||||
const char *pmode = strpbrk(s, ".xXnN"); /* look for special chars */
|
||||
int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0;
|
||||
if (mode == 'n') /* reject 'inf' and 'nan' */
|
||||
return NULL;
|
||||
|
@ -253,7 +258,7 @@ static const char *l_str2d (const char *s, lua_Number *result) {
|
|||
if (endptr == NULL) { /* failed? may be a different locale */
|
||||
char buff[L_MAXLENNUM + 1];
|
||||
const char *pdot = strchr(s, '.');
|
||||
if (strlen(s) > L_MAXLENNUM || pdot == NULL)
|
||||
if (pdot == NULL || strlen(s) > L_MAXLENNUM)
|
||||
return NULL; /* string too long or no dot; fail */
|
||||
strcpy(buff, s); /* copy string to buffer */
|
||||
buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */
|
||||
|
@ -333,8 +338,15 @@ int luaO_utf8esc (char *buff, unsigned long x) {
|
|||
}
|
||||
|
||||
|
||||
/* maximum length of the conversion of a number to a string */
|
||||
#define MAXNUMBER2STR 50
|
||||
/*
|
||||
** Maximum length of the conversion of a number to a string. Must be
|
||||
** enough to accommodate both LUA_INTEGER_FMT and LUA_NUMBER_FMT.
|
||||
** (For a long long int, this is 19 digits plus a sign and a final '\0',
|
||||
** adding to 21. For a long double, it can go to a sign, 33 digits,
|
||||
** the dot, an exponent letter, an exponent sign, 5 exponent digits,
|
||||
** and a final '\0', adding to 43.)
|
||||
*/
|
||||
#define MAXNUMBER2STR 44
|
||||
|
||||
|
||||
/*
|
||||
|
@ -375,7 +387,7 @@ void luaO_tostring (lua_State *L, TValue *obj) {
|
|||
*/
|
||||
|
||||
/* size for buffer space used by 'luaO_pushvfstring' */
|
||||
#define BUFVFS 400
|
||||
#define BUFVFS 200
|
||||
|
||||
/* buffer used by 'luaO_pushvfstring' */
|
||||
typedef struct BuffFS {
|
||||
|
@ -387,19 +399,17 @@ typedef struct BuffFS {
|
|||
|
||||
|
||||
/*
|
||||
** Push given string to the stack, as part of the buffer. If the stack
|
||||
** is almost full, join all partial strings in the stack into one.
|
||||
** Push given string to the stack, as part of the buffer, and
|
||||
** join the partial strings in the stack into one.
|
||||
*/
|
||||
static void pushstr (BuffFS *buff, const char *str, size_t l) {
|
||||
lua_State *L = buff->L;
|
||||
setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
|
||||
L->top++; /* may use one extra slot */
|
||||
buff->pushed++;
|
||||
if (buff->pushed > 1 && L->top + 1 >= L->stack_last) {
|
||||
luaV_concat(L, buff->pushed); /* join all partial results into one */
|
||||
luaV_concat(L, buff->pushed); /* join partial results into one */
|
||||
buff->pushed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
@ -521,8 +531,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
|||
}
|
||||
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
|
||||
clearbuff(&buff); /* empty buffer into the stack */
|
||||
if (buff.pushed > 1)
|
||||
luaV_concat(L, buff.pushed); /* join all partial results */
|
||||
lua_assert(buff.pushed == 1);
|
||||
return svalue(s2v(L->top - 1));
|
||||
}
|
||||
|
||||
|
|
|
@ -21,10 +21,12 @@
|
|||
*/
|
||||
#define LUA_TUPVAL LUA_NUMTYPES /* upvalues */
|
||||
#define LUA_TPROTO (LUA_NUMTYPES+1) /* function prototypes */
|
||||
#define LUA_TDEADKEY (LUA_NUMTYPES+2) /* removed keys in tables */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** number of all possible types (including LUA_TNONE)
|
||||
** number of all possible types (including LUA_TNONE but excluding DEADKEY)
|
||||
*/
|
||||
#define LUA_TOTALTYPES (LUA_TPROTO + 2)
|
||||
|
||||
|
@ -96,7 +98,8 @@ typedef struct TValue {
|
|||
/*
|
||||
** Any value being manipulated by the program either is non
|
||||
** collectable, or the collectable object has the right tag
|
||||
** and it is not dead.
|
||||
** and it is not dead. The option 'L == NULL' allows other
|
||||
** macros using this one to be used where L is not available.
|
||||
*/
|
||||
#define checkliveness(L,obj) \
|
||||
((void)L, lua_longassert(!iscollectable(obj) || \
|
||||
|
@ -133,10 +136,19 @@ typedef struct TValue {
|
|||
|
||||
|
||||
/*
|
||||
** Entries in the Lua stack
|
||||
** Entries in a Lua stack. Field 'tbclist' forms a list of all
|
||||
** to-be-closed variables active in this stack. Dummy entries are
|
||||
** used when the distance between two tbc variables does not fit
|
||||
** in an unsigned short. They are represented by delta==0, and
|
||||
** their real delta is always the maximum value that fits in
|
||||
** that field.
|
||||
*/
|
||||
typedef union StackValue {
|
||||
TValue val;
|
||||
struct {
|
||||
TValuefields;
|
||||
unsigned short delta;
|
||||
} tbclist;
|
||||
} StackValue;
|
||||
|
||||
|
||||
|
@ -554,7 +566,7 @@ typedef struct Proto {
|
|||
|
||||
/*
|
||||
** {==================================================================
|
||||
** Closures
|
||||
** Functions
|
||||
** ===================================================================
|
||||
*/
|
||||
|
||||
|
@ -567,10 +579,11 @@ typedef struct Proto {
|
|||
#define LUA_VCCL makevariant(LUA_TFUNCTION, 2) /* C closure */
|
||||
|
||||
#define ttisfunction(o) checktype(o, LUA_TFUNCTION)
|
||||
#define ttisclosure(o) ((rawtt(o) & 0x1F) == LUA_VLCL)
|
||||
#define ttisLclosure(o) checktag((o), ctb(LUA_VLCL))
|
||||
#define ttislcf(o) checktag((o), LUA_VLCF)
|
||||
#define ttisCclosure(o) checktag((o), ctb(LUA_VCCL))
|
||||
#define ttisclosure(o) (ttisLclosure(o) || ttisCclosure(o))
|
||||
|
||||
|
||||
#define isLfunction(o) ttisLclosure(o)
|
||||
|
||||
|
@ -703,9 +716,9 @@ typedef union Node {
|
|||
*/
|
||||
|
||||
#define BITRAS (1 << 7)
|
||||
#define isrealasize(t) (!((t)->marked & BITRAS))
|
||||
#define setrealasize(t) ((t)->marked &= cast_byte(~BITRAS))
|
||||
#define setnorealasize(t) ((t)->marked |= BITRAS)
|
||||
#define isrealasize(t) (!((t)->flags & BITRAS))
|
||||
#define setrealasize(t) ((t)->flags &= cast_byte(~BITRAS))
|
||||
#define setnorealasize(t) ((t)->flags |= BITRAS)
|
||||
|
||||
|
||||
typedef struct Table {
|
||||
|
@ -742,13 +755,13 @@ typedef struct Table {
|
|||
|
||||
|
||||
/*
|
||||
** Use a "nil table" to mark dead keys in a table. Those keys serve
|
||||
** to keep space for removed entries, which may still be part of
|
||||
** chains. Note that the 'keytt' does not have the BIT_ISCOLLECTABLE
|
||||
** set, so these values are considered not collectable and are different
|
||||
** from any valid value.
|
||||
** Dead keys in tables have the tag DEADKEY but keep their original
|
||||
** gcvalue. This distinguishes them from regular keys but allows them to
|
||||
** be found when searched in a special way. ('next' needs that to find
|
||||
** keys removed from a table during a traversal.)
|
||||
*/
|
||||
#define setdeadkey(n) (keytt(n) = LUA_TTABLE, gckey(n) = NULL)
|
||||
#define setdeadkey(node) (keytt(node) = LUA_TDEADKEY)
|
||||
#define keyisdead(node) (keytt(node) == LUA_TDEADKEY)
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
|
|
@ -225,13 +225,13 @@ OP_SELF,/* A B C R[A+1] := R[B]; R[A] := R[B][RK(C):string] */
|
|||
|
||||
OP_ADDI,/* A B sC R[A] := R[B] + sC */
|
||||
|
||||
OP_ADDK,/* A B C R[A] := R[B] + K[C] */
|
||||
OP_SUBK,/* A B C R[A] := R[B] - K[C] */
|
||||
OP_MULK,/* A B C R[A] := R[B] * K[C] */
|
||||
OP_MODK,/* A B C R[A] := R[B] % K[C] */
|
||||
OP_POWK,/* A B C R[A] := R[B] ^ K[C] */
|
||||
OP_DIVK,/* A B C R[A] := R[B] / K[C] */
|
||||
OP_IDIVK,/* A B C R[A] := R[B] // K[C] */
|
||||
OP_ADDK,/* A B C R[A] := R[B] + K[C]:number */
|
||||
OP_SUBK,/* A B C R[A] := R[B] - K[C]:number */
|
||||
OP_MULK,/* A B C R[A] := R[B] * K[C]:number */
|
||||
OP_MODK,/* A B C R[A] := R[B] % K[C]:number */
|
||||
OP_POWK,/* A B C R[A] := R[B] ^ K[C]:number */
|
||||
OP_DIVK,/* A B C R[A] := R[B] / K[C]:number */
|
||||
OP_IDIVK,/* A B C R[A] := R[B] // K[C]:number */
|
||||
|
||||
OP_BANDK,/* A B C R[A] := R[B] & K[C]:integer */
|
||||
OP_BORK,/* A B C R[A] := R[B] | K[C]:integer */
|
||||
|
@ -261,7 +261,7 @@ OP_MMBINK,/* A B C k call C metamethod over R[A] and K[B] */
|
|||
OP_UNM,/* A B R[A] := -R[B] */
|
||||
OP_BNOT,/* A B R[A] := ~R[B] */
|
||||
OP_NOT,/* A B R[A] := not R[B] */
|
||||
OP_LEN,/* A B R[A] := length of R[B] */
|
||||
OP_LEN,/* A B R[A] := #R[B] (length operator) */
|
||||
|
||||
OP_CONCAT,/* A B R[A] := R[A].. ... ..R[A + B - 1] */
|
||||
|
||||
|
@ -297,7 +297,7 @@ OP_TFORPREP,/* A Bx create upvalue for R[A + 3]; pc+=Bx */
|
|||
OP_TFORCALL,/* A C R[A+4], ... ,R[A+3+C] := R[A](R[A+1], R[A+2]); */
|
||||
OP_TFORLOOP,/* A Bx if R[A+2] ~= nil then { R[A]=R[A+2]; pc -= Bx } */
|
||||
|
||||
OP_SETLIST,/* A B C k R[A][(C-1)*FPF+i] := R[A+i], 1 <= i <= B */
|
||||
OP_SETLIST,/* A B C k R[A][C+i] := R[A+i], 1 <= i <= B */
|
||||
|
||||
OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ static int os_tmpname (lua_State *L) {
|
|||
char buff[LUA_TMPNAMBUFSIZE];
|
||||
int err;
|
||||
lua_tmpnam(buff, err);
|
||||
if (err)
|
||||
if (l_unlikely(err))
|
||||
return luaL_error(L, "unable to generate a unique filename");
|
||||
lua_pushstring(L, buff);
|
||||
return 1;
|
||||
|
@ -208,7 +208,7 @@ static int os_clock (lua_State *L) {
|
|||
*/
|
||||
static void setfield (lua_State *L, const char *key, int value, int delta) {
|
||||
#if (defined(LUA_NUMTIME) && LUA_MAXINTEGER <= INT_MAX)
|
||||
if (value > LUA_MAXINTEGER - delta)
|
||||
if (l_unlikely(value > LUA_MAXINTEGER - delta))
|
||||
luaL_error(L, "field '%s' is out-of-bound", key);
|
||||
#endif
|
||||
lua_pushinteger(L, (lua_Integer)value + delta);
|
||||
|
@ -253,9 +253,9 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
|
|||
int t = lua_getfield(L, -1, key); /* get field and its type */
|
||||
lua_Integer res = lua_tointegerx(L, -1, &isnum);
|
||||
if (!isnum) { /* field is not an integer? */
|
||||
if (t != LUA_TNIL) /* some other value? */
|
||||
if (l_unlikely(t != LUA_TNIL)) /* some other value? */
|
||||
return luaL_error(L, "field '%s' is not an integer", key);
|
||||
else if (d < 0) /* absent field; no default? */
|
||||
else if (l_unlikely(d < 0)) /* absent field; no default? */
|
||||
return luaL_error(L, "field '%s' missing in date table", key);
|
||||
res = d;
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ static void checknext (LexState *ls, int c) {
|
|||
** in line 'where' (if that is not the current line).
|
||||
*/
|
||||
static void check_match (LexState *ls, int what, int who, int where) {
|
||||
if (unlikely(!testnext(ls, what))) {
|
||||
if (l_unlikely(!testnext(ls, what))) {
|
||||
if (where == ls->linenumber) /* all in the same line? */
|
||||
error_expected(ls, what); /* do not need a complex message */
|
||||
else {
|
||||
|
@ -222,26 +222,26 @@ static Vardesc *getlocalvardesc (FuncState *fs, int vidx) {
|
|||
|
||||
|
||||
/*
|
||||
** Convert 'nvar', a compiler index level, to it corresponding
|
||||
** stack index level. For that, search for the highest variable
|
||||
** below that level that is in the stack and uses its stack
|
||||
** index ('sidx').
|
||||
** Convert 'nvar', a compiler index level, to its corresponding
|
||||
** register. For that, search for the highest variable below that level
|
||||
** that is in a register and uses its register index ('ridx') plus one.
|
||||
*/
|
||||
static int stacklevel (FuncState *fs, int nvar) {
|
||||
static int reglevel (FuncState *fs, int nvar) {
|
||||
while (nvar-- > 0) {
|
||||
Vardesc *vd = getlocalvardesc(fs, nvar); /* get variable */
|
||||
if (vd->vd.kind != RDKCTC) /* is in the stack? */
|
||||
return vd->vd.sidx + 1;
|
||||
Vardesc *vd = getlocalvardesc(fs, nvar); /* get previous variable */
|
||||
if (vd->vd.kind != RDKCTC) /* is in a register? */
|
||||
return vd->vd.ridx + 1;
|
||||
}
|
||||
return 0; /* no variables in the stack */
|
||||
return 0; /* no variables in registers */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Return the number of variables in the stack for function 'fs'
|
||||
** Return the number of variables in the register stack for the given
|
||||
** function.
|
||||
*/
|
||||
int luaY_nvarstack (FuncState *fs) {
|
||||
return stacklevel(fs, fs->nactvar);
|
||||
return reglevel(fs, fs->nactvar);
|
||||
}
|
||||
|
||||
|
||||
|
@ -267,7 +267,7 @@ static void init_var (FuncState *fs, expdesc *e, int vidx) {
|
|||
e->f = e->t = NO_JUMP;
|
||||
e->k = VLOCAL;
|
||||
e->u.var.vidx = vidx;
|
||||
e->u.var.sidx = getlocalvardesc(fs, vidx)->vd.sidx;
|
||||
e->u.var.ridx = getlocalvardesc(fs, vidx)->vd.ridx;
|
||||
}
|
||||
|
||||
|
||||
|
@ -310,12 +310,12 @@ static void check_readonly (LexState *ls, expdesc *e) {
|
|||
*/
|
||||
static void adjustlocalvars (LexState *ls, int nvars) {
|
||||
FuncState *fs = ls->fs;
|
||||
int stklevel = luaY_nvarstack(fs);
|
||||
int reglevel = luaY_nvarstack(fs);
|
||||
int i;
|
||||
for (i = 0; i < nvars; i++) {
|
||||
int vidx = fs->nactvar++;
|
||||
Vardesc *var = getlocalvardesc(fs, vidx);
|
||||
var->vd.sidx = stklevel++;
|
||||
var->vd.ridx = reglevel++;
|
||||
var->vd.pidx = registerlocalvar(ls, fs, var->vd.name);
|
||||
}
|
||||
}
|
||||
|
@ -366,7 +366,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
|
|||
FuncState *prev = fs->prev;
|
||||
if (v->k == VLOCAL) {
|
||||
up->instack = 1;
|
||||
up->idx = v->u.var.sidx;
|
||||
up->idx = v->u.var.ridx;
|
||||
up->kind = getlocalvardesc(prev, v->u.var.vidx)->vd.kind;
|
||||
lua_assert(eqstr(name, getlocalvardesc(prev, v->u.var.vidx)->vd.name));
|
||||
}
|
||||
|
@ -489,12 +489,10 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
** Macros to limit the maximum recursion depth while parsing
|
||||
*/
|
||||
#define enterlevel(ls) luaE_enterCcall((ls)->L)
|
||||
#define enterlevel(ls) luaE_incCstack(ls->L)
|
||||
|
||||
#define leavelevel(ls) luaE_exitCcall((ls)->L)
|
||||
|
||||
#define leavelevel(ls) ((ls)->L->nCcalls--)
|
||||
|
||||
|
||||
/*
|
||||
|
@ -519,7 +517,7 @@ static void solvegoto (LexState *ls, int g, Labeldesc *label) {
|
|||
Labellist *gl = &ls->dyd->gt; /* list of goto's */
|
||||
Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */
|
||||
lua_assert(eqstr(gt->name, label->name));
|
||||
if (unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */
|
||||
if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */
|
||||
jumpscopeerror(ls, gt);
|
||||
luaK_patchlist(ls->fs, gt->pc, label->pc);
|
||||
for (i = g; i < gl->n - 1; i++) /* remove goto from pending list */
|
||||
|
@ -622,7 +620,7 @@ static void movegotosout (FuncState *fs, BlockCnt *bl) {
|
|||
for (i = bl->firstgoto; i < gl->n; i++) { /* for each pending goto */
|
||||
Labeldesc *gt = &gl->arr[i];
|
||||
/* leaving a variable scope? */
|
||||
if (stacklevel(fs, gt->nactvar) > stacklevel(fs, bl->nactvar))
|
||||
if (reglevel(fs, gt->nactvar) > reglevel(fs, bl->nactvar))
|
||||
gt->close |= bl->upval; /* jump may need a close */
|
||||
gt->nactvar = bl->nactvar; /* update goto level */
|
||||
}
|
||||
|
@ -663,7 +661,7 @@ static void leaveblock (FuncState *fs) {
|
|||
BlockCnt *bl = fs->bl;
|
||||
LexState *ls = fs->ls;
|
||||
int hasclose = 0;
|
||||
int stklevel = stacklevel(fs, bl->nactvar); /* level outside the block */
|
||||
int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */
|
||||
if (bl->isloop) /* fix pending breaks? */
|
||||
hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
|
||||
if (!hasclose && bl->previous && bl->upval)
|
||||
|
@ -947,7 +945,7 @@ static void setvararg (FuncState *fs, int nparams) {
|
|||
|
||||
|
||||
static void parlist (LexState *ls) {
|
||||
/* parlist -> [ param { ',' param } ] */
|
||||
/* parlist -> [ {NAME ','} (NAME | '...') ] */
|
||||
FuncState *fs = ls->fs;
|
||||
Proto *f = fs->f;
|
||||
int nparams = 0;
|
||||
|
@ -955,12 +953,12 @@ static void parlist (LexState *ls) {
|
|||
if (ls->t.token != ')') { /* is 'parlist' not empty? */
|
||||
do {
|
||||
switch (ls->t.token) {
|
||||
case TK_NAME: { /* param -> NAME */
|
||||
case TK_NAME: {
|
||||
new_localvar(ls, str_checkname(ls));
|
||||
nparams++;
|
||||
break;
|
||||
}
|
||||
case TK_DOTS: { /* param -> '...' */
|
||||
case TK_DOTS: {
|
||||
luaX_next(ls);
|
||||
isvararg = 1;
|
||||
break;
|
||||
|
@ -1332,13 +1330,13 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
|
|||
}
|
||||
}
|
||||
else { /* table is a register */
|
||||
if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.sidx) {
|
||||
if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.ridx) {
|
||||
conflict = 1; /* table is the local being assigned now */
|
||||
lh->v.u.ind.t = extra; /* assignment will use safe copy */
|
||||
}
|
||||
/* is index the local being assigned? */
|
||||
if (lh->v.k == VINDEXED && v->k == VLOCAL &&
|
||||
lh->v.u.ind.idx == v->u.var.sidx) {
|
||||
lh->v.u.ind.idx == v->u.var.ridx) {
|
||||
conflict = 1;
|
||||
lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */
|
||||
}
|
||||
|
@ -1348,7 +1346,7 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
|
|||
if (conflict) {
|
||||
/* copy upvalue/local value to a temporary (in position 'extra') */
|
||||
if (v->k == VLOCAL)
|
||||
luaK_codeABC(fs, OP_MOVE, extra, v->u.var.sidx, 0);
|
||||
luaK_codeABC(fs, OP_MOVE, extra, v->u.var.ridx, 0);
|
||||
else
|
||||
luaK_codeABC(fs, OP_GETUPVAL, extra, v->u.info, 0);
|
||||
luaK_reserveregs(fs, 1);
|
||||
|
@ -1413,7 +1411,7 @@ static void gotostat (LexState *ls) {
|
|||
newgotoentry(ls, name, line, luaK_jump(fs));
|
||||
else { /* found a label */
|
||||
/* backward jump; will be resolved here */
|
||||
int lblevel = stacklevel(fs, lb->nactvar); /* label level */
|
||||
int lblevel = reglevel(fs, lb->nactvar); /* label level */
|
||||
if (luaY_nvarstack(fs) > lblevel) /* leaving the scope of a variable? */
|
||||
luaK_codeABC(fs, OP_CLOSE, lblevel, 0, 0);
|
||||
/* create jump and link it to the label */
|
||||
|
@ -1437,7 +1435,7 @@ static void breakstat (LexState *ls) {
|
|||
*/
|
||||
static void checkrepeated (LexState *ls, TString *name) {
|
||||
Labeldesc *lb = findlabel(ls, name);
|
||||
if (unlikely(lb != NULL)) { /* already defined? */
|
||||
if (l_unlikely(lb != NULL)) { /* already defined? */
|
||||
const char *msg = "label '%s' already defined on line %d";
|
||||
msg = luaO_pushfstring(ls->L, msg, getstr(name), lb->line);
|
||||
luaK_semerror(ls, msg); /* error */
|
||||
|
@ -1490,7 +1488,7 @@ static void repeatstat (LexState *ls, int line) {
|
|||
if (bl2.upval) { /* upvalues? */
|
||||
int exit = luaK_jump(fs); /* normal exit must jump over fix */
|
||||
luaK_patchtohere(fs, condexit); /* repetition must close upvalues */
|
||||
luaK_codeABC(fs, OP_CLOSE, stacklevel(fs, bl2.nactvar), 0, 0);
|
||||
luaK_codeABC(fs, OP_CLOSE, reglevel(fs, bl2.nactvar), 0, 0);
|
||||
condexit = luaK_jump(fs); /* repeat after closing upvalues */
|
||||
luaK_patchtohere(fs, exit); /* normal exit comes to here */
|
||||
}
|
||||
|
@ -1522,7 +1520,7 @@ static void fixforjump (FuncState *fs, int pc, int dest, int back) {
|
|||
int offset = dest - (pc + 1);
|
||||
if (back)
|
||||
offset = -offset;
|
||||
if (unlikely(offset > MAXARG_Bx))
|
||||
if (l_unlikely(offset > MAXARG_Bx))
|
||||
luaX_syntaxerror(fs->ls, "control structure too long");
|
||||
SETARG_Bx(*jmp, offset);
|
||||
}
|
||||
|
@ -1625,59 +1623,21 @@ static void forstat (LexState *ls, int line) {
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
** Check whether next instruction is a single jump (a 'break', a 'goto'
|
||||
** to a forward label, or a 'goto' to a backward label with no variable
|
||||
** to close). If so, set the name of the 'label' it is jumping to
|
||||
** ("break" for a 'break') or to where it is jumping to ('target') and
|
||||
** return true. If not a single jump, leave input unchanged, to be
|
||||
** handled as a regular statement.
|
||||
*/
|
||||
static int issinglejump (LexState *ls, TString **label, int *target) {
|
||||
if (testnext(ls, TK_BREAK)) { /* a break? */
|
||||
*label = luaS_newliteral(ls->L, "break");
|
||||
return 1;
|
||||
}
|
||||
else if (ls->t.token != TK_GOTO || luaX_lookahead(ls) != TK_NAME)
|
||||
return 0; /* not a valid goto */
|
||||
else {
|
||||
TString *lname = ls->lookahead.seminfo.ts; /* label's id */
|
||||
Labeldesc *lb = findlabel(ls, lname);
|
||||
if (lb) { /* a backward jump? */
|
||||
/* does it need to close variables? */
|
||||
if (luaY_nvarstack(ls->fs) > stacklevel(ls->fs, lb->nactvar))
|
||||
return 0; /* not a single jump; cannot optimize */
|
||||
*target = lb->pc;
|
||||
}
|
||||
else /* jump forward */
|
||||
*label = lname;
|
||||
luaX_next(ls); /* skip goto */
|
||||
luaX_next(ls); /* skip name */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_then_block (LexState *ls, int *escapelist) {
|
||||
/* test_then_block -> [IF | ELSEIF] cond THEN block */
|
||||
BlockCnt bl;
|
||||
int line;
|
||||
FuncState *fs = ls->fs;
|
||||
TString *jlb = NULL;
|
||||
int target = NO_JUMP;
|
||||
expdesc v;
|
||||
int jf; /* instruction to skip 'then' code (if condition is false) */
|
||||
luaX_next(ls); /* skip IF or ELSEIF */
|
||||
expr(ls, &v); /* read condition */
|
||||
checknext(ls, TK_THEN);
|
||||
line = ls->linenumber;
|
||||
if (issinglejump(ls, &jlb, &target)) { /* 'if x then goto' ? */
|
||||
luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */
|
||||
if (ls->t.token == TK_BREAK) { /* 'if x then break' ? */
|
||||
int line = ls->linenumber;
|
||||
luaK_goiffalse(ls->fs, &v); /* will jump if condition is true */
|
||||
luaX_next(ls); /* skip 'break' */
|
||||
enterblock(fs, &bl, 0); /* must enter block before 'goto' */
|
||||
if (jlb != NULL) /* forward jump? */
|
||||
newgotoentry(ls, jlb, line, v.t); /* will be resolved later */
|
||||
else /* backward jump */
|
||||
luaK_patchlist(fs, v.t, target); /* jump directly to 'target' */
|
||||
newgotoentry(ls, luaS_newliteral(ls->L, "break"), line, v.t);
|
||||
while (testnext(ls, ';')) {} /* skip semicolons */
|
||||
if (block_follow(ls, 0)) { /* jump is the entire block? */
|
||||
leaveblock(fs);
|
||||
|
@ -1686,7 +1646,7 @@ static void test_then_block (LexState *ls, int *escapelist) {
|
|||
else /* must skip over 'then' part if condition is false */
|
||||
jf = luaK_jump(fs);
|
||||
}
|
||||
else { /* regular case (not a jump) */
|
||||
else { /* regular case (not a break) */
|
||||
luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */
|
||||
enterblock(fs, &bl, 0);
|
||||
jf = v.f;
|
||||
|
@ -1748,13 +1708,13 @@ static void checktoclose (LexState *ls, int level) {
|
|||
FuncState *fs = ls->fs;
|
||||
markupval(fs, level + 1);
|
||||
fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
|
||||
luaK_codeABC(fs, OP_TBC, stacklevel(fs, level), 0, 0);
|
||||
luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void localstat (LexState *ls) {
|
||||
/* stat -> LOCAL ATTRIB NAME {',' ATTRIB NAME} ['=' explist] */
|
||||
/* stat -> LOCAL NAME ATTRIB { ',' NAME ATTRIB } ['=' explist] */
|
||||
FuncState *fs = ls->fs;
|
||||
int toclose = -1; /* index of to-be-closed variable (if any) */
|
||||
Vardesc *var; /* last variable */
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
/* kinds of variables/expressions */
|
||||
typedef enum {
|
||||
VVOID, /* when 'expdesc' describes the last expression a list,
|
||||
VVOID, /* when 'expdesc' describes the last expression of a list,
|
||||
this kind means an empty list (so, no expression) */
|
||||
VNIL, /* constant nil */
|
||||
VTRUE, /* constant true */
|
||||
|
@ -35,10 +35,11 @@ typedef enum {
|
|||
(string is fixed by the lexer) */
|
||||
VNONRELOC, /* expression has its value in a fixed register;
|
||||
info = result register */
|
||||
VLOCAL, /* local variable; var.sidx = stack index (local register);
|
||||
VLOCAL, /* local variable; var.ridx = register index;
|
||||
var.vidx = relative index in 'actvar.arr' */
|
||||
VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
|
||||
VCONST, /* compile-time constant; info = absolute index in 'actvar.arr' */
|
||||
VCONST, /* compile-time <const> variable;
|
||||
info = absolute index in 'actvar.arr' */
|
||||
VINDEXED, /* indexed variable;
|
||||
ind.t = table register;
|
||||
ind.idx = key's R index */
|
||||
|
@ -76,7 +77,7 @@ typedef struct expdesc {
|
|||
lu_byte t; /* table (register or upvalue) */
|
||||
} ind;
|
||||
struct { /* for local variables */
|
||||
lu_byte sidx; /* index in the stack */
|
||||
lu_byte ridx; /* register holding the variable */
|
||||
unsigned short vidx; /* compiler index (in 'actvar.arr') */
|
||||
} var;
|
||||
} u;
|
||||
|
@ -96,7 +97,7 @@ typedef union Vardesc {
|
|||
struct {
|
||||
TValuefields; /* constant value (if it is a compile-time constant) */
|
||||
lu_byte kind;
|
||||
lu_byte sidx; /* index of the variable in the stack */
|
||||
lu_byte ridx; /* register holding the variable */
|
||||
short pidx; /* index of the variable in the Proto's 'locvars' array */
|
||||
TString *name; /* variable name */
|
||||
} vd;
|
||||
|
|
160
lua/src/lstate.c
160
lua/src/lstate.c
|
@ -76,7 +76,7 @@ static unsigned int luai_makeseed (lua_State *L) {
|
|||
addbuff(buff, p, &h); /* local variable */
|
||||
addbuff(buff, p, &lua_newstate); /* public function */
|
||||
lua_assert(p == sizeof(buff));
|
||||
return luaS_hash(buff, p, h, 1);
|
||||
return luaS_hash(buff, p, h);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -97,66 +97,14 @@ void luaE_setdebt (global_State *g, l_mem debt) {
|
|||
|
||||
|
||||
LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) {
|
||||
global_State *g = G(L);
|
||||
int ccalls;
|
||||
luaE_freeCI(L); /* release unused CIs */
|
||||
ccalls = getCcalls(L);
|
||||
if (limit >= 40000)
|
||||
return 0; /* out of bounds */
|
||||
limit += CSTACKERR;
|
||||
if (L != g-> mainthread)
|
||||
return 0; /* only main thread can change the C stack */
|
||||
else if (ccalls <= CSTACKERR)
|
||||
return 0; /* handling overflow */
|
||||
else {
|
||||
int diff = limit - g->Cstacklimit;
|
||||
if (ccalls + diff <= CSTACKERR)
|
||||
return 0; /* new limit would cause an overflow */
|
||||
g->Cstacklimit = limit; /* set new limit */
|
||||
L->nCcalls += diff; /* correct 'nCcalls' */
|
||||
return limit - diff - CSTACKERR; /* success; return previous limit */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Decrement count of "C calls" and check for overflows. In case of
|
||||
** a stack overflow, check appropriate error ("regular" overflow or
|
||||
** overflow while handling stack overflow). If 'nCcalls' is smaller
|
||||
** than CSTACKERR but larger than CSTACKMARK, it means it has just
|
||||
** entered the "overflow zone", so the function raises an overflow
|
||||
** error. If 'nCcalls' is smaller than CSTACKMARK (which means it is
|
||||
** already handling an overflow) but larger than CSTACKERRMARK, does
|
||||
** not report an error (to allow message handling to work). Otherwise,
|
||||
** report a stack overflow while handling a stack overflow (probably
|
||||
** caused by a repeating error in the message handling function).
|
||||
*/
|
||||
|
||||
void luaE_enterCcall (lua_State *L) {
|
||||
int ncalls = getCcalls(L);
|
||||
L->nCcalls--;
|
||||
if (ncalls <= CSTACKERR) { /* possible overflow? */
|
||||
luaE_freeCI(L); /* release unused CIs */
|
||||
ncalls = getCcalls(L); /* update call count */
|
||||
if (ncalls <= CSTACKERR) { /* still overflow? */
|
||||
if (ncalls <= CSTACKERRMARK) /* below error-handling zone? */
|
||||
luaD_throw(L, LUA_ERRERR); /* error while handling stack error */
|
||||
else if (ncalls >= CSTACKMARK) {
|
||||
/* not in error-handling zone; raise the error now */
|
||||
L->nCcalls = (CSTACKMARK - 1); /* enter error-handling zone */
|
||||
luaG_runerror(L, "C stack overflow");
|
||||
}
|
||||
/* else stack is in the error-handling zone;
|
||||
allow message handler to work */
|
||||
}
|
||||
}
|
||||
UNUSED(L); UNUSED(limit);
|
||||
return LUAI_MAXCCALLS; /* warning?? */
|
||||
}
|
||||
|
||||
|
||||
CallInfo *luaE_extendCI (lua_State *L) {
|
||||
CallInfo *ci;
|
||||
lua_assert(L->ci->next == NULL);
|
||||
luaE_enterCcall(L);
|
||||
ci = luaM_new(L, CallInfo);
|
||||
lua_assert(L->ci->next == NULL);
|
||||
L->ci->next = ci;
|
||||
|
@ -175,13 +123,11 @@ void luaE_freeCI (lua_State *L) {
|
|||
CallInfo *ci = L->ci;
|
||||
CallInfo *next = ci->next;
|
||||
ci->next = NULL;
|
||||
L->nCcalls += L->nci; /* add removed elements back to 'nCcalls' */
|
||||
while ((ci = next) != NULL) {
|
||||
next = ci->next;
|
||||
luaM_free(L, ci);
|
||||
L->nci--;
|
||||
}
|
||||
L->nCcalls -= L->nci; /* adjust result */
|
||||
}
|
||||
|
||||
|
||||
|
@ -194,7 +140,6 @@ void luaE_shrinkCI (lua_State *L) {
|
|||
CallInfo *next;
|
||||
if (ci == NULL)
|
||||
return; /* no extra elements */
|
||||
L->nCcalls += L->nci; /* add removed elements back to 'nCcalls' */
|
||||
while ((next = ci->next) != NULL) { /* two extra elements? */
|
||||
CallInfo *next2 = next->next; /* next's next */
|
||||
ci->next = next2; /* remove next from the list */
|
||||
|
@ -207,19 +152,40 @@ void luaE_shrinkCI (lua_State *L) {
|
|||
ci = next2; /* continue */
|
||||
}
|
||||
}
|
||||
L->nCcalls -= L->nci; /* adjust result */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Called when 'getCcalls(L)' larger or equal to LUAI_MAXCCALLS.
|
||||
** If equal, raises an overflow error. If value is larger than
|
||||
** LUAI_MAXCCALLS (which means it is handling an overflow) but
|
||||
** not much larger, does not report an error (to allow overflow
|
||||
** handling to work).
|
||||
*/
|
||||
void luaE_checkcstack (lua_State *L) {
|
||||
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 */
|
||||
}
|
||||
|
||||
|
||||
LUAI_FUNC void luaE_incCstack (lua_State *L) {
|
||||
L->nCcalls++;
|
||||
if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
|
||||
luaE_checkcstack(L);
|
||||
}
|
||||
|
||||
|
||||
static void stack_init (lua_State *L1, lua_State *L) {
|
||||
int i; CallInfo *ci;
|
||||
/* initialize stack array */
|
||||
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, StackValue);
|
||||
L1->stacksize = BASIC_STACK_SIZE;
|
||||
for (i = 0; i < BASIC_STACK_SIZE; i++)
|
||||
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
|
||||
L1->tbclist = L1->stack;
|
||||
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
|
||||
setnilvalue(s2v(L1->stack + i)); /* erase new stack */
|
||||
L1->top = L1->stack;
|
||||
L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK;
|
||||
L1->stack_last = L1->stack + BASIC_STACK_SIZE;
|
||||
/* initialize first ci */
|
||||
ci = &L1->base_ci;
|
||||
ci->next = ci->previous = NULL;
|
||||
|
@ -240,7 +206,7 @@ static void freestack (lua_State *L) {
|
|||
L->ci = &L->base_ci; /* free the entire 'ci' list */
|
||||
luaE_freeCI(L);
|
||||
lua_assert(L->nci == 0);
|
||||
luaM_freearray(L, L->stack, L->stacksize); /* free stack array */
|
||||
luaM_freearray(L, L->stack, stacksize(L) + EXTRA_STACK); /* free stack */
|
||||
}
|
||||
|
||||
|
||||
|
@ -248,24 +214,19 @@ static void freestack (lua_State *L) {
|
|||
** Create registry table and its predefined values
|
||||
*/
|
||||
static void init_registry (lua_State *L, global_State *g) {
|
||||
TValue temp;
|
||||
/* create registry */
|
||||
Table *registry = luaH_new(L);
|
||||
sethvalue(L, &g->l_registry, registry);
|
||||
luaH_resize(L, registry, LUA_RIDX_LAST, 0);
|
||||
/* registry[LUA_RIDX_MAINTHREAD] = L */
|
||||
setthvalue(L, &temp, L); /* temp = L */
|
||||
luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp);
|
||||
/* registry[LUA_RIDX_GLOBALS] = table of globals */
|
||||
sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */
|
||||
luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp);
|
||||
setthvalue(L, ®istry->array[LUA_RIDX_MAINTHREAD - 1], L);
|
||||
/* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */
|
||||
sethvalue(L, ®istry->array[LUA_RIDX_GLOBALS - 1], luaH_new(L));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** open parts of the state that may cause memory-allocation errors.
|
||||
** ('g->nilvalue' being a nil value flags that the state was completely
|
||||
** build.)
|
||||
*/
|
||||
static void f_luaopen (lua_State *L, void *ud) {
|
||||
global_State *g = G(L);
|
||||
|
@ -276,7 +237,7 @@ static void f_luaopen (lua_State *L, void *ud) {
|
|||
luaT_init(L);
|
||||
luaX_init(L);
|
||||
g->gcrunning = 1; /* allow gc */
|
||||
setnilvalue(&g->nilvalue);
|
||||
setnilvalue(&g->nilvalue); /* now state is complete */
|
||||
luai_userstateopen(L);
|
||||
}
|
||||
|
||||
|
@ -290,8 +251,8 @@ static void preinit_thread (lua_State *L, global_State *g) {
|
|||
L->stack = NULL;
|
||||
L->ci = NULL;
|
||||
L->nci = 0;
|
||||
L->stacksize = 0;
|
||||
L->twups = L; /* thread has no upvalues */
|
||||
L->nCcalls = 0;
|
||||
L->errorJmp = NULL;
|
||||
L->hook = NULL;
|
||||
L->hookmask = 0;
|
||||
|
@ -301,15 +262,19 @@ static void preinit_thread (lua_State *L, global_State *g) {
|
|||
L->openupval = NULL;
|
||||
L->status = LUA_OK;
|
||||
L->errfunc = 0;
|
||||
L->oldpc = 0;
|
||||
}
|
||||
|
||||
|
||||
static void close_state (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
luaF_close(L, L->stack, CLOSEPROTECT); /* close all upvalues */
|
||||
if (!completestate(g)) /* closing a partially built state? */
|
||||
luaC_freeallobjects(L); /* jucst collect its objects */
|
||||
else { /* closing a fully built state */
|
||||
luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */
|
||||
luaC_freeallobjects(L); /* collect all objects */
|
||||
if (ttisnil(&g->nilvalue)) /* closing a fully built state? */
|
||||
luai_userstateclose(L);
|
||||
}
|
||||
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
|
||||
freestack(L);
|
||||
lua_assert(gettotalbytes(g) == sizeof(LG));
|
||||
|
@ -318,9 +283,10 @@ static void close_state (lua_State *L) {
|
|||
|
||||
|
||||
LUA_API lua_State *lua_newthread (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
global_State *g;
|
||||
lua_State *L1;
|
||||
lua_lock(L);
|
||||
g = G(L);
|
||||
luaC_checkGC(L);
|
||||
/* create new thread */
|
||||
L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;
|
||||
|
@ -333,7 +299,6 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
|
|||
setthvalue2s(L, L->top, L1);
|
||||
api_incr_top(L);
|
||||
preinit_thread(L1, g);
|
||||
L1->nCcalls = getCcalls(L);
|
||||
L1->hookmask = L->hookmask;
|
||||
L1->basehookcount = L->basehookcount;
|
||||
L1->hook = L->hook;
|
||||
|
@ -350,7 +315,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
|
|||
|
||||
void luaE_freethread (lua_State *L, lua_State *L1) {
|
||||
LX *l = fromstate(L1);
|
||||
luaF_close(L1, L1->stack, NOCLOSINGMETH); /* close all upvalues */
|
||||
luaF_closeupval(L1, L1->stack); /* close all upvalues */
|
||||
lua_assert(L1->openupval == NULL);
|
||||
luai_userstatefree(L, L1);
|
||||
freestack(L1);
|
||||
|
@ -358,23 +323,29 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
|
|||
}
|
||||
|
||||
|
||||
int lua_resetthread (lua_State *L) {
|
||||
CallInfo *ci;
|
||||
int status;
|
||||
lua_lock(L);
|
||||
L->ci = ci = &L->base_ci; /* unwind CallInfo list */
|
||||
int luaE_resetthread (lua_State *L, int status) {
|
||||
CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
|
||||
setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */
|
||||
ci->func = L->stack;
|
||||
ci->callstatus = CIST_C;
|
||||
status = luaF_close(L, L->stack, CLOSEPROTECT);
|
||||
if (status != CLOSEPROTECT) /* real errors? */
|
||||
luaD_seterrorobj(L, status, L->stack + 1);
|
||||
else {
|
||||
if (status == LUA_YIELD)
|
||||
status = LUA_OK;
|
||||
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 = status;
|
||||
L->status = cast_byte(status);
|
||||
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_resetthread (lua_State *L) {
|
||||
int status;
|
||||
lua_lock(L);
|
||||
status = luaE_resetthread(L, L->status);
|
||||
lua_unlock(L);
|
||||
return status;
|
||||
}
|
||||
|
@ -394,7 +365,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||
preinit_thread(L, g);
|
||||
g->allgc = obj2gco(L); /* by now, only object is the main thread */
|
||||
L->next = NULL;
|
||||
g->Cstacklimit = L->nCcalls = LUAI_MAXCSTACK + CSTACKERR;
|
||||
incnny(L); /* main thread is always non yieldable */
|
||||
g->frealloc = f;
|
||||
g->ud = ud;
|
||||
g->warnf = NULL;
|
||||
|
@ -408,10 +379,11 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||
g->panic = NULL;
|
||||
g->gcstate = GCSpause;
|
||||
g->gckind = KGC_INC;
|
||||
g->gcstopem = 0;
|
||||
g->gcemergency = 0;
|
||||
g->finobj = g->tobefnz = g->fixedgc = NULL;
|
||||
g->survival = g->old = g->reallyold = NULL;
|
||||
g->finobjsur = g->finobjold = g->finobjrold = NULL;
|
||||
g->firstold1 = g->survival = g->old1 = g->reallyold = NULL;
|
||||
g->finobjsur = g->finobjold1 = g->finobjrold = NULL;
|
||||
g->sweepgc = NULL;
|
||||
g->gray = g->grayagain = NULL;
|
||||
g->weak = g->ephemeron = g->allweak = NULL;
|
||||
|
@ -436,8 +408,8 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||
|
||||
|
||||
LUA_API void lua_close (lua_State *L) {
|
||||
L = G(L)->mainthread; /* only the main thread can be closed */
|
||||
lua_lock(L);
|
||||
L = G(L)->mainthread; /* only the main thread can be closed */
|
||||
close_state(L);
|
||||
}
|
||||
|
||||
|
|
182
lua/src/lstate.h
182
lua/src/lstate.h
|
@ -32,13 +32,29 @@
|
|||
**
|
||||
** 'allgc' -> 'survival': new objects;
|
||||
** 'survival' -> 'old': objects that survived one collection;
|
||||
** 'old' -> 'reallyold': objects that became old in last collection;
|
||||
** 'old1' -> 'reallyold': objects that became old in last collection;
|
||||
** 'reallyold' -> NULL: objects old for more than one cycle.
|
||||
**
|
||||
** 'finobj' -> 'finobjsur': new objects marked for finalization;
|
||||
** 'finobjsur' -> 'finobjold': survived """";
|
||||
** 'finobjold' -> 'finobjrold': just old """";
|
||||
** 'finobjsur' -> 'finobjold1': survived """";
|
||||
** 'finobjold1' -> 'finobjrold': just old """";
|
||||
** 'finobjrold' -> NULL: really old """".
|
||||
**
|
||||
** All lists can contain elements older than their main ages, due
|
||||
** to 'luaC_checkfinalizer' and 'udata2finalize', which move
|
||||
** objects between the normal lists and the "marked for finalization"
|
||||
** lists. Moreover, barriers can age young objects in young lists as
|
||||
** OLD0, which then become OLD1. However, a list never contains
|
||||
** elements younger than their main ages.
|
||||
**
|
||||
** The generational collector also uses a pointer 'firstold1', which
|
||||
** points to the first OLD1 object in the list. It is used to optimize
|
||||
** 'markold'. (Potentially OLD1 objects can be anywhere between 'allgc'
|
||||
** and 'reallyold', but often the list has no OLD1 objects or they are
|
||||
** after 'old1'.) Note the difference between it and 'old1':
|
||||
** 'firstold1': no OLD1 objects before this point; there can be all
|
||||
** ages after it.
|
||||
** 'old1': no objects younger than OLD1 after this point.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -47,7 +63,7 @@
|
|||
** can become gray have such a field. The field is not the same
|
||||
** in all objects, but it always has this name.) Any gray object
|
||||
** must belong to one of these lists, and all objects in these lists
|
||||
** must be gray:
|
||||
** must be gray (with two exceptions explained below):
|
||||
**
|
||||
** 'gray': regular gray objects, still waiting to be visited.
|
||||
** 'grayagain': objects that must be revisited at the atomic phase.
|
||||
|
@ -58,54 +74,26 @@
|
|||
** 'weak': tables with weak values to be cleared;
|
||||
** 'ephemeron': ephemeron tables with white->white entries;
|
||||
** 'allweak': tables with weak keys and/or weak values to be cleared.
|
||||
**
|
||||
** The exceptions to that "gray rule" are:
|
||||
** - TOUCHED2 objects in generational mode stay in a gray list (because
|
||||
** they must be visited again at the end of the cycle), but they are
|
||||
** marked black because assignments to them must activate barriers (to
|
||||
** move them back to TOUCHED1).
|
||||
** - Open upvales are kept gray to avoid barriers, but they stay out
|
||||
** of gray lists. (They don't even have a 'gclist' field.)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** About 'nCcalls': each thread in Lua (a lua_State) keeps a count of
|
||||
** how many "C calls" it still can do in the C stack, to avoid C-stack
|
||||
** overflow. This count is very rough approximation; it considers only
|
||||
** recursive functions inside the interpreter, as non-recursive calls
|
||||
** can be considered using a fixed (although unknown) amount of stack
|
||||
** space.
|
||||
**
|
||||
** The count has two parts: the lower part is the count itself; the
|
||||
** higher part counts the number of non-yieldable calls in the stack.
|
||||
** (They are together so that we can change both with one instruction.)
|
||||
**
|
||||
** Because calls to external C functions can use an unknown amount
|
||||
** of space (e.g., functions using an auxiliary buffer), calls
|
||||
** to these functions add more than one to the count (see CSTACKCF).
|
||||
**
|
||||
** The proper count excludes the number of CallInfo structures allocated
|
||||
** by Lua, as a kind of "potential" calls. So, when Lua calls a function
|
||||
** (and "consumes" one CallInfo), it needs neither to decrement nor to
|
||||
** check 'nCcalls', as its use of C stack is already accounted for.
|
||||
** About 'nCcalls': This count has two parts: the lower 16 bits counts
|
||||
** the number of recursive invocations in the C stack; the higher
|
||||
** 16 bits counts the number of non-yieldable calls in the stack.
|
||||
** (They are together so that we can change and save both with one
|
||||
** instruction.)
|
||||
*/
|
||||
|
||||
/* number of "C stack slots" used by an external C function */
|
||||
#define CSTACKCF 10
|
||||
|
||||
|
||||
/*
|
||||
** The C-stack size is sliced in the following zones:
|
||||
** - larger than CSTACKERR: normal stack;
|
||||
** - [CSTACKMARK, CSTACKERR]: buffer zone to signal a stack overflow;
|
||||
** - [CSTACKCF, CSTACKERRMARK]: error-handling zone;
|
||||
** - below CSTACKERRMARK: buffer zone to signal overflow during overflow;
|
||||
** (Because the counter can be decremented CSTACKCF at once, we need
|
||||
** the so called "buffer zones", with at least that size, to properly
|
||||
** detect a change from one zone to the next.)
|
||||
*/
|
||||
#define CSTACKERR (8 * CSTACKCF)
|
||||
#define CSTACKMARK (CSTACKERR - (CSTACKCF + 2))
|
||||
#define CSTACKERRMARK (CSTACKCF + 2)
|
||||
|
||||
|
||||
/* initial limit for the C-stack of threads */
|
||||
#define CSTACKTHREAD (2 * CSTACKERR)
|
||||
|
||||
|
||||
/* true if this thread does not have non-yieldable calls in the stack */
|
||||
#define yieldable(L) (((L)->nCcalls & 0xffff0000) == 0)
|
||||
|
@ -120,13 +108,8 @@
|
|||
/* Decrement the number of non-yieldable calls */
|
||||
#define decnny(L) ((L)->nCcalls -= 0x10000)
|
||||
|
||||
/* Increment the number of non-yieldable calls and decrement nCcalls */
|
||||
#define incXCcalls(L) ((L)->nCcalls += 0x10000 - CSTACKCF)
|
||||
|
||||
/* Decrement the number of non-yieldable calls and increment nCcalls */
|
||||
#define decXCcalls(L) ((L)->nCcalls -= 0x10000 - CSTACKCF)
|
||||
|
||||
|
||||
/* Non-yieldable call increment */
|
||||
#define nyci (0x10000 | 1)
|
||||
|
||||
|
||||
|
||||
|
@ -144,12 +127,20 @@ struct lua_longjmp; /* defined in ldo.c */
|
|||
#endif
|
||||
|
||||
|
||||
/* extra stack space to handle TM calls and some other extras */
|
||||
/*
|
||||
** Extra stack space to handle TM calls and some other extras. This
|
||||
** space is not included in 'stack_last'. It is used only to avoid stack
|
||||
** checks, either because the element will be promptly popped or because
|
||||
** there will be a stack check soon after the push. Function frames
|
||||
** never use this extra space, so it does not need to be kept clean.
|
||||
*/
|
||||
#define EXTRA_STACK 5
|
||||
|
||||
|
||||
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
|
||||
|
||||
#define stacksize(th) cast_int((th)->stack_last - (th)->stack)
|
||||
|
||||
|
||||
/* kinds of Garbage Collection */
|
||||
#define KGC_INC 0 /* incremental gc */
|
||||
|
@ -165,6 +156,18 @@ typedef struct stringtable {
|
|||
|
||||
/*
|
||||
** Information about a call.
|
||||
** About union 'u':
|
||||
** - field 'l' is used only for Lua functions;
|
||||
** - field 'c' is used only for C functions.
|
||||
** About union 'u2':
|
||||
** - field 'funcidx' is used only by C functions while doing a
|
||||
** protected call;
|
||||
** - 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;
|
||||
** - field 'transferinfo' is used only during call/returnhooks,
|
||||
** before the function starts or after it ends.
|
||||
*/
|
||||
typedef struct CallInfo {
|
||||
StkId func; /* function index in the stack */
|
||||
|
@ -185,6 +188,7 @@ typedef struct CallInfo {
|
|||
union {
|
||||
int funcidx; /* called-function index */
|
||||
int nyield; /* number of values yielded */
|
||||
int nres; /* number of values returned */
|
||||
struct { /* info about transferred values (for call/return hooks) */
|
||||
unsigned short ftransfer; /* offset of first value transferred */
|
||||
unsigned short ntransfer; /* number of values transferred */
|
||||
|
@ -200,16 +204,34 @@ typedef struct CallInfo {
|
|||
*/
|
||||
#define CIST_OAH (1<<0) /* original value of 'allowhook' */
|
||||
#define CIST_C (1<<1) /* call is running a C function */
|
||||
#define CIST_HOOKED (1<<2) /* call is running a debug hook */
|
||||
#define CIST_YPCALL (1<<3) /* call is a yieldable protected call */
|
||||
#define CIST_TAIL (1<<4) /* call was tail called */
|
||||
#define CIST_HOOKYIELD (1<<5) /* last hook called yielded */
|
||||
#define CIST_FIN (1<<6) /* call is running a finalizer */
|
||||
#define CIST_TRAN (1<<7) /* 'ci' has transfer information */
|
||||
#define CIST_FRESH (1<<2) /* call is on a fresh "luaV_execute" frame */
|
||||
#define CIST_HOOKED (1<<3) /* call is running a debug hook */
|
||||
#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_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) */
|
||||
#define CIST_RECST 10
|
||||
#if defined(LUA_COMPAT_LT_LE)
|
||||
#define CIST_LEQ (1<<8) /* using __lt for __le */
|
||||
#define CIST_LEQ (1<<13) /* using __lt for __le */
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Field CIST_RECST stores the "recover status", used to keep the error
|
||||
** status while closing to-be-closed variables in coroutines, so that
|
||||
** Lua can correctly resume after an yield from a __close method called
|
||||
** because of an error. (Three bits are enough for error status.)
|
||||
*/
|
||||
#define getcistrecst(ci) (((ci)->callstatus >> CIST_RECST) & 7)
|
||||
#define setcistrecst(ci,st) \
|
||||
check_exp(((st) & 7) == (st), /* status must fit in three bits */ \
|
||||
((ci)->callstatus = ((ci)->callstatus & ~(7 << CIST_RECST)) \
|
||||
| ((st) << CIST_RECST)))
|
||||
|
||||
|
||||
/* active function is a Lua function */
|
||||
#define isLua(ci) (!((ci)->callstatus & CIST_C))
|
||||
|
||||
|
@ -238,6 +260,7 @@ typedef struct global_State {
|
|||
lu_byte currentwhite;
|
||||
lu_byte gcstate; /* state of garbage collector */
|
||||
lu_byte gckind; /* kind of GC running */
|
||||
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 */
|
||||
|
@ -257,10 +280,11 @@ typedef struct global_State {
|
|||
GCObject *fixedgc; /* list of objects not to be collected */
|
||||
/* fields for generational collector */
|
||||
GCObject *survival; /* start of objects that survived one GC cycle */
|
||||
GCObject *old; /* start of old objects */
|
||||
GCObject *reallyold; /* old objects with more than one cycle */
|
||||
GCObject *old1; /* start of old1 objects */
|
||||
GCObject *reallyold; /* objects more than one cycle old ("really old") */
|
||||
GCObject *firstold1; /* first OLD1 object in the list (if any) */
|
||||
GCObject *finobjsur; /* list of survival objects with finalizers */
|
||||
GCObject *finobjold; /* list of old objects with finalizers */
|
||||
GCObject *finobjold1; /* list of old1 objects with finalizers */
|
||||
GCObject *finobjrold; /* list of really old objects with finalizers */
|
||||
struct lua_State *twups; /* list of threads with open upvalues */
|
||||
lua_CFunction panic; /* to be called in unprotected errors */
|
||||
|
@ -271,7 +295,6 @@ typedef struct global_State {
|
|||
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
|
||||
lua_WarnFunction warnf; /* warning function */
|
||||
void *ud_warn; /* auxiliary data to 'warnf' */
|
||||
unsigned int Cstacklimit; /* current limit for the C stack */
|
||||
} global_State;
|
||||
|
||||
|
||||
|
@ -286,18 +309,18 @@ struct lua_State {
|
|||
StkId top; /* first free slot in the stack */
|
||||
global_State *l_G;
|
||||
CallInfo *ci; /* call info for current function */
|
||||
const Instruction *oldpc; /* last pc traced */
|
||||
StkId stack_last; /* last free slot in the stack */
|
||||
StkId stack_last; /* end of stack (last element + 1) */
|
||||
StkId stack; /* stack base */
|
||||
UpVal *openupval; /* list of open upvalues in this stack */
|
||||
StkId tbclist; /* list of to-be-closed variables */
|
||||
GCObject *gclist;
|
||||
struct lua_State *twups; /* list of threads with open upvalues */
|
||||
struct lua_longjmp *errorJmp; /* current error recover point */
|
||||
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
|
||||
volatile lua_Hook hook;
|
||||
ptrdiff_t errfunc; /* current error handling function (stack index) */
|
||||
l_uint32 nCcalls; /* number of allowed nested C calls - 'nci' */
|
||||
int stacksize;
|
||||
l_uint32 nCcalls; /* number of nested (non-yieldable | C) calls */
|
||||
int oldpc; /* last pc traced */
|
||||
int basehookcount;
|
||||
int hookcount;
|
||||
volatile l_signalT hookmask;
|
||||
|
@ -306,9 +329,21 @@ struct lua_State {
|
|||
|
||||
#define G(L) (L->l_G)
|
||||
|
||||
/*
|
||||
** 'g->nilvalue' being a nil value flags that the state was completely
|
||||
** build.
|
||||
*/
|
||||
#define completestate(g) ttisnil(&g->nilvalue)
|
||||
|
||||
|
||||
/*
|
||||
** Union of all collectable objects (only for conversions)
|
||||
** ISO C99, 6.5.2.3 p.5:
|
||||
** "if a union contains several structures that share a common initial
|
||||
** sequence [...], and if the union object currently contains one
|
||||
** of these structures, it is permitted to inspect the common initial
|
||||
** part of any of them anywhere that a declaration of the complete type
|
||||
** of the union is visible."
|
||||
*/
|
||||
union GCUnion {
|
||||
GCObject gc; /* common header */
|
||||
|
@ -322,6 +357,11 @@ union GCUnion {
|
|||
};
|
||||
|
||||
|
||||
/*
|
||||
** ISO C99, 6.7.2.1 p.14:
|
||||
** "A pointer to a union object, suitably converted, points to each of
|
||||
** its members [...], and vice versa."
|
||||
*/
|
||||
#define cast_u(o) cast(union GCUnion *, (o))
|
||||
|
||||
/* macros to convert a GCObject into a specific value */
|
||||
|
@ -353,12 +393,12 @@ LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
|
|||
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
|
||||
LUAI_FUNC void luaE_freeCI (lua_State *L);
|
||||
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
||||
LUAI_FUNC void luaE_enterCcall (lua_State *L);
|
||||
LUAI_FUNC void luaE_checkcstack (lua_State *L);
|
||||
LUAI_FUNC void luaE_incCstack (lua_State *L);
|
||||
LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
|
||||
LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
|
||||
LUAI_FUNC int luaE_resetthread (lua_State *L, int status);
|
||||
|
||||
|
||||
#define luaE_exitCcall(L) ((L)->nCcalls++)
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -22,16 +22,6 @@
|
|||
#include "lstring.h"
|
||||
|
||||
|
||||
/*
|
||||
** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a long string to
|
||||
** compute its hash
|
||||
*/
|
||||
#if !defined(LUAI_HASHLIMIT)
|
||||
#define LUAI_HASHLIMIT 5
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Maximum size for string table.
|
||||
*/
|
||||
|
@ -50,10 +40,9 @@ int luaS_eqlngstr (TString *a, TString *b) {
|
|||
}
|
||||
|
||||
|
||||
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed,
|
||||
size_t step) {
|
||||
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
|
||||
unsigned int h = seed ^ cast_uint(l);
|
||||
for (; l >= step; l -= step)
|
||||
for (; l > 0; l--)
|
||||
h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
|
||||
return h;
|
||||
}
|
||||
|
@ -63,8 +52,7 @@ unsigned int luaS_hashlongstr (TString *ts) {
|
|||
lua_assert(ts->tt == LUA_VLNGSTR);
|
||||
if (ts->extra == 0) { /* no hash? */
|
||||
size_t len = ts->u.lnglen;
|
||||
size_t step = (len >> LUAI_HASHLIMIT) + 1;
|
||||
ts->hash = luaS_hash(getstr(ts), len, ts->hash, step);
|
||||
ts->hash = luaS_hash(getstr(ts), len, ts->hash);
|
||||
ts->extra = 1; /* now it has its hash */
|
||||
}
|
||||
return ts->hash;
|
||||
|
@ -101,7 +89,7 @@ void luaS_resize (lua_State *L, int nsize) {
|
|||
if (nsize < osize) /* shrinking table? */
|
||||
tablerehash(tb->hash, osize, nsize); /* depopulate shrinking part */
|
||||
newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*);
|
||||
if (unlikely(newvect == NULL)) { /* reallocation failed? */
|
||||
if (l_unlikely(newvect == NULL)) { /* reallocation failed? */
|
||||
if (nsize < osize) /* was it shrinking table? */
|
||||
tablerehash(tb->hash, nsize, osize); /* restore to original size */
|
||||
/* leave table as it was */
|
||||
|
@ -184,7 +172,7 @@ void luaS_remove (lua_State *L, TString *ts) {
|
|||
|
||||
|
||||
static void growstrtab (lua_State *L, stringtable *tb) {
|
||||
if (unlikely(tb->nuse == MAX_INT)) { /* too many strings? */
|
||||
if (l_unlikely(tb->nuse == MAX_INT)) { /* too many strings? */
|
||||
luaC_fullgc(L, 1); /* try to free some... */
|
||||
if (tb->nuse == MAX_INT) /* still too many? */
|
||||
luaM_error(L); /* cannot even create a message... */
|
||||
|
@ -201,7 +189,7 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
|
|||
TString *ts;
|
||||
global_State *g = G(L);
|
||||
stringtable *tb = &g->strt;
|
||||
unsigned int h = luaS_hash(str, l, g->seed, 1);
|
||||
unsigned int h = luaS_hash(str, l, g->seed);
|
||||
TString **list = &tb->hash[lmod(h, tb->size)];
|
||||
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
|
||||
for (ts = *list; ts != NULL; ts = ts->u.hnext) {
|
||||
|
@ -235,7 +223,7 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
|
|||
return internshrstr(L, str, l);
|
||||
else {
|
||||
TString *ts;
|
||||
if (unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char)))
|
||||
if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char)))
|
||||
luaM_toobig(L);
|
||||
ts = luaS_createlngstrobj(L, l);
|
||||
memcpy(getstr(ts), str, l * sizeof(char));
|
||||
|
@ -271,7 +259,7 @@ Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) {
|
|||
Udata *u;
|
||||
int i;
|
||||
GCObject *o;
|
||||
if (unlikely(s > MAX_SIZE - udatamemoffset(nuvalue)))
|
||||
if (l_unlikely(s > MAX_SIZE - udatamemoffset(nuvalue)))
|
||||
luaM_toobig(L);
|
||||
o = luaC_newobj(L, LUA_VUSERDATA, sizeudata(nuvalue, s));
|
||||
u = gco2u(o);
|
||||
|
|
|
@ -41,8 +41,7 @@
|
|||
#define eqshrstr(a,b) check_exp((a)->tt == LUA_VSHRSTR, (a) == (b))
|
||||
|
||||
|
||||
LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l,
|
||||
unsigned int seed, size_t step);
|
||||
LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
|
||||
LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts);
|
||||
LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
|
||||
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
|
||||
|
|
|
@ -152,8 +152,9 @@ static int str_rep (lua_State *L) {
|
|||
const char *s = luaL_checklstring(L, 1, &l);
|
||||
lua_Integer n = luaL_checkinteger(L, 2);
|
||||
const char *sep = luaL_optlstring(L, 3, "", &lsep);
|
||||
if (n <= 0) lua_pushliteral(L, "");
|
||||
else if (l + lsep < l || l + lsep > MAXSIZE / n) /* may overflow? */
|
||||
if (n <= 0)
|
||||
lua_pushliteral(L, "");
|
||||
else if (l_unlikely(l + lsep < l || l + lsep > MAXSIZE / n))
|
||||
return luaL_error(L, "resulting string too large");
|
||||
else {
|
||||
size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep;
|
||||
|
@ -181,7 +182,7 @@ static int str_byte (lua_State *L) {
|
|||
size_t pose = getendpos(L, 3, pi, l);
|
||||
int n, i;
|
||||
if (posi > pose) return 0; /* empty interval; return no values */
|
||||
if (pose - posi >= (size_t)INT_MAX) /* arithmetic overflow? */
|
||||
if (l_unlikely(pose - posi >= (size_t)INT_MAX)) /* arithmetic overflow? */
|
||||
return luaL_error(L, "string slice too long");
|
||||
n = (int)(pose - posi) + 1;
|
||||
luaL_checkstack(L, n, "string slice too long");
|
||||
|
@ -235,7 +236,7 @@ static int str_dump (lua_State *L) {
|
|||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
lua_settop(L, 1); /* ensure function is on the top of the stack */
|
||||
state.init = 0;
|
||||
if (lua_dump(L, writer, &state, strip) != 0)
|
||||
if (l_unlikely(lua_dump(L, writer, &state, strip) != 0))
|
||||
return luaL_error(L, "unable to dump given function");
|
||||
luaL_pushresult(&state.B);
|
||||
return 1;
|
||||
|
@ -275,7 +276,8 @@ static int tonum (lua_State *L, int arg) {
|
|||
|
||||
static void trymt (lua_State *L, const char *mtname) {
|
||||
lua_settop(L, 2); /* back to the original arguments */
|
||||
if (lua_type(L, 2) == LUA_TSTRING || !luaL_getmetafield(L, 2, mtname))
|
||||
if (l_unlikely(lua_type(L, 2) == LUA_TSTRING ||
|
||||
!luaL_getmetafield(L, 2, mtname)))
|
||||
luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2,
|
||||
luaL_typename(L, -2), luaL_typename(L, -1));
|
||||
lua_insert(L, -3); /* put metamethod before arguments */
|
||||
|
@ -383,7 +385,8 @@ static const char *match (MatchState *ms, const char *s, const char *p);
|
|||
|
||||
static int check_capture (MatchState *ms, int l) {
|
||||
l -= '1';
|
||||
if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
|
||||
if (l_unlikely(l < 0 || l >= ms->level ||
|
||||
ms->capture[l].len == CAP_UNFINISHED))
|
||||
return luaL_error(ms->L, "invalid capture index %%%d", l + 1);
|
||||
return l;
|
||||
}
|
||||
|
@ -400,14 +403,14 @@ static int capture_to_close (MatchState *ms) {
|
|||
static const char *classend (MatchState *ms, const char *p) {
|
||||
switch (*p++) {
|
||||
case L_ESC: {
|
||||
if (p == ms->p_end)
|
||||
if (l_unlikely(p == ms->p_end))
|
||||
luaL_error(ms->L, "malformed pattern (ends with '%%')");
|
||||
return p+1;
|
||||
}
|
||||
case '[': {
|
||||
if (*p == '^') p++;
|
||||
do { /* look for a ']' */
|
||||
if (p == ms->p_end)
|
||||
if (l_unlikely(p == ms->p_end))
|
||||
luaL_error(ms->L, "malformed pattern (missing ']')");
|
||||
if (*(p++) == L_ESC && p < ms->p_end)
|
||||
p++; /* skip escapes (e.g. '%]') */
|
||||
|
@ -482,7 +485,7 @@ static int singlematch (MatchState *ms, const char *s, const char *p,
|
|||
|
||||
static const char *matchbalance (MatchState *ms, const char *s,
|
||||
const char *p) {
|
||||
if (p >= ms->p_end - 1)
|
||||
if (l_unlikely(p >= ms->p_end - 1))
|
||||
luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')");
|
||||
if (*s != *p) return NULL;
|
||||
else {
|
||||
|
@ -565,7 +568,7 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
|
|||
|
||||
|
||||
static const char *match (MatchState *ms, const char *s, const char *p) {
|
||||
if (ms->matchdepth-- == 0)
|
||||
if (l_unlikely(ms->matchdepth-- == 0))
|
||||
luaL_error(ms->L, "pattern too complex");
|
||||
init: /* using goto's to optimize tail recursion */
|
||||
if (p != ms->p_end) { /* end of pattern? */
|
||||
|
@ -599,7 +602,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
|
|||
case 'f': { /* frontier? */
|
||||
const char *ep; char previous;
|
||||
p += 2;
|
||||
if (*p != '[')
|
||||
if (l_unlikely(*p != '['))
|
||||
luaL_error(ms->L, "missing '[' after '%%f' in pattern");
|
||||
ep = classend(ms, p); /* points to what is next */
|
||||
previous = (s == ms->src_init) ? '\0' : *(s - 1);
|
||||
|
@ -699,7 +702,7 @@ static const char *lmemfind (const char *s1, size_t l1,
|
|||
static size_t get_onecapture (MatchState *ms, int i, const char *s,
|
||||
const char *e, const char **cap) {
|
||||
if (i >= ms->level) {
|
||||
if (i != 0)
|
||||
if (l_unlikely(i != 0))
|
||||
luaL_error(ms->L, "invalid capture index %%%d", i + 1);
|
||||
*cap = s;
|
||||
return e - s;
|
||||
|
@ -707,7 +710,7 @@ static size_t get_onecapture (MatchState *ms, int i, const char *s,
|
|||
else {
|
||||
ptrdiff_t capl = ms->capture[i].len;
|
||||
*cap = ms->capture[i].init;
|
||||
if (capl == CAP_UNFINISHED)
|
||||
if (l_unlikely(capl == CAP_UNFINISHED))
|
||||
luaL_error(ms->L, "unfinished capture");
|
||||
else if (capl == CAP_POSITION)
|
||||
lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1);
|
||||
|
@ -926,7 +929,7 @@ static int add_value (MatchState *ms, luaL_Buffer *b, const char *s,
|
|||
luaL_addlstring(b, s, e - s); /* keep original text */
|
||||
return 0; /* no changes */
|
||||
}
|
||||
else if (!lua_isstring(L, -1))
|
||||
else if (l_unlikely(!lua_isstring(L, -1)))
|
||||
return luaL_error(L, "invalid replacement value (a %s)",
|
||||
luaL_typename(L, -1));
|
||||
else {
|
||||
|
@ -1058,7 +1061,7 @@ static int lua_number2strx (lua_State *L, char *buff, int sz,
|
|||
for (i = 0; i < n; i++)
|
||||
buff[i] = toupper(uchar(buff[i]));
|
||||
}
|
||||
else if (fmt[SIZELENMOD] != 'a')
|
||||
else if (l_unlikely(fmt[SIZELENMOD] != 'a'))
|
||||
return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
|
||||
return n;
|
||||
}
|
||||
|
@ -1358,17 +1361,6 @@ struct cD {
|
|||
#define MAXALIGN (offsetof(struct cD, u))
|
||||
|
||||
|
||||
/*
|
||||
** Union for serializing floats
|
||||
*/
|
||||
typedef union Ftypes {
|
||||
float f;
|
||||
double d;
|
||||
lua_Number n;
|
||||
char buff[5 * sizeof(lua_Number)]; /* enough for any float type */
|
||||
} Ftypes;
|
||||
|
||||
|
||||
/*
|
||||
** information to pack/unpack stuff
|
||||
*/
|
||||
|
@ -1385,7 +1377,9 @@ typedef struct Header {
|
|||
typedef enum KOption {
|
||||
Kint, /* signed integers */
|
||||
Kuint, /* unsigned integers */
|
||||
Kfloat, /* floating-point numbers */
|
||||
Kfloat, /* single-precision floating-point numbers */
|
||||
Knumber, /* Lua "native" floating-point numbers */
|
||||
Kdouble, /* double-precision floating-point numbers */
|
||||
Kchar, /* fixed-length strings */
|
||||
Kstring, /* strings with prefixed length */
|
||||
Kzstr, /* zero-terminated strings */
|
||||
|
@ -1420,7 +1414,7 @@ static int getnum (const char **fmt, int df) {
|
|||
*/
|
||||
static int getnumlimit (Header *h, const char **fmt, int df) {
|
||||
int sz = getnum(fmt, df);
|
||||
if (sz > MAXINTSIZE || sz <= 0)
|
||||
if (l_unlikely(sz > MAXINTSIZE || sz <= 0))
|
||||
return luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
|
||||
sz, MAXINTSIZE);
|
||||
return sz;
|
||||
|
@ -1454,14 +1448,14 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
|
|||
case 'J': *size = sizeof(lua_Integer); return Kuint;
|
||||
case 'T': *size = sizeof(size_t); return Kuint;
|
||||
case 'f': *size = sizeof(float); return Kfloat;
|
||||
case 'd': *size = sizeof(double); return Kfloat;
|
||||
case 'n': *size = sizeof(lua_Number); return Kfloat;
|
||||
case 'n': *size = sizeof(lua_Number); return Knumber;
|
||||
case 'd': *size = sizeof(double); return Kdouble;
|
||||
case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint;
|
||||
case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
|
||||
case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
|
||||
case 'c':
|
||||
*size = getnum(fmt, -1);
|
||||
if (*size == -1)
|
||||
if (l_unlikely(*size == -1))
|
||||
luaL_error(h->L, "missing size for format option 'c'");
|
||||
return Kchar;
|
||||
case 'z': return Kzstr;
|
||||
|
@ -1500,7 +1494,7 @@ static KOption getdetails (Header *h, size_t totalsize,
|
|||
else {
|
||||
if (align > h->maxalign) /* enforce maximum alignment */
|
||||
align = h->maxalign;
|
||||
if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */
|
||||
if (l_unlikely((align & (align - 1)) != 0)) /* not a power of 2? */
|
||||
luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
|
||||
*ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);
|
||||
}
|
||||
|
@ -1535,12 +1529,10 @@ static void packint (luaL_Buffer *b, lua_Unsigned n,
|
|||
** Copy 'size' bytes from 'src' to 'dest', correcting endianness if
|
||||
** given 'islittle' is different from native endianness.
|
||||
*/
|
||||
static void copywithendian (volatile char *dest, volatile const char *src,
|
||||
static void copywithendian (char *dest, const char *src,
|
||||
int size, int islittle) {
|
||||
if (islittle == nativeendian.little) {
|
||||
while (size-- != 0)
|
||||
*(dest++) = *(src++);
|
||||
}
|
||||
if (islittle == nativeendian.little)
|
||||
memcpy(dest, src, size);
|
||||
else {
|
||||
dest += size - 1;
|
||||
while (size-- != 0)
|
||||
|
@ -1583,15 +1575,27 @@ static int str_pack (lua_State *L) {
|
|||
packint(&b, (lua_Unsigned)n, h.islittle, size, 0);
|
||||
break;
|
||||
}
|
||||
case Kfloat: { /* floating-point options */
|
||||
volatile Ftypes u;
|
||||
char *buff = luaL_prepbuffsize(&b, size);
|
||||
lua_Number n = luaL_checknumber(L, arg); /* get argument */
|
||||
if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */
|
||||
else if (size == sizeof(u.d)) u.d = (double)n;
|
||||
else u.n = n;
|
||||
/* move 'u' to final result, correcting endianness if needed */
|
||||
copywithendian(buff, u.buff, size, h.islittle);
|
||||
case Kfloat: { /* C float */
|
||||
float f = (float)luaL_checknumber(L, arg); /* get argument */
|
||||
char *buff = luaL_prepbuffsize(&b, sizeof(f));
|
||||
/* move 'f' to final result, correcting endianness if needed */
|
||||
copywithendian(buff, (char *)&f, sizeof(f), h.islittle);
|
||||
luaL_addsize(&b, size);
|
||||
break;
|
||||
}
|
||||
case Knumber: { /* Lua float */
|
||||
lua_Number f = luaL_checknumber(L, arg); /* get argument */
|
||||
char *buff = luaL_prepbuffsize(&b, sizeof(f));
|
||||
/* move 'f' to final result, correcting endianness if needed */
|
||||
copywithendian(buff, (char *)&f, sizeof(f), h.islittle);
|
||||
luaL_addsize(&b, size);
|
||||
break;
|
||||
}
|
||||
case Kdouble: { /* C double */
|
||||
double f = (double)luaL_checknumber(L, arg); /* get argument */
|
||||
char *buff = luaL_prepbuffsize(&b, sizeof(f));
|
||||
/* move 'f' to final result, correcting endianness if needed */
|
||||
copywithendian(buff, (char *)&f, sizeof(f), h.islittle);
|
||||
luaL_addsize(&b, size);
|
||||
break;
|
||||
}
|
||||
|
@ -1682,7 +1686,7 @@ static lua_Integer unpackint (lua_State *L, const char *str,
|
|||
else if (size > SZINT) { /* must check unread bytes */
|
||||
int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC;
|
||||
for (i = limit; i < size; i++) {
|
||||
if ((unsigned char)str[islittle ? i : size - 1 - i] != mask)
|
||||
if (l_unlikely((unsigned char)str[islittle ? i : size - 1 - i] != mask))
|
||||
luaL_error(L, "%d-byte integer does not fit into Lua Integer", size);
|
||||
}
|
||||
}
|
||||
|
@ -1717,13 +1721,21 @@ static int str_unpack (lua_State *L) {
|
|||
break;
|
||||
}
|
||||
case Kfloat: {
|
||||
volatile Ftypes u;
|
||||
lua_Number num;
|
||||
copywithendian(u.buff, data + pos, size, h.islittle);
|
||||
if (size == sizeof(u.f)) num = (lua_Number)u.f;
|
||||
else if (size == sizeof(u.d)) num = (lua_Number)u.d;
|
||||
else num = u.n;
|
||||
lua_pushnumber(L, num);
|
||||
float f;
|
||||
copywithendian((char *)&f, data + pos, sizeof(f), h.islittle);
|
||||
lua_pushnumber(L, (lua_Number)f);
|
||||
break;
|
||||
}
|
||||
case Knumber: {
|
||||
lua_Number f;
|
||||
copywithendian((char *)&f, data + pos, sizeof(f), h.islittle);
|
||||
lua_pushnumber(L, f);
|
||||
break;
|
||||
}
|
||||
case Kdouble: {
|
||||
double f;
|
||||
copywithendian((char *)&f, data + pos, sizeof(f), h.islittle);
|
||||
lua_pushnumber(L, (lua_Number)f);
|
||||
break;
|
||||
}
|
||||
case Kchar: {
|
||||
|
@ -1738,7 +1750,7 @@ static int str_unpack (lua_State *L) {
|
|||
break;
|
||||
}
|
||||
case Kzstr: {
|
||||
size_t len = (int)strlen(data + pos);
|
||||
size_t len = strlen(data + pos);
|
||||
luaL_argcheck(L, pos + len < ld, 2,
|
||||
"unfinished string for format 'z'");
|
||||
lua_pushlstring(L, data + pos, len);
|
||||
|
|
159
lua/src/ltable.c
159
lua/src/ltable.c
|
@ -68,20 +68,25 @@
|
|||
#define MAXHSIZE luaM_limitN(1u << MAXHBITS, Node)
|
||||
|
||||
|
||||
/*
|
||||
** When the original hash value is good, hashing by a power of 2
|
||||
** avoids the cost of '%'.
|
||||
*/
|
||||
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
|
||||
|
||||
/*
|
||||
** for other types, it is better to avoid modulo by power of 2, as
|
||||
** they can have many 2 factors.
|
||||
*/
|
||||
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
|
||||
|
||||
|
||||
#define hashstr(t,str) hashpow2(t, (str)->hash)
|
||||
#define hashboolean(t,p) hashpow2(t, p)
|
||||
|
||||
#define hashint(t,i) hashpow2(t, i)
|
||||
|
||||
|
||||
/*
|
||||
** for some types, it is better to avoid modulus by power of 2, as
|
||||
** they tend to have many 2 factors.
|
||||
*/
|
||||
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
|
||||
|
||||
|
||||
#define hashpointer(t,p) hashmod(t, point2uint(p))
|
||||
|
||||
|
||||
|
@ -135,24 +140,38 @@ static int l_hashfloat (lua_Number n) {
|
|||
*/
|
||||
static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
|
||||
switch (withvariant(ktt)) {
|
||||
case LUA_VNUMINT:
|
||||
return hashint(t, ivalueraw(*kvl));
|
||||
case LUA_VNUMFLT:
|
||||
return hashmod(t, l_hashfloat(fltvalueraw(*kvl)));
|
||||
case LUA_VSHRSTR:
|
||||
return hashstr(t, tsvalueraw(*kvl));
|
||||
case LUA_VLNGSTR:
|
||||
return hashpow2(t, luaS_hashlongstr(tsvalueraw(*kvl)));
|
||||
case LUA_VNUMINT: {
|
||||
lua_Integer key = ivalueraw(*kvl);
|
||||
return hashint(t, key);
|
||||
}
|
||||
case LUA_VNUMFLT: {
|
||||
lua_Number n = fltvalueraw(*kvl);
|
||||
return hashmod(t, l_hashfloat(n));
|
||||
}
|
||||
case LUA_VSHRSTR: {
|
||||
TString *ts = tsvalueraw(*kvl);
|
||||
return hashstr(t, ts);
|
||||
}
|
||||
case LUA_VLNGSTR: {
|
||||
TString *ts = tsvalueraw(*kvl);
|
||||
return hashpow2(t, luaS_hashlongstr(ts));
|
||||
}
|
||||
case LUA_VFALSE:
|
||||
return hashboolean(t, 0);
|
||||
case LUA_VTRUE:
|
||||
return hashboolean(t, 1);
|
||||
case LUA_VLIGHTUSERDATA:
|
||||
return hashpointer(t, pvalueraw(*kvl));
|
||||
case LUA_VLCF:
|
||||
return hashpointer(t, fvalueraw(*kvl));
|
||||
default:
|
||||
return hashpointer(t, gcvalueraw(*kvl));
|
||||
case LUA_VLIGHTUSERDATA: {
|
||||
void *p = pvalueraw(*kvl);
|
||||
return hashpointer(t, p);
|
||||
}
|
||||
case LUA_VLCF: {
|
||||
lua_CFunction f = fvalueraw(*kvl);
|
||||
return hashpointer(t, f);
|
||||
}
|
||||
default: {
|
||||
GCObject *o = gcvalueraw(*kvl);
|
||||
return hashpointer(t, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,17 +185,30 @@ static Node *mainpositionTV (const Table *t, const TValue *key) {
|
|||
|
||||
|
||||
/*
|
||||
** Check whether key 'k1' is equal to the key in node 'n2'.
|
||||
** This equality is raw, so there are no metamethods. Floats
|
||||
** with integer values have been normalized, so integers cannot
|
||||
** be equal to floats. It is assumed that 'eqshrstr' is simply
|
||||
** pointer equality, so that short strings are handled in the
|
||||
** default case.
|
||||
** Check whether key 'k1' is equal to the key in node 'n2'. This
|
||||
** equality is raw, so there are no metamethods. Floats with integer
|
||||
** values have been normalized, so integers cannot be equal to
|
||||
** floats. It is assumed that 'eqshrstr' is simply pointer equality, so
|
||||
** that short strings are handled in the default case.
|
||||
** A true 'deadok' means to accept dead keys as equal to their original
|
||||
** values. All dead keys are compared in the default case, by pointer
|
||||
** identity. (Only collectable objects can produce dead keys.) Note that
|
||||
** dead long strings are also compared by identity.
|
||||
** Once a key is dead, its corresponding value may be collected, and
|
||||
** then another value can be created with the same address. If this
|
||||
** other value is given to 'next', 'equalkey' will signal a false
|
||||
** positive. In a regular traversal, this situation should never happen,
|
||||
** as all keys given to 'next' came from the table itself, and therefore
|
||||
** could not have been collected. Outside a regular traversal, we
|
||||
** have garbage in, garbage out. What is relevant is that this false
|
||||
** positive does not break anything. (In particular, 'next' will return
|
||||
** some other valid item on the table or nil.)
|
||||
*/
|
||||
static int equalkey (const TValue *k1, const Node *n2) {
|
||||
if (rawtt(k1) != keytt(n2)) /* not the same variants? */
|
||||
static int equalkey (const TValue *k1, const Node *n2, int deadok) {
|
||||
if ((rawtt(k1) != keytt(n2)) && /* not the same variants? */
|
||||
!(deadok && keyisdead(n2) && iscollectable(k1)))
|
||||
return 0; /* cannot be same key */
|
||||
switch (ttypetag(k1)) {
|
||||
switch (keytt(n2)) {
|
||||
case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE:
|
||||
return 1;
|
||||
case LUA_VNUMINT:
|
||||
|
@ -187,7 +219,7 @@ static int equalkey (const TValue *k1, const Node *n2) {
|
|||
return pvalue(k1) == pvalueraw(keyval(n2));
|
||||
case LUA_VLCF:
|
||||
return fvalue(k1) == fvalueraw(keyval(n2));
|
||||
case LUA_VLNGSTR:
|
||||
case ctb(LUA_VLNGSTR):
|
||||
return luaS_eqlngstr(tsvalue(k1), keystrval(n2));
|
||||
default:
|
||||
return gcvalue(k1) == gcvalueraw(keyval(n2));
|
||||
|
@ -251,11 +283,12 @@ static unsigned int setlimittosize (Table *t) {
|
|||
/*
|
||||
** "Generic" get version. (Not that generic: not valid for integers,
|
||||
** which may be in array part, nor for floats with integral values.)
|
||||
** See explanation about 'deadok' in function 'equalkey'.
|
||||
*/
|
||||
static const TValue *getgeneric (Table *t, const TValue *key) {
|
||||
static const TValue *getgeneric (Table *t, const TValue *key, int deadok) {
|
||||
Node *n = mainpositionTV(t, key);
|
||||
for (;;) { /* check whether 'key' is somewhere in the chain */
|
||||
if (equalkey(key, n))
|
||||
if (equalkey(key, n, deadok))
|
||||
return gval(n); /* that's it */
|
||||
else {
|
||||
int nx = gnext(n);
|
||||
|
@ -292,8 +325,8 @@ static unsigned int findindex (lua_State *L, Table *t, TValue *key,
|
|||
if (i - 1u < asize) /* is 'key' inside array part? */
|
||||
return i; /* yes; that's the index */
|
||||
else {
|
||||
const TValue *n = getgeneric(t, key);
|
||||
if (unlikely(isabstkey(n)))
|
||||
const TValue *n = getgeneric(t, key, 1);
|
||||
if (l_unlikely(isabstkey(n)))
|
||||
luaG_runerror(L, "invalid key to 'next'"); /* key not found */
|
||||
i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */
|
||||
/* hash elements are numbered after array ones */
|
||||
|
@ -471,7 +504,7 @@ static void reinsert (lua_State *L, Table *ot, Table *t) {
|
|||
already present in the table */
|
||||
TValue k;
|
||||
getnodekey(L, &k, old);
|
||||
setobjt2t(L, luaH_set(L, t, &k), gval(old));
|
||||
luaH_set(L, t, &k, gval(old));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -527,7 +560,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
|
|||
}
|
||||
/* allocate new array */
|
||||
newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue);
|
||||
if (unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */
|
||||
if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */
|
||||
freehash(L, &newt); /* release new hash part */
|
||||
luaM_error(L); /* raise error (with array unchanged) */
|
||||
}
|
||||
|
@ -583,7 +616,7 @@ Table *luaH_new (lua_State *L) {
|
|||
GCObject *o = luaC_newobj(L, LUA_VTABLE, sizeof(Table));
|
||||
Table *t = gco2t(o);
|
||||
t->metatable = NULL;
|
||||
t->flags = cast_byte(~0);
|
||||
t->flags = cast_byte(maskflags); /* table has no metamethod fields */
|
||||
t->array = NULL;
|
||||
t->alimit = 0;
|
||||
setnodevector(L, t, 0);
|
||||
|
@ -618,10 +651,10 @@ static Node *getfreepos (Table *t) {
|
|||
** put new key in its main position; otherwise (colliding node is in its main
|
||||
** position), new key goes to an empty position.
|
||||
*/
|
||||
TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
|
||||
void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
|
||||
Node *mp;
|
||||
TValue aux;
|
||||
if (unlikely(ttisnil(key)))
|
||||
if (l_unlikely(ttisnil(key)))
|
||||
luaG_runerror(L, "table index is nil");
|
||||
else if (ttisfloat(key)) {
|
||||
lua_Number f = fltvalue(key);
|
||||
|
@ -630,9 +663,11 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
|
|||
setivalue(&aux, k);
|
||||
key = &aux; /* insert it as an integer */
|
||||
}
|
||||
else if (unlikely(luai_numisnan(f)))
|
||||
else if (l_unlikely(luai_numisnan(f)))
|
||||
luaG_runerror(L, "table index is NaN");
|
||||
}
|
||||
if (ttisnil(value))
|
||||
return; /* do not insert nil values */
|
||||
mp = mainpositionTV(t, key);
|
||||
if (!isempty(gval(mp)) || isdummy(t)) { /* main position is taken? */
|
||||
Node *othern;
|
||||
|
@ -640,7 +675,8 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
|
|||
if (f == NULL) { /* cannot find a free place? */
|
||||
rehash(L, t, key); /* grow table */
|
||||
/* whatever called 'newkey' takes care of TM cache */
|
||||
return luaH_set(L, t, key); /* insert key into grown table */
|
||||
luaH_set(L, t, key, value); /* insert key into grown table */
|
||||
return;
|
||||
}
|
||||
lua_assert(!isdummy(t));
|
||||
othern = mainposition(t, keytt(mp), &keyval(mp));
|
||||
|
@ -668,7 +704,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
|
|||
setnodekey(L, mp, key);
|
||||
luaC_barrierback(L, obj2gco(t), key);
|
||||
lua_assert(isempty(gval(mp)));
|
||||
return gval(mp);
|
||||
setobj2t(L, gval(mp), value);
|
||||
}
|
||||
|
||||
|
||||
|
@ -730,7 +766,7 @@ const TValue *luaH_getstr (Table *t, TString *key) {
|
|||
else { /* for long strings, use generic case */
|
||||
TValue ko;
|
||||
setsvalue(cast(lua_State *, NULL), &ko, key);
|
||||
return getgeneric(t, &ko);
|
||||
return getgeneric(t, &ko, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -750,34 +786,45 @@ const TValue *luaH_get (Table *t, const TValue *key) {
|
|||
/* else... */
|
||||
} /* FALLTHROUGH */
|
||||
default:
|
||||
return getgeneric(t, key);
|
||||
return getgeneric(t, key, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Finish a raw "set table" operation, where 'slot' is where the value
|
||||
** should have been (the result of a previous "get table").
|
||||
** Beware: when using this function you probably need to check a GC
|
||||
** barrier and invalidate the TM cache.
|
||||
*/
|
||||
void luaH_finishset (lua_State *L, Table *t, const TValue *key,
|
||||
const TValue *slot, TValue *value) {
|
||||
if (isabstkey(slot))
|
||||
luaH_newkey(L, t, key, value);
|
||||
else
|
||||
setobj2t(L, cast(TValue *, slot), value);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** beware: when using this function you probably need to check a GC
|
||||
** barrier and invalidate the TM cache.
|
||||
*/
|
||||
TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
|
||||
const TValue *p = luaH_get(t, key);
|
||||
if (!isabstkey(p))
|
||||
return cast(TValue *, p);
|
||||
else return luaH_newkey(L, t, key);
|
||||
void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) {
|
||||
const TValue *slot = luaH_get(t, key);
|
||||
luaH_finishset(L, t, key, slot, value);
|
||||
}
|
||||
|
||||
|
||||
void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
|
||||
const TValue *p = luaH_getint(t, key);
|
||||
TValue *cell;
|
||||
if (!isabstkey(p))
|
||||
cell = cast(TValue *, p);
|
||||
else {
|
||||
if (isabstkey(p)) {
|
||||
TValue k;
|
||||
setivalue(&k, key);
|
||||
cell = luaH_newkey(L, t, &k);
|
||||
luaH_newkey(L, t, &k, value);
|
||||
}
|
||||
setobj2t(L, cell, value);
|
||||
else
|
||||
setobj2t(L, cast(TValue *, p), value);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,7 +15,12 @@
|
|||
#define gnext(n) ((n)->u.next)
|
||||
|
||||
|
||||
#define invalidateTMcache(t) ((t)->flags = 0)
|
||||
/*
|
||||
** Clear all bits of fast-access metamethods, which means that the table
|
||||
** may have any of these metamethods. (First access that fails after the
|
||||
** clearing will set the bit again.)
|
||||
*/
|
||||
#define invalidateTMcache(t) ((t)->flags &= ~maskflags)
|
||||
|
||||
|
||||
/* true when 't' is using 'dummynode' as its hash part */
|
||||
|
@ -36,8 +41,12 @@ LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
|
|||
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
|
||||
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
|
||||
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
|
||||
LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key);
|
||||
LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key);
|
||||
LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key,
|
||||
TValue *value);
|
||||
LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key,
|
||||
TValue *value);
|
||||
LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key,
|
||||
const TValue *slot, TValue *value);
|
||||
LUAI_FUNC Table *luaH_new (lua_State *L);
|
||||
LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
|
||||
unsigned int nhsize);
|
||||
|
|
|
@ -145,8 +145,8 @@ static int tmove (lua_State *L) {
|
|||
|
||||
static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
|
||||
lua_geti(L, 1, i);
|
||||
if (!lua_isstring(L, -1))
|
||||
luaL_error(L, "invalid value (%s) at index %d in table for 'concat'",
|
||||
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_addvalue(b);
|
||||
}
|
||||
|
@ -196,7 +196,8 @@ static int tunpack (lua_State *L) {
|
|||
lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
|
||||
if (i > e) return 0; /* empty range */
|
||||
n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */
|
||||
if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n)))
|
||||
if (l_unlikely(n >= (unsigned int)INT_MAX ||
|
||||
!lua_checkstack(L, (int)(++n))))
|
||||
return luaL_error(L, "too many results to unpack");
|
||||
for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */
|
||||
lua_geti(L, 1, i);
|
||||
|
@ -300,14 +301,14 @@ static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
|
|||
for (;;) {
|
||||
/* next loop: repeat ++i while a[i] < P */
|
||||
while ((void)lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {
|
||||
if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */
|
||||
if (l_unlikely(i == up - 1)) /* a[i] < P but a[up - 1] == P ?? */
|
||||
luaL_error(L, "invalid order function for sorting");
|
||||
lua_pop(L, 1); /* remove a[i] */
|
||||
}
|
||||
/* after the loop, a[i] >= P and a[lo .. i - 1] < P */
|
||||
/* next loop: repeat --j while P < a[j] */
|
||||
while ((void)lua_geti(L, 1, --j), sort_comp(L, -3, -1)) {
|
||||
if (j < i) /* j < i but a[j] > P ?? */
|
||||
if (l_unlikely(j < i)) /* j < i but a[j] > P ?? */
|
||||
luaL_error(L, "invalid order function for sorting");
|
||||
lua_pop(L, 1); /* remove a[j] */
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
|||
|
||||
void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
||||
StkId res, TMS event) {
|
||||
if (!callbinTM(L, p1, p2, res, event)) {
|
||||
if (l_unlikely(!callbinTM(L, p1, p2, res, event))) {
|
||||
switch (event) {
|
||||
case TM_BAND: case TM_BOR: case TM_BXOR:
|
||||
case TM_SHL: case TM_SHR: case TM_BNOT: {
|
||||
|
@ -166,7 +166,8 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
|||
|
||||
void luaT_tryconcatTM (lua_State *L) {
|
||||
StkId top = L->top;
|
||||
if (!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2, TM_CONCAT))
|
||||
if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
|
||||
TM_CONCAT)))
|
||||
luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
|
||||
}
|
||||
|
||||
|
@ -240,7 +241,7 @@ void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
|
|||
int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */
|
||||
int nextra = actual - nfixparams; /* number of extra arguments */
|
||||
ci->u.l.nextraargs = nextra;
|
||||
checkstackGC(L, p->maxstacksize + 1);
|
||||
luaD_checkstack(L, p->maxstacksize + 1);
|
||||
/* copy function to the top of the stack */
|
||||
setobjs2s(L, L->top++, ci->func);
|
||||
/* move fixed parameters to the top of the stack */
|
||||
|
@ -259,7 +260,7 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
|
|||
int nextra = ci->u.l.nextraargs;
|
||||
if (wanted < 0) {
|
||||
wanted = nextra; /* get all extra arguments available */
|
||||
checkstackp(L, nextra, where); /* ensure stack space */
|
||||
checkstackGCp(L, nextra, where); /* ensure stack space */
|
||||
L->top = where + nextra; /* next instruction will need top */
|
||||
}
|
||||
for (i = 0; i < wanted && i < nextra; i++)
|
||||
|
|
|
@ -45,6 +45,15 @@ typedef enum {
|
|||
} TMS;
|
||||
|
||||
|
||||
/*
|
||||
** Mask with 1 in all fast-access methods. A 1 in any of these bits
|
||||
** in the flag of a (meta)table means the metatable does not have the
|
||||
** corresponding metamethod field. (Bit 7 of the flag is used for
|
||||
** 'isrealasize'.)
|
||||
*/
|
||||
#define maskflags (~(~0u << (TM_EQ + 1)))
|
||||
|
||||
|
||||
/*
|
||||
** Test whether there is no tagmethod.
|
||||
** (Because tagmethods use raw accesses, the result may be an "empty" nil.)
|
||||
|
|
|
@ -37,6 +37,26 @@ static lua_State *globalL = NULL;
|
|||
static const char *progname = LUA_PROGNAME;
|
||||
|
||||
|
||||
#if defined(LUA_USE_POSIX) /* { */
|
||||
|
||||
/*
|
||||
** Use 'sigaction' when available.
|
||||
*/
|
||||
static void setsignal (int sig, void (*handler)(int)) {
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = handler;
|
||||
sa.sa_flags = 0;
|
||||
sigemptyset(&sa.sa_mask); /* do not mask any signal */
|
||||
sigaction(sig, &sa, NULL);
|
||||
}
|
||||
|
||||
#else /* }{ */
|
||||
|
||||
#define setsignal signal
|
||||
|
||||
#endif /* } */
|
||||
|
||||
|
||||
/*
|
||||
** Hook set by signal function to stop the interpreter.
|
||||
*/
|
||||
|
@ -55,7 +75,7 @@ static void lstop (lua_State *L, lua_Debug *ar) {
|
|||
*/
|
||||
static void laction (int i) {
|
||||
int flag = LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT;
|
||||
signal(i, SIG_DFL); /* if another SIGINT happens, terminate process */
|
||||
setsignal(i, SIG_DFL); /* if another SIGINT happens, terminate process */
|
||||
lua_sethook(globalL, lstop, flag, 1);
|
||||
}
|
||||
|
||||
|
@ -135,9 +155,9 @@ static int docall (lua_State *L, int narg, int nres) {
|
|||
lua_pushcfunction(L, msghandler); /* push message handler */
|
||||
lua_insert(L, base); /* put it under function and args */
|
||||
globalL = L; /* to be available to 'laction' */
|
||||
signal(SIGINT, laction); /* set C-signal handler */
|
||||
setsignal(SIGINT, laction); /* set C-signal handler */
|
||||
status = lua_pcall(L, narg, nres, base);
|
||||
signal(SIGINT, SIG_DFL); /* reset C-signal handler */
|
||||
setsignal(SIGINT, SIG_DFL); /* reset C-signal handler */
|
||||
lua_remove(L, base); /* remove message handler from the stack */
|
||||
return status;
|
||||
}
|
||||
|
@ -416,15 +436,19 @@ static int handle_luainit (lua_State *L) {
|
|||
|
||||
|
||||
/*
|
||||
** Returns the string to be used as a prompt by the interpreter.
|
||||
** Return the string to be used as a prompt by the interpreter. Leave
|
||||
** the string (or nil, if using the default value) on the stack, to keep
|
||||
** it anchored.
|
||||
*/
|
||||
static const char *get_prompt (lua_State *L, int firstline) {
|
||||
const char *p;
|
||||
lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2");
|
||||
p = lua_tostring(L, -1);
|
||||
if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
|
||||
if (lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2") == LUA_TNIL)
|
||||
return (firstline ? LUA_PROMPT : LUA_PROMPT2); /* use the default */
|
||||
else { /* apply 'tostring' over the value */
|
||||
const char *p = luaL_tolstring(L, -1, NULL);
|
||||
lua_remove(L, -2); /* remove original value */
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
/* mark in error messages for incomplete statements */
|
||||
#define EOFMARK "<eof>"
|
||||
|
|
|
@ -18,14 +18,14 @@
|
|||
|
||||
#define LUA_VERSION_MAJOR "5"
|
||||
#define LUA_VERSION_MINOR "4"
|
||||
#define LUA_VERSION_RELEASE "0"
|
||||
#define LUA_VERSION_RELEASE "3"
|
||||
|
||||
#define LUA_VERSION_NUM 504
|
||||
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 0)
|
||||
|
||||
#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-2020 Lua.org, PUC-Rio"
|
||||
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2021 Lua.org, PUC-Rio"
|
||||
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
|
||||
|
||||
|
||||
|
@ -348,6 +348,7 @@ LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
|
|||
LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
|
||||
|
||||
LUA_API void (lua_toclose) (lua_State *L, int idx);
|
||||
LUA_API void (lua_closeslot) (lua_State *L, int idx);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -491,7 +492,7 @@ struct lua_Debug {
|
|||
|
||||
|
||||
/******************************************************************************
|
||||
* Copyright (C) 1994-2020 Lua.org, PUC-Rio.
|
||||
* Copyright (C) 1994-2021 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
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
** ===================================================================
|
||||
** General Configuration File for Lua
|
||||
**
|
||||
** Some definitions here can be changed externally, through the
|
||||
** compiler (e.g., with '-D' options). Those are protected by
|
||||
** '#if !defined' guards. However, several other definitions should
|
||||
** be changed directly here, either because they affect the Lua
|
||||
** ABI (by making the changes here, you ensure that all software
|
||||
** connected to Lua, such as C libraries, will be compiled with the
|
||||
** same configuration); or because they are seldom changed.
|
||||
** Some definitions here can be changed externally, through the compiler
|
||||
** (e.g., with '-D' options): They are commented out or protected
|
||||
** by '#if !defined' guards. However, several other definitions
|
||||
** should be changed directly here, either because they affect the
|
||||
** Lua ABI (by making the changes here, you ensure that all software
|
||||
** connected to Lua, such as C libraries, will be compiled with the same
|
||||
** configuration); or because they are seldom changed.
|
||||
**
|
||||
** Search for "@@" to find all configurable definitions.
|
||||
** ===================================================================
|
||||
|
@ -36,21 +36,6 @@
|
|||
** =====================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ LUAI_MAXCSTACK defines the maximum depth for nested calls and
|
||||
** also limits the maximum depth of other recursive algorithms in
|
||||
** the implementation, such as syntactic analysis. A value too
|
||||
** large may allow the interpreter to crash (C-stack overflow).
|
||||
** The default value seems ok for regular machines, but may be
|
||||
** too high for restricted hardware.
|
||||
** The test file 'cstack.lua' may help finding a good limit.
|
||||
** (It will crash with a limit too high.)
|
||||
*/
|
||||
#if !defined(LUAI_MAXCSTACK)
|
||||
#define LUAI_MAXCSTACK 2000
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_USE_C89 controls the use of non-ISO-C89 features.
|
||||
** Define it if you want Lua to avoid the use of a few C99 features
|
||||
|
@ -96,26 +81,12 @@
|
|||
|
||||
/*
|
||||
** {==================================================================
|
||||
** Configuration for Number types.
|
||||
** Configuration for Number types. These options should not be
|
||||
** set externally, because any other code connected to Lua must
|
||||
** use the same configuration.
|
||||
** ===================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats.
|
||||
*/
|
||||
/* #define LUA_32BITS */
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for
|
||||
** C89 ('long' and 'double'); Windows always has '__int64', so it does
|
||||
** not need to use this case.
|
||||
*/
|
||||
#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)
|
||||
#define LUA_C89_NUMBERS
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_INT_TYPE defines the type for Lua integers.
|
||||
@@ LUA_FLOAT_TYPE defines the type for Lua floats.
|
||||
|
@ -136,7 +107,31 @@
|
|||
#define LUA_FLOAT_DOUBLE 2
|
||||
#define LUA_FLOAT_LONGDOUBLE 3
|
||||
|
||||
#if defined(LUA_32BITS) /* { */
|
||||
|
||||
/* Default configuration ('long long' and 'double', for 64-bit Lua) */
|
||||
#define LUA_INT_DEFAULT LUA_INT_LONGLONG
|
||||
#define LUA_FLOAT_DEFAULT LUA_FLOAT_DOUBLE
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats.
|
||||
*/
|
||||
#define LUA_32BITS 0
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for
|
||||
** C89 ('long' and 'double'); Windows always has '__int64', so it does
|
||||
** not need to use this case.
|
||||
*/
|
||||
#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)
|
||||
#define LUA_C89_NUMBERS 1
|
||||
#else
|
||||
#define LUA_C89_NUMBERS 0
|
||||
#endif
|
||||
|
||||
|
||||
#if LUA_32BITS /* { */
|
||||
/*
|
||||
** 32-bit integers and 'float'
|
||||
*/
|
||||
|
@ -147,27 +142,22 @@
|
|||
#endif
|
||||
#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT
|
||||
|
||||
#elif defined(LUA_C89_NUMBERS) /* }{ */
|
||||
#elif LUA_C89_NUMBERS /* }{ */
|
||||
/*
|
||||
** largest types available for C89 ('long' and 'double')
|
||||
*/
|
||||
#define LUA_INT_TYPE LUA_INT_LONG
|
||||
#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
|
||||
|
||||
#else /* }{ */
|
||||
/* use defaults */
|
||||
|
||||
#define LUA_INT_TYPE LUA_INT_DEFAULT
|
||||
#define LUA_FLOAT_TYPE LUA_FLOAT_DEFAULT
|
||||
|
||||
#endif /* } */
|
||||
|
||||
|
||||
/*
|
||||
** default configuration for 64-bit Lua ('long long' and 'double')
|
||||
*/
|
||||
#if !defined(LUA_INT_TYPE)
|
||||
#define LUA_INT_TYPE LUA_INT_LONGLONG
|
||||
#endif
|
||||
|
||||
#if !defined(LUA_FLOAT_TYPE)
|
||||
#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
|
||||
#endif
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
|
@ -388,14 +378,13 @@
|
|||
|
||||
/*
|
||||
** {==================================================================
|
||||
** Configuration for Numbers.
|
||||
** Configuration for Numbers (low-level part).
|
||||
** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
|
||||
** satisfy your needs.
|
||||
** ===================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ LUA_NUMBER is the floating-point type used by Lua.
|
||||
@@ LUAI_UACNUMBER is the result of a 'default argument promotion'
|
||||
@@ over a floating number.
|
||||
@@ l_floatatt(x) corrects float attribute 'x' to the proper float type
|
||||
|
@ -488,10 +477,7 @@
|
|||
|
||||
|
||||
/*
|
||||
@@ LUA_INTEGER is the integer type used by Lua.
|
||||
**
|
||||
@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
|
||||
**
|
||||
@@ LUAI_UACINT is the result of a 'default argument promotion'
|
||||
@@ over a LUA_INTEGER.
|
||||
@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
|
||||
|
@ -674,6 +660,34 @@
|
|||
#define lua_getlocaledecpoint() (localeconv()->decimal_point[0])
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** macros to improve jump prediction, used mostly for error handling
|
||||
** and debug facilities. (Some macros in the Lua API use these macros.
|
||||
** Define LUA_NOBUILTIN if you do not want '__builtin_expect' in your
|
||||
** code.)
|
||||
*/
|
||||
#if !defined(luai_likely)
|
||||
|
||||
#if defined(__GNUC__) && !defined(LUA_NOBUILTIN)
|
||||
#define luai_likely(x) (__builtin_expect(((x) != 0), 1))
|
||||
#define luai_unlikely(x) (__builtin_expect(((x) != 0), 0))
|
||||
#else
|
||||
#define luai_likely(x) (x)
|
||||
#define luai_unlikely(x) (x)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(LUA_CORE) || defined(LUA_LIB)
|
||||
/* shorter names for Lua's own use */
|
||||
#define l_likely(x) luai_likely(x)
|
||||
#define l_unlikely(x) luai_unlikely(x)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
|
|
|
@ -49,10 +49,4 @@ LUAMOD_API int (luaopen_package) (lua_State *L);
|
|||
LUALIB_API void (luaL_openlibs) (lua_State *L);
|
||||
|
||||
|
||||
|
||||
#if !defined(lua_assert)
|
||||
#define lua_assert(x) ((void)0)
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -120,7 +120,10 @@ static TString *loadStringN (LoadState *S, Proto *p) {
|
|||
}
|
||||
else { /* long string */
|
||||
ts = luaS_createlngstrobj(L, size); /* create string */
|
||||
setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */
|
||||
luaD_inctop(L);
|
||||
loadVector(S, getstr(ts), size); /* load directly in final place */
|
||||
L->top--; /* pop string */
|
||||
}
|
||||
luaC_objbarrier(L, p, ts);
|
||||
return ts;
|
||||
|
@ -200,13 +203,20 @@ static void loadProtos (LoadState *S, Proto *f) {
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
** Load the upvalues for a function. The names must be filled first,
|
||||
** because the filling of the other fields can raise read errors and
|
||||
** the creation of the error message can call an emergency collection;
|
||||
** in that case all prototypes must be consistent for the GC.
|
||||
*/
|
||||
static void loadUpvalues (LoadState *S, Proto *f) {
|
||||
int i, n;
|
||||
n = loadInt(S);
|
||||
f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
|
||||
f->sizeupvalues = n;
|
||||
for (i = 0; i < n; i++) {
|
||||
for (i = 0; i < n; i++) /* make array valid for GC */
|
||||
f->upvalues[i].name = NULL;
|
||||
for (i = 0; i < n; i++) { /* following calls can raise errors */
|
||||
f->upvalues[i].instack = loadByte(S);
|
||||
f->upvalues[i].idx = loadByte(S);
|
||||
f->upvalues[i].kind = loadByte(S);
|
||||
|
|
156
lua/src/lvm.c
156
lua/src/lvm.c
|
@ -229,17 +229,17 @@ static int forprep (lua_State *L, StkId ra) {
|
|||
count /= l_castS2U(-(step + 1)) + 1u;
|
||||
}
|
||||
/* store the counter in place of the limit (which won't be
|
||||
needed anymore */
|
||||
needed anymore) */
|
||||
setivalue(plimit, l_castU2S(count));
|
||||
}
|
||||
}
|
||||
else { /* try making all values floats */
|
||||
lua_Number init; lua_Number limit; lua_Number step;
|
||||
if (unlikely(!tonumber(plimit, &limit)))
|
||||
if (l_unlikely(!tonumber(plimit, &limit)))
|
||||
luaG_forerror(L, plimit, "limit");
|
||||
if (unlikely(!tonumber(pstep, &step)))
|
||||
if (l_unlikely(!tonumber(pstep, &step)))
|
||||
luaG_forerror(L, pstep, "step");
|
||||
if (unlikely(!tonumber(pinit, &init)))
|
||||
if (l_unlikely(!tonumber(pinit, &init)))
|
||||
luaG_forerror(L, pinit, "initial value");
|
||||
if (step == 0)
|
||||
luaG_runerror(L, "'for' step is zero");
|
||||
|
@ -292,7 +292,7 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
|
|||
if (slot == NULL) { /* 't' is not a table? */
|
||||
lua_assert(!ttistable(t));
|
||||
tm = luaT_gettmbyobj(L, t, TM_INDEX);
|
||||
if (unlikely(notm(tm)))
|
||||
if (l_unlikely(notm(tm)))
|
||||
luaG_typeerror(L, t, "index"); /* no metamethod */
|
||||
/* else will try the metamethod */
|
||||
}
|
||||
|
@ -337,10 +337,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
|
|||
lua_assert(isempty(slot)); /* slot must be empty */
|
||||
tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
|
||||
if (tm == NULL) { /* no metamethod? */
|
||||
if (isabstkey(slot)) /* no previous entry? */
|
||||
slot = luaH_newkey(L, h, key); /* create one */
|
||||
/* no metamethod and (now) there is an entry with given key */
|
||||
setobj2t(L, cast(TValue *, slot), val); /* set its new value */
|
||||
luaH_finishset(L, h, key, slot, val); /* set new value */
|
||||
invalidateTMcache(h);
|
||||
luaC_barrierback(L, obj2gco(h), val);
|
||||
return;
|
||||
|
@ -349,7 +346,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
|
|||
}
|
||||
else { /* not a table; check metamethod */
|
||||
tm = luaT_gettmbyobj(L, t, TM_NEWINDEX);
|
||||
if (unlikely(notm(tm)))
|
||||
if (l_unlikely(notm(tm)))
|
||||
luaG_typeerror(L, t, "index");
|
||||
}
|
||||
/* try the metamethod */
|
||||
|
@ -571,8 +568,13 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
|
|||
if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER)
|
||||
return 0; /* only numbers can be equal with different variants */
|
||||
else { /* two numbers with different variants */
|
||||
lua_Integer i1, i2; /* compare them as integers */
|
||||
return (tointegerns(t1, &i1) && tointegerns(t2, &i2) && i1 == i2);
|
||||
/* One of them is an integer. If the other does not have an
|
||||
integer value, they cannot be equal; otherwise, compare their
|
||||
integer values. */
|
||||
lua_Integer i1, i2;
|
||||
return (luaV_tointegerns(t1, &i1, F2Ieq) &&
|
||||
luaV_tointegerns(t2, &i2, F2Ieq) &&
|
||||
i1 == i2);
|
||||
}
|
||||
}
|
||||
/* values have same type and same variant */
|
||||
|
@ -634,7 +636,8 @@ static void copy2buff (StkId top, int n, char *buff) {
|
|||
** from 'L->top - total' up to 'L->top - 1'.
|
||||
*/
|
||||
void luaV_concat (lua_State *L, int total) {
|
||||
lua_assert(total >= 2);
|
||||
if (total == 1)
|
||||
return; /* "all" values already concatenated */
|
||||
do {
|
||||
StkId top = L->top;
|
||||
int n = 2; /* number of elements handled in this pass (at least 2) */
|
||||
|
@ -653,7 +656,7 @@ void luaV_concat (lua_State *L, int total) {
|
|||
/* collect total length and number of strings */
|
||||
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
|
||||
size_t l = vslen(s2v(top - n - 1));
|
||||
if (unlikely(l >= (MAX_SIZE/sizeof(char)) - tl))
|
||||
if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl))
|
||||
luaG_runerror(L, "string length overflow");
|
||||
tl += l;
|
||||
}
|
||||
|
@ -697,7 +700,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
|
|||
}
|
||||
default: { /* try metamethod */
|
||||
tm = luaT_gettmbyobj(L, rb, TM_LEN);
|
||||
if (unlikely(notm(tm))) /* no metamethod? */
|
||||
if (l_unlikely(notm(tm))) /* no metamethod? */
|
||||
luaG_typeerror(L, rb, "get length of");
|
||||
break;
|
||||
}
|
||||
|
@ -713,7 +716,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
|
|||
** otherwise 'floor(q) == trunc(q) - 1'.
|
||||
*/
|
||||
lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) {
|
||||
if (unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */
|
||||
if (l_unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */
|
||||
if (n == 0)
|
||||
luaG_runerror(L, "attempt to divide by zero");
|
||||
return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */
|
||||
|
@ -733,7 +736,7 @@ lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) {
|
|||
** about luaV_idiv.)
|
||||
*/
|
||||
lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) {
|
||||
if (unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */
|
||||
if (l_unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */
|
||||
if (n == 0)
|
||||
luaG_runerror(L, "attempt to perform 'n%%0'");
|
||||
return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */
|
||||
|
@ -840,10 +843,12 @@ void luaV_finishOp (lua_State *L) {
|
|||
int a = GETARG_A(inst); /* first element to concatenate */
|
||||
int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */
|
||||
setobjs2s(L, top - 2, top); /* put TM result in proper position */
|
||||
if (total > 1) { /* are there elements to concat? */
|
||||
L->top = top - 1; /* top is one after last element (at top-2) */
|
||||
luaV_concat(L, total); /* concat them (may yield again) */
|
||||
break;
|
||||
}
|
||||
case OP_CLOSE: case OP_RETURN: { /* yielded closing variables */
|
||||
ci->u.l.savedpc--; /* repeat instruction to close other vars. */
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
@ -921,7 +926,7 @@ void luaV_finishOp (lua_State *L) {
|
|||
*/
|
||||
#define op_arithfK(L,fop) { \
|
||||
TValue *v1 = vRB(i); \
|
||||
TValue *v2 = KC(i); \
|
||||
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
|
||||
op_arithf_aux(L, v1, v2, fop); }
|
||||
|
||||
|
||||
|
@ -950,7 +955,7 @@ void luaV_finishOp (lua_State *L) {
|
|||
*/
|
||||
#define op_arithK(L,iop,fop) { \
|
||||
TValue *v1 = vRB(i); \
|
||||
TValue *v2 = KC(i); \
|
||||
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
|
||||
op_arith_aux(L, v1, v2, iop, fop); }
|
||||
|
||||
|
||||
|
@ -1049,7 +1054,8 @@ void luaV_finishOp (lua_State *L) {
|
|||
#define updatebase(ci) (base = ci->func + 1)
|
||||
|
||||
|
||||
#define updatestack(ci) { if (trap) { updatebase(ci); ra = RA(i); } }
|
||||
#define updatestack(ci) \
|
||||
{ if (l_unlikely(trap)) { updatebase(ci); ra = RA(i); } }
|
||||
|
||||
|
||||
/*
|
||||
|
@ -1093,25 +1099,21 @@ void luaV_finishOp (lua_State *L) {
|
|||
#define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci))
|
||||
|
||||
/*
|
||||
** Protect code that will finish the loop (returns) or can only raise
|
||||
** errors. (That is, it will not return to the interpreter main loop
|
||||
** after changing the stack or hooks.)
|
||||
** Protect code that can only raise errors. (That is, it cannnot change
|
||||
** the stack or hooks.)
|
||||
*/
|
||||
#define halfProtect(exp) (savestate(L,ci), (exp))
|
||||
|
||||
/* idem, but without changing the stack */
|
||||
#define halfProtectNT(exp) (savepc(L), (exp))
|
||||
|
||||
|
||||
/* 'c' is the limit of live values in the stack */
|
||||
#define checkGC(L,c) \
|
||||
{ luaC_condGC(L, L->top = (c), /* limit of live values */ \
|
||||
{ luaC_condGC(L, (savepc(L), L->top = (c)), \
|
||||
updatetrap(ci)); \
|
||||
luai_threadyield(L); }
|
||||
|
||||
|
||||
/* fetch an instruction and prepare its execution */
|
||||
#define vmfetch() { \
|
||||
if (trap) { /* stack reallocation or hooks? */ \
|
||||
if (l_unlikely(trap)) { /* stack reallocation or hooks? */ \
|
||||
trap = luaG_traceexec(L, pc); /* handle hooks */ \
|
||||
updatebase(ci); /* correct stack */ \
|
||||
} \
|
||||
|
@ -1133,17 +1135,20 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||
#if LUA_USE_JUMPTABLE
|
||||
#include "ljumptab.h"
|
||||
#endif
|
||||
tailcall:
|
||||
startfunc:
|
||||
trap = L->hookmask;
|
||||
returning: /* trap already set */
|
||||
cl = clLvalue(s2v(ci->func));
|
||||
k = cl->p->k;
|
||||
pc = ci->u.l.savedpc;
|
||||
if (trap) {
|
||||
if (l_unlikely(trap)) {
|
||||
if (pc == cl->p->code) { /* first instruction (not resuming)? */
|
||||
if (cl->p->is_vararg)
|
||||
trap = 0; /* hooks will start after VARARGPREP instruction */
|
||||
else if (pc == cl->p->code) /* first instruction (not resuming)? */
|
||||
else /* check 'call' hook */
|
||||
luaD_hookcall(L, ci);
|
||||
ci->u.l.trap = 1; /* there may be other hooks */
|
||||
}
|
||||
ci->u.l.trap = 1; /* assume trap is on, for now */
|
||||
}
|
||||
base = ci->func + 1;
|
||||
/* main loop of interpreter */
|
||||
|
@ -1151,8 +1156,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||
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)));
|
||||
lua_assert(base == ci->func + 1);
|
||||
lua_assert(base <= L->top && L->top < L->stack + L->stacksize);
|
||||
lua_assert(base <= L->top && L->top < L->stack_last);
|
||||
/* invalidate top for instructions not expecting it */
|
||||
lua_assert(isIT(i) || (cast_void(L->top = base), 1));
|
||||
vmdispatch (GET_OPCODE(i)) {
|
||||
|
@ -1529,7 +1536,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||
vmbreak;
|
||||
}
|
||||
vmcase(OP_CLOSE) {
|
||||
Protect(luaF_close(L, ra, LUA_OK));
|
||||
Protect(luaF_close(L, ra, LUA_OK, 1));
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_TBC) {
|
||||
|
@ -1607,47 +1614,54 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||
vmbreak;
|
||||
}
|
||||
vmcase(OP_CALL) {
|
||||
CallInfo *newci;
|
||||
int b = GETARG_B(i);
|
||||
int nresults = GETARG_C(i) - 1;
|
||||
if (b != 0) /* fixed number of arguments? */
|
||||
L->top = ra + b; /* top signals number of arguments */
|
||||
/* else previous instruction set top */
|
||||
ProtectNT(luaD_call(L, ra, nresults));
|
||||
savepc(L); /* in case of errors */
|
||||
if ((newci = luaD_precall(L, ra, nresults)) == NULL)
|
||||
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 nparams1 = GETARG_C(i);
|
||||
/* delat is virtual 'func' - real 'func' (vararg functions) */
|
||||
/* delta is virtual 'func' - real 'func' (vararg functions) */
|
||||
int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
|
||||
if (b != 0)
|
||||
L->top = ra + b;
|
||||
else /* previous instruction set top */
|
||||
b = cast_int(L->top - ra);
|
||||
savepc(ci); /* some calls here can raise errors */
|
||||
savepc(ci); /* several calls here can raise errors */
|
||||
if (TESTARG_k(i)) {
|
||||
/* close upvalues from current call; the compiler ensures
|
||||
that there are no to-be-closed variables here, so this
|
||||
call cannot change the stack */
|
||||
luaF_close(L, base, NOCLOSINGMETH);
|
||||
luaF_closeupval(L, base); /* close upvalues from current call */
|
||||
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 */
|
||||
checkstackp(L, 1, ra);
|
||||
checkstackGCp(L, 1, ra);
|
||||
}
|
||||
if (!ttisLclosure(s2v(ra))) { /* C function? */
|
||||
luaD_call(L, ra, LUA_MULTRET); /* call it */
|
||||
luaD_precall(L, ra, LUA_MULTRET); /* call it */
|
||||
updatetrap(ci);
|
||||
updatestack(ci); /* stack may have been relocated */
|
||||
ci->func -= delta;
|
||||
luaD_poscall(L, ci, cast_int(L->top - ra));
|
||||
return;
|
||||
ci->func -= delta; /* restore 'func' (if vararg) */
|
||||
luaD_poscall(L, ci, cast_int(L->top - ra)); /* finish caller */
|
||||
updatetrap(ci); /* 'luaD_poscall' can change hooks */
|
||||
goto ret; /* caller returns after the tail call */
|
||||
}
|
||||
ci->func -= delta;
|
||||
ci->func -= delta; /* restore 'func' (if vararg) */
|
||||
luaD_pretailcall(L, ci, ra, b); /* prepare call frame */
|
||||
goto tailcall;
|
||||
goto startfunc; /* execute the callee */
|
||||
}
|
||||
vmcase(OP_RETURN) {
|
||||
int n = GETARG_B(i) - 1; /* number of results */
|
||||
|
@ -1658,7 +1672,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||
if (TESTARG_k(i)) { /* may there be open upvalues? */
|
||||
if (L->top < ci->top)
|
||||
L->top = ci->top;
|
||||
luaF_close(L, base, LUA_OK);
|
||||
luaF_close(L, base, CLOSEKTOP, 1);
|
||||
updatetrap(ci);
|
||||
updatestack(ci);
|
||||
}
|
||||
|
@ -1666,26 +1680,31 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||
ci->func -= ci->u.l.nextraargs + nparams1;
|
||||
L->top = ra + n; /* set call for 'luaD_poscall' */
|
||||
luaD_poscall(L, ci, n);
|
||||
return;
|
||||
updatetrap(ci); /* 'luaD_poscall' can change hooks */
|
||||
goto ret;
|
||||
}
|
||||
vmcase(OP_RETURN0) {
|
||||
if (L->hookmask) {
|
||||
if (l_unlikely(L->hookmask)) {
|
||||
L->top = ra;
|
||||
halfProtectNT(luaD_poscall(L, ci, 0)); /* no hurry... */
|
||||
savepc(ci);
|
||||
luaD_poscall(L, ci, 0); /* no hurry... */
|
||||
trap = 1;
|
||||
}
|
||||
else { /* do the 'poscall' here */
|
||||
int nres = ci->nresults;
|
||||
int nres;
|
||||
L->ci = ci->previous; /* back to caller */
|
||||
L->top = base - 1;
|
||||
while (nres-- > 0)
|
||||
for (nres = ci->nresults; l_unlikely(nres > 0); nres--)
|
||||
setnilvalue(s2v(L->top++)); /* all results are nil */
|
||||
}
|
||||
return;
|
||||
goto ret;
|
||||
}
|
||||
vmcase(OP_RETURN1) {
|
||||
if (L->hookmask) {
|
||||
if (l_unlikely(L->hookmask)) {
|
||||
L->top = ra + 1;
|
||||
halfProtectNT(luaD_poscall(L, ci, 1)); /* no hurry... */
|
||||
savepc(ci);
|
||||
luaD_poscall(L, ci, 1); /* no hurry... */
|
||||
trap = 1;
|
||||
}
|
||||
else { /* do the 'poscall' here */
|
||||
int nres = ci->nresults;
|
||||
|
@ -1695,11 +1714,17 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||
else {
|
||||
setobjs2s(L, base - 1, ra); /* at least this result */
|
||||
L->top = base;
|
||||
while (--nres > 0) /* complete missing results */
|
||||
setnilvalue(s2v(L->top++));
|
||||
for (; l_unlikely(nres > 1); nres--)
|
||||
setnilvalue(s2v(L->top++)); /* complete missing results */
|
||||
}
|
||||
}
|
||||
return;
|
||||
ret: /* return from a Lua function */
|
||||
if (ci->callstatus & CIST_FRESH)
|
||||
return; /* end this frame */
|
||||
else {
|
||||
ci = ci->previous;
|
||||
goto returning; /* continue running caller in this frame */
|
||||
}
|
||||
}
|
||||
vmcase(OP_FORLOOP) {
|
||||
if (ttisinteger(s2v(ra + 2))) { /* integer loop? */
|
||||
|
@ -1792,11 +1817,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||
vmbreak;
|
||||
}
|
||||
vmcase(OP_VARARGPREP) {
|
||||
luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p);
|
||||
updatetrap(ci);
|
||||
if (trap) {
|
||||
ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p));
|
||||
if (l_unlikely(trap)) { /* previous "Protect" updated trap */
|
||||
luaD_hookcall(L, ci);
|
||||
L->oldpc = pc + 1; /* next opcode will be seen as a "new" line */
|
||||
L->oldpc = 1; /* next opcode will be seen as a "new" line */
|
||||
}
|
||||
updatebase(ci); /* function has new base after adjustment */
|
||||
vmbreak;
|
||||
|
|
|
@ -60,12 +60,14 @@ typedef enum {
|
|||
|
||||
/* convert an object to an integer (including string coercion) */
|
||||
#define tointeger(o,i) \
|
||||
(ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))
|
||||
(l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \
|
||||
: luaV_tointeger(o,i,LUA_FLOORN2I))
|
||||
|
||||
|
||||
/* convert an object to an integer (without string coercion) */
|
||||
#define tointegerns(o,i) \
|
||||
(ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointegerns(o,i,LUA_FLOORN2I))
|
||||
(l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \
|
||||
: luaV_tointegerns(o,i,LUA_FLOORN2I))
|
||||
|
||||
|
||||
#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
|
||||
|
|
Loading…
Reference in a new issue