1
0
mirror of https://github.com/lua/lua synced 2026-06-08 15:34:49 +00:00

Compare commits

...

101 Commits

Author SHA1 Message Date
Roberto Ierusalimschy 934fdd481c Bug: Constructors with nils can overflow counters 2025-08-27 14:58:02 -03:00
Roberto Ierusalimschy 9ac9d23f41 Bug: error with option '--' without a script 2025-08-27 14:55:35 -03:00
Roberto Ierusalimschy 1b0f943da7 Bug: new metatable in weak table can fool the GC
All-weak tables are not being revisited after being visited during
propagation; if it gets a new metatable after that, the new metatable
may not be marked.
2025-06-16 16:33:02 -03:00
Roberto Ierusalimschy 6e22fedb74 New release number, updated copyright year 2025-05-21 13:52:56 -03:00
Roberto Ierusalimschy 267ef461d0 Bug: check for constructor overflow in [exp] fields
The check for constructor overflow was considering only fields with
explicit names, ignoring fields with syntax '[exp]=exp'.
2025-05-20 17:55:08 -03:00
Roberto Ierusalimschy d1ee2a4deb Bug: Bad error message with fields of string _ENV
Errors with fields of the string _ENV (e.g., ("_ENV").u + 1) report
the error as comming from a global.
2025-05-15 15:14:56 -03:00
Roberto Ierusalimschy 3fe7be956f Bug: message handler can be overwritten
A __close metamethod can overwrite a message handler in the stack
when closing a thread or a state.
2025-03-17 16:14:17 -03:00
Roberto Ierusalimschy 983bc433e6 Bug: Use after free in 'luaV_finishset'
If a metatable is a weak table, its __newindex field could be collected
by an emergency collection while being used in 'luaV_finishset'. (This
bug has similarities with bug 5.3.2-1, fixed in commit a272fa66.)
2025-03-13 15:42:39 -03:00
Roberto Ierusalimschy 25da574fcb Bug: 'luaD_seterrorobj' should not raise errors
This function can be called unprotected, so it should not raise any
kind of errors. (It could raise a memory-allocation error when creating
a message).
2025-03-12 16:01:03 -03:00
Roberto Ierusalimschy f5e55be2a0 Bug: Missing error status in panic function
'luaD_throw' may call 'luaE_resetthread', which returns an error code
but clears 'L->status'; so, 'luaD_throw' should set that status again.
2025-01-16 16:25:11 -03:00
Roberto Ierusalimschy 9f0c0fe0de Bug: Wrong limit for local variables in 16-bit systems
USHRT_MAX does not fit in an 'int' in 16-bit systems.
2024-09-10 11:34:42 -03:00
Roberto Ierusalimschy 782ef85b22 Bug: wrong code gen. for indices with comparisons
In function 'luaK_exp2val', used to generate code for indices: Macro
'hasjumps' does not consider the case when the whole expression is a
"jump" (a test). In all other of its uses, the surrounding code ensures
that the expression cannot be VJMP.
2024-08-17 12:37:04 -03:00
Roberto Ierusalimschy 30982bec96 Bug: Bad stack manipulation in 'multiline' (REPL)
'incomplete' was popping error message that should be used in case
there is no more lines to complete the input, that is, 'pushline'
returns NULL, due to end of file.
2024-07-05 14:31:07 -03:00
Roberto Ierusalimschy 1ab3208a1f 'lua.h' back to redundancy in version definitions
Several tools inspect 'lua.h' to extract version information, and
they assume the file will have some specific format.
2024-06-13 15:13:52 -03:00
Roberto Ierusalimschy 21ff8de33a Bug: Tricky _PROMPT may trigger undefined behavior 2024-06-05 13:37:16 -03:00
Roberto Ierusalimschy 7eb1ed21b7 More permissive use of 'errno'
Assume that no function will put garbage on errno (although ISO C allows
that). If any function during an operation set errno, and the operation
result in an error, assume that errno has something to say.
2024-06-05 11:50:42 -03:00
Roberto Ierusalimschy 2db966fcbf Bug: luaL_traceback may need more than 5 stack slots 2024-06-04 16:40:53 -03:00
Roberto Ierusalimschy ae9a0cbbb4 Bug: overlapping assignments
ISO C forbids assignment of a union field to another field of the same
union.
2024-06-04 12:52:52 -03:00
Roberto Ierusalimschy d5212c13b0 More disciplined use of 'errno'
Set errno to zero before calling any function where we may use its
errno, and check errno for zero before using it (as functions may
not set it even in error).
2024-06-04 12:48:29 -03:00
Roberto Ierusalimschy e0efebdbe4 Detail in the manual
Function 'lua_toclose' can raise a non-memory error (but not a
memory error).
2024-05-14 17:59:54 -03:00
Roberto Ierusalimschy e84f7bf198 Details
Typos in comments.
2024-05-13 13:23:45 -03:00
Roberto Ierusalimschy dfbde4c7d5 Bug: Active-lines for stripped vararg functions
Lua seg. faults when asked to create the 'activelines' table for a
vararg function with no debug information.
2024-05-13 13:10:35 -03:00
Roberto Ierusalimschy de794a6527 Towards release 5.4.7 2024-04-26 14:55:18 -03:00
Roberto Ierusalimschy 8b83417de9 Avoids a warning when lua_Number is 'float' 2024-02-07 14:17:03 -03:00
Roberto Ierusalimschy e288c5a918 Bug: Yielding in a hook stops in the wrong instruction
Yielding in a hook must decrease the program counter, because it already
counted an instruction that, in the end, was not executed. However,
that decrement should be done only when about to restart the thread.
Otherwise, inspecting the thread with the debug library shows it one
instruction behind of where it really is.
2024-01-11 13:44:16 -03:00
Roberto Ierusalimschy 5853c37a83 Bug: Buffer overflow in string concatenation
Even if the string fits in size_t, the whole size of the TString object
can overflow when we add the header.
2023-12-21 13:37:51 -03:00
Roberto Ierusalimschy 842a83f09c Panic functions should not raise errors
The standard panic function was using 'lua_tostring', which may raise
a memory-allocation error if error value is a number.
2023-11-24 16:08:55 -03:00
Roberto Ierusalimschy 7923dbbf72 Bug: Recursion in 'getobjname' can stack overflow
'getobjname' now broken in two, a basic version that handles locals,
upvalues, and constants, and a full version, which uses the basic
version to handle table accesses (globals and fields).
2023-11-01 12:00:54 -03:00
Roberto Ierusalimschy 81e4fce530 Simpler test in 'luaH_getint'
The test whether key is inside the array part of a table uses a bit
trick to avoid computing the real size of the array part.
2023-10-26 16:12:25 -03:00
Roberto Ierusalimschy 6baee9ef9d Removed test for "corrupted binary dump"
Test is too non portable. (For instance, it does not work for
different number types.)
2023-09-08 16:19:21 -03:00
Roberto Ierusalimschy edd8589f47 Avoid casts from unsigned long to floating-point
Old Microsoft compilers do not support those casts.
2023-09-08 11:34:39 -03:00
Roberto Ierusalimschy 07a9eab23a Cannot use 'getshrstr' before setting 'shrlen' 2023-08-25 15:55:14 -03:00
Roberto Ierusalimschy 9363a8b990 Documentation for "LUA_NOENV"
Registry field "LUA_NOENV" (that signals to libraries that option -E
is on) now part of the "official" API of Lua stand-alone.
2023-08-23 13:50:38 -03:00
Roberto Ierusalimschy 5ab6a5756b Bug: Wrong line number for function calls 2023-08-23 13:49:27 -03:00
Roberto Ierusalimschy 9b4f39ab14 More disciplined use of 'getstr' and 'tsslen'
We may want to add other string variants in the future; this change
documents better where the code may need to handle those variants.
2023-08-17 15:59:28 -03:00
Roberto Ierusalimschy f4211a5ea4 More control over encoding of test files
The few UTF-8 test files are commented as such, and there is only one
non UTF-8 test file (to test non UTF-8 sources).
2023-08-17 10:42:56 -03:00
Roberto Ierusalimschy 1b3f507f62 Bug: Call hook may be called twice when count hook yields
Took the opportunity and moved the code that controls call hooks
in 'luaV_execute' into a function.
2023-07-25 16:50:44 -03:00
Roberto Ierusalimschy 6b51133a98 Thread stacks resized in the atomic phase
Although stack resize can be a little expensive, it seems unusual to
have too many threads needing resize during one GC cycle. On the other
hand, the change allows full collections to skip the propagate phase,
going straight from a pause to the atomic phase.
2023-07-13 14:55:46 -03:00
Roberto Ierusalimschy cbae016202 Details 2023-07-03 14:12:54 -03:00
Roberto Ierusalimschy ea39042e13 Removed redundancy in definitions of version/release
String rendering now derived from the numeric original definitions.
2023-06-21 15:04:24 -03:00
Roberto Ierusalimschy 05ec55f16b Avoid inclusion loop in 'ltm.h' 2023-06-16 11:52:14 -03:00
Roberto Ierusalimschy f623b96932 Bug: read overflow in 'l_strcmp'
Equality according to 'strcoll' does not imply that strings have
the same length.
2023-06-14 14:38:07 -03:00
Roberto Ierusalimschy 9be74ccc21 Several functions turned 'static'
Several functions that were already being used only inside their
own file have been declared as 'static'.
2023-05-22 14:47:54 -03:00
Roberto Ierusalimschy 09f3c2372f Option '-l' discards version sufix from file name
Like 'require', the command-line option '-l' discards an optional
version suffix (everything after an hyphen) from a file name when
creating the module name.
2023-05-15 13:46:38 -03:00
Roberto Ierusalimschy c197885cb0 Small improvements in tests 2023-05-15 10:20:13 -03:00
Roberto Ierusalimschy 934e77a286 Details
- Better comments about short strings in opcodes.
- luaH_newkey made static.
2023-05-15 10:07:25 -03:00
Roberto Ierusalimschy 6443185167 "Emergency" new version 5.4.6
'lua_resetthread' is back to its original signature, to avoid
incompatibilities in the ABI between releases of the same version.
New function 'lua_closethread' added with the "correct" signature.
2023-05-02 16:41:43 -03:00
Roberto Ierusalimschy e15f1f2bb7 Details
Typos in comments and details in the manual.
2023-04-18 09:44:10 -03:00
Roberto Ierusalimschy b5c65705ca New year (2023)
Also, small tweak in makefile. (-Wsign-compare is already enabled by
-Wextra.)
2023-03-31 11:47:31 -03:00
Roberto Ierusalimschy 7ca8105a2e More orderliness in casts of enumerations 2023-03-27 16:29:39 -03:00
Roberto Ierusalimschy 94689ac3ad More regularity in uses of enums in 'lcode.c' 2023-03-24 15:52:03 -03:00
Roberto Ierusalimschy ab859fe59b Bug: Loading a corrupted binary file can segfault
The size of the list of upvalue names are stored separated from the
size of the list of upvalues, but they share the same array.
2023-03-17 15:52:09 -03:00
Roberto Ierusalimschy c4b71b7ba0 Details
Comments in 'onelua.c'
2023-03-09 11:12:11 -03:00
Roberto Ierusalimschy 1de2f31694 Corrected support for 16-bit systems
We still need access to a 16-bit system to correctly test
these changes.
2023-03-09 11:10:04 -03:00
Roberto Ierusalimschy 02bab9fc25 Bug: Wrong line in error message for arith. errors
It also causes 'L->top' to be wrong when the error happens,
triggering an 'assert'.
2023-02-08 14:15:41 -03:00
Roberto Ierusalimschy 5e08b41567 Simpler definition for LUA_STRFTIMEOPTIONS
There is no need for those intermediate definitions.
2023-02-07 10:48:39 -03:00
Roberto Ierusalimschy cf08915d62 New macro LUA_USE_IOS
Do not try to detect automatically whether system is iOS; it is
simpler and more reliable to let the programmer inform that.
2023-02-02 13:43:41 -03:00
Roberto Ierusalimschy c888ae0aea Small changes in hash of pointers
When converting from pointer to integer, use 'uintptr_t' if available;
otherwise try 'uintmax_t', and use 'size_t' as last resource.
2023-02-02 13:37:11 -03:00
Roberto Ierusalimschy d69789da1c Fix absence of 'system' in iOS
Despite claiming to be ISO, the C library in some Apple platforms
does not implement 'system'.
2023-01-24 15:04:17 -03:00
Roberto Ierusalimschy 314745ed84 Avoid excessive name pollution in test files
Test files are more polite regarding the use of globals when locals
would do, and when globals are necessary deleting them after use.
2022-12-28 18:34:11 -03:00
Roberto Ierusalimschy 0825cf237d Detail in make file for testes/libs
Everything depends on the Lua version (as given by 'lua.h')
2022-12-23 11:28:11 -03:00
Roberto Ierusalimschy f874d37fa2 Small change in barrier macros
Reuse macros for objects when defining the macros for values.
2022-12-15 14:18:03 -03:00
Roberto Ierusalimschy 35e01ed21d Small improvements in 'lmem.c'
Added some auxiliary macros + fixed a bug in compilation option
EMERGENCYGCTESTS. (It should not try to force an emergency collection
when it cannot run one.)
2022-12-15 10:44:55 -03:00
Roberto Ierusalimschy 6aabf4b15e Details in some header files
Identifier LUA_NUMTAGS was deprecated (changed to LUA_NUMTYPES) +
better handling of some inclusion loops.
2022-12-14 16:20:39 -03:00
Roberto Ierusalimschy fa2f294dd1 Reduce calls to 'luaC_step' when GC is stopped 2022-12-09 16:35:19 -03:00
Roberto Ierusalimschy 82fae58e25 Details
Parentheses and comments.
2022-12-02 11:33:09 -03:00
Roberto Ierusalimschy 9a77f57edc Stop GC while building initial state 2022-11-23 14:17:28 -03:00
Roberto Ierusalimschy be908a7d4d Removed unused field 'UpVal.tbc' 2022-11-08 10:15:10 -03:00
Roberto Ierusalimschy 9ede317c70 Threads are created like other objects
Using a version of 'luaC_newobj' that allows offsets (extra space
before the object itself).
2022-11-01 17:14:01 -03:00
Roberto Ierusalimschy ee645472eb Stack reallocation done with a single realloc
To avoid the need of both the old and the new stack addresses valid
at the same time, to correct the pointers to the stack, these pointers
are changed to offsets before the reallocation and then changed back
to pointers after the reallocation.
2022-10-31 15:06:20 -03:00
Roberto Ierusalimschy 413a393e62 Stack indices changed to union's
That will allow to change pointers to offsets while reallocating
the stack.
2022-10-29 12:06:37 -03:00
Roberto Ierusalimschy ba089bcb08 Details
Added comments in the makefile about other useful '-fsanitize' options.
2022-10-26 10:15:09 -03:00
Roberto Ierusalimschy 1e64c1391f Bug: stack overflow with nesting of coroutine.close 2022-10-25 16:44:06 -03:00
Roberto Ierusalimschy b85816b9a8 Removed test function 'luaH_isdummy'
It was not being used anywhere.
2022-10-21 09:18:13 -03:00
Roberto Ierusalimschy c954db3924 Option '-l g=mod' added to the manual
Plus some other improvements in the manual.
2022-10-19 16:30:39 -03:00
Roberto Ierusalimschy 14d2803e55 Details
Some cast operations rewritten to use respective macros.
2022-10-19 16:29:54 -03:00
Roberto Ierusalimschy 7f12bf40c4 Portability issue in a test for 'string.format' 2022-10-19 16:20:11 -03:00
Roberto Ierusalimschy 26be27459b Negation in constant folding of '>>' may overflow 2022-09-23 11:08:10 -03:00
Roberto Ierusalimschy cfbe378f90 Small simplification in overflow check in 'getfield'
Subtracting a small non-negative int from a non-negative int cannot
overflow, and adding a non-negative int to INT_MIN cannot overflow.
2022-09-23 10:57:35 -03:00
Roberto Ierusalimschy a1089b415a Bug: 'utf8.codes' accepts spurious continuation bytes 2022-09-23 10:41:16 -03:00
Roberto Ierusalimschy f8c4c4fcf2 New test for table rehash 2022-09-16 17:05:22 -03:00
Roberto Ierusalimschy 71bc69c2af Note in the manual about using '...' as an expression 2022-09-08 17:21:02 -03:00
Roberto Ierusalimschy cd56f222b7 Corrected error message in 'table.remove' 2022-09-07 12:21:46 -03:00
Roberto Ierusalimschy 69b77b6fde Changed the growth rate of string buffers
The growth rate of string buffers was reduced from 2 to 1.5 (3/2).
As string buffers start larger (256~1024 bytes), they don't need to
grow that fast. Moreover, a lower rate allows multiplicative growth up
to larger sizes (3/2 of the maximum). (After that, the growth becomes
linear, which is mostly useless.)
2022-09-06 10:58:55 -03:00
Roberto Ierusalimschy 997f11f543 Bug: 'break' may not properly close variable in a 'for' loop
Function 'leaveblock' was generating "break" label before removing
variables from the closing block. If 'createlabel' created a 'close'
instruction (which it did when matching a goto/break that exited
the scope of an upvalue), that instruction would use the wrong level.
2022-08-24 17:36:47 -03:00
Roberto Ierusalimschy 02060b7a37 Simpler handling of Byte Order Mark (BOM) 2022-08-23 16:08:53 -03:00
Roberto Ierusalimschy a1f77a234a Bug: set correct pause when (re)entering gen. collection. 2022-08-23 16:06:23 -03:00
Roberto Ierusalimschy c6cea857a4 Better documentation for 'multires' expressions
Manual has a new section explaining multires expressions, lists of
expressions, and adjustments. This commit also corrects some comments
in the code.
2022-08-19 14:10:18 -03:00
Roberto Ierusalimschy d61b0c6028 More checks and documentation for uses of EXTRA_STACK 2022-05-26 15:14:54 -03:00
Roberto Ierusalimschy 196bb94d66 Bug: 'lua_settop' may use an invalid pointer to stack 2022-05-25 17:41:39 -03:00
Roberto Ierusalimschy 603b2c64ad 'luaV_concat' can use invalidated pointer to stack
Bug introduced in commit 42d40581.
2022-05-23 17:50:47 -03:00
Roberto Ierusalimschy 4a00f61276 'lua_checkstack' doesn't need to check stack overflow
'luaD_growstack' already checks that. This commit also fixes an
internal bug in 'luaD_growstack': a large 'n' could cause an arithmetic
overflow when computing 'needed'.
2022-05-23 10:38:03 -03:00
Roberto Ierusalimschy 42d40581dd Save stack space while handling errors
Because error handling (luaG_errormsg) uses slots from EXTRA_STACK,
and some errors can recur (e.g., string overflow while creating an
error message in 'luaG_runerror', or a C-stack overflow before calling
the message handler), the code should use stack slots with parsimony.

This commit fixes the bug "Lua-stack overflow when C stack overflows
while handling an error".
2022-05-20 13:14:33 -03:00
Roberto Ierusalimschy e435aaabef Details (identation and typos) 2022-05-10 11:13:39 -03:00
Roberto Ierusalimschy 315639d3bb Factoring out common parts of 'codearith' and 'codebitwise' 2022-05-06 17:52:46 -03:00
Roberto Ierusalimschy c764ca71a6 Bug: Wrong code generation in bitwise operations 2022-04-25 14:42:51 -03:00
Roberto Ierusalimschy 295cde9454 New release number (5.4.5) 2022-04-07 10:52:15 -03:00
Roberto Ierusalimschy f3cfd5bf2b Details
Comments + manual + identation + asserts about stack limits that were
not allowing the use of the full stack
2022-04-01 13:55:44 -03:00
Roberto Ierusalimschy 8426d9b4d4 Avoid computing invalid addresses
luaV_execute should compute 'ra' only when the instruction uses it.
Computing an illegal address is undefined behavior even if the address
is never dereferenced.
2022-02-18 13:22:25 -03:00
Roberto Ierusalimschy 1f3c6f4534 Bug: Lua can generate wrong code when _ENV is <const> 2022-02-15 12:28:46 -03:00
Roberto Ierusalimschy 25b143dd34 Bug: lua.c assumes that argv has at least one element 2022-02-07 10:16:35 -03:00
78 changed files with 2389 additions and 1471 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
make -s -j make -s -j
cd testes/libs; make -s cd testes/libs; make -s
cd .. # back to directory 'testes' cd .. # back to directory 'testes'
ulimit -S -s 1000 ulimit -S -s 1100
if { ../lua -W all.lua; } then if { ../lua -W all.lua; } then
echo -e "\n\n final OK!!!!\n\n" echo -e "\n\n final OK!!!!\n\n"
else else
+126 -129
View File
@@ -60,27 +60,28 @@ const char lua_ident[] =
static TValue *index2value (lua_State *L, int idx) { static TValue *index2value (lua_State *L, int idx) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (idx > 0) { if (idx > 0) {
StkId o = ci->func + idx; StkId o = ci->func.p + idx;
api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index"); api_check(L, idx <= ci->top.p - (ci->func.p + 1), "unacceptable index");
if (o >= L->top) return &G(L)->nilvalue; if (o >= L->top.p) return &G(L)->nilvalue;
else return s2v(o); else return s2v(o);
} }
else if (!ispseudo(idx)) { /* negative index */ else if (!ispseudo(idx)) { /* negative index */
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
return s2v(L->top + idx); "invalid index");
return s2v(L->top.p + idx);
} }
else if (idx == LUA_REGISTRYINDEX) else if (idx == LUA_REGISTRYINDEX)
return &G(L)->l_registry; return &G(L)->l_registry;
else { /* upvalues */ else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx; idx = LUA_REGISTRYINDEX - idx;
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
if (ttisCclosure(s2v(ci->func))) { /* C closure? */ if (ttisCclosure(s2v(ci->func.p))) { /* C closure? */
CClosure *func = clCvalue(s2v(ci->func)); CClosure *func = clCvalue(s2v(ci->func.p));
return (idx <= func->nupvalues) ? &func->upvalue[idx-1] return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
: &G(L)->nilvalue; : &G(L)->nilvalue;
} }
else { /* light C function or Lua function (through a hook)?) */ else { /* light C function or Lua function (through a hook)?) */
api_check(L, ttislcf(s2v(ci->func)), "caller not a C function"); api_check(L, ttislcf(s2v(ci->func.p)), "caller not a C function");
return &G(L)->nilvalue; /* no upvalues */ return &G(L)->nilvalue; /* no upvalues */
} }
} }
@@ -94,14 +95,15 @@ static TValue *index2value (lua_State *L, int idx) {
l_sinline StkId index2stack (lua_State *L, int idx) { l_sinline StkId index2stack (lua_State *L, int idx) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (idx > 0) { if (idx > 0) {
StkId o = ci->func + idx; StkId o = ci->func.p + idx;
api_check(L, o < L->top, "invalid index"); api_check(L, o < L->top.p, "invalid index");
return o; return o;
} }
else { /* non-positive index */ else { /* non-positive index */
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
"invalid index");
api_check(L, !ispseudo(idx), "invalid index"); api_check(L, !ispseudo(idx), "invalid index");
return L->top + idx; return L->top.p + idx;
} }
} }
@@ -112,17 +114,12 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
lua_lock(L); lua_lock(L);
ci = L->ci; ci = L->ci;
api_check(L, n >= 0, "negative 'n'"); api_check(L, n >= 0, "negative 'n'");
if (L->stack_last - L->top > n) /* stack large enough? */ if (L->stack_last.p - L->top.p > n) /* stack large enough? */
res = 1; /* yes; check is OK */ res = 1; /* yes; check is OK */
else { /* no; need to grow stack */ else /* need to grow stack */
int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; res = luaD_growstack(L, n, 0);
if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */ if (res && ci->top.p < L->top.p + n)
res = 0; /* no */ ci->top.p = L->top.p + n; /* adjust frame top */
else /* try to grow stack */
res = luaD_growstack(L, n, 0);
}
if (res && ci->top < L->top + n)
ci->top = L->top + n; /* adjust frame top */
lua_unlock(L); lua_unlock(L);
return res; return res;
} }
@@ -134,11 +131,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
lua_lock(to); lua_lock(to);
api_checknelems(from, n); api_checknelems(from, n);
api_check(from, G(from) == G(to), "moving among independent states"); api_check(from, G(from) == G(to), "moving among independent states");
api_check(from, to->ci->top - to->top >= n, "stack overflow"); api_check(from, to->ci->top.p - to->top.p >= n, "stack overflow");
from->top -= n; from->top.p -= n;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
setobjs2s(to, to->top, from->top + i); setobjs2s(to, to->top.p, from->top.p + i);
to->top++; /* stack already checked by previous 'api_check' */ to->top.p++; /* stack already checked by previous 'api_check' */
} }
lua_unlock(to); lua_unlock(to);
} }
@@ -172,12 +169,12 @@ LUA_API lua_Number lua_version (lua_State *L) {
LUA_API int lua_absindex (lua_State *L, int idx) { LUA_API int lua_absindex (lua_State *L, int idx) {
return (idx > 0 || ispseudo(idx)) return (idx > 0 || ispseudo(idx))
? idx ? idx
: cast_int(L->top - L->ci->func) + idx; : cast_int(L->top.p - L->ci->func.p) + idx;
} }
LUA_API int lua_gettop (lua_State *L) { LUA_API int lua_gettop (lua_State *L) {
return cast_int(L->top - (L->ci->func + 1)); return cast_int(L->top.p - (L->ci->func.p + 1));
} }
@@ -187,24 +184,24 @@ LUA_API void lua_settop (lua_State *L, int idx) {
ptrdiff_t diff; /* difference for new top */ ptrdiff_t diff; /* difference for new top */
lua_lock(L); lua_lock(L);
ci = L->ci; ci = L->ci;
func = ci->func; func = ci->func.p;
if (idx >= 0) { if (idx >= 0) {
api_check(L, idx <= ci->top - (func + 1), "new top too large"); api_check(L, idx <= ci->top.p - (func + 1), "new top too large");
diff = ((func + 1) + idx) - L->top; diff = ((func + 1) + idx) - L->top.p;
for (; diff > 0; diff--) for (; diff > 0; diff--)
setnilvalue(s2v(L->top++)); /* clear new slots */ setnilvalue(s2v(L->top.p++)); /* clear new slots */
} }
else { else {
api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); api_check(L, -(idx+1) <= (L->top.p - (func + 1)), "invalid new top");
diff = idx + 1; /* will "subtract" index (as it is negative) */ diff = idx + 1; /* will "subtract" index (as it is negative) */
} }
api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot"); api_check(L, L->tbclist.p < L->top.p, "previous pop of an unclosed slot");
newtop = L->top + diff; newtop = L->top.p + diff;
if (diff < 0 && L->tbclist >= newtop) { if (diff < 0 && L->tbclist.p >= newtop) {
lua_assert(hastocloseCfunc(ci->nresults)); lua_assert(hastocloseCfunc(ci->nresults));
luaF_close(L, newtop, CLOSEKTOP, 0); newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
} }
L->top = newtop; /* correct top only after closing any upvalue */ L->top.p = newtop; /* correct top only after closing any upvalue */
lua_unlock(L); lua_unlock(L);
} }
@@ -213,10 +210,9 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
StkId level; StkId level;
lua_lock(L); lua_lock(L);
level = index2stack(L, idx); level = index2stack(L, idx);
api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level, api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level,
"no variable to close at given level"); "no variable to close at given level");
luaF_close(L, level, CLOSEKTOP, 0); level = luaF_close(L, level, CLOSEKTOP, 0);
level = index2stack(L, idx); /* stack may be moved */
setnilvalue(s2v(level)); setnilvalue(s2v(level));
lua_unlock(L); lua_unlock(L);
} }
@@ -245,7 +241,7 @@ l_sinline void reverse (lua_State *L, StkId from, StkId to) {
LUA_API void lua_rotate (lua_State *L, int idx, int n) { LUA_API void lua_rotate (lua_State *L, int idx, int n) {
StkId p, t, m; StkId p, t, m;
lua_lock(L); lua_lock(L);
t = L->top - 1; /* end of stack segment being rotated */ t = L->top.p - 1; /* end of stack segment being rotated */
p = index2stack(L, idx); /* start of segment */ p = index2stack(L, idx); /* start of segment */
api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'"); api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */ m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
@@ -264,7 +260,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
api_check(L, isvalid(L, to), "invalid index"); api_check(L, isvalid(L, to), "invalid index");
setobj(L, to, fr); setobj(L, to, fr);
if (isupvalue(toidx)) /* function upvalue? */ if (isupvalue(toidx)) /* function upvalue? */
luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr); luaC_barrier(L, clCvalue(s2v(L->ci->func.p)), fr);
/* LUA_REGISTRYINDEX does not need gc barrier /* LUA_REGISTRYINDEX does not need gc barrier
(collector revisits it before finishing collection) */ (collector revisits it before finishing collection) */
lua_unlock(L); lua_unlock(L);
@@ -273,7 +269,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API void lua_pushvalue (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
setobj2s(L, L->top, index2value(L, idx)); setobj2s(L, L->top.p, index2value(L, idx));
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@@ -342,12 +338,12 @@ LUA_API void lua_arith (lua_State *L, int op) {
api_checknelems(L, 2); /* all other operations expect two operands */ api_checknelems(L, 2); /* all other operations expect two operands */
else { /* for unary operations, add fake 2nd operand */ else { /* for unary operations, add fake 2nd operand */
api_checknelems(L, 1); api_checknelems(L, 1);
setobjs2s(L, L->top, L->top - 1); setobjs2s(L, L->top.p, L->top.p - 1);
api_incr_top(L); api_incr_top(L);
} }
/* first operand at top - 2, second at top - 1; result go to top - 2 */ /* first operand at top - 2, second at top - 1; result go to top - 2 */
luaO_arith(L, op, s2v(L->top - 2), s2v(L->top - 1), L->top - 2); luaO_arith(L, op, s2v(L->top.p - 2), s2v(L->top.p - 1), L->top.p - 2);
L->top--; /* remove second operand */ L->top.p--; /* remove second operand */
lua_unlock(L); lua_unlock(L);
} }
@@ -373,7 +369,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) { LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
size_t sz = luaO_str2num(s, s2v(L->top)); size_t sz = luaO_str2num(s, s2v(L->top.p));
if (sz != 0) if (sz != 0)
api_incr_top(L); api_incr_top(L);
return sz; return sz;
@@ -421,9 +417,9 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
o = index2value(L, idx); /* previous call may reallocate the stack */ o = index2value(L, idx); /* previous call may reallocate the stack */
} }
if (len != NULL) if (len != NULL)
*len = vslen(o); *len = tsslen(tsvalue(o));
lua_unlock(L); lua_unlock(L);
return svalue(o); return getstr(tsvalue(o));
} }
@@ -500,7 +496,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
LUA_API void lua_pushnil (lua_State *L) { LUA_API void lua_pushnil (lua_State *L) {
lua_lock(L); lua_lock(L);
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@@ -508,7 +504,7 @@ LUA_API void lua_pushnil (lua_State *L) {
LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
lua_lock(L); lua_lock(L);
setfltvalue(s2v(L->top), n); setfltvalue(s2v(L->top.p), n);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@@ -516,7 +512,7 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
lua_lock(L); lua_lock(L);
setivalue(s2v(L->top), n); setivalue(s2v(L->top.p), n);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@@ -531,7 +527,7 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts; TString *ts;
lua_lock(L); lua_lock(L);
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
setsvalue2s(L, L->top, ts); setsvalue2s(L, L->top.p, ts);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L); luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
@@ -542,11 +538,11 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
LUA_API const char *lua_pushstring (lua_State *L, const char *s) { LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
lua_lock(L); lua_lock(L);
if (s == NULL) if (s == NULL)
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
else { else {
TString *ts; TString *ts;
ts = luaS_new(L, s); ts = luaS_new(L, s);
setsvalue2s(L, L->top, ts); setsvalue2s(L, L->top.p, ts);
s = getstr(ts); /* internal copy's address */ s = getstr(ts); /* internal copy's address */
} }
api_incr_top(L); api_incr_top(L);
@@ -583,7 +579,7 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
lua_lock(L); lua_lock(L);
if (n == 0) { if (n == 0) {
setfvalue(s2v(L->top), fn); setfvalue(s2v(L->top.p), fn);
api_incr_top(L); api_incr_top(L);
} }
else { else {
@@ -592,13 +588,13 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
api_check(L, n <= MAXUPVAL, "upvalue index too large"); api_check(L, n <= MAXUPVAL, "upvalue index too large");
cl = luaF_newCclosure(L, n); cl = luaF_newCclosure(L, n);
cl->f = fn; cl->f = fn;
L->top -= n; L->top.p -= n;
while (n--) { while (n--) {
setobj2n(L, &cl->upvalue[n], s2v(L->top + n)); setobj2n(L, &cl->upvalue[n], s2v(L->top.p + n));
/* does not need barrier because closure is white */ /* does not need barrier because closure is white */
lua_assert(iswhite(cl)); lua_assert(iswhite(cl));
} }
setclCvalue(L, s2v(L->top), cl); setclCvalue(L, s2v(L->top.p), cl);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L); luaC_checkGC(L);
} }
@@ -609,9 +605,9 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
LUA_API void lua_pushboolean (lua_State *L, int b) { LUA_API void lua_pushboolean (lua_State *L, int b) {
lua_lock(L); lua_lock(L);
if (b) if (b)
setbtvalue(s2v(L->top)); setbtvalue(s2v(L->top.p));
else else
setbfvalue(s2v(L->top)); setbfvalue(s2v(L->top.p));
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@@ -619,7 +615,7 @@ LUA_API void lua_pushboolean (lua_State *L, int b) {
LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
lua_lock(L); lua_lock(L);
setpvalue(s2v(L->top), p); setpvalue(s2v(L->top.p), p);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@@ -627,7 +623,7 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
LUA_API int lua_pushthread (lua_State *L) { LUA_API int lua_pushthread (lua_State *L) {
lua_lock(L); lua_lock(L);
setthvalue(L, s2v(L->top), L); setthvalue(L, s2v(L->top.p), L);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return (G(L)->mainthread == L); return (G(L)->mainthread == L);
@@ -644,16 +640,16 @@ l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot; const TValue *slot;
TString *str = luaS_new(L, k); TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) { if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
setobj2s(L, L->top, slot); setobj2s(L, L->top.p, slot);
api_incr_top(L); api_incr_top(L);
} }
else { else {
setsvalue2s(L, L->top, str); setsvalue2s(L, L->top.p, str);
api_incr_top(L); api_incr_top(L);
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot); luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
} }
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
@@ -680,13 +676,13 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
TValue *t; TValue *t;
lua_lock(L); lua_lock(L);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastget(L, t, s2v(L->top - 1), slot, luaH_get)) { if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) {
setobj2s(L, L->top - 1, slot); setobj2s(L, L->top.p - 1, slot);
} }
else else
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot); luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
@@ -702,27 +698,27 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L); lua_lock(L);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) { if (luaV_fastgeti(L, t, n, slot)) {
setobj2s(L, L->top, slot); setobj2s(L, L->top.p, slot);
} }
else { else {
TValue aux; TValue aux;
setivalue(&aux, n); setivalue(&aux, n);
luaV_finishget(L, t, &aux, L->top, slot); luaV_finishget(L, t, &aux, L->top.p, slot);
} }
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
l_sinline int finishrawget (lua_State *L, const TValue *val) { l_sinline int finishrawget (lua_State *L, const TValue *val) {
if (isempty(val)) /* avoid copying empty items to the stack */ if (isempty(val)) /* avoid copying empty items to the stack */
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
else else
setobj2s(L, L->top, val); setobj2s(L, L->top.p, val);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
@@ -739,8 +735,8 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = gettable(L, idx); t = gettable(L, idx);
val = luaH_get(t, s2v(L->top - 1)); val = luaH_get(t, s2v(L->top.p - 1));
L->top--; /* remove key */ L->top.p--; /* remove key */
return finishrawget(L, val); return finishrawget(L, val);
} }
@@ -767,7 +763,7 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t; Table *t;
lua_lock(L); lua_lock(L);
t = luaH_new(L); t = luaH_new(L);
sethvalue2s(L, L->top, t); sethvalue2s(L, L->top.p, t);
api_incr_top(L); api_incr_top(L);
if (narray > 0 || nrec > 0) if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec); luaH_resize(L, t, narray, nrec);
@@ -794,7 +790,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
break; break;
} }
if (mt != NULL) { if (mt != NULL) {
sethvalue2s(L, L->top, mt); sethvalue2s(L, L->top.p, mt);
api_incr_top(L); api_incr_top(L);
res = 1; res = 1;
} }
@@ -810,12 +806,12 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
o = index2value(L, idx); o = index2value(L, idx);
api_check(L, ttisfulluserdata(o), "full userdata expected"); api_check(L, ttisfulluserdata(o), "full userdata expected");
if (n <= 0 || n > uvalue(o)->nuvalue) { if (n <= 0 || n > uvalue(o)->nuvalue) {
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
t = LUA_TNONE; t = LUA_TNONE;
} }
else { else {
setobj2s(L, L->top, &uvalue(o)->uv[n - 1].uv); setobj2s(L, L->top.p, &uvalue(o)->uv[n - 1].uv);
t = ttype(s2v(L->top)); t = ttype(s2v(L->top.p));
} }
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
@@ -835,14 +831,14 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
TString *str = luaS_new(L, k); TString *str = luaS_new(L, k);
api_checknelems(L, 1); api_checknelems(L, 1);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) { if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1)); luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
L->top--; /* pop value */ L->top.p--; /* pop value */
} }
else { else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ setsvalue2s(L, L->top.p, str); /* push 'str' (to make it a TValue) */
api_incr_top(L); api_incr_top(L);
luaV_finishset(L, t, s2v(L->top - 1), s2v(L->top - 2), slot); luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), slot);
L->top -= 2; /* pop value and key */ L->top.p -= 2; /* pop value and key */
} }
lua_unlock(L); /* lock done by caller */ lua_unlock(L); /* lock done by caller */
} }
@@ -862,12 +858,12 @@ LUA_API void lua_settable (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 2); api_checknelems(L, 2);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastget(L, t, s2v(L->top - 2), slot, luaH_get)) { if (luaV_fastget(L, t, s2v(L->top.p - 2), slot, luaH_get)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1)); luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
} }
else else
luaV_finishset(L, t, s2v(L->top - 2), s2v(L->top - 1), slot); luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), slot);
L->top -= 2; /* pop index and value */ L->top.p -= 2; /* pop index and value */
lua_unlock(L); lua_unlock(L);
} }
@@ -885,14 +881,14 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
api_checknelems(L, 1); api_checknelems(L, 1);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) { if (luaV_fastgeti(L, t, n, slot)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1)); luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
} }
else { else {
TValue aux; TValue aux;
setivalue(&aux, n); setivalue(&aux, n);
luaV_finishset(L, t, &aux, s2v(L->top - 1), slot); luaV_finishset(L, t, &aux, s2v(L->top.p - 1), slot);
} }
L->top--; /* pop value */ L->top.p--; /* pop value */
lua_unlock(L); lua_unlock(L);
} }
@@ -902,16 +898,16 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
lua_lock(L); lua_lock(L);
api_checknelems(L, n); api_checknelems(L, n);
t = gettable(L, idx); t = gettable(L, idx);
luaH_set(L, t, key, s2v(L->top - 1)); luaH_set(L, t, key, s2v(L->top.p - 1));
invalidateTMcache(t); invalidateTMcache(t);
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1)); luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
L->top -= n; L->top.p -= n;
lua_unlock(L); lua_unlock(L);
} }
LUA_API void lua_rawset (lua_State *L, int idx) { LUA_API void lua_rawset (lua_State *L, int idx) {
aux_rawset(L, idx, s2v(L->top - 2), 2); aux_rawset(L, idx, s2v(L->top.p - 2), 2);
} }
@@ -927,9 +923,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = gettable(L, idx); t = gettable(L, idx);
luaH_setint(L, t, n, s2v(L->top - 1)); luaH_setint(L, t, n, s2v(L->top.p - 1));
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1)); luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
L->top--; L->top.p--;
lua_unlock(L); lua_unlock(L);
} }
@@ -940,11 +936,11 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
obj = index2value(L, objindex); obj = index2value(L, objindex);
if (ttisnil(s2v(L->top - 1))) if (ttisnil(s2v(L->top.p - 1)))
mt = NULL; mt = NULL;
else { else {
api_check(L, ttistable(s2v(L->top - 1)), "table expected"); api_check(L, ttistable(s2v(L->top.p - 1)), "table expected");
mt = hvalue(s2v(L->top - 1)); mt = hvalue(s2v(L->top.p - 1));
} }
switch (ttype(obj)) { switch (ttype(obj)) {
case LUA_TTABLE: { case LUA_TTABLE: {
@@ -968,7 +964,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
break; break;
} }
} }
L->top--; L->top.p--;
lua_unlock(L); lua_unlock(L);
return 1; return 1;
} }
@@ -984,11 +980,11 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue))) if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue)))
res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */ res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */
else { else {
setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top - 1)); setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top.p - 1));
luaC_barrierback(L, gcvalue(o), s2v(L->top - 1)); luaC_barrierback(L, gcvalue(o), s2v(L->top.p - 1));
res = 1; res = 1;
} }
L->top--; L->top.p--;
lua_unlock(L); lua_unlock(L);
return res; return res;
} }
@@ -1000,7 +996,8 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
#define checkresults(L,na,nr) \ #define checkresults(L,na,nr) \
api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \ api_check(L, (nr) == LUA_MULTRET \
|| (L->ci->top.p - L->top.p >= (nr) - (na)), \
"results from function overflow current stack size") "results from function overflow current stack size")
@@ -1013,7 +1010,7 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
api_checknelems(L, nargs+1); api_checknelems(L, nargs+1);
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults); checkresults(L, nargs, nresults);
func = L->top - (nargs+1); func = L->top.p - (nargs+1);
if (k != NULL && yieldable(L)) { /* need to prepare continuation? */ if (k != NULL && yieldable(L)) { /* need to prepare continuation? */
L->ci->u.c.k = k; /* save continuation */ L->ci->u.c.k = k; /* save continuation */
L->ci->u.c.ctx = ctx; /* save context */ L->ci->u.c.ctx = ctx; /* save context */
@@ -1061,7 +1058,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
api_check(L, ttisfunction(s2v(o)), "error handler must be a function"); api_check(L, ttisfunction(s2v(o)), "error handler must be a function");
func = savestack(L, o); func = savestack(L, o);
} }
c.func = L->top - (nargs+1); /* function to be called */ c.func = L->top.p - (nargs+1); /* function to be called */
if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */ if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */
c.nresults = nresults; /* do a 'conventional' protected call */ c.nresults = nresults; /* do a 'conventional' protected call */
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
@@ -1096,12 +1093,12 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
luaZ_init(L, &z, reader, data); luaZ_init(L, &z, reader, data);
status = luaD_protectedparser(L, &z, chunkname, mode); status = luaD_protectedparser(L, &z, chunkname, mode);
if (status == LUA_OK) { /* no errors? */ if (status == LUA_OK) { /* no errors? */
LClosure *f = clLvalue(s2v(L->top - 1)); /* get newly created function */ LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */
if (f->nupvalues >= 1) { /* does it have an upvalue? */ if (f->nupvalues >= 1) { /* does it have an upvalue? */
/* get global table from registry */ /* get global table from registry */
const TValue *gt = getGtable(L); const TValue *gt = getGtable(L);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
setobj(L, f->upvals[0]->v, gt); setobj(L, f->upvals[0]->v.p, gt);
luaC_barrier(L, f->upvals[0], gt); luaC_barrier(L, f->upvals[0], gt);
} }
} }
@@ -1115,7 +1112,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
TValue *o; TValue *o;
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
o = s2v(L->top - 1); o = s2v(L->top.p - 1);
if (isLfunction(o)) if (isLfunction(o))
status = luaU_dump(L, getproto(o), writer, data, strip); status = luaU_dump(L, getproto(o), writer, data, strip);
else else
@@ -1241,7 +1238,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
LUA_API int lua_error (lua_State *L) { LUA_API int lua_error (lua_State *L) {
TValue *errobj; TValue *errobj;
lua_lock(L); lua_lock(L);
errobj = s2v(L->top - 1); errobj = s2v(L->top.p - 1);
api_checknelems(L, 1); api_checknelems(L, 1);
/* error object is the memory error message? */ /* error object is the memory error message? */
if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg)) if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
@@ -1259,12 +1256,12 @@ LUA_API int lua_next (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = gettable(L, idx); t = gettable(L, idx);
more = luaH_next(L, t, L->top - 1); more = luaH_next(L, t, L->top.p - 1);
if (more) { if (more) {
api_incr_top(L); api_incr_top(L);
} }
else /* no more elements */ else /* no more elements */
L->top -= 1; /* remove key */ L->top.p -= 1; /* remove key */
lua_unlock(L); lua_unlock(L);
return more; return more;
} }
@@ -1276,7 +1273,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
o = index2stack(L, idx); o = index2stack(L, idx);
nresults = L->ci->nresults; nresults = L->ci->nresults;
api_check(L, L->tbclist < o, "given index below or equal a marked one"); api_check(L, L->tbclist.p < o, "given index below or equal a marked one");
luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */ luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
if (!hastocloseCfunc(nresults)) /* function not marked yet? */ if (!hastocloseCfunc(nresults)) /* function not marked yet? */
L->ci->nresults = codeNresults(nresults); /* mark it */ L->ci->nresults = codeNresults(nresults); /* mark it */
@@ -1291,7 +1288,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
if (n > 0) if (n > 0)
luaV_concat(L, n); luaV_concat(L, n);
else { /* nothing to concatenate */ else { /* nothing to concatenate */
setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); /* push empty string */ setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */
api_incr_top(L); api_incr_top(L);
} }
luaC_checkGC(L); luaC_checkGC(L);
@@ -1303,7 +1300,7 @@ LUA_API void lua_len (lua_State *L, int idx) {
TValue *t; TValue *t;
lua_lock(L); lua_lock(L);
t = index2value(L, idx); t = index2value(L, idx);
luaV_objlen(L, L->top, t); luaV_objlen(L, L->top.p, t);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@@ -1346,9 +1343,9 @@ void lua_warning (lua_State *L, const char *msg, int tocont) {
LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) { LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
Udata *u; Udata *u;
lua_lock(L); lua_lock(L);
api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value"); api_check(L, 0 <= nuvalue && nuvalue < SHRT_MAX, "invalid value");
u = luaS_newudata(L, size, nuvalue); u = luaS_newudata(L, size, nuvalue);
setuvalue(L, s2v(L->top), u); setuvalue(L, s2v(L->top.p), u);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L); luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
@@ -1374,7 +1371,7 @@ static const char *aux_upvalue (TValue *fi, int n, TValue **val,
Proto *p = f->p; Proto *p = f->p;
if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues))) if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues)))
return NULL; /* 'n' not in [1, p->sizeupvalues] */ return NULL; /* 'n' not in [1, p->sizeupvalues] */
*val = f->upvals[n-1]->v; *val = f->upvals[n-1]->v.p;
if (owner) *owner = obj2gco(f->upvals[n - 1]); if (owner) *owner = obj2gco(f->upvals[n - 1]);
name = p->upvalues[n-1].name; name = p->upvalues[n-1].name;
return (name == NULL) ? "(no name)" : getstr(name); return (name == NULL) ? "(no name)" : getstr(name);
@@ -1390,7 +1387,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
lua_lock(L); lua_lock(L);
name = aux_upvalue(index2value(L, funcindex), n, &val, NULL); name = aux_upvalue(index2value(L, funcindex), n, &val, NULL);
if (name) { if (name) {
setobj2s(L, L->top, val); setobj2s(L, L->top.p, val);
api_incr_top(L); api_incr_top(L);
} }
lua_unlock(L); lua_unlock(L);
@@ -1408,8 +1405,8 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
api_checknelems(L, 1); api_checknelems(L, 1);
name = aux_upvalue(fi, n, &val, &owner); name = aux_upvalue(fi, n, &val, &owner);
if (name) { if (name) {
L->top--; L->top.p--;
setobj(L, val, s2v(L->top)); setobj(L, val, s2v(L->top.p));
luaC_barrier(L, owner, val); luaC_barrier(L, owner, val);
} }
lua_unlock(L); lua_unlock(L);
+10 -7
View File
@@ -12,23 +12,26 @@
#include "lstate.h" #include "lstate.h"
/* Increments 'L->top', checking for stack overflows */ /* Increments 'L->top.p', checking for stack overflows */
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ #define api_incr_top(L) {L->top.p++; \
"stack overflow");} api_check(L, L->top.p <= L->ci->top.p, \
"stack overflow");}
/* /*
** If a call returns too many multiple returns, the callee may not have ** If a call returns too many multiple returns, the callee may not have
** stack space to accommodate all results. In this case, this macro ** stack space to accommodate all results. In this case, this macro
** increases its stack space ('L->ci->top'). ** increases its stack space ('L->ci->top.p').
*/ */
#define adjustresults(L,nres) \ #define adjustresults(L,nres) \
{ if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } { if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
L->ci->top.p = L->top.p; }
/* Ensure the stack has at least 'n' elements */ /* Ensure the stack has at least 'n' elements */
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ #define api_checknelems(L,n) \
"not enough elements in the stack") api_check(L, (n) < (L->top.p - L->ci->func.p), \
"not enough elements in the stack")
/* /*
+52 -32
View File
@@ -80,6 +80,7 @@ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
int top = lua_gettop(L); int top = lua_gettop(L);
lua_getinfo(L, "f", ar); /* push function */ lua_getinfo(L, "f", ar); /* push function */
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
luaL_checkstack(L, 6, "not enough stack"); /* slots for 'findfield' */
if (findfield(L, top + 1, 2)) { if (findfield(L, top + 1, 2)) {
const char *name = lua_tostring(L, -1); const char *name = lua_tostring(L, -1);
if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */ if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */
@@ -249,11 +250,13 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
return 1; return 1;
} }
else { else {
const char *msg;
luaL_pushfail(L); luaL_pushfail(L);
msg = (en != 0) ? strerror(en) : "(no extra info)";
if (fname) if (fname)
lua_pushfstring(L, "%s: %s", fname, strerror(en)); lua_pushfstring(L, "%s: %s", fname, msg);
else else
lua_pushstring(L, strerror(en)); lua_pushstring(L, msg);
lua_pushinteger(L, en); lua_pushinteger(L, en);
return 3; return 3;
} }
@@ -526,13 +529,14 @@ static void newbox (lua_State *L) {
/* /*
** Compute new size for buffer 'B', enough to accommodate extra 'sz' ** Compute new size for buffer 'B', enough to accommodate extra 'sz'
** bytes. ** bytes. (The test for "not big enough" also gets the case when the
** computation of 'newsize' overflows.)
*/ */
static size_t newbuffsize (luaL_Buffer *B, size_t sz) { static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
size_t newsize = B->size * 2; /* double buffer size */ size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */
if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */ if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */
return luaL_error(B->L, "buffer too large"); return luaL_error(B->L, "buffer too large");
if (newsize < B->n + sz) /* double is not big enough? */ if (newsize < B->n + sz) /* not big enough? */
newsize = B->n + sz; newsize = B->n + sz;
return newsize; return newsize;
} }
@@ -611,7 +615,7 @@ LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
** box (if existent) is not on the top of the stack. So, instead of ** box (if existent) is not on the top of the stack. So, instead of
** calling 'luaL_addlstring', it replicates the code using -2 as the ** calling 'luaL_addlstring', it replicates the code using -2 as the
** last argument to 'prepbuffsize', signaling that the box is (or will ** last argument to 'prepbuffsize', signaling that the box is (or will
** be) bellow the string being added to the buffer. (Box creation can ** be) below the string being added to the buffer. (Box creation can
** trigger an emergency GC, so we should not remove the string from the ** trigger an emergency GC, so we should not remove the string from the
** stack before we have the space guaranteed.) ** stack before we have the space guaranteed.)
*/ */
@@ -731,25 +735,29 @@ static const char *getF (lua_State *L, void *ud, size_t *size) {
static int errfile (lua_State *L, const char *what, int fnameindex) { static int errfile (lua_State *L, const char *what, int fnameindex) {
const char *serr = strerror(errno); int err = errno;
const char *filename = lua_tostring(L, fnameindex) + 1; const char *filename = lua_tostring(L, fnameindex) + 1;
lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); if (err != 0)
lua_pushfstring(L, "cannot %s %s: %s", what, filename, strerror(err));
else
lua_pushfstring(L, "cannot %s %s", what, filename);
lua_remove(L, fnameindex); lua_remove(L, fnameindex);
return LUA_ERRFILE; return LUA_ERRFILE;
} }
static int skipBOM (LoadF *lf) { /*
const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ ** Skip an optional BOM at the start of a stream. If there is an
int c; ** incomplete BOM (the first character is correct but the rest is
lf->n = 0; ** not), returns the first character anyway to force an error
do { ** (as no chunk can start with 0xEF).
c = getc(lf->f); */
if (c == EOF || c != *(const unsigned char *)p++) return c; static int skipBOM (FILE *f) {
lf->buff[lf->n++] = c; /* to be read by the parser */ int c = getc(f); /* read first character */
} while (*p != '\0'); if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */
lf->n = 0; /* prefix matched; discard it */ return getc(f); /* ignore BOM and return next char */
return getc(lf->f); /* return next character */ else /* no (valid) BOM */
return c; /* return first character */
} }
@@ -760,13 +768,13 @@ static int skipBOM (LoadF *lf) {
** first "valid" character of the file (after the optional BOM and ** first "valid" character of the file (after the optional BOM and
** a first-line comment). ** a first-line comment).
*/ */
static int skipcomment (LoadF *lf, int *cp) { static int skipcomment (FILE *f, int *cp) {
int c = *cp = skipBOM(lf); int c = *cp = skipBOM(f);
if (c == '#') { /* first line is a comment (Unix exec. file)? */ if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */ do { /* skip first line */
c = getc(lf->f); c = getc(f);
} while (c != EOF && c != '\n'); } while (c != EOF && c != '\n');
*cp = getc(lf->f); /* skip end-of-line, if present */ *cp = getc(f); /* next character after comment, if present */
return 1; /* there was a comment */ return 1; /* there was a comment */
} }
else return 0; /* no comment */ else return 0; /* no comment */
@@ -785,18 +793,25 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
} }
else { else {
lua_pushfstring(L, "@%s", filename); lua_pushfstring(L, "@%s", filename);
errno = 0;
lf.f = fopen(filename, "r"); lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex); if (lf.f == NULL) return errfile(L, "open", fnameindex);
} }
if (skipcomment(&lf, &c)) /* read initial portion */ lf.n = 0;
lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ if (skipcomment(lf.f, &c)) /* read initial portion */
if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ if (c == LUA_SIGNATURE[0]) { /* binary file? */
if (lf.f == NULL) return errfile(L, "reopen", fnameindex); lf.n = 0; /* remove possible newline */
skipcomment(&lf, &c); /* re-read initial portion */ if (filename) { /* "real" file? */
errno = 0;
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
skipcomment(lf.f, &c); /* re-read initial portion */
}
} }
if (c != EOF) if (c != EOF)
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
errno = 0;
status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
readstatus = ferror(lf.f); readstatus = ferror(lf.f);
if (filename) fclose(lf.f); /* close file (even in case of errors) */ if (filename) fclose(lf.f); /* close file (even in case of errors) */
@@ -927,7 +942,7 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
luaL_checkstack(L, nup, "too many upvalues"); luaL_checkstack(L, nup, "too many upvalues");
for (; l->name != NULL; l++) { /* fill the table with given functions */ for (; l->name != NULL; l++) { /* fill the table with given functions */
if (l->func == NULL) /* place holder? */ if (l->func == NULL) /* placeholder? */
lua_pushboolean(L, 0); lua_pushboolean(L, 0);
else { else {
int i; int i;
@@ -1019,9 +1034,14 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
} }
/*
** Standard panic funcion just prints an error message. The test
** with 'lua_type' avoids possible memory errors in 'lua_tostring'.
*/
static int panic (lua_State *L) { static int panic (lua_State *L) {
const char *msg = lua_tostring(L, -1); const char *msg = (lua_type(L, -1) == LUA_TSTRING)
if (msg == NULL) msg = "error object is not a string"; ? lua_tostring(L, -1)
: "error object is not a string";
lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
msg); msg);
return 0; /* return to Lua to abort */ return 0; /* return to Lua to abort */
+108 -65
View File
@@ -35,6 +35,7 @@
#define MAXREGS 255 #define MAXREGS 255
/* (note that expressions VJMP also have jumps.) */
#define hasjumps(e) ((e)->t != (e)->f) #define hasjumps(e) ((e)->t != (e)->f)
@@ -415,7 +416,7 @@ int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
/* /*
** Format and emit an 'iAsBx' instruction. ** Format and emit an 'iAsBx' instruction.
*/ */
int luaK_codeAsBx (FuncState *fs, OpCode o, int a, int bc) { static int codeAsBx (FuncState *fs, OpCode o, int a, int bc) {
unsigned int b = bc + OFFSET_sBx; unsigned int b = bc + OFFSET_sBx;
lua_assert(getOpMode(o) == iAsBx); lua_assert(getOpMode(o) == iAsBx);
lua_assert(a <= MAXARG_A && b <= MAXARG_Bx); lua_assert(a <= MAXARG_A && b <= MAXARG_Bx);
@@ -671,7 +672,7 @@ static int fitsBx (lua_Integer i) {
void luaK_int (FuncState *fs, int reg, lua_Integer i) { void luaK_int (FuncState *fs, int reg, lua_Integer i) {
if (fitsBx(i)) if (fitsBx(i))
luaK_codeAsBx(fs, OP_LOADI, reg, cast_int(i)); codeAsBx(fs, OP_LOADI, reg, cast_int(i));
else else
luaK_codek(fs, reg, luaK_intK(fs, i)); luaK_codek(fs, reg, luaK_intK(fs, i));
} }
@@ -680,7 +681,7 @@ void luaK_int (FuncState *fs, int reg, lua_Integer i) {
static void luaK_float (FuncState *fs, int reg, lua_Number f) { static void luaK_float (FuncState *fs, int reg, lua_Number f) {
lua_Integer fi; lua_Integer fi;
if (luaV_flttointeger(f, &fi, F2Ieq) && fitsBx(fi)) if (luaV_flttointeger(f, &fi, F2Ieq) && fitsBx(fi))
luaK_codeAsBx(fs, OP_LOADF, reg, cast_int(fi)); codeAsBx(fs, OP_LOADF, reg, cast_int(fi));
else else
luaK_codek(fs, reg, luaK_numberK(fs, f)); luaK_codek(fs, reg, luaK_numberK(fs, f));
} }
@@ -776,7 +777,8 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
break; break;
} }
case VLOCAL: { /* already in a register */ case VLOCAL: { /* already in a register */
e->u.info = e->u.var.ridx; int temp = e->u.var.ridx;
e->u.info = temp; /* (can't do a direct assignment; values overlap) */
e->k = VNONRELOC; /* becomes a non-relocatable value */ e->k = VNONRELOC; /* becomes a non-relocatable value */
break; break;
} }
@@ -984,7 +986,7 @@ void luaK_exp2anyregup (FuncState *fs, expdesc *e) {
** or it is a constant. ** or it is a constant.
*/ */
void luaK_exp2val (FuncState *fs, expdesc *e) { void luaK_exp2val (FuncState *fs, expdesc *e) {
if (hasjumps(e)) if (e->k == VJMP || hasjumps(e))
luaK_exp2anyreg(fs, e); luaK_exp2anyreg(fs, e);
else else
luaK_dischargevars(fs, e); luaK_dischargevars(fs, e);
@@ -1025,7 +1027,7 @@ static int luaK_exp2K (FuncState *fs, expdesc *e) {
** in the range of R/K indices). ** in the range of R/K indices).
** Returns 1 iff expression is K. ** Returns 1 iff expression is K.
*/ */
int luaK_exp2RK (FuncState *fs, expdesc *e) { static int exp2RK (FuncState *fs, expdesc *e) {
if (luaK_exp2K(fs, e)) if (luaK_exp2K(fs, e))
return 1; return 1;
else { /* not a constant in the right range: put it in a register */ else { /* not a constant in the right range: put it in a register */
@@ -1037,7 +1039,7 @@ int luaK_exp2RK (FuncState *fs, expdesc *e) {
static void codeABRK (FuncState *fs, OpCode o, int a, int b, static void codeABRK (FuncState *fs, OpCode o, int a, int b,
expdesc *ec) { expdesc *ec) {
int k = luaK_exp2RK(fs, ec); int k = exp2RK(fs, ec);
luaK_codeABCk(fs, o, a, b, ec->u.info, k); luaK_codeABCk(fs, o, a, b, ec->u.info, k);
} }
@@ -1215,7 +1217,7 @@ static void codenot (FuncState *fs, expdesc *e) {
/* /*
** Check whether expression 'e' is a small literal string ** Check whether expression 'e' is a short literal string
*/ */
static int isKstr (FuncState *fs, expdesc *e) { static int isKstr (FuncState *fs, expdesc *e) {
return (e->k == VK && !hasjumps(e) && e->u.info <= MAXARG_B && return (e->k == VK && !hasjumps(e) && e->u.info <= MAXARG_B &&
@@ -1225,7 +1227,7 @@ static int isKstr (FuncState *fs, expdesc *e) {
/* /*
** Check whether expression 'e' is a literal integer. ** Check whether expression 'e' is a literal integer.
*/ */
int luaK_isKint (expdesc *e) { static int isKint (expdesc *e) {
return (e->k == VKINT && !hasjumps(e)); return (e->k == VKINT && !hasjumps(e));
} }
@@ -1235,7 +1237,7 @@ int luaK_isKint (expdesc *e) {
** proper range to fit in register C ** proper range to fit in register C
*/ */
static int isCint (expdesc *e) { static int isCint (expdesc *e) {
return luaK_isKint(e) && (l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C)); return isKint(e) && (l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C));
} }
@@ -1244,7 +1246,7 @@ static int isCint (expdesc *e) {
** proper range to fit in register sC ** proper range to fit in register sC
*/ */
static int isSCint (expdesc *e) { static int isSCint (expdesc *e) {
return luaK_isKint(e) && fitsC(e->u.ival); return isKint(e) && fitsC(e->u.ival);
} }
@@ -1283,15 +1285,17 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */ if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */
luaK_exp2anyreg(fs, t); /* put it in a register */ luaK_exp2anyreg(fs, t); /* put it in a register */
if (t->k == VUPVAL) { if (t->k == VUPVAL) {
t->u.ind.t = t->u.info; /* upvalue index */ int temp = t->u.info; /* upvalue index */
t->u.ind.idx = k->u.info; /* literal string */ lua_assert(isKstr(fs, k));
t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */
t->u.ind.idx = k->u.info; /* literal short string */
t->k = VINDEXUP; t->k = VINDEXUP;
} }
else { else {
/* register index of the table */ /* register index of the table */
t->u.ind.t = (t->k == VLOCAL) ? t->u.var.ridx: t->u.info; t->u.ind.t = (t->k == VLOCAL) ? t->u.var.ridx: t->u.info;
if (isKstr(fs, k)) { if (isKstr(fs, k)) {
t->u.ind.idx = k->u.info; /* literal string */ t->u.ind.idx = k->u.info; /* literal short string */
t->k = VINDEXSTR; t->k = VINDEXSTR;
} }
else if (isCint(k)) { else if (isCint(k)) {
@@ -1351,6 +1355,35 @@ static int constfolding (FuncState *fs, int op, expdesc *e1,
} }
/*
** Convert a BinOpr to an OpCode (ORDER OPR - ORDER OP)
*/
l_sinline OpCode binopr2op (BinOpr opr, BinOpr baser, OpCode base) {
lua_assert(baser <= opr &&
((baser == OPR_ADD && opr <= OPR_SHR) ||
(baser == OPR_LT && opr <= OPR_LE)));
return cast(OpCode, (cast_int(opr) - cast_int(baser)) + cast_int(base));
}
/*
** Convert a UnOpr to an OpCode (ORDER OPR - ORDER OP)
*/
l_sinline OpCode unopr2op (UnOpr opr) {
return cast(OpCode, (cast_int(opr) - cast_int(OPR_MINUS)) +
cast_int(OP_UNM));
}
/*
** Convert a BinOpr to a tag method (ORDER OPR - ORDER TM)
*/
l_sinline TMS binopr2TM (BinOpr opr) {
lua_assert(OPR_ADD <= opr && opr <= OPR_SHR);
return cast(TMS, (cast_int(opr) - cast_int(OPR_ADD)) + cast_int(TM_ADD));
}
/* /*
** Emit code for unary expressions that "produce values" ** Emit code for unary expressions that "produce values"
** (everything but 'not'). ** (everything but 'not').
@@ -1389,12 +1422,15 @@ static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2,
** Emit code for binary expressions that "produce values" over ** Emit code for binary expressions that "produce values" over
** two registers. ** two registers.
*/ */
static void codebinexpval (FuncState *fs, OpCode op, static void codebinexpval (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) { expdesc *e1, expdesc *e2, int line) {
int v2 = luaK_exp2anyreg(fs, e2); /* both operands are in registers */ OpCode op = binopr2op(opr, OPR_ADD, OP_ADD);
int v2 = luaK_exp2anyreg(fs, e2); /* make sure 'e2' is in a register */
/* 'e1' must be already in a register or it is a constant */
lua_assert((VNIL <= e1->k && e1->k <= VKSTR) ||
e1->k == VNONRELOC || e1->k == VRELOC);
lua_assert(OP_ADD <= op && op <= OP_SHR); lua_assert(OP_ADD <= op && op <= OP_SHR);
finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, binopr2TM(opr));
cast(TMS, (op - OP_ADD) + TM_ADD));
} }
@@ -1410,12 +1446,24 @@ static void codebini (FuncState *fs, OpCode op,
} }
/*
** Code binary operators with K operand.
*/
static void codebinK (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
TMS event = binopr2TM(opr);
int v2 = e2->u.info; /* K index */
OpCode op = binopr2op(opr, OPR_ADD, OP_ADDK);
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
}
/* Try to code a binary operator negating its second operand. /* Try to code a binary operator negating its second operand.
** For the metamethod, 2nd operand must keep its original value. ** For the metamethod, 2nd operand must keep its original value.
*/ */
static int finishbinexpneg (FuncState *fs, expdesc *e1, expdesc *e2, static int finishbinexpneg (FuncState *fs, expdesc *e1, expdesc *e2,
OpCode op, int line, TMS event) { OpCode op, int line, TMS event) {
if (!luaK_isKint(e2)) if (!isKint(e2))
return 0; /* not an integer constant */ return 0; /* not an integer constant */
else { else {
lua_Integer i2 = e2->u.ival; lua_Integer i2 = e2->u.ival;
@@ -1437,24 +1485,27 @@ static void swapexps (expdesc *e1, expdesc *e2) {
} }
/*
** Code binary operators with no constant operand.
*/
static void codebinNoK (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
if (flip)
swapexps(e1, e2); /* back to original order */
codebinexpval(fs, opr, e1, e2, line); /* use standard operators */
}
/* /*
** Code arithmetic operators ('+', '-', ...). If second operand is a ** Code arithmetic operators ('+', '-', ...). If second operand is a
** constant in the proper range, use variant opcodes with K operands. ** constant in the proper range, use variant opcodes with K operands.
*/ */
static void codearith (FuncState *fs, BinOpr opr, static void codearith (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) { expdesc *e1, expdesc *e2, int flip, int line) {
TMS event = cast(TMS, opr + TM_ADD); if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) /* K operand? */
if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */ codebinK(fs, opr, e1, e2, flip, line);
int v2 = e2->u.info; /* K index */ else /* 'e2' is neither an immediate nor a K operand */
OpCode op = cast(OpCode, opr + OP_ADDK); codebinNoK(fs, opr, e1, e2, flip, line);
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
}
else { /* 'e2' is neither an immediate nor a K operand */
OpCode op = cast(OpCode, opr + OP_ADD);
if (flip)
swapexps(e1, e2); /* back to original order */
codebinexpval(fs, op, e1, e2, line); /* use standard operators */
}
} }
@@ -1471,35 +1522,27 @@ static void codecommutative (FuncState *fs, BinOpr op,
flip = 1; flip = 1;
} }
if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */ if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */
codebini(fs, cast(OpCode, OP_ADDI), e1, e2, flip, line, TM_ADD); codebini(fs, OP_ADDI, e1, e2, flip, line, TM_ADD);
else else
codearith(fs, op, e1, e2, flip, line); codearith(fs, op, e1, e2, flip, line);
} }
/* /*
** Code bitwise operations; they are all associative, so the function ** Code bitwise operations; they are all commutative, so the function
** tries to put an integer constant as the 2nd operand (a K operand). ** tries to put an integer constant as the 2nd operand (a K operand).
*/ */
static void codebitwise (FuncState *fs, BinOpr opr, static void codebitwise (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) { expdesc *e1, expdesc *e2, int line) {
int flip = 0; int flip = 0;
int v2; if (e1->k == VKINT) {
OpCode op;
if (e1->k == VKINT && luaK_exp2RK(fs, e1)) {
swapexps(e1, e2); /* 'e2' will be the constant operand */ swapexps(e1, e2); /* 'e2' will be the constant operand */
flip = 1; flip = 1;
} }
else if (!(e2->k == VKINT && luaK_exp2RK(fs, e2))) { /* no constants? */ if (e2->k == VKINT && luaK_exp2K(fs, e2)) /* K operand? */
op = cast(OpCode, opr + OP_ADD); codebinK(fs, opr, e1, e2, flip, line);
codebinexpval(fs, op, e1, e2, line); /* all-register opcodes */ else /* no constants */
return; codebinNoK(fs, opr, e1, e2, flip, line);
}
v2 = e2->u.info; /* index in K array */
op = cast(OpCode, opr + OP_ADDK);
lua_assert(ttisinteger(&fs->f->k[v2]));
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK,
cast(TMS, opr + TM_ADD));
} }
@@ -1507,25 +1550,27 @@ static void codebitwise (FuncState *fs, BinOpr opr,
** Emit code for order comparisons. When using an immediate operand, ** Emit code for order comparisons. When using an immediate operand,
** 'isfloat' tells whether the original value was a float. ** 'isfloat' tells whether the original value was a float.
*/ */
static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
int r1, r2; int r1, r2;
int im; int im;
int isfloat = 0; int isfloat = 0;
OpCode op;
if (isSCnumber(e2, &im, &isfloat)) { if (isSCnumber(e2, &im, &isfloat)) {
/* use immediate operand */ /* use immediate operand */
r1 = luaK_exp2anyreg(fs, e1); r1 = luaK_exp2anyreg(fs, e1);
r2 = im; r2 = im;
op = cast(OpCode, (op - OP_LT) + OP_LTI); op = binopr2op(opr, OPR_LT, OP_LTI);
} }
else if (isSCnumber(e1, &im, &isfloat)) { else if (isSCnumber(e1, &im, &isfloat)) {
/* transform (A < B) to (B > A) and (A <= B) to (B >= A) */ /* transform (A < B) to (B > A) and (A <= B) to (B >= A) */
r1 = luaK_exp2anyreg(fs, e2); r1 = luaK_exp2anyreg(fs, e2);
r2 = im; r2 = im;
op = (op == OP_LT) ? OP_GTI : OP_GEI; op = binopr2op(opr, OPR_LT, OP_GTI);
} }
else { /* regular case, compare two registers */ else { /* regular case, compare two registers */
r1 = luaK_exp2anyreg(fs, e1); r1 = luaK_exp2anyreg(fs, e1);
r2 = luaK_exp2anyreg(fs, e2); r2 = luaK_exp2anyreg(fs, e2);
op = binopr2op(opr, OPR_LT, OP_LT);
} }
freeexps(fs, e1, e2); freeexps(fs, e1, e2);
e1->u.info = condjump(fs, op, r1, r2, isfloat, 1); e1->u.info = condjump(fs, op, r1, r2, isfloat, 1);
@@ -1551,7 +1596,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
op = OP_EQI; op = OP_EQI;
r2 = im; /* immediate operand */ r2 = im; /* immediate operand */
} }
else if (luaK_exp2RK(fs, e2)) { /* 1st expression is constant? */ else if (exp2RK(fs, e2)) { /* 2nd expression is constant? */
op = OP_EQK; op = OP_EQK;
r2 = e2->u.info; /* constant index */ r2 = e2->u.info; /* constant index */
} }
@@ -1568,16 +1613,16 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
/* /*
** Apply prefix operation 'op' to expression 'e'. ** Apply prefix operation 'op' to expression 'e'.
*/ */
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { void luaK_prefix (FuncState *fs, UnOpr opr, expdesc *e, int line) {
static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
luaK_dischargevars(fs, e); luaK_dischargevars(fs, e);
switch (op) { switch (opr) {
case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */ case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */
if (constfolding(fs, op + LUA_OPUNM, e, &ef)) if (constfolding(fs, opr + LUA_OPUNM, e, &ef))
break; break;
/* else */ /* FALLTHROUGH */ /* else */ /* FALLTHROUGH */
case OPR_LEN: case OPR_LEN:
codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); codeunexpval(fs, unopr2op(opr), e, line);
break; break;
case OPR_NOT: codenot(fs, e); break; case OPR_NOT: codenot(fs, e); break;
default: lua_assert(0); default: lua_assert(0);
@@ -1611,12 +1656,13 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
case OPR_SHL: case OPR_SHR: { case OPR_SHL: case OPR_SHR: {
if (!tonumeral(v, NULL)) if (!tonumeral(v, NULL))
luaK_exp2anyreg(fs, v); luaK_exp2anyreg(fs, v);
/* else keep numeral, which may be folded with 2nd operand */ /* else keep numeral, which may be folded or used as an immediate
operand */
break; break;
} }
case OPR_EQ: case OPR_NE: { case OPR_EQ: case OPR_NE: {
if (!tonumeral(v, NULL)) if (!tonumeral(v, NULL))
luaK_exp2RK(fs, v); exp2RK(fs, v);
/* else keep numeral, which may be an immediate operand */ /* else keep numeral, which may be an immediate operand */
break; break;
} }
@@ -1706,30 +1752,27 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
/* coded as (r1 >> -I) */; /* coded as (r1 >> -I) */;
} }
else /* regular case (two registers) */ else /* regular case (two registers) */
codebinexpval(fs, OP_SHL, e1, e2, line); codebinexpval(fs, opr, e1, e2, line);
break; break;
} }
case OPR_SHR: { case OPR_SHR: {
if (isSCint(e2)) if (isSCint(e2))
codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */ codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */
else /* regular case (two registers) */ else /* regular case (two registers) */
codebinexpval(fs, OP_SHR, e1, e2, line); codebinexpval(fs, opr, e1, e2, line);
break; break;
} }
case OPR_EQ: case OPR_NE: { case OPR_EQ: case OPR_NE: {
codeeq(fs, opr, e1, e2); codeeq(fs, opr, e1, e2);
break; break;
} }
case OPR_LT: case OPR_LE: {
OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
codeorder(fs, op, e1, e2);
break;
}
case OPR_GT: case OPR_GE: { case OPR_GT: case OPR_GE: {
/* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */ /* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */
OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
swapexps(e1, e2); swapexps(e1, e2);
codeorder(fs, op, e1, e2); opr = cast(BinOpr, (opr - OPR_GT) + OPR_LT);
} /* FALLTHROUGH */
case OPR_LT: case OPR_LE: {
codeorder(fs, opr, e1, e2);
break; break;
} }
default: lua_assert(0); default: lua_assert(0);
-3
View File
@@ -61,10 +61,8 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
LUAI_FUNC int luaK_code (FuncState *fs, Instruction i); LUAI_FUNC int luaK_code (FuncState *fs, Instruction i);
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx);
LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
int B, int C, int k); int B, int C, int k);
LUAI_FUNC int luaK_isKint (expdesc *e);
LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v); LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
LUAI_FUNC void luaK_fixline (FuncState *fs, int line); LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
@@ -76,7 +74,6 @@ LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
+2 -2
View File
@@ -76,7 +76,7 @@ static int luaB_auxwrap (lua_State *L) {
if (l_unlikely(r < 0)) { /* error? */ if (l_unlikely(r < 0)) { /* error? */
int stat = lua_status(co); int stat = lua_status(co);
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
stat = lua_resetthread(co); /* close its tbc variables */ stat = lua_closethread(co, L); /* close its tbc variables */
lua_assert(stat != LUA_OK); lua_assert(stat != LUA_OK);
lua_xmove(co, L, 1); /* move error message to the caller */ lua_xmove(co, L, 1); /* move error message to the caller */
} }
@@ -172,7 +172,7 @@ static int luaB_close (lua_State *L) {
int status = auxstatus(L, co); int status = auxstatus(L, co);
switch (status) { switch (status) {
case COS_DEAD: case COS_YIELD: { case COS_DEAD: case COS_YIELD: {
status = lua_resetthread(co); status = lua_closethread(co, L);
if (status == LUA_OK) { if (status == LUA_OK) {
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
return 1; return 1;
+182 -129
View File
@@ -31,12 +31,15 @@
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) #define LuaClosure(f) ((f) != NULL && (f)->c.tt == LUA_VLCL)
static const char *funcnamefromcall (lua_State *L, CallInfo *ci, static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
const char **name); const char **name);
static const char strlocal[] = "local";
static const char strupval[] = "upvalue";
static int currentpc (CallInfo *ci) { static int currentpc (CallInfo *ci) {
lua_assert(isLua(ci)); lua_assert(isLua(ci));
@@ -182,10 +185,10 @@ static const char *upvalname (const Proto *p, int uv) {
static const char *findvararg (CallInfo *ci, int n, StkId *pos) { static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
if (clLvalue(s2v(ci->func))->p->is_vararg) { if (clLvalue(s2v(ci->func.p))->p->is_vararg) {
int nextra = ci->u.l.nextraargs; int nextra = ci->u.l.nextraargs;
if (n >= -nextra) { /* 'n' is negative */ if (n >= -nextra) { /* 'n' is negative */
*pos = ci->func - nextra - (n + 1); *pos = ci->func.p - nextra - (n + 1);
return "(vararg)"; /* generic name for any vararg */ return "(vararg)"; /* generic name for any vararg */
} }
} }
@@ -194,7 +197,7 @@ static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) { const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
StkId base = ci->func + 1; StkId base = ci->func.p + 1;
const char *name = NULL; const char *name = NULL;
if (isLua(ci)) { if (isLua(ci)) {
if (n < 0) /* access to vararg values? */ if (n < 0) /* access to vararg values? */
@@ -203,7 +206,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
} }
if (name == NULL) { /* no 'standard' name? */ if (name == NULL) { /* no 'standard' name? */
StkId limit = (ci == L->ci) ? L->top : ci->next->func; StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */ if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
/* generic name for any valid slot */ /* generic name for any valid slot */
name = isLua(ci) ? "(temporary)" : "(C temporary)"; name = isLua(ci) ? "(temporary)" : "(C temporary)";
@@ -221,16 +224,16 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
const char *name; const char *name;
lua_lock(L); lua_lock(L);
if (ar == NULL) { /* information about non-active function? */ if (ar == NULL) { /* information about non-active function? */
if (!isLfunction(s2v(L->top - 1))) /* not a Lua function? */ if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */
name = NULL; name = NULL;
else /* consider live variables at function start (parameters) */ else /* consider live variables at function start (parameters) */
name = luaF_getlocalname(clLvalue(s2v(L->top - 1))->p, n, 0); name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
} }
else { /* active function; get information through 'ar' */ else { /* active function; get information through 'ar' */
StkId pos = NULL; /* to avoid warnings */ StkId pos = NULL; /* to avoid warnings */
name = luaG_findlocal(L, ar->i_ci, n, &pos); name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) { if (name) {
setobjs2s(L, L->top, pos); setobjs2s(L, L->top.p, pos);
api_incr_top(L); api_incr_top(L);
} }
} }
@@ -245,8 +248,8 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
lua_lock(L); lua_lock(L);
name = luaG_findlocal(L, ar->i_ci, n, &pos); name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) { if (name) {
setobjs2s(L, pos, L->top - 1); setobjs2s(L, pos, L->top.p - 1);
L->top--; /* pop value */ L->top.p--; /* pop value */
} }
lua_unlock(L); lua_unlock(L);
return name; return name;
@@ -254,7 +257,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
static void funcinfo (lua_Debug *ar, Closure *cl) { static void funcinfo (lua_Debug *ar, Closure *cl) {
if (noLuaClosure(cl)) { if (!LuaClosure(cl)) {
ar->source = "=[C]"; ar->source = "=[C]";
ar->srclen = LL("=[C]"); ar->srclen = LL("=[C]");
ar->linedefined = -1; ar->linedefined = -1;
@@ -288,29 +291,31 @@ static int nextline (const Proto *p, int currentline, int pc) {
static void collectvalidlines (lua_State *L, Closure *f) { static void collectvalidlines (lua_State *L, Closure *f) {
if (noLuaClosure(f)) { if (!LuaClosure(f)) {
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
api_incr_top(L); api_incr_top(L);
} }
else { else {
int i;
TValue v;
const Proto *p = f->l.p; const Proto *p = f->l.p;
int currentline = p->linedefined; int currentline = p->linedefined;
Table *t = luaH_new(L); /* new table to store active lines */ Table *t = luaH_new(L); /* new table to store active lines */
sethvalue2s(L, L->top, t); /* push it on stack */ sethvalue2s(L, L->top.p, t); /* push it on stack */
api_incr_top(L); api_incr_top(L);
setbtvalue(&v); /* boolean 'true' to be the value of all indices */ if (p->lineinfo != NULL) { /* proto with debug information? */
if (!p->is_vararg) /* regular function? */ int i;
i = 0; /* consider all instructions */ TValue v;
else { /* vararg function */ setbtvalue(&v); /* boolean 'true' to be the value of all indices */
lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); if (!p->is_vararg) /* regular function? */
currentline = nextline(p, currentline, 0); i = 0; /* consider all instructions */
i = 1; /* skip first instruction (OP_VARARGPREP) */ else { /* vararg function */
} lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
for (; i < p->sizelineinfo; i++) { /* for each instruction */ currentline = nextline(p, currentline, 0);
currentline = nextline(p, currentline, i); /* get its line */ i = 1; /* skip first instruction (OP_VARARGPREP) */
luaH_setint(L, t, currentline, &v); /* table[line] = true */ }
for (; i < p->sizelineinfo; i++) { /* for each instruction */
currentline = nextline(p, currentline, i); /* get its line */
luaH_setint(L, t, currentline, &v); /* table[line] = true */
}
} }
} }
} }
@@ -339,7 +344,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
} }
case 'u': { case 'u': {
ar->nups = (f == NULL) ? 0 : f->c.nupvalues; ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
if (noLuaClosure(f)) { if (!LuaClosure(f)) {
ar->isvararg = 1; ar->isvararg = 1;
ar->nparams = 0; ar->nparams = 0;
} }
@@ -388,20 +393,20 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
lua_lock(L); lua_lock(L);
if (*what == '>') { if (*what == '>') {
ci = NULL; ci = NULL;
func = s2v(L->top - 1); func = s2v(L->top.p - 1);
api_check(L, ttisfunction(func), "function expected"); api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */ what++; /* skip the '>' */
L->top--; /* pop function */ L->top.p--; /* pop function */
} }
else { else {
ci = ar->i_ci; ci = ar->i_ci;
func = s2v(ci->func); func = s2v(ci->func.p);
lua_assert(ttisfunction(func)); lua_assert(ttisfunction(func));
} }
cl = ttisclosure(func) ? clvalue(func) : NULL; cl = ttisclosure(func) ? clvalue(func) : NULL;
status = auxgetinfo(L, what, ar, cl, ci); status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) { if (strchr(what, 'f')) {
setobj2s(L, L->top, func); setobj2s(L, L->top.p, func);
api_incr_top(L); api_incr_top(L);
} }
if (strchr(what, 'L')) if (strchr(what, 'L'))
@@ -417,40 +422,6 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
** ======================================================= ** =======================================================
*/ */
static const char *getobjname (const Proto *p, int lastpc, int reg,
const char **name);
/*
** Find a "name" for the constant 'c'.
*/
static void kname (const Proto *p, int c, const char **name) {
TValue *kvalue = &p->k[c];
*name = (ttisstring(kvalue)) ? svalue(kvalue) : "?";
}
/*
** Find a "name" for the register 'c'.
*/
static void rname (const Proto *p, int pc, int c, const char **name) {
const char *what = getobjname(p, pc, c, name); /* search for 'c' */
if (!(what && *what == 'c')) /* did not find a constant name? */
*name = "?";
}
/*
** Find a "name" for a 'C' value in an RK instruction.
*/
static void rkname (const Proto *p, int pc, Instruction i, const char **name) {
int c = GETARG_C(i); /* key index */
if (GETARG_k(i)) /* is 'c' a constant? */
kname(p, c, name);
else /* 'c' is a register */
rname(p, pc, c, name);
}
static int filterpc (int pc, int jmptarget) { static int filterpc (int pc, int jmptarget) {
if (pc < jmptarget) /* is code conditional (inside a jump)? */ if (pc < jmptarget) /* is code conditional (inside a jump)? */
@@ -509,28 +480,29 @@ static int findsetreg (const Proto *p, int lastpc, int reg) {
/* /*
** Check whether table being indexed by instruction 'i' is the ** Find a "name" for the constant 'c'.
** environment '_ENV'
*/ */
static const char *gxf (const Proto *p, int pc, Instruction i, int isup) { static const char *kname (const Proto *p, int index, const char **name) {
int t = GETARG_B(i); /* table index */ TValue *kvalue = &p->k[index];
const char *name; /* name of indexed variable */ if (ttisstring(kvalue)) {
if (isup) /* is an upvalue? */ *name = getstr(tsvalue(kvalue));
name = upvalname(p, t); return "constant";
else }
getobjname(p, pc, t, &name); else {
return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field"; *name = "?";
return NULL;
}
} }
static const char *getobjname (const Proto *p, int lastpc, int reg, static const char *basicgetobjname (const Proto *p, int *ppc, int reg,
const char **name) { const char **name) {
int pc; int pc = *ppc;
*name = luaF_getlocalname(p, reg + 1, lastpc); *name = luaF_getlocalname(p, reg + 1, pc);
if (*name) /* is a local? */ if (*name) /* is a local? */
return "local"; return strlocal;
/* else try symbolic execution */ /* else try symbolic execution */
pc = findsetreg(p, lastpc, reg); *ppc = pc = findsetreg(p, pc, reg);
if (pc != -1) { /* could find instruction? */ if (pc != -1) { /* could find instruction? */
Instruction i = p->code[pc]; Instruction i = p->code[pc];
OpCode op = GET_OPCODE(i); OpCode op = GET_OPCODE(i);
@@ -538,18 +510,86 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
case OP_MOVE: { case OP_MOVE: {
int b = GETARG_B(i); /* move from 'b' to 'a' */ int b = GETARG_B(i); /* move from 'b' to 'a' */
if (b < GETARG_A(i)) if (b < GETARG_A(i))
return getobjname(p, pc, b, name); /* get name for 'b' */ return basicgetobjname(p, ppc, b, name); /* get name for 'b' */
break; break;
} }
case OP_GETUPVAL: {
*name = upvalname(p, GETARG_B(i));
return strupval;
}
case OP_LOADK: return kname(p, GETARG_Bx(i), name);
case OP_LOADKX: return kname(p, GETARG_Ax(p->code[pc + 1]), name);
default: break;
}
}
return NULL; /* could not find reasonable name */
}
/*
** Find a "name" for the register 'c'.
*/
static void rname (const Proto *p, int pc, int c, const char **name) {
const char *what = basicgetobjname(p, &pc, c, name); /* search for 'c' */
if (!(what && *what == 'c')) /* did not find a constant name? */
*name = "?";
}
/*
** Find a "name" for a 'C' value in an RK instruction.
*/
static void rkname (const Proto *p, int pc, Instruction i, const char **name) {
int c = GETARG_C(i); /* key index */
if (GETARG_k(i)) /* is 'c' a constant? */
kname(p, c, name);
else /* 'c' is a register */
rname(p, pc, c, name);
}
/*
** Check whether table being indexed by instruction 'i' is the
** environment '_ENV'. If the table is an upvalue, get its name;
** otherwise, find some "name" for the table and check whether
** that name is the name of a local variable (and not, for instance,
** a string). Then check that, if there is a name, it is '_ENV'.
*/
static const char *isEnv (const Proto *p, int pc, Instruction i, int isup) {
int t = GETARG_B(i); /* table index */
const char *name; /* name of indexed variable */
if (isup) /* is 't' an upvalue? */
name = upvalname(p, t);
else { /* 't' is a register */
const char *what = basicgetobjname(p, &pc, t, &name);
if (what != strlocal && what != strupval)
name = NULL; /* cannot be the variable _ENV */
}
return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field";
}
/*
** Extend 'basicgetobjname' to handle table accesses
*/
static const char *getobjname (const Proto *p, int lastpc, int reg,
const char **name) {
const char *kind = basicgetobjname(p, &lastpc, reg, name);
if (kind != NULL)
return kind;
else if (lastpc != -1) { /* could find instruction? */
Instruction i = p->code[lastpc];
OpCode op = GET_OPCODE(i);
switch (op) {
case OP_GETTABUP: { case OP_GETTABUP: {
int k = GETARG_C(i); /* key index */ int k = GETARG_C(i); /* key index */
kname(p, k, name); kname(p, k, name);
return gxf(p, pc, i, 1); return isEnv(p, lastpc, i, 1);
} }
case OP_GETTABLE: { case OP_GETTABLE: {
int k = GETARG_C(i); /* key index */ int k = GETARG_C(i); /* key index */
rname(p, pc, k, name); rname(p, lastpc, k, name);
return gxf(p, pc, i, 0); return isEnv(p, lastpc, i, 0);
} }
case OP_GETI: { case OP_GETI: {
*name = "integer index"; *name = "integer index";
@@ -558,24 +598,10 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
case OP_GETFIELD: { case OP_GETFIELD: {
int k = GETARG_C(i); /* key index */ int k = GETARG_C(i); /* key index */
kname(p, k, name); kname(p, k, name);
return gxf(p, pc, i, 0); return isEnv(p, lastpc, i, 0);
}
case OP_GETUPVAL: {
*name = upvalname(p, GETARG_B(i));
return "upvalue";
}
case OP_LOADK:
case OP_LOADKX: {
int b = (op == OP_LOADK) ? GETARG_Bx(i)
: GETARG_Ax(p->code[pc + 1]);
if (ttisstring(&p->k[b])) {
*name = svalue(&p->k[b]);
return "constant";
}
break;
} }
case OP_SELF: { case OP_SELF: {
rkname(p, pc, i, name); rkname(p, lastpc, i, name);
return "method"; return "method";
} }
default: break; /* go through to return NULL */ default: break; /* go through to return NULL */
@@ -627,7 +653,7 @@ static const char *funcnamefromcode (lua_State *L, const Proto *p,
default: default:
return NULL; /* cannot find a reasonable name */ return NULL; /* cannot find a reasonable name */
} }
*name = getstr(G(L)->tmname[tm]) + 2; *name = getshrstr(G(L)->tmname[tm]) + 2;
return "metamethod"; return "metamethod";
} }
@@ -656,18 +682,19 @@ static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
/* /*
** Check whether pointer 'o' points to some value in the stack ** Check whether pointer 'o' points to some value in the stack frame of
** frame of the current function. Because 'o' may not point to a ** the current function and, if so, returns its index. Because 'o' may
** value in this stack, we cannot compare it with the region ** not point to a value in this stack, we cannot compare it with the
** boundaries (undefined behaviour in ISO C). ** region boundaries (undefined behavior in ISO C).
*/ */
static int isinstack (CallInfo *ci, const TValue *o) { static int instack (CallInfo *ci, const TValue *o) {
StkId pos; int pos;
for (pos = ci->func + 1; pos < ci->top; pos++) { StkId base = ci->func.p + 1;
if (o == s2v(pos)) for (pos = 0; base + pos < ci->top.p; pos++) {
return 1; if (o == s2v(base + pos))
return pos;
} }
return 0; /* not found */ return -1; /* not found */
} }
@@ -681,9 +708,9 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
LClosure *c = ci_func(ci); LClosure *c = ci_func(ci);
int i; int i;
for (i = 0; i < c->nupvalues; i++) { for (i = 0; i < c->nupvalues; i++) {
if (c->upvals[i]->v == o) { if (c->upvals[i]->v.p == o) {
*name = upvalname(c->p, i); *name = upvalname(c->p, i);
return "upvalue"; return strupval;
} }
} }
return NULL; return NULL;
@@ -708,9 +735,11 @@ static const char *varinfo (lua_State *L, const TValue *o) {
const char *kind = NULL; const char *kind = NULL;
if (isLua(ci)) { if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
if (!kind && isinstack(ci, o)) /* no? try a register */ if (!kind) { /* not an upvalue? */
kind = getobjname(ci_func(ci)->p, currentpc(ci), int reg = instack(ci, o); /* try a register */
cast_int(cast(StkId, o) - (ci->func + 1)), &name); if (reg >= 0) /* is 'o' a register? */
kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name);
}
} }
return formatvarinfo(L, kind, name); return formatvarinfo(L, kind, name);
} }
@@ -807,10 +836,10 @@ l_noret luaG_errormsg (lua_State *L) {
if (L->errfunc != 0) { /* is there an error handling function? */ if (L->errfunc != 0) { /* is there an error handling function? */
StkId errfunc = restorestack(L, L->errfunc); StkId errfunc = restorestack(L, L->errfunc);
lua_assert(ttisfunction(s2v(errfunc))); lua_assert(ttisfunction(s2v(errfunc)));
setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */
setobjs2s(L, L->top - 1, errfunc); /* push function */ setobjs2s(L, L->top.p - 1, errfunc); /* push function */
L->top++; /* assume EXTRA_STACK */ L->top.p++; /* assume EXTRA_STACK */
luaD_callnoyield(L, L->top - 2, 1); /* call it */ luaD_callnoyield(L, L->top.p - 2, 1); /* call it */
} }
luaD_throw(L, LUA_ERRRUN); luaD_throw(L, LUA_ERRRUN);
} }
@@ -824,8 +853,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
va_start(argp, fmt); va_start(argp, fmt);
msg = luaO_pushvfstring(L, fmt, argp); /* format message */ msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp); va_end(argp);
if (isLua(ci)) /* if Lua function, add source:line information */ if (isLua(ci)) { /* if Lua function, add source:line information */
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci)); luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
L->top.p--;
}
luaG_errormsg(L); luaG_errormsg(L);
} }
@@ -842,7 +874,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
if (p->lineinfo == NULL) /* no debug information? */ if (p->lineinfo == NULL) /* no debug information? */
return 0; return 0;
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */ if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
int delta = 0; /* line diference */ int delta = 0; /* line difference */
int pc = oldpc; int pc = oldpc;
for (;;) { for (;;) {
int lineinfo = p->lineinfo[++pc]; int lineinfo = p->lineinfo[++pc];
@@ -859,6 +891,28 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
} }
/*
** Traces Lua calls. If code is running the first instruction of a function,
** and function is not vararg, and it is not coming from an yield,
** calls 'luaD_hookcall'. (Vararg functions will call 'luaD_hookcall'
** after adjusting its variable arguments; otherwise, they could call
** a line/count hook before the call hook. Functions coming from
** an yield already called 'luaD_hookcall' before yielding.)
*/
int luaG_tracecall (lua_State *L) {
CallInfo *ci = L->ci;
Proto *p = ci_func(ci)->p;
ci->u.l.trap = 1; /* ensure hooks will be checked */
if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */
if (p->is_vararg)
return 0; /* hooks will start at VARARGPREP instruction */
else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yieded? */
luaD_hookcall(L, ci); /* check 'call' hook */
}
return 1; /* keep 'trap' on */
}
/* /*
** Traces the execution of a Lua function. Called before the execution ** Traces the execution of a Lua function. Called before the execution
** of each opcode, when debug is on. 'L->oldpc' stores the last ** of each opcode, when debug is on. 'L->oldpc' stores the last
@@ -869,7 +923,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc' ** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
** at most causes an extra call to a line hook.) ** at most causes an extra call to a line hook.)
** This function is not "Protected" when called, so it should correct ** This function is not "Protected" when called, so it should correct
** 'L->top' before calling anything that can run the GC. ** 'L->top.p' before calling anything that can run the GC.
*/ */
int luaG_traceexec (lua_State *L, const Instruction *pc) { int luaG_traceexec (lua_State *L, const Instruction *pc) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
@@ -882,17 +936,17 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
} }
pc++; /* reference is always next instruction */ pc++; /* reference is always next instruction */
ci->u.l.savedpc = pc; /* save 'pc' */ ci->u.l.savedpc = pc; /* save 'pc' */
counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); counthook = (mask & LUA_MASKCOUNT) && (--L->hookcount == 0);
if (counthook) if (counthook)
resethookcount(L); /* reset count */ resethookcount(L); /* reset count */
else if (!(mask & LUA_MASKLINE)) else if (!(mask & LUA_MASKLINE))
return 1; /* no line hook and count != 0; nothing to be done now */ return 1; /* no line hook and count != 0; nothing to be done now */
if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ if (ci->callstatus & CIST_HOOKYIELD) { /* hook yielded last time? */
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
return 1; /* do not call hook again (VM yielded, so it did not move) */ return 1; /* do not call hook again (VM yielded, so it did not move) */
} }
if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */ if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
L->top = ci->top; /* correct top */ L->top.p = ci->top.p; /* correct top */
if (counthook) if (counthook)
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */ luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
if (mask & LUA_MASKLINE) { if (mask & LUA_MASKLINE) {
@@ -909,7 +963,6 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
if (L->status == LUA_YIELD) { /* did hook yield? */ if (L->status == LUA_YIELD) { /* did hook yield? */
if (counthook) if (counthook)
L->hookcount = 1; /* undo decrement to zero */ L->hookcount = 1; /* undo decrement to zero */
ci->u.l.savedpc--; /* undo increment (resume will increment it again) */
ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
luaD_throw(L, LUA_YIELD); luaD_throw(L, LUA_YIELD);
} }
+2 -1
View File
@@ -15,7 +15,7 @@
/* Active Lua function (given call info) */ /* Active Lua function (given call info) */
#define ci_func(ci) (clLvalue(s2v((ci)->func))) #define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
#define resethookcount(L) (L->hookcount = L->basehookcount) #define resethookcount(L) (L->hookcount = L->basehookcount)
@@ -58,6 +58,7 @@ LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
TString *src, int line); TString *src, int line);
LUAI_FUNC l_noret luaG_errormsg (lua_State *L); LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc); LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
LUAI_FUNC int luaG_tracecall (lua_State *L);
#endif #endif
+146 -108
View File
@@ -94,21 +94,17 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */
break; break;
} }
case LUA_ERRERR: {
setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
break;
}
case LUA_OK: { /* special case only for closing upvalues */ case LUA_OK: { /* special case only for closing upvalues */
setnilvalue(s2v(oldtop)); /* no error message */ setnilvalue(s2v(oldtop)); /* no error message */
break; break;
} }
default: { default: {
lua_assert(errorstatus(errcode)); /* real error */ lua_assert(errorstatus(errcode)); /* real error */
setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */
break; break;
} }
} }
L->top = oldtop + 1; L->top.p = oldtop + 1;
} }
@@ -120,8 +116,9 @@ l_noret luaD_throw (lua_State *L, int errcode) {
else { /* thread has no error handler */ else { /* thread has no error handler */
global_State *g = G(L); global_State *g = G(L);
errcode = luaE_resetthread(L, errcode); /* close all upvalues */ errcode = luaE_resetthread(L, errcode); /* close all upvalues */
L->status = errcode;
if (g->mainthread->errorJmp) { /* main thread has a handler? */ if (g->mainthread->errorJmp) { /* main thread has a handler? */
setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ setobjs2s(L, g->mainthread->top.p++, L->top.p - 1); /* copy error obj. */
luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ luaD_throw(g->mainthread, errcode); /* re-throw in main thread */
} }
else { /* no handler at all; abort */ else { /* no handler at all; abort */
@@ -157,16 +154,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
** Stack reallocation ** Stack reallocation
** =================================================================== ** ===================================================================
*/ */
static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
/*
** Change all pointers to the stack into offsets.
*/
static void relstack (lua_State *L) {
CallInfo *ci; CallInfo *ci;
UpVal *up; UpVal *up;
L->top = (L->top - oldstack) + newstack; L->top.offset = savestack(L, L->top.p);
L->tbclist = (L->tbclist - oldstack) + newstack; L->tbclist.offset = savestack(L, L->tbclist.p);
for (up = L->openupval; up != NULL; up = up->u.open.next) for (up = L->openupval; up != NULL; up = up->u.open.next)
up->v = s2v((uplevel(up) - oldstack) + newstack); up->v.offset = savestack(L, uplevel(up));
for (ci = L->ci; ci != NULL; ci = ci->previous) { for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top = (ci->top - oldstack) + newstack; ci->top.offset = savestack(L, ci->top.p);
ci->func = (ci->func - oldstack) + newstack; ci->func.offset = savestack(L, ci->func.p);
}
}
/*
** Change back all offsets into pointers.
*/
static void correctstack (lua_State *L) {
CallInfo *ci;
UpVal *up;
L->top.p = restorestack(L, L->top.offset);
L->tbclist.p = restorestack(L, L->tbclist.offset);
for (up = L->openupval; up != NULL; up = up->u.open.next)
up->v.p = s2v(restorestack(L, up->v.offset));
for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top.p = restorestack(L, ci->top.offset);
ci->func.p = restorestack(L, ci->func.offset);
if (isLua(ci)) if (isLua(ci))
ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */ ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
} }
@@ -177,43 +196,54 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) #define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
/* raise an error while running the message handler */
l_noret luaD_errerr (lua_State *L) {
TString *msg = luaS_newliteral(L, "error in error handling");
setsvalue2s(L, L->top.p, msg);
L->top.p++; /* assume EXTRA_STACK */
luaD_throw(L, LUA_ERRERR);
}
/* /*
** Reallocate the stack to a new size, correcting all pointers into ** Reallocate the stack to a new size, correcting all pointers into it.
** it. (There are pointers to a stack from its upvalues, from its list ** In ISO C, any pointer use after the pointer has been deallocated is
** of call infos, plus a few individual pointers.) The reallocation is ** undefined behavior. So, before the reallocation, all pointers are
** done in two steps (allocation + free) because the correction must be ** changed to offsets, and after the reallocation they are changed back
** done while both addresses (the old stack and the new one) are valid. ** to pointers. As during the reallocation the pointers are invalid, the
** (In ISO C, any pointer use after the pointer has been deallocated is ** reallocation cannot run emergency collections.
** undefined behavior.) **
** In case of allocation error, raise an error or return false according ** In case of allocation error, raise an error or return false according
** to 'raiseerror'. ** to 'raiseerror'.
*/ */
int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
int oldsize = stacksize(L); int oldsize = stacksize(L);
int i; int i;
StkId newstack = luaM_reallocvector(L, NULL, 0, StkId newstack;
newsize + EXTRA_STACK, StackValue); int oldgcstop = G(L)->gcstopem;
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
relstack(L); /* change pointers to offsets */
G(L)->gcstopem = 1; /* stop emergency collection */
newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
newsize + EXTRA_STACK, StackValue);
G(L)->gcstopem = oldgcstop; /* restore emergency collection */
if (l_unlikely(newstack == NULL)) { /* reallocation failed? */ if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
correctstack(L); /* change offsets back to pointers */
if (raiseerror) if (raiseerror)
luaM_error(L); luaM_error(L);
else return 0; /* do not raise an error */ else return 0; /* do not raise an error */
} }
/* number of elements to be copied to the new stack */ L->stack.p = newstack;
i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK; correctstack(L); /* change offsets back to pointers */
memcpy(newstack, L->stack, i * sizeof(StackValue)); L->stack_last.p = L->stack.p + newsize;
for (; i < newsize + EXTRA_STACK; i++) for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
setnilvalue(s2v(newstack + i)); /* erase new segment */ setnilvalue(s2v(newstack + i)); /* erase new segment */
correctstack(L, L->stack, newstack);
luaM_freearray(L, L->stack, oldsize + EXTRA_STACK);
L->stack = newstack;
L->stack_last = L->stack + newsize;
return 1; return 1;
} }
/* /*
** Try to grow the stack by at least 'n' elements. when 'raiseerror' ** Try to grow the stack by at least 'n' elements. When 'raiseerror'
** is true, raises any error; otherwise, return 0 in case of errors. ** is true, raises any error; otherwise, return 0 in case of errors.
*/ */
int luaD_growstack (lua_State *L, int n, int raiseerror) { int luaD_growstack (lua_State *L, int n, int raiseerror) {
@@ -224,38 +254,41 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) {
a stack error; cannot grow further than that. */ a stack error; cannot grow further than that. */
lua_assert(stacksize(L) == ERRORSTACKSIZE); lua_assert(stacksize(L) == ERRORSTACKSIZE);
if (raiseerror) if (raiseerror)
luaD_throw(L, LUA_ERRERR); /* error inside message handler */ luaD_errerr(L); /* error inside message handler */
return 0; /* if not 'raiseerror', just signal it */ return 0; /* if not 'raiseerror', just signal it */
} }
else { else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */
int newsize = 2 * size; /* tentative new size */ int newsize = 2 * size; /* tentative new size */
int needed = cast_int(L->top - L->stack) + n; int needed = cast_int(L->top.p - L->stack.p) + n;
if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */ if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */
newsize = LUAI_MAXSTACK; newsize = LUAI_MAXSTACK;
if (newsize < needed) /* but must respect what was asked for */ if (newsize < needed) /* but must respect what was asked for */
newsize = needed; newsize = needed;
if (l_likely(newsize <= LUAI_MAXSTACK)) if (l_likely(newsize <= LUAI_MAXSTACK))
return luaD_reallocstack(L, newsize, raiseerror); return luaD_reallocstack(L, newsize, raiseerror);
else { /* stack overflow */
/* add extra size to be able to handle the error message */
luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
if (raiseerror)
luaG_runerror(L, "stack overflow");
return 0;
}
} }
/* else stack overflow */
/* add extra size to be able to handle the error message */
luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
if (raiseerror)
luaG_runerror(L, "stack overflow");
return 0;
} }
/*
** Compute how much of the stack is being used, by computing the
** maximum top of all call frames in the stack and the current top.
*/
static int stackinuse (lua_State *L) { static int stackinuse (lua_State *L) {
CallInfo *ci; CallInfo *ci;
int res; int res;
StkId lim = L->top; StkId lim = L->top.p;
for (ci = L->ci; ci != NULL; ci = ci->previous) { for (ci = L->ci; ci != NULL; ci = ci->previous) {
if (lim < ci->top) lim = ci->top; if (lim < ci->top.p) lim = ci->top.p;
} }
lua_assert(lim <= L->stack_last); lua_assert(lim <= L->stack_last.p + EXTRA_STACK);
res = cast_int(lim - L->stack) + 1; /* part of stack in use */ res = cast_int(lim - L->stack.p) + 1; /* part of stack in use */
if (res < LUA_MINSTACK) if (res < LUA_MINSTACK)
res = LUA_MINSTACK; /* ensure a minimum size */ res = LUA_MINSTACK; /* ensure a minimum size */
return res; return res;
@@ -273,17 +306,13 @@ static int stackinuse (lua_State *L) {
*/ */
void luaD_shrinkstack (lua_State *L) { void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L); int inuse = stackinuse(L);
int nsize = inuse * 2; /* proposed new size */ int max = (inuse > LUAI_MAXSTACK / 3) ? LUAI_MAXSTACK : inuse * 3;
int max = inuse * 3; /* maximum "reasonable" size */
if (max > LUAI_MAXSTACK) {
max = LUAI_MAXSTACK; /* respect stack limit */
if (nsize > LUAI_MAXSTACK)
nsize = LUAI_MAXSTACK;
}
/* if thread is currently not handling a stack overflow and its /* if thread is currently not handling a stack overflow and its
size is larger than maximum "reasonable" size, shrink it */ size is larger than maximum "reasonable" size, shrink it */
if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) {
int nsize = (inuse > LUAI_MAXSTACK / 2) ? LUAI_MAXSTACK : inuse * 2;
luaD_reallocstack(L, nsize, 0); /* ok if that fails */ luaD_reallocstack(L, nsize, 0); /* ok if that fails */
}
else /* don't change stack */ else /* don't change stack */
condmovestack(L,{},{}); /* (change only for debugging) */ condmovestack(L,{},{}); /* (change only for debugging) */
luaE_shrinkCI(L); /* shrink CI list */ luaE_shrinkCI(L); /* shrink CI list */
@@ -292,7 +321,7 @@ void luaD_shrinkstack (lua_State *L) {
void luaD_inctop (lua_State *L) { void luaD_inctop (lua_State *L) {
luaD_checkstack(L, 1); luaD_checkstack(L, 1);
L->top++; L->top.p++;
} }
/* }================================================================== */ /* }================================================================== */
@@ -309,8 +338,8 @@ void luaD_hook (lua_State *L, int event, int line,
if (hook && L->allowhook) { /* make sure there is a hook */ if (hook && L->allowhook) { /* make sure there is a hook */
int mask = CIST_HOOKED; int mask = CIST_HOOKED;
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top); /* preserve original 'top' */ ptrdiff_t top = savestack(L, L->top.p); /* preserve original 'top' */
ptrdiff_t ci_top = savestack(L, ci->top); /* idem for 'ci->top' */ ptrdiff_t ci_top = savestack(L, ci->top.p); /* idem for 'ci->top' */
lua_Debug ar; lua_Debug ar;
ar.event = event; ar.event = event;
ar.currentline = line; ar.currentline = line;
@@ -320,11 +349,11 @@ void luaD_hook (lua_State *L, int event, int line,
ci->u2.transferinfo.ftransfer = ftransfer; ci->u2.transferinfo.ftransfer = ftransfer;
ci->u2.transferinfo.ntransfer = ntransfer; ci->u2.transferinfo.ntransfer = ntransfer;
} }
if (isLua(ci) && L->top < ci->top) if (isLua(ci) && L->top.p < ci->top.p)
L->top = ci->top; /* protect entire activation register */ L->top.p = ci->top.p; /* protect entire activation register */
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
if (ci->top < L->top + LUA_MINSTACK) if (ci->top.p < L->top.p + LUA_MINSTACK)
ci->top = L->top + LUA_MINSTACK; ci->top.p = L->top.p + LUA_MINSTACK;
L->allowhook = 0; /* cannot call hooks inside a hook */ L->allowhook = 0; /* cannot call hooks inside a hook */
ci->callstatus |= mask; ci->callstatus |= mask;
lua_unlock(L); lua_unlock(L);
@@ -332,8 +361,8 @@ void luaD_hook (lua_State *L, int event, int line,
lua_lock(L); lua_lock(L);
lua_assert(!L->allowhook); lua_assert(!L->allowhook);
L->allowhook = 1; L->allowhook = 1;
ci->top = restorestack(L, ci_top); ci->top.p = restorestack(L, ci_top);
L->top = restorestack(L, top); L->top.p = restorestack(L, top);
ci->callstatus &= ~mask; ci->callstatus &= ~mask;
} }
} }
@@ -364,7 +393,7 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) {
*/ */
static void rethook (lua_State *L, CallInfo *ci, int nres) { static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (L->hookmask & LUA_MASKRET) { /* is return hook on? */ if (L->hookmask & LUA_MASKRET) { /* is return hook on? */
StkId firstres = L->top - nres; /* index of first result */ StkId firstres = L->top.p - nres; /* index of first result */
int delta = 0; /* correction for vararg functions */ int delta = 0; /* correction for vararg functions */
int ftransfer; int ftransfer;
if (isLua(ci)) { if (isLua(ci)) {
@@ -372,10 +401,10 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (p->is_vararg) if (p->is_vararg)
delta = ci->u.l.nextraargs + p->numparams + 1; delta = ci->u.l.nextraargs + p->numparams + 1;
} }
ci->func += delta; /* if vararg, back to virtual 'func' */ ci->func.p += delta; /* if vararg, back to virtual 'func' */
ftransfer = cast(unsigned short, firstres - ci->func); ftransfer = cast(unsigned short, firstres - ci->func.p);
luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */ luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */
ci->func -= delta; ci->func.p -= delta;
} }
if (isLua(ci = ci->previous)) if (isLua(ci = ci->previous))
L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */ L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */
@@ -387,16 +416,16 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
** stack, below original 'func', so that 'luaD_precall' can call it. Raise ** stack, below original 'func', so that 'luaD_precall' can call it. Raise
** an error if there is no '__call' metafield. ** an error if there is no '__call' metafield.
*/ */
StkId luaD_tryfuncTM (lua_State *L, StkId func) { static StkId tryfuncTM (lua_State *L, StkId func) {
const TValue *tm; const TValue *tm;
StkId p; StkId p;
checkstackGCp(L, 1, func); /* space for metamethod */ checkstackGCp(L, 1, func); /* space for metamethod */
tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */ tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */
if (l_unlikely(ttisnil(tm))) if (l_unlikely(ttisnil(tm)))
luaG_callerror(L, s2v(func)); /* nothing to call */ luaG_callerror(L, s2v(func)); /* nothing to call */
for (p = L->top; p > func; p--) /* open space for metamethod */ for (p = L->top.p; p > func; p--) /* open space for metamethod */
setobjs2s(L, p, p-1); setobjs2s(L, p, p-1);
L->top++; /* stack space pre-allocated by the caller */ L->top.p++; /* stack space pre-allocated by the caller */
setobj2s(L, func, tm); /* metamethod is the new function to be called */ setobj2s(L, func, tm); /* metamethod is the new function to be called */
return func; return func;
} }
@@ -413,28 +442,29 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
int i; int i;
switch (wanted) { /* handle typical cases separately */ switch (wanted) { /* handle typical cases separately */
case 0: /* no values needed */ case 0: /* no values needed */
L->top = res; L->top.p = res;
return; return;
case 1: /* one value needed */ case 1: /* one value needed */
if (nres == 0) /* no results? */ if (nres == 0) /* no results? */
setnilvalue(s2v(res)); /* adjust with nil */ setnilvalue(s2v(res)); /* adjust with nil */
else /* at least one result */ else /* at least one result */
setobjs2s(L, res, L->top - nres); /* move it to proper place */ setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
L->top = res + 1; L->top.p = res + 1;
return; return;
case LUA_MULTRET: case LUA_MULTRET:
wanted = nres; /* we want all results */ wanted = nres; /* we want all results */
break; break;
default: /* two/more results and/or to-be-closed variables */ default: /* two/more results and/or to-be-closed variables */
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
ptrdiff_t savedres = savestack(L, res);
L->ci->callstatus |= CIST_CLSRET; /* in case of yields */ L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
L->ci->u2.nres = nres; L->ci->u2.nres = nres;
luaF_close(L, res, CLOSEKTOP, 1); res = luaF_close(L, res, CLOSEKTOP, 1);
L->ci->callstatus &= ~CIST_CLSRET; L->ci->callstatus &= ~CIST_CLSRET;
if (L->hookmask) /* if needed, call hook after '__close's */ if (L->hookmask) { /* if needed, call hook after '__close's */
ptrdiff_t savedres = savestack(L, res);
rethook(L, L->ci, nres); rethook(L, L->ci, nres);
res = restorestack(L, savedres); /* close and hook can move stack */ res = restorestack(L, savedres); /* hook can move stack */
}
wanted = decodeNresults(wanted); wanted = decodeNresults(wanted);
if (wanted == LUA_MULTRET) if (wanted == LUA_MULTRET)
wanted = nres; /* we want all results */ wanted = nres; /* we want all results */
@@ -442,14 +472,14 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
break; break;
} }
/* generic case */ /* generic case */
firstresult = L->top - nres; /* index of first result */ firstresult = L->top.p - nres; /* index of first result */
if (nres > wanted) /* extra results? */ if (nres > wanted) /* extra results? */
nres = wanted; /* don't need them */ nres = wanted; /* don't need them */
for (i = 0; i < nres; i++) /* move all results to correct place */ for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstresult + i); setobjs2s(L, res + i, firstresult + i);
for (; i < wanted; i++) /* complete wanted number of results */ for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(s2v(res + i)); setnilvalue(s2v(res + i));
L->top = res + wanted; /* top points after the last result */ L->top.p = res + wanted; /* top points after the last result */
} }
@@ -464,7 +494,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted))) if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
rethook(L, ci, nres); rethook(L, ci, nres);
/* move results to proper place */ /* move results to proper place */
moveresults(L, ci->func, nres, wanted); moveresults(L, ci->func.p, nres, wanted);
/* function cannot be in any of these cases when returning */ /* function cannot be in any of these cases when returning */
lua_assert(!(ci->callstatus & lua_assert(!(ci->callstatus &
(CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET))); (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
@@ -479,10 +509,10 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret, l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,
int mask, StkId top) { int mask, StkId top) {
CallInfo *ci = L->ci = next_ci(L); /* new frame */ CallInfo *ci = L->ci = next_ci(L); /* new frame */
ci->func = func; ci->func.p = func;
ci->nresults = nret; ci->nresults = nret;
ci->callstatus = mask; ci->callstatus = mask;
ci->top = top; ci->top.p = top;
return ci; return ci;
} }
@@ -496,10 +526,10 @@ l_sinline int precallC (lua_State *L, StkId func, int nresults,
CallInfo *ci; CallInfo *ci;
checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
L->ci = ci = prepCallInfo(L, func, nresults, CIST_C, L->ci = ci = prepCallInfo(L, func, nresults, CIST_C,
L->top + LUA_MINSTACK); L->top.p + LUA_MINSTACK);
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top.p <= L->stack_last.p);
if (l_unlikely(L->hookmask & LUA_MASKCALL)) { if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
int narg = cast_int(L->top - func) - 1; int narg = cast_int(L->top.p - func) - 1;
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg); luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
} }
lua_unlock(L); lua_unlock(L);
@@ -531,21 +561,21 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int nfixparams = p->numparams; int nfixparams = p->numparams;
int i; int i;
checkstackGCp(L, fsize - delta, func); checkstackGCp(L, fsize - delta, func);
ci->func -= delta; /* restore 'func' (if vararg) */ ci->func.p -= delta; /* restore 'func' (if vararg) */
for (i = 0; i < narg1; i++) /* move down function and arguments */ for (i = 0; i < narg1; i++) /* move down function and arguments */
setobjs2s(L, ci->func + i, func + i); setobjs2s(L, ci->func.p + i, func + i);
func = ci->func; /* moved-down function */ func = ci->func.p; /* moved-down function */
for (; narg1 <= nfixparams; narg1++) for (; narg1 <= nfixparams; narg1++)
setnilvalue(s2v(func + narg1)); /* complete missing arguments */ setnilvalue(s2v(func + narg1)); /* complete missing arguments */
ci->top = func + 1 + fsize; /* top for new function */ ci->top.p = func + 1 + fsize; /* top for new function */
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top.p <= L->stack_last.p);
ci->u.l.savedpc = p->code; /* starting point */ ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus |= CIST_TAIL; ci->callstatus |= CIST_TAIL;
L->top = func + narg1; /* set top */ L->top.p = func + narg1; /* set top */
return -1; return -1;
} }
default: { /* not a function */ default: { /* not a function */
func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ func = tryfuncTM(L, func); /* try to get '__call' metamethod */
/* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */ /* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */
narg1++; narg1++;
goto retry; /* try again */ goto retry; /* try again */
@@ -574,19 +604,19 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
case LUA_VLCL: { /* Lua function */ case LUA_VLCL: { /* Lua function */
CallInfo *ci; CallInfo *ci;
Proto *p = clLvalue(s2v(func))->p; Proto *p = clLvalue(s2v(func))->p;
int narg = cast_int(L->top - func) - 1; /* number of real arguments */ int narg = cast_int(L->top.p - func) - 1; /* number of real arguments */
int nfixparams = p->numparams; int nfixparams = p->numparams;
int fsize = p->maxstacksize; /* frame size */ int fsize = p->maxstacksize; /* frame size */
checkstackGCp(L, fsize, func); checkstackGCp(L, fsize, func);
L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize); L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize);
ci->u.l.savedpc = p->code; /* starting point */ ci->u.l.savedpc = p->code; /* starting point */
for (; narg < nfixparams; narg++) for (; narg < nfixparams; narg++)
setnilvalue(s2v(L->top++)); /* complete missing arguments */ setnilvalue(s2v(L->top.p++)); /* complete missing arguments */
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top.p <= L->stack_last.p);
return ci; return ci;
} }
default: { /* not a function */ default: { /* not a function */
func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ func = tryfuncTM(L, func); /* try to get '__call' metamethod */
/* return luaD_precall(L, func, nresults); */ /* return luaD_precall(L, func, nresults); */
goto retry; /* try again with metamethod */ goto retry; /* try again with metamethod */
} }
@@ -598,12 +628,17 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
** Call a function (C or Lua) through C. 'inc' can be 1 (increment ** Call a function (C or Lua) through C. 'inc' can be 1 (increment
** number of recursive invocations in the C stack) or nyci (the same ** number of recursive invocations in the C stack) or nyci (the same
** plus increment number of non-yieldable calls). ** plus increment number of non-yieldable calls).
** This function can be called with some use of EXTRA_STACK, so it should
** check the stack before doing anything else. 'luaD_precall' already
** does that.
*/ */
l_sinline void ccall (lua_State *L, StkId func, int nResults, int inc) { l_sinline void ccall (lua_State *L, StkId func, int nResults, l_uint32 inc) {
CallInfo *ci; CallInfo *ci;
L->nCcalls += inc; L->nCcalls += inc;
if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) {
checkstackp(L, 0, func); /* free any use of EXTRA_STACK */
luaE_checkcstack(L); luaE_checkcstack(L);
}
if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */ if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */
ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */
luaV_execute(L, ci); /* call it */ luaV_execute(L, ci); /* call it */
@@ -651,8 +686,7 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
else { /* error */ else { /* error */
StkId func = restorestack(L, ci->u2.funcidx); StkId func = restorestack(L, ci->u2.funcidx);
L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */ L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */
luaF_close(L, func, status, 1); /* can yield or raise an error */ func = luaF_close(L, func, status, 1); /* can yield or raise an error */
func = restorestack(L, ci->u2.funcidx); /* stack may be moved */
luaD_seterrorobj(L, status, func); luaD_seterrorobj(L, status, func);
luaD_shrinkstack(L); /* restore stack size in case of overflow */ luaD_shrinkstack(L); /* restore stack size in case of overflow */
setcistrecst(ci, LUA_OK); /* clear original status */ setcistrecst(ci, LUA_OK); /* clear original status */
@@ -740,8 +774,8 @@ static CallInfo *findpcall (lua_State *L) {
** coroutine error handler and should not kill the coroutine.) ** coroutine error handler and should not kill the coroutine.)
*/ */
static int resume_error (lua_State *L, const char *msg, int narg) { static int resume_error (lua_State *L, const char *msg, int narg) {
L->top -= narg; /* remove args from the stack */ L->top.p -= narg; /* remove args from the stack */
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ setsvalue2s(L, L->top.p, luaS_new(L, msg)); /* push error message */
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return LUA_ERRRUN; return LUA_ERRRUN;
@@ -757,7 +791,7 @@ static int resume_error (lua_State *L, const char *msg, int narg) {
*/ */
static void resume (lua_State *L, void *ud) { static void resume (lua_State *L, void *ud) {
int n = *(cast(int*, ud)); /* number of arguments */ int n = *(cast(int*, ud)); /* number of arguments */
StkId firstArg = L->top - n; /* first argument */ StkId firstArg = L->top.p - n; /* first argument */
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (L->status == LUA_OK) /* starting a coroutine? */ if (L->status == LUA_OK) /* starting a coroutine? */
ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */ ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */
@@ -765,7 +799,11 @@ static void resume (lua_State *L, void *ud) {
lua_assert(L->status == LUA_YIELD); lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */ L->status = LUA_OK; /* mark that it is running (again) */
if (isLua(ci)) { /* yielded inside a hook? */ if (isLua(ci)) { /* yielded inside a hook? */
L->top = firstArg; /* discard arguments */ /* undo increment made by 'luaG_traceexec': instruction was not
executed yet */
lua_assert(ci->callstatus & CIST_HOOKYIELD);
ci->u.l.savedpc--;
L->top.p = firstArg; /* discard arguments */
luaV_execute(L, ci); /* just continue running Lua code */ luaV_execute(L, ci); /* just continue running Lua code */
} }
else { /* 'common' yield */ else { /* 'common' yield */
@@ -808,7 +846,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
if (L->status == LUA_OK) { /* may be starting a coroutine */ if (L->status == LUA_OK) { /* may be starting a coroutine */
if (L->ci != &L->base_ci) /* not in base level? */ if (L->ci != &L->base_ci) /* not in base level? */
return resume_error(L, "cannot resume non-suspended coroutine", nargs); return resume_error(L, "cannot resume non-suspended coroutine", nargs);
else if (L->top - (L->ci->func + 1) == nargs) /* no function? */ else if (L->top.p - (L->ci->func.p + 1) == nargs) /* no function? */
return resume_error(L, "cannot resume dead coroutine", nargs); return resume_error(L, "cannot resume dead coroutine", nargs);
} }
else if (L->status != LUA_YIELD) /* ended with errors? */ else if (L->status != LUA_YIELD) /* ended with errors? */
@@ -826,11 +864,11 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
lua_assert(status == L->status); /* normal end or yield */ lua_assert(status == L->status); /* normal end or yield */
else { /* unrecoverable error */ else { /* unrecoverable error */
L->status = cast_byte(status); /* mark thread as 'dead' */ L->status = cast_byte(status); /* mark thread as 'dead' */
luaD_seterrorobj(L, status, L->top); /* push error message */ luaD_seterrorobj(L, status, L->top.p); /* push error message */
L->ci->top = L->top; L->ci->top.p = L->top.p;
} }
*nresults = (status == LUA_YIELD) ? L->ci->u2.nyield *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield
: cast_int(L->top - (L->ci->func + 1)); : cast_int(L->top.p - (L->ci->func.p + 1));
lua_unlock(L); lua_unlock(L);
return status; return status;
} }
@@ -985,7 +1023,7 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
p.dyd.gt.arr = NULL; p.dyd.gt.size = 0; p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
p.dyd.label.arr = NULL; p.dyd.label.size = 0; p.dyd.label.arr = NULL; p.dyd.label.size = 0;
luaZ_initbuffer(L, &p.buff); luaZ_initbuffer(L, &p.buff);
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); status = luaD_pcall(L, f_parser, &p, savestack(L, L->top.p), L->errfunc);
luaZ_freebuffer(L, &p.buff); luaZ_freebuffer(L, &p.buff);
luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);
+14 -5
View File
@@ -8,6 +8,7 @@
#define ldo_h #define ldo_h
#include "llimits.h"
#include "lobject.h" #include "lobject.h"
#include "lstate.h" #include "lstate.h"
#include "lzio.h" #include "lzio.h"
@@ -23,7 +24,7 @@
** at every check. ** at every check.
*/ */
#define luaD_checkstackaux(L,n,pre,pos) \ #define luaD_checkstackaux(L,n,pre,pos) \
if (l_unlikely(L->stack_last - L->top <= (n))) \ if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \
{ pre; luaD_growstack(L, n, 1); pos; } \ { pre; luaD_growstack(L, n, 1); pos; } \
else { condmovestack(L,pre,pos); } else { condmovestack(L,pre,pos); }
@@ -32,11 +33,18 @@
#define savestack(L,p) ((char *)(p) - (char *)L->stack) #define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p))
#define restorestack(L,n) ((StkId)((char *)L->stack + (n))) #define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n))
/* macro to check stack size, preserving 'p' */ /* macro to check stack size, preserving 'p' */
#define checkstackp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
/* macro to check stack size and GC, preserving 'p' */
#define checkstackGCp(L,n,p) \ #define checkstackGCp(L,n,p) \
luaD_checkstackaux(L, n, \ luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
@@ -52,17 +60,18 @@
/* type of protected functions, to be ran by 'runprotected' */ /* type of protected functions, to be ran by 'runprotected' */
typedef void (*Pfunc) (lua_State *L, void *ud); typedef void (*Pfunc) (lua_State *L, void *ud);
LUAI_FUNC l_noret luaD_errerr (lua_State *L);
LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop);
LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
const char *mode); const char *mode);
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
int fTransfer, int nTransfer); int fTransfer, int nTransfer);
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1, int delta); LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int narg1, int delta);
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func);
LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status); LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status);
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t oldtop, ptrdiff_t ef); ptrdiff_t oldtop, ptrdiff_t ef);
+6 -2
View File
@@ -10,6 +10,7 @@
#include "lprefix.h" #include "lprefix.h"
#include <limits.h>
#include <stddef.h> #include <stddef.h>
#include "lua.h" #include "lua.h"
@@ -55,8 +56,11 @@ static void dumpByte (DumpState *D, int y) {
} }
/* dumpInt Buff Size */ /*
#define DIBS ((sizeof(size_t) * 8 / 7) + 1) ** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6"
** rounds up the division.)
*/
#define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7)
static void dumpSize (DumpState *D, size_t x) { static void dumpSize (DumpState *D, size_t x) {
lu_byte buff[DIBS]; lu_byte buff[DIBS];
+27 -27
View File
@@ -50,8 +50,8 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
for (i = 0; i < cl->nupvalues; i++) { for (i = 0; i < cl->nupvalues; i++) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal)); GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o); UpVal *uv = gco2upv(o);
uv->v = &uv->u.value; /* make it closed */ uv->v.p = &uv->u.value; /* make it closed */
setnilvalue(uv->v); setnilvalue(uv->v.p);
cl->upvals[i] = uv; cl->upvals[i] = uv;
luaC_objbarrier(L, cl, uv); luaC_objbarrier(L, cl, uv);
} }
@@ -62,12 +62,11 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
** Create a new upvalue at the given level, and link it to the list of ** Create a new upvalue at the given level, and link it to the list of
** open upvalues of 'L' after entry 'prev'. ** open upvalues of 'L' after entry 'prev'.
**/ **/
static UpVal *newupval (lua_State *L, int tbc, StkId level, UpVal **prev) { static UpVal *newupval (lua_State *L, StkId level, UpVal **prev) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal)); GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o); UpVal *uv = gco2upv(o);
UpVal *next = *prev; UpVal *next = *prev;
uv->v = s2v(level); /* current value lives in the stack */ uv->v.p = s2v(level); /* current value lives in the stack */
uv->tbc = tbc;
uv->u.open.next = next; /* link it to list of open upvalues */ uv->u.open.next = next; /* link it to list of open upvalues */
uv->u.open.previous = prev; uv->u.open.previous = prev;
if (next) if (next)
@@ -96,7 +95,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
pp = &p->u.open.next; pp = &p->u.open.next;
} }
/* not found: create a new upvalue after 'pp' */ /* not found: create a new upvalue after 'pp' */
return newupval(L, 0, level, pp); return newupval(L, level, pp);
} }
@@ -106,12 +105,12 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
** (This function assumes EXTRA_STACK.) ** (This function assumes EXTRA_STACK.)
*/ */
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) { static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
StkId top = L->top; StkId top = L->top.p;
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
setobj2s(L, top, tm); /* will call metamethod... */ setobj2s(L, top, tm); /* will call metamethod... */
setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */ setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */ setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
L->top = top + 3; /* add function and arguments */ L->top.p = top + 3; /* add function and arguments */
if (yy) if (yy)
luaD_call(L, top, 0); luaD_call(L, top, 0);
else else
@@ -126,7 +125,7 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
static void checkclosemth (lua_State *L, StkId level) { static void checkclosemth (lua_State *L, StkId level) {
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE); const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
if (ttisnil(tm)) { /* no metamethod? */ if (ttisnil(tm)) { /* no metamethod? */
int idx = cast_int(level - L->ci->func); /* variable index */ int idx = cast_int(level - L->ci->func.p); /* variable index */
const char *vname = luaG_findlocal(L, L->ci, idx, NULL); const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
if (vname == NULL) vname = "?"; if (vname == NULL) vname = "?";
luaG_runerror(L, "variable '%s' got a non-closable value", vname); luaG_runerror(L, "variable '%s' got a non-closable value", vname);
@@ -160,23 +159,23 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
** is used.) ** is used.)
*/ */
#define MAXDELTA \ #define MAXDELTA \
((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1) ((256ul << ((sizeof(L->stack.p->tbclist.delta) - 1) * 8)) - 1)
/* /*
** Insert a variable in the list of to-be-closed variables. ** Insert a variable in the list of to-be-closed variables.
*/ */
void luaF_newtbcupval (lua_State *L, StkId level) { void luaF_newtbcupval (lua_State *L, StkId level) {
lua_assert(level > L->tbclist); lua_assert(level > L->tbclist.p);
if (l_isfalse(s2v(level))) if (l_isfalse(s2v(level)))
return; /* false doesn't need to be closed */ return; /* false doesn't need to be closed */
checkclosemth(L, level); /* value must have a close method */ checkclosemth(L, level); /* value must have a close method */
while (cast_uint(level - L->tbclist) > MAXDELTA) { while (cast_uint(level - L->tbclist.p) > MAXDELTA) {
L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */ L->tbclist.p += MAXDELTA; /* create a dummy node at maximum delta */
L->tbclist->tbclist.delta = 0; L->tbclist.p->tbclist.delta = 0;
} }
level->tbclist.delta = cast(unsigned short, level - L->tbclist); level->tbclist.delta = cast(unsigned short, level - L->tbclist.p);
L->tbclist = level; L->tbclist.p = level;
} }
@@ -196,10 +195,10 @@ void luaF_closeupval (lua_State *L, StkId level) {
StkId upl; /* stack index pointed by 'uv' */ StkId upl; /* stack index pointed by 'uv' */
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
TValue *slot = &uv->u.value; /* new position for value */ TValue *slot = &uv->u.value; /* new position for value */
lua_assert(uplevel(uv) < L->top); lua_assert(uplevel(uv) < L->top.p);
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */ luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
setobj(L, slot, uv->v); /* move value to upvalue slot */ setobj(L, slot, uv->v.p); /* move value to upvalue slot */
uv->v = slot; /* now current value lives here */ uv->v.p = slot; /* now current value lives here */
if (!iswhite(uv)) { /* neither white nor dead? */ if (!iswhite(uv)) { /* neither white nor dead? */
nw2black(uv); /* closed upvalues cannot be gray */ nw2black(uv); /* closed upvalues cannot be gray */
luaC_barrier(L, uv, slot); luaC_barrier(L, uv, slot);
@@ -209,31 +208,32 @@ void luaF_closeupval (lua_State *L, StkId level) {
/* /*
** Remove firt element from the tbclist plus its dummy nodes. ** Remove first element from the tbclist plus its dummy nodes.
*/ */
static void poptbclist (lua_State *L) { static void poptbclist (lua_State *L) {
StkId tbc = L->tbclist; StkId tbc = L->tbclist.p;
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */ lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
tbc -= tbc->tbclist.delta; tbc -= tbc->tbclist.delta;
while (tbc > L->stack && tbc->tbclist.delta == 0) while (tbc > L->stack.p && tbc->tbclist.delta == 0)
tbc -= MAXDELTA; /* remove dummy nodes */ tbc -= MAXDELTA; /* remove dummy nodes */
L->tbclist = tbc; L->tbclist.p = tbc;
} }
/* /*
** Close all upvalues and to-be-closed variables up to the given stack ** Close all upvalues and to-be-closed variables up to the given stack
** level. ** level. Return restored 'level'.
*/ */
void luaF_close (lua_State *L, StkId level, int status, int yy) { StkId luaF_close (lua_State *L, StkId level, int status, int yy) {
ptrdiff_t levelrel = savestack(L, level); ptrdiff_t levelrel = savestack(L, level);
luaF_closeupval(L, level); /* first, close the upvalues */ luaF_closeupval(L, level); /* first, close the upvalues */
while (L->tbclist >= level) { /* traverse tbc's down to that level */ while (L->tbclist.p >= level) { /* traverse tbc's down to that level */
StkId tbc = L->tbclist; /* get variable index */ StkId tbc = L->tbclist.p; /* get variable index */
poptbclist(L); /* remove it from list */ poptbclist(L); /* remove it from list */
prepcallclosemth(L, tbc, status, yy); /* close variable */ prepcallclosemth(L, tbc, status, yy); /* close variable */
level = restorestack(L, levelrel); level = restorestack(L, levelrel);
} }
return level;
} }
+3 -3
View File
@@ -29,10 +29,10 @@
#define MAXUPVAL 255 #define MAXUPVAL 255
#define upisopen(up) ((up)->v != &(up)->u.value) #define upisopen(up) ((up)->v.p != &(up)->u.value)
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v)) #define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p))
/* /*
@@ -54,7 +54,7 @@ LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level); LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy); LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy);
LUAI_FUNC void luaF_unlinkupval (UpVal *uv); LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
+74 -58
View File
@@ -252,12 +252,13 @@ void luaC_fix (lua_State *L, GCObject *o) {
/* /*
** create a new collectable object (with given type and size) and link ** create a new collectable object (with given type, size, and offset)
** it to 'allgc' list. ** and link it to 'allgc' list.
*/ */
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
global_State *g = G(L); global_State *g = G(L);
GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz)); char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
GCObject *o = cast(GCObject *, p + offset);
o->marked = luaC_white(g); o->marked = luaC_white(g);
o->tt = tt; o->tt = tt;
o->next = g->allgc; o->next = g->allgc;
@@ -265,6 +266,11 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return o; return o;
} }
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return luaC_newobjdt(L, tt, sz, 0);
}
/* }====================================================== */ /* }====================================================== */
@@ -301,7 +307,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
set2gray(uv); /* open upvalues are kept gray */ set2gray(uv); /* open upvalues are kept gray */
else else
set2black(uv); /* closed upvalues are visited here */ set2black(uv); /* closed upvalues are visited here */
markvalue(g, uv->v); /* mark its content */ markvalue(g, uv->v.p); /* mark its content */
break; break;
} }
case LUA_VUSERDATA: { case LUA_VUSERDATA: {
@@ -376,7 +382,7 @@ static int remarkupvals (global_State *g) {
work++; work++;
if (!iswhite(uv)) { /* upvalue already visited? */ if (!iswhite(uv)) { /* upvalue already visited? */
lua_assert(upisopen(uv) && isgray(uv)); lua_assert(upisopen(uv) && isgray(uv));
markvalue(g, uv->v); /* mark its value */ markvalue(g, uv->v.p); /* mark its value */
} }
} }
} }
@@ -536,17 +542,23 @@ static void traversestrongtable (global_State *g, Table *h) {
static lu_mem traversetable (global_State *g, Table *h) { static lu_mem traversetable (global_State *g, Table *h) {
const char *weakkey, *weakvalue; const char *weakkey, *weakvalue;
const TValue *mode = gfasttm(g, h->metatable, TM_MODE); const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
TString *smode;
markobjectN(g, h->metatable); markobjectN(g, h->metatable);
if (mode && ttisstring(mode) && /* is there a weak mode? */ if (mode && ttisshrstring(mode) && /* is there a weak mode? */
(cast_void(weakkey = strchr(svalue(mode), 'k')), (cast_void(smode = tsvalue(mode)),
cast_void(weakvalue = strchr(svalue(mode), 'v')), cast_void(weakkey = strchr(getshrstr(smode), 'k')),
cast_void(weakvalue = strchr(getshrstr(smode), 'v')),
(weakkey || weakvalue))) { /* is really weak? */ (weakkey || weakvalue))) { /* is really weak? */
if (!weakkey) /* strong keys? */ if (!weakkey) /* strong keys? */
traverseweakvalue(g, h); traverseweakvalue(g, h);
else if (!weakvalue) /* strong values? */ else if (!weakvalue) /* strong values? */
traverseephemeron(g, h, 0); traverseephemeron(g, h, 0);
else /* all weak */ else { /* all weak */
linkgclist(h, g->allweak); /* nothing to traverse now */ if (g->gcstate == GCSpropagate)
linkgclist(h, g->grayagain); /* must visit again its metatable */
else
linkgclist(h, g->allweak); /* must clear collected entries */
}
} }
else /* not weak */ else /* not weak */
traversestrongtable(g, h); traversestrongtable(g, h);
@@ -620,19 +632,21 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
*/ */
static int traversethread (global_State *g, lua_State *th) { static int traversethread (global_State *g, lua_State *th) {
UpVal *uv; UpVal *uv;
StkId o = th->stack; StkId o = th->stack.p;
if (isold(th) || g->gcstate == GCSpropagate) if (isold(th) || g->gcstate == GCSpropagate)
linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
if (o == NULL) if (o == NULL)
return 1; /* stack not completely built yet */ return 1; /* stack not completely built yet */
lua_assert(g->gcstate == GCSatomic || lua_assert(g->gcstate == GCSatomic ||
th->openupval == NULL || isintwups(th)); th->openupval == NULL || isintwups(th));
for (; o < th->top; o++) /* mark live elements in the stack */ for (; o < th->top.p; o++) /* mark live elements in the stack */
markvalue(g, s2v(o)); markvalue(g, s2v(o));
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next) for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
markobject(g, uv); /* open upvalues cannot be collected */ markobject(g, uv); /* open upvalues cannot be collected */
if (g->gcstate == GCSatomic) { /* final traversal? */ if (g->gcstate == GCSatomic) { /* final traversal? */
for (; o < th->stack_last + EXTRA_STACK; o++) if (!g->gcemergency)
luaD_shrinkstack(th); /* do not change stack in emergency cycle */
for (o = th->top.p; o < th->stack_last.p + EXTRA_STACK; o++)
setnilvalue(s2v(o)); /* clear dead stack slice */ setnilvalue(s2v(o)); /* clear dead stack slice */
/* 'remarkupvals' may have removed thread from 'twups' list */ /* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) { if (!isintwups(th) && th->openupval != NULL) {
@@ -640,8 +654,6 @@ static int traversethread (global_State *g, lua_State *th) {
g->twups = th; g->twups = th;
} }
} }
else if (!g->gcemergency)
luaD_shrinkstack(th); /* do not change stack in emergency cycle */
return 1 + stacksize(th); return 1 + stacksize(th);
} }
@@ -892,7 +904,7 @@ static GCObject *udata2finalize (global_State *g) {
static void dothecall (lua_State *L, void *ud) { static void dothecall (lua_State *L, void *ud) {
UNUSED(ud); UNUSED(ud);
luaD_callnoyield(L, L->top - 2, 0); luaD_callnoyield(L, L->top.p - 2, 0);
} }
@@ -909,16 +921,16 @@ static void GCTM (lua_State *L) {
int oldgcstp = g->gcstp; int oldgcstp = g->gcstp;
g->gcstp |= GCSTPGC; /* avoid GC steps */ g->gcstp |= GCSTPGC; /* avoid GC steps */
L->allowhook = 0; /* stop debug hooks during GC metamethod */ L->allowhook = 0; /* stop debug hooks during GC metamethod */
setobj2s(L, L->top++, tm); /* push finalizer... */ setobj2s(L, L->top.p++, tm); /* push finalizer... */
setobj2s(L, L->top++, &v); /* ... and its argument */ setobj2s(L, L->top.p++, &v); /* ... and its argument */
L->ci->callstatus |= CIST_FIN; /* will run a finalizer */ L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0);
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */ L->allowhook = oldah; /* restore hooks */
g->gcstp = oldgcstp; /* restore state */ g->gcstp = oldgcstp; /* restore state */
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */ if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
luaE_warnerror(L, "__gc"); luaE_warnerror(L, "__gc");
L->top--; /* pops error object */ L->top.p--; /* pops error object */
} }
} }
} }
@@ -1041,7 +1053,25 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
** ======================================================= ** =======================================================
*/ */
static void setpause (global_State *g);
/*
** Set the "time" to wait before starting a new GC cycle; cycle will
** start when memory use hits the threshold of ('estimate' * pause /
** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
** because Lua cannot even start with less than PAUSEADJ bytes).
*/
static void setpause (global_State *g) {
l_mem threshold, debt;
int pause = getgcparam(g->gcpause);
l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
lua_assert(estimate > 0);
threshold = (pause < MAX_LMEM / estimate) /* overflow? */
? estimate * pause /* no overflow */
: MAX_LMEM; /* overflow; truncate to maximum */
debt = gettotalbytes(g) - threshold;
if (debt > 0) debt = 0;
luaE_setdebt(g, debt);
}
/* /*
@@ -1285,6 +1315,15 @@ static void atomic2gen (lua_State *L, global_State *g) {
} }
/*
** Set debt for the next minor collection, which will happen when
** memory grows 'genminormul'%.
*/
static void setminordebt (global_State *g) {
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
}
/* /*
** Enter generational mode. Must go until the end of an atomic cycle ** Enter generational mode. Must go until the end of an atomic cycle
** to ensure that all objects are correctly marked and weak tables ** to ensure that all objects are correctly marked and weak tables
@@ -1297,6 +1336,7 @@ static lu_mem entergen (lua_State *L, global_State *g) {
luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
numobjs = atomic(L); /* propagates all and then do the atomic stuff */ numobjs = atomic(L); /* propagates all and then do the atomic stuff */
atomic2gen(L, g); atomic2gen(L, g);
setminordebt(g); /* set debt assuming next cycle will be minor */
return numobjs; return numobjs;
} }
@@ -1342,15 +1382,6 @@ static lu_mem fullgen (lua_State *L, global_State *g) {
} }
/*
** Set debt for the next minor collection, which will happen when
** memory grows 'genminormul'%.
*/
static void setminordebt (global_State *g) {
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
}
/* /*
** Does a major collection after last collection was a "bad collection". ** Does a major collection after last collection was a "bad collection".
** **
@@ -1384,7 +1415,7 @@ static void stepgenfull (lua_State *L, global_State *g) {
setminordebt(g); setminordebt(g);
} }
else { /* another bad collection; stay in incremental mode */ else { /* another bad collection; stay in incremental mode */
g->GCestimate = gettotalbytes(g); /* first estimate */; g->GCestimate = gettotalbytes(g); /* first estimate */
entersweep(L); entersweep(L);
luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */
setpause(g); setpause(g);
@@ -1422,8 +1453,8 @@ static void genstep (lua_State *L, global_State *g) {
lu_mem numobjs = fullgen(L, g); /* do a major collection */ lu_mem numobjs = fullgen(L, g); /* do a major collection */
if (gettotalbytes(g) < majorbase + (majorinc / 2)) { if (gettotalbytes(g) < majorbase + (majorinc / 2)) {
/* collected at least half of memory growth since last major /* collected at least half of memory growth since last major
collection; keep doing minor collections */ collection; keep doing minor collections. */
setminordebt(g); lua_assert(g->lastatomic == 0);
} }
else { /* bad collection */ else { /* bad collection */
g->lastatomic = numobjs; /* signal that last collection was bad */ g->lastatomic = numobjs; /* signal that last collection was bad */
@@ -1449,26 +1480,6 @@ static void genstep (lua_State *L, global_State *g) {
*/ */
/*
** Set the "time" to wait before starting a new GC cycle; cycle will
** start when memory use hits the threshold of ('estimate' * pause /
** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
** because Lua cannot even start with less than PAUSEADJ bytes).
*/
static void setpause (global_State *g) {
l_mem threshold, debt;
int pause = getgcparam(g->gcpause);
l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
lua_assert(estimate > 0);
threshold = (pause < MAX_LMEM / estimate) /* overflow? */
? estimate * pause /* no overflow */
: MAX_LMEM; /* overflow; truncate to maximum */
debt = gettotalbytes(g) - threshold;
if (debt > 0) debt = 0;
luaE_setdebt(g, debt);
}
/* /*
** Enter first sweep phase. ** Enter first sweep phase.
** The call to 'sweeptolive' makes the pointer point to an object ** The call to 'sweeptolive' makes the pointer point to an object
@@ -1599,7 +1610,7 @@ static lu_mem singlestep (lua_State *L) {
case GCSenteratomic: { case GCSenteratomic: {
work = atomic(L); /* work is what was traversed by 'atomic' */ work = atomic(L); /* work is what was traversed by 'atomic' */
entersweep(L); entersweep(L);
g->GCestimate = gettotalbytes(g); /* first estimate */; g->GCestimate = gettotalbytes(g); /* first estimate */
break; break;
} }
case GCSswpallgc: { /* sweep "regular" objects */ case GCSswpallgc: { /* sweep "regular" objects */
@@ -1676,12 +1687,15 @@ static void incstep (lua_State *L, global_State *g) {
} }
/* /*
** performs a basic GC step if collector is running ** Performs a basic GC step if collector is running. (If collector is
** not running, set a reasonable debt to avoid it being called at
** every single check.)
*/ */
void luaC_step (lua_State *L) { void luaC_step (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
lua_assert(!g->gcemergency); if (!gcrunning(g)) /* not running? */
if (gcrunning(g)) { /* running? */ luaE_setdebt(g, -2000);
else {
if(isdecGCmodegen(g)) if(isdecGCmodegen(g))
genstep(L, g); genstep(L, g);
else else
@@ -1702,6 +1716,8 @@ static void fullinc (lua_State *L, global_State *g) {
entersweep(L); /* sweep everything to turn them back to white */ entersweep(L); /* sweep everything to turn them back to white */
/* finish any pending sweep phase to start a new cycle */ /* finish any pending sweep phase to start a new cycle */
luaC_runtilstate(L, bitmask(GCSpause)); luaC_runtilstate(L, bitmask(GCSpause));
luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
g->gcstate = GCSenteratomic; /* go straight to atomic phase */
luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */
/* estimate must be correct after a full GC cycle */ /* estimate must be correct after a full GC cycle */
lua_assert(g->GCestimate == gettotalbytes(g)); lua_assert(g->GCestimate == gettotalbytes(g));
+11 -8
View File
@@ -172,24 +172,27 @@
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0) #define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
#define luaC_barrier(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
#define luaC_barrierback(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrierback_(L,p) : cast_void(0))
#define luaC_objbarrier(L,p,o) ( \ #define luaC_objbarrier(L,p,o) ( \
(isblack(p) && iswhite(o)) ? \ (isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
#define luaC_barrier(L,p,v) ( \
iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0))
#define luaC_objbarrierback(L,p,o) ( \
(isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0))
#define luaC_barrierback(L,p,v) ( \
iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0))
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L); LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L);
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz,
size_t offset);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
+20 -7
View File
@@ -245,8 +245,8 @@ static int f_gc (lua_State *L) {
*/ */
static int io_fclose (lua_State *L) { static int io_fclose (lua_State *L) {
LStream *p = tolstream(L); LStream *p = tolstream(L);
int res = fclose(p->f); errno = 0;
return luaL_fileresult(L, (res == 0), NULL); return luaL_fileresult(L, (fclose(p->f) == 0), NULL);
} }
@@ -272,6 +272,7 @@ static int io_open (lua_State *L) {
LStream *p = newfile(L); LStream *p = newfile(L);
const char *md = mode; /* to traverse/check mode */ const char *md = mode; /* to traverse/check mode */
luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); luaL_argcheck(L, l_checkmode(md), 2, "invalid mode");
errno = 0;
p->f = fopen(filename, mode); p->f = fopen(filename, mode);
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
} }
@@ -292,6 +293,7 @@ static int io_popen (lua_State *L) {
const char *mode = luaL_optstring(L, 2, "r"); const char *mode = luaL_optstring(L, 2, "r");
LStream *p = newprefile(L); LStream *p = newprefile(L);
luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode"); luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode");
errno = 0;
p->f = l_popen(L, filename, mode); p->f = l_popen(L, filename, mode);
p->closef = &io_pclose; p->closef = &io_pclose;
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
@@ -300,6 +302,7 @@ static int io_popen (lua_State *L) {
static int io_tmpfile (lua_State *L) { static int io_tmpfile (lua_State *L) {
LStream *p = newfile(L); LStream *p = newfile(L);
errno = 0;
p->f = tmpfile(); p->f = tmpfile();
return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
} }
@@ -567,6 +570,7 @@ static int g_read (lua_State *L, FILE *f, int first) {
int nargs = lua_gettop(L) - 1; int nargs = lua_gettop(L) - 1;
int n, success; int n, success;
clearerr(f); clearerr(f);
errno = 0;
if (nargs == 0) { /* no arguments? */ if (nargs == 0) { /* no arguments? */
success = read_line(L, f, 1); success = read_line(L, f, 1);
n = first + 1; /* to return 1 result */ n = first + 1; /* to return 1 result */
@@ -660,6 +664,7 @@ static int io_readline (lua_State *L) {
static int g_write (lua_State *L, FILE *f, int arg) { static int g_write (lua_State *L, FILE *f, int arg) {
int nargs = lua_gettop(L) - arg; int nargs = lua_gettop(L) - arg;
int status = 1; int status = 1;
errno = 0;
for (; nargs--; arg++) { for (; nargs--; arg++) {
if (lua_type(L, arg) == LUA_TNUMBER) { if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */ /* optimization: could be done exactly as for strings */
@@ -678,7 +683,8 @@ static int g_write (lua_State *L, FILE *f, int arg) {
} }
if (l_likely(status)) if (l_likely(status))
return 1; /* file handle already on stack top */ return 1; /* file handle already on stack top */
else return luaL_fileresult(L, status, NULL); else
return luaL_fileresult(L, status, NULL);
} }
@@ -703,6 +709,7 @@ static int f_seek (lua_State *L) {
l_seeknum offset = (l_seeknum)p3; l_seeknum offset = (l_seeknum)p3;
luaL_argcheck(L, (lua_Integer)offset == p3, 3, luaL_argcheck(L, (lua_Integer)offset == p3, 3,
"not an integer in proper range"); "not an integer in proper range");
errno = 0;
op = l_fseek(f, offset, mode[op]); op = l_fseek(f, offset, mode[op]);
if (l_unlikely(op)) if (l_unlikely(op))
return luaL_fileresult(L, 0, NULL); /* error */ return luaL_fileresult(L, 0, NULL); /* error */
@@ -719,19 +726,25 @@ static int f_setvbuf (lua_State *L) {
FILE *f = tofile(L); FILE *f = tofile(L);
int op = luaL_checkoption(L, 2, NULL, modenames); int op = luaL_checkoption(L, 2, NULL, modenames);
lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
int res = setvbuf(f, NULL, mode[op], (size_t)sz); int res;
errno = 0;
res = setvbuf(f, NULL, mode[op], (size_t)sz);
return luaL_fileresult(L, res == 0, NULL); return luaL_fileresult(L, res == 0, NULL);
} }
static int io_flush (lua_State *L) { static int io_flush (lua_State *L) {
return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); FILE *f = getiofile(L, IO_OUTPUT);
errno = 0;
return luaL_fileresult(L, fflush(f) == 0, NULL);
} }
static int f_flush (lua_State *L) { static int f_flush (lua_State *L) {
return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); FILE *f = tofile(L);
errno = 0;
return luaL_fileresult(L, fflush(f) == 0, NULL);
} }
@@ -773,7 +786,7 @@ static const luaL_Reg meth[] = {
** metamethods for file handles ** metamethods for file handles
*/ */
static const luaL_Reg metameth[] = { static const luaL_Reg metameth[] = {
{"__index", NULL}, /* place holder */ {"__index", NULL}, /* placeholder */
{"__gc", f_gc}, {"__gc", f_gc},
{"__close", f_gc}, {"__close", f_gc},
{"__tostring", f_tostring}, {"__tostring", f_tostring},
+3 -3
View File
@@ -128,7 +128,7 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
** ensuring there is only one copy of each unique string. The table ** ensuring there is only one copy of each unique string. The table
** here is used as a set: the string enters as the key, while its value ** here is used as a set: the string enters as the key, while its value
** is irrelevant. We use the string itself as the value only because it ** is irrelevant. We use the string itself as the value only because it
** is a TValue readly available. Later, the code generation can change ** is a TValue readily available. Later, the code generation can change
** this value. ** this value.
*/ */
TString *luaX_newstring (LexState *ls, const char *str, size_t l) { TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
@@ -138,12 +138,12 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
if (!ttisnil(o)) /* string already present? */ if (!ttisnil(o)) /* string already present? */
ts = keystrval(nodefromval(o)); /* get saved copy */ ts = keystrval(nodefromval(o)); /* get saved copy */
else { /* not in use yet */ else { /* not in use yet */
TValue *stv = s2v(L->top++); /* reserve stack space for string */ TValue *stv = s2v(L->top.p++); /* reserve stack space for string */
setsvalue(L, stv, ts); /* temporarily anchor the string */ setsvalue(L, stv, ts); /* temporarily anchor the string */
luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */ luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */
/* table is not a metatable, so it does not need to invalidate cache */ /* table is not a metatable, so it does not need to invalidate cache */
luaC_checkGC(L); luaC_checkGC(L);
L->top--; /* remove string from stack */ L->top.p--; /* remove string from stack */
} }
return ts; return ts;
} }
+17 -4
View File
@@ -71,11 +71,24 @@ typedef signed char ls_byte;
/* /*
** conversion of pointer to unsigned integer: ** conversion of pointer to unsigned integer: this is for hashing only;
** this is for hashing only; there is no problem if the integer ** there is no problem if the integer cannot hold the whole pointer
** cannot hold the whole pointer value ** value. (In strict ISO C this may cause undefined behavior, but no
** actual machine seems to bother.)
*/ */
#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX)) #if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
__STDC_VERSION__ >= 199901L
#include <stdint.h>
#if defined(UINTPTR_MAX) /* even in C99 this type is optional */
#define L_P2I uintptr_t
#else /* no 'intptr'? */
#define L_P2I uintmax_t /* use the largest available integer */
#endif
#else /* C89 option */
#define L_P2I size_t
#endif
#define point2uint(p) ((unsigned int)((L_P2I)(p) & UINT_MAX))
+29 -12
View File
@@ -249,6 +249,15 @@ static int math_type (lua_State *L) {
** =================================================================== ** ===================================================================
*/ */
/*
** This code uses lots of shifts. ANSI C does not allow shifts greater
** than or equal to the width of the type being shifted, so some shifts
** are written in convoluted ways to match that restriction. For
** preprocessor tests, it assumes a width of 32 bits, so the maximum
** shift there is 31 bits.
*/
/* number of binary digits in the mantissa of a float */ /* number of binary digits in the mantissa of a float */
#define FIGS l_floatatt(MANT_DIG) #define FIGS l_floatatt(MANT_DIG)
@@ -267,20 +276,23 @@ static int math_type (lua_State *L) {
/* try to find an integer type with at least 64 bits */ /* try to find an integer type with at least 64 bits */
#if (ULONG_MAX >> 31 >> 31) >= 3 #if ((ULONG_MAX >> 31) >> 31) >= 3
/* 'long' has at least 64 bits */ /* 'long' has at least 64 bits */
#define Rand64 unsigned long #define Rand64 unsigned long
#define SRand64 long
#elif !defined(LUA_USE_C89) && defined(LLONG_MAX) #elif !defined(LUA_USE_C89) && defined(LLONG_MAX)
/* there is a 'long long' type (which must have at least 64 bits) */ /* there is a 'long long' type (which must have at least 64 bits) */
#define Rand64 unsigned long long #define Rand64 unsigned long long
#define SRand64 long long
#elif (LUA_MAXUNSIGNED >> 31 >> 31) >= 3 #elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
/* 'lua_Integer' has at least 64 bits */ /* 'lua_Unsigned' has at least 64 bits */
#define Rand64 lua_Unsigned #define Rand64 lua_Unsigned
#define SRand64 lua_Integer
#endif #endif
@@ -319,23 +331,30 @@ static Rand64 nextrand (Rand64 *state) {
} }
/* must take care to not shift stuff by more than 63 slots */
/* /*
** Convert bits from a random integer into a float in the ** Convert bits from a random integer into a float in the
** interval [0,1), getting the higher FIG bits from the ** interval [0,1), getting the higher FIG bits from the
** random unsigned integer and converting that to a float. ** random unsigned integer and converting that to a float.
** Some old Microsoft compilers cannot cast an unsigned long
** to a floating-point number, so we use a signed long as an
** intermediary. When lua_Number is float or double, the shift ensures
** that 'sx' is non negative; in that case, a good compiler will remove
** the correction.
*/ */
/* must throw out the extra (64 - FIGS) bits */ /* must throw out the extra (64 - FIGS) bits */
#define shift64_FIG (64 - FIGS) #define shift64_FIG (64 - FIGS)
/* to scale to [0, 1), multiply by scaleFIG = 2^(-FIGS) */ /* 2^(-FIGS) == 2^-1 / 2^(FIGS-1) */
#define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1))) #define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1)))
static lua_Number I2d (Rand64 x) { static lua_Number I2d (Rand64 x) {
return (lua_Number)(trim64(x) >> shift64_FIG) * scaleFIG; SRand64 sx = (SRand64)(trim64(x) >> shift64_FIG);
lua_Number res = (lua_Number)(sx) * scaleFIG;
if (sx < 0)
res += l_mathop(1.0); /* correct the two's complement if negative */
lua_assert(0 <= res && res < 1);
return res;
} }
/* convert a 'Rand64' to a 'lua_Unsigned' */ /* convert a 'Rand64' to a 'lua_Unsigned' */
@@ -471,8 +490,6 @@ static lua_Number I2d (Rand64 x) {
#else /* 32 < FIGS <= 64 */ #else /* 32 < FIGS <= 64 */
/* must take care to not shift stuff by more than 31 slots */
/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */ /* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
#define scaleFIG \ #define scaleFIG \
(l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33))) (l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33)))
@@ -500,12 +517,12 @@ static lua_Number I2d (Rand64 x) {
/* convert a 'Rand64' to a 'lua_Unsigned' */ /* convert a 'Rand64' to a 'lua_Unsigned' */
static lua_Unsigned I2UInt (Rand64 x) { static lua_Unsigned I2UInt (Rand64 x) {
return ((lua_Unsigned)trim32(x.h) << 31 << 1) | (lua_Unsigned)trim32(x.l); return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l);
} }
/* convert a 'lua_Unsigned' to a 'Rand64' */ /* convert a 'lua_Unsigned' to a 'Rand64' */
static Rand64 Int2I (lua_Unsigned n) { static Rand64 Int2I (lua_Unsigned n) {
return packI((lu_int32)(n >> 31 >> 1), (lu_int32)n); return packI((lu_int32)((n >> 31) >> 1), (lu_int32)n);
} }
#endif /* } */ #endif /* } */
+41 -27
View File
@@ -22,25 +22,6 @@
#include "lstate.h" #include "lstate.h"
#if defined(EMERGENCYGCTESTS)
/*
** First allocation will fail whenever not building initial state.
** (This fail will trigger 'tryagain' and a full GC cycle at every
** allocation.)
*/
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
if (completestate(g) && ns > 0) /* frees never fail */
return NULL; /* fail */
else /* normal allocation */
return (*g->frealloc)(g->ud, block, os, ns);
}
#else
#define firsttry(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
#endif
/* /*
** About the realloc function: ** About the realloc function:
@@ -60,6 +41,43 @@ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
*/ */
/*
** Macro to call the allocation function.
*/
#define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
/*
** When an allocation fails, it will try again after an emergency
** collection, except when it cannot run a collection. The GC should
** not be called while the state is not fully built, as the collector
** is not yet fully initialized. Also, it should not be called when
** 'gcstopem' is true, because then the interpreter is in the middle of
** a collection step.
*/
#define cantryagain(g) (completestate(g) && !g->gcstopem)
#if defined(EMERGENCYGCTESTS)
/*
** First allocation will fail except when freeing a block (frees never
** fail) and when it cannot try again; this fail will trigger 'tryagain'
** and a full GC cycle at every allocation.
*/
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
if (ns > 0 && cantryagain(g))
return NULL; /* fail */
else /* normal allocation */
return callfrealloc(g, block, os, ns);
}
#else
#define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns)
#endif
/* /*
@@ -132,7 +150,7 @@ l_noret luaM_toobig (lua_State *L) {
void luaM_free_ (lua_State *L, void *block, size_t osize) { void luaM_free_ (lua_State *L, void *block, size_t osize) {
global_State *g = G(L); global_State *g = G(L);
lua_assert((osize == 0) == (block == NULL)); lua_assert((osize == 0) == (block == NULL));
(*g->frealloc)(g->ud, block, osize, 0); callfrealloc(g, block, osize, 0);
g->GCdebt -= osize; g->GCdebt -= osize;
} }
@@ -140,19 +158,15 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
/* /*
** In case of allocation fail, this function will do an emergency ** In case of allocation fail, this function will do an emergency
** collection to free some memory and then try the allocation again. ** collection to free some memory and then try the allocation again.
** The GC should not be called while state is not fully built, as the
** collector is not yet fully initialized. Also, it should not be called
** when 'gcstopem' is true, because then the interpreter is in the
** middle of a collection step.
*/ */
static void *tryagain (lua_State *L, void *block, static void *tryagain (lua_State *L, void *block,
size_t osize, size_t nsize) { size_t osize, size_t nsize) {
global_State *g = G(L); global_State *g = G(L);
if (completestate(g) && !g->gcstopem) { if (cantryagain(g)) {
luaC_fullgc(L, 1); /* try to free some memory... */ luaC_fullgc(L, 1); /* try to free some memory... */
return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ return callfrealloc(g, block, osize, nsize); /* try again */
} }
else return NULL; /* cannot free any memory without a full state */ else return NULL; /* cannot run an emergency collection */
} }
+7 -11
View File
@@ -24,15 +24,6 @@
#include "lualib.h" #include "lualib.h"
/*
** LUA_IGMARK is a mark to ignore all before it when building the
** luaopen_ function name.
*/
#if !defined (LUA_IGMARK)
#define LUA_IGMARK "-"
#endif
/* /*
** LUA_CSUBSEP is the character that replaces dots in submodule names ** LUA_CSUBSEP is the character that replaces dots in submodule names
** when searching for a C loader. ** when searching for a C loader.
@@ -708,8 +699,13 @@ static const luaL_Reg ll_funcs[] = {
static void createsearcherstable (lua_State *L) { static void createsearcherstable (lua_State *L) {
static const lua_CFunction searchers[] = static const lua_CFunction searchers[] = {
{searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; searcher_preload,
searcher_Lua,
searcher_C,
searcher_Croot,
NULL
};
int i; int i;
/* create 'searchers' table */ /* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
+24 -14
View File
@@ -62,7 +62,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
case LUA_OPBOR: return intop(|, v1, v2); case LUA_OPBOR: return intop(|, v1, v2);
case LUA_OPBXOR: return intop(^, v1, v2); case LUA_OPBXOR: return intop(^, v1, v2);
case LUA_OPSHL: return luaV_shiftl(v1, v2); case LUA_OPSHL: return luaV_shiftl(v1, v2);
case LUA_OPSHR: return luaV_shiftl(v1, -v2); case LUA_OPSHR: return luaV_shiftr(v1, v2);
case LUA_OPUNM: return intop(-, 0, v1); case LUA_OPUNM: return intop(-, 0, v1);
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
default: lua_assert(0); return 0; default: lua_assert(0); return 0;
@@ -386,29 +386,39 @@ void luaO_tostring (lua_State *L, TValue *obj) {
** =================================================================== ** ===================================================================
*/ */
/* size for buffer space used by 'luaO_pushvfstring' */ /*
#define BUFVFS 200 ** Size for buffer space used by 'luaO_pushvfstring'. It should be
** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages,
** so that 'luaG_addinfo' can work directly on the buffer.
*/
#define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95)
/* buffer used by 'luaO_pushvfstring' */ /* buffer used by 'luaO_pushvfstring' */
typedef struct BuffFS { typedef struct BuffFS {
lua_State *L; lua_State *L;
int pushed; /* number of string pieces already on the stack */ int pushed; /* true if there is a part of the result on the stack */
int blen; /* length of partial string in 'space' */ int blen; /* length of partial string in 'space' */
char space[BUFVFS]; /* holds last part of the result */ char space[BUFVFS]; /* holds last part of the result */
} BuffFS; } BuffFS;
/* /*
** Push given string to the stack, as part of the buffer, and ** Push given string to the stack, as part of the result, and
** join the partial strings in the stack into one. ** join it to previous partial result if there is one.
** It may call 'luaV_concat' while using one slot from EXTRA_STACK.
** This call cannot invoke metamethods, as both operands must be
** strings. It can, however, raise an error if the result is too
** long. In that case, 'luaV_concat' frees the extra slot before
** raising the error.
*/ */
static void pushstr (BuffFS *buff, const char *str, size_t l) { static void pushstr (BuffFS *buff, const char *str, size_t lstr) {
lua_State *L = buff->L; lua_State *L = buff->L;
setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); setsvalue2s(L, L->top.p, luaS_newlstr(L, str, lstr));
L->top++; /* may use one extra slot */ L->top.p++; /* may use one slot from EXTRA_STACK */
buff->pushed++; if (!buff->pushed) /* no previous string on the stack? */
luaV_concat(L, buff->pushed); /* join partial results into one */ buff->pushed = 1; /* now there is one */
buff->pushed = 1; else /* join previous string with new one */
luaV_concat(L, 2);
} }
@@ -454,7 +464,7 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
/* /*
** Add a number to the buffer. ** Add a numeral to the buffer.
*/ */
static void addnum2buff (BuffFS *buff, TValue *num) { static void addnum2buff (BuffFS *buff, TValue *num) {
char *numbuff = getbuff(buff, MAXNUMBER2STR); char *numbuff = getbuff(buff, MAXNUMBER2STR);
@@ -532,7 +542,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */ addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
clearbuff(&buff); /* empty buffer into the stack */ clearbuff(&buff); /* empty buffer into the stack */
lua_assert(buff.pushed == 1); lua_assert(buff.pushed == 1);
return svalue(s2v(L->top - 1)); return getstr(tsvalue(s2v(L->top.p - 1)));
} }
+25 -12
View File
@@ -52,6 +52,8 @@ typedef union Value {
lua_CFunction f; /* light C functions */ lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */ lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */ lua_Number n; /* float numbers */
/* not used, but may avoid warnings for uninitialized value */
lu_byte ub;
} Value; } Value;
@@ -155,6 +157,17 @@ typedef union StackValue {
/* index to stack elements */ /* index to stack elements */
typedef StackValue *StkId; typedef StackValue *StkId;
/*
** When reallocating the stack, change all pointers to the stack into
** proper offsets.
*/
typedef union {
StkId p; /* actual pointer */
ptrdiff_t offset; /* used while the stack is being reallocated */
} StkIdRel;
/* convert a 'StackValue' to a 'TValue' */ /* convert a 'StackValue' to a 'TValue' */
#define s2v(o) (&(o)->val) #define s2v(o) (&(o)->val)
@@ -373,7 +386,7 @@ typedef struct GCObject {
typedef struct TString { typedef struct TString {
CommonHeader; CommonHeader;
lu_byte extra; /* reserved words for short strings; "has hash" for longs */ lu_byte extra; /* reserved words for short strings; "has hash" for longs */
lu_byte shrlen; /* length for short strings */ lu_byte shrlen; /* length for short strings, 0xFF for long strings */
unsigned int hash; unsigned int hash;
union { union {
size_t lnglen; /* length for long strings */ size_t lnglen; /* length for long strings */
@@ -385,19 +398,17 @@ typedef struct TString {
/* /*
** Get the actual string (array of bytes) from a 'TString'. ** Get the actual string (array of bytes) from a 'TString'. (Generic
** version and specialized versions for long and short strings.)
*/ */
#define getstr(ts) ((ts)->contents) #define getstr(ts) ((ts)->contents)
#define getlngstr(ts) check_exp((ts)->shrlen == 0xFF, (ts)->contents)
#define getshrstr(ts) check_exp((ts)->shrlen != 0xFF, (ts)->contents)
/* get the actual string (array of bytes) from a Lua value */
#define svalue(o) getstr(tsvalue(o))
/* get string length from 'TString *s' */ /* get string length from 'TString *s' */
#define tsslen(s) ((s)->tt == LUA_VSHRSTR ? (s)->shrlen : (s)->u.lnglen) #define tsslen(s) \
((s)->shrlen != 0xFF ? (s)->shrlen : (s)->u.lnglen)
/* get string length from 'TValue *o' */
#define vslen(o) tsslen(tsvalue(o))
/* }================================================================== */ /* }================================================================== */
@@ -615,8 +626,10 @@ typedef struct Proto {
*/ */
typedef struct UpVal { typedef struct UpVal {
CommonHeader; CommonHeader;
lu_byte tbc; /* true if it represents a to-be-closed variable */ union {
TValue *v; /* points to stack or to its own value */ TValue *p; /* points to stack or to its own value */
ptrdiff_t offset; /* used while the stack is being reallocated */
} v;
union { union {
struct { /* (when open) */ struct { /* (when open) */
struct UpVal *next; /* linked list */ struct UpVal *next; /* linked list */
+5 -5
View File
@@ -21,7 +21,7 @@ iABC C(8) | B(8) |k| A(8) | Op(7) |
iABx Bx(17) | A(8) | Op(7) | iABx Bx(17) | A(8) | Op(7) |
iAsBx sBx (signed)(17) | A(8) | Op(7) | iAsBx sBx (signed)(17) | A(8) | Op(7) |
iAx Ax(25) | Op(7) | iAx Ax(25) | Op(7) |
isJ sJ(25) | Op(7) | isJ sJ (signed)(25) | Op(7) |
A signed argument is represented in excess K: the represented value is A signed argument is represented in excess K: the represented value is
the written unsigned value minus K, where K is half the maximum for the the written unsigned value minus K, where K is half the maximum for the
@@ -210,15 +210,15 @@ OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */
OP_GETUPVAL,/* A B R[A] := UpValue[B] */ OP_GETUPVAL,/* A B R[A] := UpValue[B] */
OP_SETUPVAL,/* A B UpValue[B] := R[A] */ OP_SETUPVAL,/* A B UpValue[B] := R[A] */
OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:string] */ OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:shortstring] */
OP_GETTABLE,/* A B C R[A] := R[B][R[C]] */ OP_GETTABLE,/* A B C R[A] := R[B][R[C]] */
OP_GETI,/* A B C R[A] := R[B][C] */ OP_GETI,/* A B C R[A] := R[B][C] */
OP_GETFIELD,/* A B C R[A] := R[B][K[C]:string] */ OP_GETFIELD,/* A B C R[A] := R[B][K[C]:shortstring] */
OP_SETTABUP,/* A B C UpValue[A][K[B]:string] := RK(C) */ OP_SETTABUP,/* A B C UpValue[A][K[B]:shortstring] := RK(C) */
OP_SETTABLE,/* A B C R[A][R[B]] := RK(C) */ OP_SETTABLE,/* A B C R[A][R[B]] := RK(C) */
OP_SETI,/* A B C R[A][B] := RK(C) */ OP_SETI,/* A B C R[A][B] := RK(C) */
OP_SETFIELD,/* A B C R[A][K[B]:string] := RK(C) */ OP_SETFIELD,/* A B C R[A][K[B]:shortstring] := RK(C) */
OP_NEWTABLE,/* A B C k R[A] := {} */ OP_NEWTABLE,/* A B C k R[A] := {} */
+19 -19
View File
@@ -30,23 +30,14 @@
*/ */
#if !defined(LUA_STRFTIMEOPTIONS) /* { */ #if !defined(LUA_STRFTIMEOPTIONS) /* { */
/* options for ANSI C 89 (only 1-char options) */
#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
/* options for ISO C 99 and POSIX */
#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
/* options for Windows */
#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
#if defined(LUA_USE_WINDOWS) #if defined(LUA_USE_WINDOWS)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN #define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
#elif defined(LUA_USE_C89) "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89 #elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
#else /* C99 specification */ #else /* C99 specification */
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99 #define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
#endif #endif
#endif /* } */ #endif /* } */
@@ -138,12 +129,21 @@
/* }================================================================== */ /* }================================================================== */
#if !defined(l_system)
#if defined(LUA_USE_IOS)
/* Despite claiming to be ISO C, iOS does not implement 'system'. */
#define l_system(cmd) ((cmd) == NULL ? 0 : -1)
#else
#define l_system(cmd) system(cmd) /* default definition */
#endif
#endif
static int os_execute (lua_State *L) { static int os_execute (lua_State *L) {
const char *cmd = luaL_optstring(L, 1, NULL); const char *cmd = luaL_optstring(L, 1, NULL);
int stat; int stat;
errno = 0; errno = 0;
stat = system(cmd); stat = l_system(cmd);
if (cmd != NULL) if (cmd != NULL)
return luaL_execresult(L, stat); return luaL_execresult(L, stat);
else { else {
@@ -155,6 +155,7 @@ static int os_execute (lua_State *L) {
static int os_remove (lua_State *L) { static int os_remove (lua_State *L) {
const char *filename = luaL_checkstring(L, 1); const char *filename = luaL_checkstring(L, 1);
errno = 0;
return luaL_fileresult(L, remove(filename) == 0, filename); return luaL_fileresult(L, remove(filename) == 0, filename);
} }
@@ -162,6 +163,7 @@ static int os_remove (lua_State *L) {
static int os_rename (lua_State *L) { static int os_rename (lua_State *L) {
const char *fromname = luaL_checkstring(L, 1); const char *fromname = luaL_checkstring(L, 1);
const char *toname = luaL_checkstring(L, 2); const char *toname = luaL_checkstring(L, 2);
errno = 0;
return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);
} }
@@ -260,9 +262,7 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
res = d; res = d;
} }
else { else {
/* unsigned avoids overflow when lua_Integer has 32 bits */ if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res))
if (!(res >= 0 ? (lua_Unsigned)res <= (lua_Unsigned)INT_MAX + delta
: (lua_Integer)INT_MIN + delta <= res))
return luaL_error(L, "field '%s' is out-of-bound", key); return luaL_error(L, "field '%s' is out-of-bound", key);
res -= delta; res -= delta;
} }
+27 -25
View File
@@ -198,7 +198,7 @@ static int new_localvar (LexState *ls, TString *name) {
checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
MAXVARS, "local variables"); MAXVARS, "local variables");
luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1, luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1,
dyd->actvar.size, Vardesc, USHRT_MAX, "local variables"); dyd->actvar.size, Vardesc, SHRT_MAX, "local variables");
var = &dyd->actvar.arr[dyd->actvar.n++]; var = &dyd->actvar.arr[dyd->actvar.n++];
var->vd.kind = VDKREG; /* default */ var->vd.kind = VDKREG; /* default */
var->vd.name = name; var->vd.name = name;
@@ -468,6 +468,7 @@ static void singlevar (LexState *ls, expdesc *var) {
expdesc key; expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k != VVOID); /* this one must exist */ lua_assert(var->k != VVOID); /* this one must exist */
luaK_exp2anyregup(fs, var); /* but could be a constant */
codestring(&key, varname); /* key is variable name */ codestring(&key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */ luaK_indexed(fs, var, &key); /* env[varname] */
} }
@@ -520,12 +521,12 @@ static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
/* /*
** Solves the goto at index 'g' to given 'label' and removes it ** Solves the goto at index 'g' to given 'label' and removes it
** from the list of pending goto's. ** from the list of pending gotos.
** If it jumps into the scope of some variable, raises an error. ** If it jumps into the scope of some variable, raises an error.
*/ */
static void solvegoto (LexState *ls, int g, Labeldesc *label) { static void solvegoto (LexState *ls, int g, Labeldesc *label) {
int i; int i;
Labellist *gl = &ls->dyd->gt; /* list of goto's */ Labellist *gl = &ls->dyd->gt; /* list of gotos */
Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */ Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */
lua_assert(eqstr(gt->name, label->name)); lua_assert(eqstr(gt->name, label->name));
if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */ if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */
@@ -579,7 +580,7 @@ static int newgotoentry (LexState *ls, TString *name, int line, int pc) {
/* /*
** Solves forward jumps. Check whether new label 'lb' matches any ** Solves forward jumps. Check whether new label 'lb' matches any
** pending gotos in current block and solves them. Return true ** pending gotos in current block and solves them. Return true
** if any of the goto's need to close upvalues. ** if any of the gotos need to close upvalues.
*/ */
static int solvegotos (LexState *ls, Labeldesc *lb) { static int solvegotos (LexState *ls, Labeldesc *lb) {
Labellist *gl = &ls->dyd->gt; Labellist *gl = &ls->dyd->gt;
@@ -600,7 +601,7 @@ static int solvegotos (LexState *ls, Labeldesc *lb) {
/* /*
** Create a new label with the given 'name' at the given 'line'. ** Create a new label with the given 'name' at the given 'line'.
** 'last' tells whether label is the last non-op statement in its ** 'last' tells whether label is the last non-op statement in its
** block. Solves all pending goto's to this new label and adds ** block. Solves all pending gotos to this new label and adds
** a close instruction if necessary. ** a close instruction if necessary.
** Returns true iff it added a close instruction. ** Returns true iff it added a close instruction.
*/ */
@@ -673,19 +674,19 @@ static void leaveblock (FuncState *fs) {
LexState *ls = fs->ls; LexState *ls = fs->ls;
int hasclose = 0; int hasclose = 0;
int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */ int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */
if (bl->isloop) /* fix pending breaks? */ removevars(fs, bl->nactvar); /* remove block locals */
lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */
if (bl->isloop) /* has to fix pending breaks? */
hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0); hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
if (!hasclose && bl->previous && bl->upval) if (!hasclose && bl->previous && bl->upval) /* still need a 'close'? */
luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0); luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0);
fs->bl = bl->previous;
removevars(fs, bl->nactvar);
lua_assert(bl->nactvar == fs->nactvar);
fs->freereg = stklevel; /* free registers */ fs->freereg = stklevel; /* free registers */
ls->dyd->label.n = bl->firstlabel; /* remove local labels */ ls->dyd->label.n = bl->firstlabel; /* remove local labels */
if (bl->previous) /* inner block? */ fs->bl = bl->previous; /* current block now is previous one */
movegotosout(fs, bl); /* update pending gotos to outer block */ if (bl->previous) /* was it a nested block? */
movegotosout(fs, bl); /* update pending gotos to enclosing block */
else { else {
if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ if (bl->firstgoto < ls->dyd->gt.n) /* still pending gotos? */
undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
} }
} }
@@ -848,12 +849,11 @@ static void recfield (LexState *ls, ConsControl *cc) {
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
int reg = ls->fs->freereg; int reg = ls->fs->freereg;
expdesc tab, key, val; expdesc tab, key, val;
if (ls->t.token == TK_NAME) { if (ls->t.token == TK_NAME)
checklimit(fs, cc->nh, MAX_INT, "items in a constructor");
codename(ls, &key); codename(ls, &key);
}
else /* ls->t.token == '[' */ else /* ls->t.token == '[' */
yindex(ls, &key); yindex(ls, &key);
checklimit(fs, cc->nh, MAX_INT, "items in a constructor");
cc->nh++; cc->nh++;
checknext(ls, '='); checknext(ls, '=');
tab = *cc->t; tab = *cc->t;
@@ -940,6 +940,8 @@ static void constructor (LexState *ls, expdesc *t) {
if (ls->t.token == '}') break; if (ls->t.token == '}') break;
closelistfield(fs, &cc); closelistfield(fs, &cc);
field(ls, &cc); field(ls, &cc);
checklimit(fs, cc.tostore + cc.na + cc.nh, INT_MAX/2,
"items in a constructor");
} while (testnext(ls, ',') || testnext(ls, ';')); } while (testnext(ls, ',') || testnext(ls, ';'));
check_match(ls, '}', '{', line); check_match(ls, '}', '{', line);
lastlistfield(fs, &cc); lastlistfield(fs, &cc);
@@ -1021,10 +1023,11 @@ static int explist (LexState *ls, expdesc *v) {
} }
static void funcargs (LexState *ls, expdesc *f, int line) { static void funcargs (LexState *ls, expdesc *f) {
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
expdesc args; expdesc args;
int base, nparams; int base, nparams;
int line = ls->linenumber;
switch (ls->t.token) { switch (ls->t.token) {
case '(': { /* funcargs -> '(' [ explist ] ')' */ case '(': { /* funcargs -> '(' [ explist ] ')' */
luaX_next(ls); luaX_next(ls);
@@ -1062,8 +1065,8 @@ static void funcargs (LexState *ls, expdesc *f, int line) {
} }
init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
luaK_fixline(fs, line); luaK_fixline(fs, line);
fs->freereg = base+1; /* call remove function and arguments and leaves fs->freereg = base+1; /* call removes function and arguments and leaves
(unless changed) one result */ one result (unless changed later) */
} }
@@ -1102,7 +1105,6 @@ static void suffixedexp (LexState *ls, expdesc *v) {
/* suffixedexp -> /* suffixedexp ->
primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
int line = ls->linenumber;
primaryexp(ls, v); primaryexp(ls, v);
for (;;) { for (;;) {
switch (ls->t.token) { switch (ls->t.token) {
@@ -1122,12 +1124,12 @@ static void suffixedexp (LexState *ls, expdesc *v) {
luaX_next(ls); luaX_next(ls);
codename(ls, &key); codename(ls, &key);
luaK_self(fs, v, &key); luaK_self(fs, v, &key);
funcargs(ls, v, line); funcargs(ls, v);
break; break;
} }
case '(': case TK_STRING: case '{': { /* funcargs */ case '(': case TK_STRING: case '{': { /* funcargs */
luaK_exp2nextreg(fs, v); luaK_exp2nextreg(fs, v);
funcargs(ls, v, line); funcargs(ls, v);
break; break;
} }
default: return; default: return;
@@ -1943,10 +1945,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
LexState lexstate; LexState lexstate;
FuncState funcstate; FuncState funcstate;
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
setclLvalue2s(L, L->top, cl); /* anchor it (to avoid being collected) */ setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */
luaD_inctop(L); luaD_inctop(L);
lexstate.h = luaH_new(L); /* create table for scanner */ lexstate.h = luaH_new(L); /* create table for scanner */
sethvalue2s(L, L->top, lexstate.h); /* anchor it */ sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */
luaD_inctop(L); luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L); funcstate.f = cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p); luaC_objbarrier(L, cl, cl->p);
@@ -1960,7 +1962,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
/* all scopes should be correctly finished */ /* all scopes should be correctly finished */
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
L->top--; /* remove scanner's table */ L->top.p--; /* remove scanner's table */
return cl; /* closure is on the stack, too */ return cl; /* closure is on the stack, too */
} }
+42 -34
View File
@@ -119,7 +119,7 @@ CallInfo *luaE_extendCI (lua_State *L) {
/* /*
** free all CallInfo structures not in use by a thread ** free all CallInfo structures not in use by a thread
*/ */
void luaE_freeCI (lua_State *L) { static void freeCI (lua_State *L) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
CallInfo *next = ci->next; CallInfo *next = ci->next;
ci->next = NULL; ci->next = NULL;
@@ -166,7 +166,7 @@ void luaE_checkcstack (lua_State *L) {
if (getCcalls(L) == LUAI_MAXCCALLS) if (getCcalls(L) == LUAI_MAXCCALLS)
luaG_runerror(L, "C stack overflow"); luaG_runerror(L, "C stack overflow");
else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11)) else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
luaD_throw(L, LUA_ERRERR); /* error while handling stack error */ luaD_errerr(L); /* error while handling stack error */
} }
@@ -180,33 +180,33 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) {
static void stack_init (lua_State *L1, lua_State *L) { static void stack_init (lua_State *L1, lua_State *L) {
int i; CallInfo *ci; int i; CallInfo *ci;
/* initialize stack array */ /* initialize stack array */
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue); L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
L1->tbclist = L1->stack; L1->tbclist.p = L1->stack.p;
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
setnilvalue(s2v(L1->stack + i)); /* erase new stack */ setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */
L1->top = L1->stack; L1->top.p = L1->stack.p;
L1->stack_last = L1->stack + BASIC_STACK_SIZE; L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
/* initialize first ci */ /* initialize first ci */
ci = &L1->base_ci; ci = &L1->base_ci;
ci->next = ci->previous = NULL; ci->next = ci->previous = NULL;
ci->callstatus = CIST_C; ci->callstatus = CIST_C;
ci->func = L1->top; ci->func.p = L1->top.p;
ci->u.c.k = NULL; ci->u.c.k = NULL;
ci->nresults = 0; ci->nresults = 0;
setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */ setnilvalue(s2v(L1->top.p)); /* 'function' entry for this 'ci' */
L1->top++; L1->top.p++;
ci->top = L1->top + LUA_MINSTACK; ci->top.p = L1->top.p + LUA_MINSTACK;
L1->ci = ci; L1->ci = ci;
} }
static void freestack (lua_State *L) { static void freestack (lua_State *L) {
if (L->stack == NULL) if (L->stack.p == NULL)
return; /* stack not completely built yet */ return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */ L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L); freeCI(L);
lua_assert(L->nci == 0); lua_assert(L->nci == 0);
luaM_freearray(L, L->stack, stacksize(L) + EXTRA_STACK); /* free stack */ luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */
} }
@@ -248,7 +248,7 @@ static void f_luaopen (lua_State *L, void *ud) {
*/ */
static void preinit_thread (lua_State *L, global_State *g) { static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g; G(L) = g;
L->stack = NULL; L->stack.p = NULL;
L->ci = NULL; L->ci = NULL;
L->nci = 0; L->nci = 0;
L->twups = L; /* thread has no upvalues */ L->twups = L; /* thread has no upvalues */
@@ -272,7 +272,9 @@ static void close_state (lua_State *L) {
luaC_freeallobjects(L); /* just collect its objects */ luaC_freeallobjects(L); /* just collect its objects */
else { /* closing a fully built state */ else { /* closing a fully built state */
L->ci = &L->base_ci; /* unwind CallInfo list */ L->ci = &L->base_ci; /* unwind CallInfo list */
L->errfunc = 0; /* stack unwind can "throw away" the error function */
luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */ luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */
L->top.p = L->stack.p + 1; /* empty the stack to run finalizers */
luaC_freeallobjects(L); /* collect all objects */ luaC_freeallobjects(L); /* collect all objects */
luai_userstateclose(L); luai_userstateclose(L);
} }
@@ -284,20 +286,16 @@ static void close_state (lua_State *L) {
LUA_API lua_State *lua_newthread (lua_State *L) { LUA_API lua_State *lua_newthread (lua_State *L) {
global_State *g; global_State *g = G(L);
GCObject *o;
lua_State *L1; lua_State *L1;
lua_lock(L); lua_lock(L);
g = G(L);
luaC_checkGC(L); luaC_checkGC(L);
/* create new thread */ /* create new thread */
L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l));
L1->marked = luaC_white(g); L1 = gco2th(o);
L1->tt = LUA_VTHREAD;
/* link it on list 'allgc' */
L1->next = g->allgc;
g->allgc = obj2gco(L1);
/* anchor it on L stack */ /* anchor it on L stack */
setthvalue2s(L, L->top, L1); setthvalue2s(L, L->top.p, L1);
api_incr_top(L); api_incr_top(L);
preinit_thread(L1, g); preinit_thread(L1, g);
L1->hookmask = L->hookmask; L1->hookmask = L->hookmask;
@@ -316,7 +314,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
void luaE_freethread (lua_State *L, lua_State *L1) { void luaE_freethread (lua_State *L, lua_State *L1) {
LX *l = fromstate(L1); LX *l = fromstate(L1);
luaF_closeupval(L1, L1->stack); /* close all upvalues */ luaF_closeupval(L1, L1->stack.p); /* close all upvalues */
lua_assert(L1->openupval == NULL); lua_assert(L1->openupval == NULL);
luai_userstatefree(L, L1); luai_userstatefree(L, L1);
freestack(L1); freestack(L1);
@@ -326,32 +324,42 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
int luaE_resetthread (lua_State *L, int status) { int luaE_resetthread (lua_State *L, int status) {
CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */ CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */ setnilvalue(s2v(L->stack.p)); /* 'function' entry for basic 'ci' */
ci->func = L->stack; ci->func.p = L->stack.p;
ci->callstatus = CIST_C; ci->callstatus = CIST_C;
if (status == LUA_YIELD) if (status == LUA_YIELD)
status = LUA_OK; status = LUA_OK;
L->status = LUA_OK; /* so it can run __close metamethods */ L->status = LUA_OK; /* so it can run __close metamethods */
L->errfunc = 0; /* stack unwind can "throw away" the error function */
status = luaD_closeprotected(L, 1, status); status = luaD_closeprotected(L, 1, status);
if (status != LUA_OK) /* errors? */ if (status != LUA_OK) /* errors? */
luaD_seterrorobj(L, status, L->stack + 1); luaD_seterrorobj(L, status, L->stack.p + 1);
else else
L->top = L->stack + 1; L->top.p = L->stack.p + 1;
ci->top = L->top + LUA_MINSTACK; ci->top.p = L->top.p + LUA_MINSTACK;
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0); luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0);
return status; return status;
} }
LUA_API int lua_resetthread (lua_State *L) { LUA_API int lua_closethread (lua_State *L, lua_State *from) {
int status; int status;
lua_lock(L); lua_lock(L);
L->nCcalls = (from) ? getCcalls(from) : 0;
status = luaE_resetthread(L, L->status); status = luaE_resetthread(L, L->status);
lua_unlock(L); lua_unlock(L);
return status; return status;
} }
/*
** Deprecated! Use 'lua_closethread' instead.
*/
LUA_API int lua_resetthread (lua_State *L) {
return lua_closethread(L, NULL);
}
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i; int i;
lua_State *L; lua_State *L;
@@ -426,9 +434,9 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
** Generate a warning from an error message ** Generate a warning from an error message
*/ */
void luaE_warnerror (lua_State *L, const char *where) { void luaE_warnerror (lua_State *L, const char *where) {
TValue *errobj = s2v(L->top - 1); /* error object */ TValue *errobj = s2v(L->top.p - 1); /* error object */
const char *msg = (ttisstring(errobj)) const char *msg = (ttisstring(errobj))
? svalue(errobj) ? getstr(tsvalue(errobj))
: "error object is not a string"; : "error object is not a string";
/* produce warning "error in %s (%s)" (where, msg) */ /* produce warning "error in %s (%s)" (where, msg) */
luaE_warning(L, "error in ", 1); luaE_warning(L, "error in ", 1);
+16 -12
View File
@@ -9,6 +9,11 @@
#include "lua.h" #include "lua.h"
/* Some header files included here need this definition */
typedef struct CallInfo CallInfo;
#include "lobject.h" #include "lobject.h"
#include "ltm.h" #include "ltm.h"
#include "lzio.h" #include "lzio.h"
@@ -139,7 +144,7 @@ struct lua_longjmp; /* defined in ldo.c */
#define BASIC_STACK_SIZE (2*LUA_MINSTACK) #define BASIC_STACK_SIZE (2*LUA_MINSTACK)
#define stacksize(th) cast_int((th)->stack_last - (th)->stack) #define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p)
/* kinds of Garbage Collection */ /* kinds of Garbage Collection */
@@ -169,14 +174,14 @@ typedef struct stringtable {
** - field 'transferinfo' is used only during call/returnhooks, ** - field 'transferinfo' is used only during call/returnhooks,
** before the function starts or after it ends. ** before the function starts or after it ends.
*/ */
typedef struct CallInfo { struct CallInfo {
StkId func; /* function index in the stack */ StkIdRel func; /* function index in the stack */
StkId top; /* top for this function */ StkIdRel top; /* top for this function */
struct CallInfo *previous, *next; /* dynamic call link */ struct CallInfo *previous, *next; /* dynamic call link */
union { union {
struct { /* only for Lua functions */ struct { /* only for Lua functions */
const Instruction *savedpc; const Instruction *savedpc;
volatile l_signalT trap; volatile l_signalT trap; /* function is tracing lines/counts */
int nextraargs; /* # of extra arguments in vararg functions */ int nextraargs; /* # of extra arguments in vararg functions */
} l; } l;
struct { /* only for C functions */ struct { /* only for C functions */
@@ -196,7 +201,7 @@ typedef struct CallInfo {
} u2; } u2;
short nresults; /* expected number of results from this function */ short nresults; /* expected number of results from this function */
unsigned short callstatus; unsigned short callstatus;
} CallInfo; };
/* /*
@@ -291,7 +296,7 @@ typedef struct global_State {
struct lua_State *mainthread; struct lua_State *mainthread;
TString *memerrmsg; /* message for memory-allocation errors */ TString *memerrmsg; /* message for memory-allocation errors */
TString *tmname[TM_N]; /* array with tag-method names */ TString *tmname[TM_N]; /* array with tag-method names */
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ struct Table *mt[LUA_NUMTYPES]; /* metatables for basic types */
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
lua_WarnFunction warnf; /* warning function */ lua_WarnFunction warnf; /* warning function */
void *ud_warn; /* auxiliary data to 'warnf' */ void *ud_warn; /* auxiliary data to 'warnf' */
@@ -306,13 +311,13 @@ struct lua_State {
lu_byte status; lu_byte status;
lu_byte allowhook; lu_byte allowhook;
unsigned short nci; /* number of items in 'ci' list */ unsigned short nci; /* number of items in 'ci' list */
StkId top; /* first free slot in the stack */ StkIdRel top; /* first free slot in the stack */
global_State *l_G; global_State *l_G;
CallInfo *ci; /* call info for current function */ CallInfo *ci; /* call info for current function */
StkId stack_last; /* end of stack (last element + 1) */ StkIdRel stack_last; /* end of stack (last element + 1) */
StkId stack; /* stack base */ StkIdRel stack; /* stack base */
UpVal *openupval; /* list of open upvalues in this stack */ UpVal *openupval; /* list of open upvalues in this stack */
StkId tbclist; /* list of to-be-closed variables */ StkIdRel tbclist; /* list of to-be-closed variables */
GCObject *gclist; GCObject *gclist;
struct lua_State *twups; /* list of threads with open upvalues */ struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */ struct lua_longjmp *errorJmp; /* current error recover point */
@@ -391,7 +396,6 @@ union GCUnion {
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
LUAI_FUNC void luaE_freeCI (lua_State *L);
LUAI_FUNC void luaE_shrinkCI (lua_State *L); LUAI_FUNC void luaE_shrinkCI (lua_State *L);
LUAI_FUNC void luaE_checkcstack (lua_State *L); LUAI_FUNC void luaE_checkcstack (lua_State *L);
LUAI_FUNC void luaE_incCstack (lua_State *L); LUAI_FUNC void luaE_incCstack (lua_State *L);
+7 -6
View File
@@ -36,7 +36,7 @@ int luaS_eqlngstr (TString *a, TString *b) {
lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR); lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR);
return (a == b) || /* same instance or... */ return (a == b) || /* same instance or... */
((len == b->u.lnglen) && /* equal length and ... */ ((len == b->u.lnglen) && /* equal length and ... */
(memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ (memcmp(getlngstr(a), getlngstr(b), len) == 0)); /* equal contents */
} }
@@ -52,7 +52,7 @@ unsigned int luaS_hashlongstr (TString *ts) {
lua_assert(ts->tt == LUA_VLNGSTR); lua_assert(ts->tt == LUA_VLNGSTR);
if (ts->extra == 0) { /* no hash? */ if (ts->extra == 0) { /* no hash? */
size_t len = ts->u.lnglen; size_t len = ts->u.lnglen;
ts->hash = luaS_hash(getstr(ts), len, ts->hash); ts->hash = luaS_hash(getlngstr(ts), len, ts->hash);
ts->extra = 1; /* now it has its hash */ ts->extra = 1; /* now it has its hash */
} }
return ts->hash; return ts->hash;
@@ -157,6 +157,7 @@ static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
TString *luaS_createlngstrobj (lua_State *L, size_t l) { TString *luaS_createlngstrobj (lua_State *L, size_t l) {
TString *ts = createstrobj(L, l, LUA_VLNGSTR, G(L)->seed); TString *ts = createstrobj(L, l, LUA_VLNGSTR, G(L)->seed);
ts->u.lnglen = l; ts->u.lnglen = l;
ts->shrlen = 0xFF; /* signals that it is a long string */
return ts; return ts;
} }
@@ -193,7 +194,7 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
TString **list = &tb->hash[lmod(h, tb->size)]; TString **list = &tb->hash[lmod(h, tb->size)];
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
for (ts = *list; ts != NULL; ts = ts->u.hnext) { for (ts = *list; ts != NULL; ts = ts->u.hnext) {
if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { if (l == ts->shrlen && (memcmp(str, getshrstr(ts), l * sizeof(char)) == 0)) {
/* found! */ /* found! */
if (isdead(g, ts)) /* dead (but not collected yet)? */ if (isdead(g, ts)) /* dead (but not collected yet)? */
changewhite(ts); /* resurrect it */ changewhite(ts); /* resurrect it */
@@ -206,8 +207,8 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */ list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */
} }
ts = createstrobj(L, l, LUA_VSHRSTR, h); ts = createstrobj(L, l, LUA_VSHRSTR, h);
memcpy(getstr(ts), str, l * sizeof(char));
ts->shrlen = cast_byte(l); ts->shrlen = cast_byte(l);
memcpy(getshrstr(ts), str, l * sizeof(char));
ts->u.hnext = *list; ts->u.hnext = *list;
*list = ts; *list = ts;
tb->nuse++; tb->nuse++;
@@ -223,10 +224,10 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
return internshrstr(L, str, l); return internshrstr(L, str, l);
else { else {
TString *ts; TString *ts;
if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char))) if (l_unlikely(l * sizeof(char) >= (MAX_SIZE - sizeof(TString))))
luaM_toobig(L); luaM_toobig(L);
ts = luaS_createlngstrobj(L, l); ts = luaS_createlngstrobj(L, l);
memcpy(getstr(ts), str, l * sizeof(char)); memcpy(getlngstr(ts), str, l * sizeof(char));
return ts; return ts;
} }
} }
+1 -1
View File
@@ -570,7 +570,7 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
static const char *match (MatchState *ms, const char *s, const char *p) { static const char *match (MatchState *ms, const char *s, const char *p) {
if (l_unlikely(ms->matchdepth-- == 0)) if (l_unlikely(ms->matchdepth-- == 0))
luaL_error(ms->L, "pattern too complex"); luaL_error(ms->L, "pattern too complex");
init: /* using goto's to optimize tail recursion */ init: /* using goto to optimize tail recursion */
if (p != ms->p_end) { /* end of pattern? */ if (p != ms->p_end) { /* end of pattern? */
switch (*p) { switch (*p) {
case '(': { /* start capture */ case '(': { /* start capture */
+31 -16
View File
@@ -107,7 +107,7 @@ static const TValue absentkey = {ABSTKEYCONSTANT};
*/ */
static Node *hashint (const Table *t, lua_Integer i) { static Node *hashint (const Table *t, lua_Integer i) {
lua_Unsigned ui = l_castS2U(i); lua_Unsigned ui = l_castS2U(i);
if (ui <= (unsigned int)INT_MAX) if (ui <= cast_uint(INT_MAX))
return hashmod(t, cast_int(ui)); return hashmod(t, cast_int(ui));
else else
return hashmod(t, ui); return hashmod(t, ui);
@@ -252,14 +252,16 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t) {
return t->alimit; /* this is the size */ return t->alimit; /* this is the size */
else { else {
unsigned int size = t->alimit; unsigned int size = t->alimit;
/* compute the smallest power of 2 not smaller than 'n' */ /* compute the smallest power of 2 not smaller than 'size' */
size |= (size >> 1); size |= (size >> 1);
size |= (size >> 2); size |= (size >> 2);
size |= (size >> 4); size |= (size >> 4);
size |= (size >> 8); size |= (size >> 8);
#if (UINT_MAX >> 14) > 3 /* unsigned int has more than 16 bits */
size |= (size >> 16); size |= (size >> 16);
#if (UINT_MAX >> 30) > 3 #if (UINT_MAX >> 30) > 3
size |= (size >> 32); /* unsigned int has more than 32 bits */ size |= (size >> 32); /* unsigned int has more than 32 bits */
#endif
#endif #endif
size++; size++;
lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size); lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size);
@@ -488,7 +490,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
luaG_runerror(L, "table overflow"); luaG_runerror(L, "table overflow");
size = twoto(lsize); size = twoto(lsize);
t->node = luaM_newvector(L, size, Node); t->node = luaM_newvector(L, size, Node);
for (i = 0; i < (int)size; i++) { for (i = 0; i < cast_int(size); i++) {
Node *n = gnode(t, i); Node *n = gnode(t, i);
gnext(n) = 0; gnext(n) = 0;
setnilkey(n); setnilkey(n);
@@ -660,7 +662,8 @@ static Node *getfreepos (Table *t) {
** put new key in its main position; otherwise (colliding node is in its main ** put new key in its main position; otherwise (colliding node is in its main
** position), new key goes to an empty position. ** position), new key goes to an empty position.
*/ */
void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { static void luaH_newkey (lua_State *L, Table *t, const TValue *key,
TValue *value) {
Node *mp; Node *mp;
TValue aux; TValue aux;
if (l_unlikely(ttisnil(key))) if (l_unlikely(ttisnil(key)))
@@ -719,22 +722,36 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
/* /*
** Search function for integers. If integer is inside 'alimit', get it ** Search function for integers. If integer is inside 'alimit', get it
** directly from the array part. Otherwise, if 'alimit' is not equal to ** directly from the array part. Otherwise, if 'alimit' is not
** the real size of the array, key still can be in the array part. In ** the real size of the array, the key still can be in the array part.
** this case, try to avoid a call to 'luaH_realasize' when key is just ** In this case, do the "Xmilia trick" to check whether 'key-1' is
** one more than the limit (so that it can be incremented without ** smaller than the real size.
** changing the real size of the array). ** The trick works as follow: let 'p' be an integer such that
** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'.
** That is, 2^(p+1) is the real size of the array, and 'p' is the highest
** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'.
** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will
** have the 'p' bit cleared. If the key is outside the array, that is,
** 'key-1 >= 2^(p+1)', then 'res' will have some bit on higher than 'p',
** therefore it will be larger or equal to 'alimit', and the check
** will fail. If 'key-1 < 2^(p+1)', then 'res' has no bit on higher than
** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller
** than 2^p, therefore smaller than 'alimit', and the check succeeds.
** As special cases, when 'alimit' is 0 the condition is trivially false,
** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'.
** If key is 0 or negative, 'res' will have its higher bit on, so that
** if cannot be smaller than alimit.
*/ */
const TValue *luaH_getint (Table *t, lua_Integer key) { const TValue *luaH_getint (Table *t, lua_Integer key) {
if (l_castS2U(key) - 1u < t->alimit) /* 'key' in [1, t->alimit]? */ lua_Unsigned alimit = t->alimit;
if (l_castS2U(key) - 1u < alimit) /* 'key' in [1, t->alimit]? */
return &t->array[key - 1]; return &t->array[key - 1];
else if (!limitequalsasize(t) && /* key still may be in the array part? */ else if (!isrealasize(t) && /* key still may be in the array part? */
(l_castS2U(key) == t->alimit + 1 || (((l_castS2U(key) - 1u) & ~(alimit - 1u)) < alimit)) {
l_castS2U(key) - 1u < luaH_realasize(t))) {
t->alimit = cast_uint(key); /* probably '#t' is here now */ t->alimit = cast_uint(key); /* probably '#t' is here now */
return &t->array[key - 1]; return &t->array[key - 1];
} }
else { else { /* key is not in the array part; check the hash */
Node *n = hashint(t, key); Node *n = hashint(t, key);
for (;;) { /* check whether 'key' is somewhere in the chain */ for (;;) { /* check whether 'key' is somewhere in the chain */
if (keyisinteger(n) && keyival(n) == key) if (keyisinteger(n) && keyival(n) == key)
@@ -975,6 +992,4 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainpositionTV(t, key); return mainpositionTV(t, key);
} }
int luaH_isdummy (const Table *t) { return isdummy(t); }
#endif #endif
-3
View File
@@ -41,8 +41,6 @@ LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key,
TValue *value);
LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key, LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key,
TValue *value); TValue *value);
LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key, LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key,
@@ -59,7 +57,6 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t);
#if defined(LUA_DEBUG) #if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
LUAI_FUNC int luaH_isdummy (const Table *t);
#endif #endif
+1 -1
View File
@@ -93,7 +93,7 @@ static int tremove (lua_State *L) {
lua_Integer pos = luaL_optinteger(L, 2, size); lua_Integer pos = luaL_optinteger(L, 2, size);
if (pos != size) /* validate 'pos' if given */ if (pos != size) /* validate 'pos' if given */
/* check whether 'pos' is in [1, size + 1] */ /* check whether 'pos' is in [1, size + 1] */
luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1, luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2,
"position out of bounds"); "position out of bounds");
lua_geti(L, 1, pos); /* result = t[pos] */ lua_geti(L, 1, pos); /* result = t[pos] */
for ( ; pos < size; pos++) { for ( ; pos < size; pos++) {
+29 -20
View File
@@ -44,7 +44,7 @@
void *l_Trick = 0; void *l_Trick = 0;
#define obj_at(L,k) s2v(L->ci->func + (k)) #define obj_at(L,k) s2v(L->ci->func.p + (k))
static int runC (lua_State *L, lua_State *L1, const char *pc); static int runC (lua_State *L, lua_State *L1, const char *pc);
@@ -57,7 +57,7 @@ static void setnameval (lua_State *L, const char *name, int val) {
static void pushobject (lua_State *L, const TValue *o) { static void pushobject (lua_State *L, const TValue *o) {
setobj2s(L, L->top, o); setobj2s(L, L->top.p, o);
api_incr_top(L); api_incr_top(L);
} }
@@ -73,8 +73,9 @@ static void badexit (const char *fmt, const char *s1, const char *s2) {
static int tpanic (lua_State *L) { static int tpanic (lua_State *L) {
const char *msg = lua_tostring(L, -1); const char *msg = (lua_type(L, -1) == LUA_TSTRING)
if (msg == NULL) msg = "error object is not a string"; ? lua_tostring(L, -1)
: "error object is not a string";
return (badexit("PANIC: unprotected error in call to Lua API (%s)\n", return (badexit("PANIC: unprotected error in call to Lua API (%s)\n",
msg, NULL), msg, NULL),
0); /* do not return to Lua */ 0); /* do not return to Lua */
@@ -419,7 +420,7 @@ static void checkLclosure (global_State *g, LClosure *cl) {
if (uv) { if (uv) {
checkobjrefN(g, clgc, uv); checkobjrefN(g, clgc, uv);
if (!upisopen(uv)) if (!upisopen(uv))
checkvalref(g, obj2gco(uv), uv->v); checkvalref(g, obj2gco(uv), uv->v.p);
} }
} }
} }
@@ -428,7 +429,7 @@ static void checkLclosure (global_State *g, LClosure *cl) {
static int lua_checkpc (CallInfo *ci) { static int lua_checkpc (CallInfo *ci) {
if (!isLua(ci)) return 1; if (!isLua(ci)) return 1;
else { else {
StkId f = ci->func; StkId f = ci->func.p;
Proto *p = clLvalue(s2v(f))->p; Proto *p = clLvalue(s2v(f))->p;
return p->code <= ci->u.l.savedpc && return p->code <= ci->u.l.savedpc &&
ci->u.l.savedpc <= p->code + p->sizecode; ci->u.l.savedpc <= p->code + p->sizecode;
@@ -441,19 +442,19 @@ static void checkstack (global_State *g, lua_State *L1) {
CallInfo *ci; CallInfo *ci;
UpVal *uv; UpVal *uv;
assert(!isdead(g, L1)); assert(!isdead(g, L1));
if (L1->stack == NULL) { /* incomplete thread? */ if (L1->stack.p == NULL) { /* incomplete thread? */
assert(L1->openupval == NULL && L1->ci == NULL); assert(L1->openupval == NULL && L1->ci == NULL);
return; return;
} }
for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next) for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next)
assert(upisopen(uv)); /* must be open */ assert(upisopen(uv)); /* must be open */
assert(L1->top <= L1->stack_last); assert(L1->top.p <= L1->stack_last.p);
assert(L1->tbclist <= L1->top); assert(L1->tbclist.p <= L1->top.p);
for (ci = L1->ci; ci != NULL; ci = ci->previous) { for (ci = L1->ci; ci != NULL; ci = ci->previous) {
assert(ci->top <= L1->stack_last); assert(ci->top.p <= L1->stack_last.p);
assert(lua_checkpc(ci)); assert(lua_checkpc(ci));
} }
for (o = L1->stack; o < L1->stack_last; o++) for (o = L1->stack.p; o < L1->stack_last.p; o++)
checkliveness(L1, s2v(o)); /* entire stack must have valid values */ checkliveness(L1, s2v(o)); /* entire stack must have valid values */
} }
@@ -465,7 +466,7 @@ static void checkrefs (global_State *g, GCObject *o) {
break; break;
} }
case LUA_VUPVAL: { case LUA_VUPVAL: {
checkvalref(g, o, gco2upv(o)->v); checkvalref(g, o, gco2upv(o)->v.p);
break; break;
} }
case LUA_VTABLE: { case LUA_VTABLE: {
@@ -533,7 +534,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead,
static lu_mem checkgraylist (global_State *g, GCObject *o) { static lu_mem checkgraylist (global_State *g, GCObject *o) {
int total = 0; /* count number of elements in the list */ int total = 0; /* count number of elements in the list */
((void)g); /* better to keep it available if we need to print an object */ cast_void(g); /* better to keep it if we need to print an object */
while (o) { while (o) {
assert(!!isgray(o) ^ (getage(o) == G_TOUCHED2)); assert(!!isgray(o) ^ (getage(o) == G_TOUCHED2));
assert(!testbit(o->marked, TESTBIT)); assert(!testbit(o->marked, TESTBIT));
@@ -980,7 +981,7 @@ static int hash_query (lua_State *L) {
static int stacklevel (lua_State *L) { static int stacklevel (lua_State *L) {
unsigned long a = 0; unsigned long a = 0;
lua_pushinteger(L, (L->top - L->stack)); lua_pushinteger(L, (L->top.p - L->stack.p));
lua_pushinteger(L, stacksize(L)); lua_pushinteger(L, stacksize(L));
lua_pushinteger(L, L->nCcalls); lua_pushinteger(L, L->nCcalls);
lua_pushinteger(L, L->nci); lua_pushinteger(L, L->nci);
@@ -1040,7 +1041,7 @@ static int string_query (lua_State *L) {
TString *ts; TString *ts;
int n = 0; int n = 0;
for (ts = tb->hash[s]; ts != NULL; ts = ts->u.hnext) { for (ts = tb->hash[s]; ts != NULL; ts = ts->u.hnext) {
setsvalue2s(L, L->top, ts); setsvalue2s(L, L->top.p, ts);
api_incr_top(L); api_incr_top(L);
n++; n++;
} }
@@ -1055,7 +1056,7 @@ static int tref (lua_State *L) {
luaL_checkany(L, 1); luaL_checkany(L, 1);
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
lua_pushinteger(L, luaL_ref(L, LUA_REGISTRYINDEX)); lua_pushinteger(L, luaL_ref(L, LUA_REGISTRYINDEX));
(void)level; /* to avoid warnings */ cast_void(level); /* to avoid warnings */
lua_assert(lua_gettop(L) == level+1); /* +1 for result */ lua_assert(lua_gettop(L) == level+1); /* +1 for result */
return 1; return 1;
} }
@@ -1063,7 +1064,7 @@ static int tref (lua_State *L) {
static int getref (lua_State *L) { static int getref (lua_State *L) {
int level = lua_gettop(L); int level = lua_gettop(L);
lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_checkinteger(L, 1)); lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_checkinteger(L, 1));
(void)level; /* to avoid warnings */ cast_void(level); /* to avoid warnings */
lua_assert(lua_gettop(L) == level+1); lua_assert(lua_gettop(L) == level+1);
return 1; return 1;
} }
@@ -1071,7 +1072,7 @@ static int getref (lua_State *L) {
static int unref (lua_State *L) { static int unref (lua_State *L) {
int level = lua_gettop(L); int level = lua_gettop(L);
luaL_unref(L, LUA_REGISTRYINDEX, cast_int(luaL_checkinteger(L, 1))); luaL_unref(L, LUA_REGISTRYINDEX, cast_int(luaL_checkinteger(L, 1)));
(void)level; /* to avoid warnings */ cast_void(level); /* to avoid warnings */
lua_assert(lua_gettop(L) == level); lua_assert(lua_gettop(L) == level);
return 0; return 0;
} }
@@ -1533,7 +1534,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
lua_newthread(L1); lua_newthread(L1);
} }
else if EQ("resetthread") { else if EQ("resetthread") {
lua_pushinteger(L1, lua_resetthread(L1)); lua_pushinteger(L1, lua_resetthread(L1)); /* deprecated */
} }
else if EQ("newuserdata") { else if EQ("newuserdata") {
lua_newuserdata(L1, getnum); lua_newuserdata(L1, getnum);
@@ -1649,6 +1650,14 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
int nres; int nres;
status = lua_resume(lua_tothread(L1, i), L, getnum, &nres); status = lua_resume(lua_tothread(L1, i), L, getnum, &nres);
} }
else if EQ("traceback") {
const char *msg = getstring;
int level = getnum;
luaL_traceback(L1, L1, msg, level);
}
else if EQ("threadstatus") {
lua_pushstring(L1, statcodes[lua_status(L1)]);
}
else if EQ("return") { else if EQ("return") {
int n = getnum; int n = getnum;
if (L1 != L) { if (L1 != L) {
@@ -1740,7 +1749,7 @@ static struct X { int x; } x;
else if EQ("tostring") { else if EQ("tostring") {
const char *s = lua_tostring(L1, getindex); const char *s = lua_tostring(L1, getindex);
const char *s1 = lua_pushstring(L1, s); const char *s1 = lua_pushstring(L1, s);
(void)s1; /* to avoid warnings */ cast_void(s1); /* to avoid warnings */
lua_longassert((s == NULL && s1 == NULL) || strcmp(s, s1) == 0); lua_longassert((s == NULL && s1 == NULL) || strcmp(s, s1) == 0);
} }
else if EQ("Ltolstring") { else if EQ("Ltolstring") {
+7
View File
@@ -125,6 +125,13 @@ LUA_API void *debug_realloc (void *ud, void *block,
#define LUAI_USER_ALIGNMENT_T union { char b[sizeof(void*) * 8]; } #define LUAI_USER_ALIGNMENT_T union { char b[sizeof(void*) * 8]; }
/*
** This one is not compatible with tests for opcode optimizations,
** as it blocks some optimizations
#define MAXINDEXRK 0
*/
/* make stack-overflow tests run faster */ /* make stack-overflow tests run faster */
#undef LUAI_MAXSTACK #undef LUAI_MAXSTACK
#define LUAI_MAXSTACK 50000 #define LUAI_MAXSTACK 50000
+19 -19
View File
@@ -102,12 +102,12 @@ const char *luaT_objtypename (lua_State *L, const TValue *o) {
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, const TValue *p3) { const TValue *p2, const TValue *p3) {
StkId func = L->top; StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */ setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */ setobj2s(L, func + 2, p2); /* 2nd argument */
setobj2s(L, func + 3, p3); /* 3rd argument */ setobj2s(L, func + 3, p3); /* 3rd argument */
L->top = func + 4; L->top.p = func + 4;
/* metamethod may yield only when called from Lua code */ /* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci)) if (isLuacode(L->ci))
luaD_call(L, func, 0); luaD_call(L, func, 0);
@@ -119,18 +119,18 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, StkId res) { const TValue *p2, StkId res) {
ptrdiff_t result = savestack(L, res); ptrdiff_t result = savestack(L, res);
StkId func = L->top; StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */ setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */ setobj2s(L, func + 2, p2); /* 2nd argument */
L->top += 3; L->top.p += 3;
/* metamethod may yield only when called from Lua code */ /* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci)) if (isLuacode(L->ci))
luaD_call(L, func, 1); luaD_call(L, func, 1);
else else
luaD_callnoyield(L, func, 1); luaD_callnoyield(L, func, 1);
res = restorestack(L, result); res = restorestack(L, result);
setobjs2s(L, res, --L->top); /* move result to its place */ setobjs2s(L, res, --L->top.p); /* move result to its place */
} }
@@ -165,7 +165,7 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
void luaT_tryconcatTM (lua_State *L) { void luaT_tryconcatTM (lua_State *L) {
StkId top = L->top; StkId top = L->top.p;
if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2, if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
TM_CONCAT))) TM_CONCAT)))
luaG_concaterror(L, s2v(top - 2), s2v(top - 1)); luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
@@ -200,15 +200,15 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
*/ */
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
TMS event) { TMS event) {
if (callbinTM(L, p1, p2, L->top, event)) /* try original event */ if (callbinTM(L, p1, p2, L->top.p, event)) /* try original event */
return !l_isfalse(s2v(L->top)); return !l_isfalse(s2v(L->top.p));
#if defined(LUA_COMPAT_LT_LE) #if defined(LUA_COMPAT_LT_LE)
else if (event == TM_LE) { else if (event == TM_LE) {
/* try '!(p2 < p1)' for '(p1 <= p2)' */ /* try '!(p2 < p1)' for '(p1 <= p2)' */
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
if (callbinTM(L, p2, p1, L->top, TM_LT)) { if (callbinTM(L, p2, p1, L->top.p, TM_LT)) {
L->ci->callstatus ^= CIST_LEQ; /* clear mark */ L->ci->callstatus ^= CIST_LEQ; /* clear mark */
return l_isfalse(s2v(L->top)); return l_isfalse(s2v(L->top.p));
} }
/* else error will remove this 'ci'; no need to clear mark */ /* else error will remove this 'ci'; no need to clear mark */
} }
@@ -238,20 +238,20 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci, void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
const Proto *p) { const Proto *p) {
int i; int i;
int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */ int actual = cast_int(L->top.p - ci->func.p) - 1; /* number of arguments */
int nextra = actual - nfixparams; /* number of extra arguments */ int nextra = actual - nfixparams; /* number of extra arguments */
ci->u.l.nextraargs = nextra; ci->u.l.nextraargs = nextra;
luaD_checkstack(L, p->maxstacksize + 1); luaD_checkstack(L, p->maxstacksize + 1);
/* copy function to the top of the stack */ /* copy function to the top of the stack */
setobjs2s(L, L->top++, ci->func); setobjs2s(L, L->top.p++, ci->func.p);
/* move fixed parameters to the top of the stack */ /* move fixed parameters to the top of the stack */
for (i = 1; i <= nfixparams; i++) { for (i = 1; i <= nfixparams; i++) {
setobjs2s(L, L->top++, ci->func + i); setobjs2s(L, L->top.p++, ci->func.p + i);
setnilvalue(s2v(ci->func + i)); /* erase original parameter (for GC) */ setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
} }
ci->func += actual + 1; ci->func.p += actual + 1;
ci->top += actual + 1; ci->top.p += actual + 1;
lua_assert(L->top <= ci->top && ci->top <= L->stack_last); lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
} }
@@ -261,10 +261,10 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
if (wanted < 0) { if (wanted < 0) {
wanted = nextra; /* get all extra arguments available */ wanted = nextra; /* get all extra arguments available */
checkstackGCp(L, nextra, where); /* ensure stack space */ checkstackGCp(L, nextra, where); /* ensure stack space */
L->top = where + nextra; /* next instruction will need top */ L->top.p = where + nextra; /* next instruction will need top */
} }
for (i = 0; i < wanted && i < nextra; i++) for (i = 0; i < wanted && i < nextra; i++)
setobjs2s(L, where + i, ci->func - nextra + i); setobjs2s(L, where + i, ci->func.p - nextra + i);
for (; i < wanted; i++) /* complete required results with nil */ for (; i < wanted; i++) /* complete required results with nil */
setnilvalue(s2v(where + i)); setnilvalue(s2v(where + i));
} }
+46 -24
View File
@@ -115,12 +115,13 @@ static void l_message (const char *pname, const char *msg) {
/* /*
** Check whether 'status' is not OK and, if so, prints the error ** Check whether 'status' is not OK and, if so, prints the error
** message on the top of the stack. It assumes that the error object ** message on the top of the stack.
** is a string, as it was either generated by Lua or by 'msghandler'.
*/ */
static int report (lua_State *L, int status) { static int report (lua_State *L, int status) {
if (status != LUA_OK) { if (status != LUA_OK) {
const char *msg = lua_tostring(L, -1); const char *msg = lua_tostring(L, -1);
if (msg == NULL)
msg = "(error message not a string)";
l_message(progname, msg); l_message(progname, msg);
lua_pop(L, 1); /* remove message */ lua_pop(L, 1); /* remove message */
} }
@@ -177,10 +178,11 @@ static void print_version (void) {
** to the script (everything after 'script') go to positive indices; ** to the script (everything after 'script') go to positive indices;
** other arguments (before the script name) go to negative indices. ** other arguments (before the script name) go to negative indices.
** If there is no script name, assume interpreter's name as base. ** If there is no script name, assume interpreter's name as base.
** (If there is no interpreter's name either, 'script' is -1, so
** table sizes are zero.)
*/ */
static void createargtable (lua_State *L, char **argv, int argc, int script) { static void createargtable (lua_State *L, char **argv, int argc, int script) {
int i, narg; int i, narg;
if (script == argc) script = 0; /* no script name? */
narg = argc - (script + 1); /* number of positive indices */ narg = argc - (script + 1); /* number of positive indices */
lua_createtable(L, narg, script + 1); lua_createtable(L, narg, script + 1);
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
@@ -209,12 +211,17 @@ static int dostring (lua_State *L, const char *s, const char *name) {
/* /*
** Receives 'globname[=modname]' and runs 'globname = require(modname)'. ** Receives 'globname[=modname]' and runs 'globname = require(modname)'.
** If there is no explicit modname and globname contains a '-', cut
** the suffix after '-' (the "version") to make the global name.
*/ */
static int dolibrary (lua_State *L, char *globname) { static int dolibrary (lua_State *L, char *globname) {
int status; int status;
char *suffix = NULL;
char *modname = strchr(globname, '='); char *modname = strchr(globname, '=');
if (modname == NULL) /* no explicit name? */ if (modname == NULL) { /* no explicit name? */
modname = globname; /* module name is equal to global name */ modname = globname; /* module name is equal to global name */
suffix = strchr(modname, *LUA_IGMARK); /* look for a suffix mark */
}
else { else {
*modname = '\0'; /* global name ends here */ *modname = '\0'; /* global name ends here */
modname++; /* module name starts after the '=' */ modname++; /* module name starts after the '=' */
@@ -222,8 +229,11 @@ static int dolibrary (lua_State *L, char *globname) {
lua_getglobal(L, "require"); lua_getglobal(L, "require");
lua_pushstring(L, modname); lua_pushstring(L, modname);
status = docall(L, 1, 1); /* call 'require(modname)' */ status = docall(L, 1, 1); /* call 'require(modname)' */
if (status == LUA_OK) if (status == LUA_OK) {
if (suffix != NULL) /* is there a suffix mark? */
*suffix = '\0'; /* remove suffix from global name */
lua_setglobal(L, globname); /* globname = require(modname) */ lua_setglobal(L, globname); /* globname = require(modname) */
}
return report(L, status); return report(L, status);
} }
@@ -268,14 +278,23 @@ static int handle_script (lua_State *L, char **argv) {
/* /*
** Traverses all arguments from 'argv', returning a mask with those ** Traverses all arguments from 'argv', returning a mask with those
** needed before running any Lua code (or an error code if it finds ** needed before running any Lua code or an error code if it finds any
** any invalid argument). 'first' returns the first not-handled argument ** invalid argument. In case of error, 'first' is the index of the bad
** (either the script name or a bad argument in case of error). ** argument. Otherwise, 'first' is -1 if there is no program name,
** 0 if there is no script name, or the index of the script name.
*/ */
static int collectargs (char **argv, int *first) { static int collectargs (char **argv, int *first) {
int args = 0; int args = 0;
int i; int i;
for (i = 1; argv[i] != NULL; i++) { if (argv[0] != NULL) { /* is there a program name? */
if (argv[0][0]) /* not empty? */
progname = argv[0]; /* save it */
}
else { /* no program name */
*first = -1;
return 0;
}
for (i = 1; argv[i] != NULL; i++) { /* handle arguments */
*first = i; *first = i;
if (argv[i][0] != '-') /* not an option? */ if (argv[i][0] != '-') /* not an option? */
return args; /* stop handling options */ return args; /* stop handling options */
@@ -283,7 +302,8 @@ static int collectargs (char **argv, int *first) {
case '-': /* '--' */ case '-': /* '--' */
if (argv[i][2] != '\0') /* extra characters after '--'? */ if (argv[i][2] != '\0') /* extra characters after '--'? */
return has_error; /* invalid option */ return has_error; /* invalid option */
*first = i + 1; /* if there is a script name, it comes after '--' */
*first = (argv[i + 1] != NULL) ? i + 1 : 0;
return args; return args;
case '\0': /* '-' */ case '\0': /* '-' */
return args; /* script "name" is '-' */ return args; /* script "name" is '-' */
@@ -316,7 +336,7 @@ static int collectargs (char **argv, int *first) {
return has_error; return has_error;
} }
} }
*first = i; /* no script name */ *first = 0; /* no script name */
return args; return args;
} }
@@ -471,10 +491,8 @@ static int incomplete (lua_State *L, int status) {
if (status == LUA_ERRSYNTAX) { if (status == LUA_ERRSYNTAX) {
size_t lmsg; size_t lmsg;
const char *msg = lua_tolstring(L, -1, &lmsg); const char *msg = lua_tolstring(L, -1, &lmsg);
if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) { if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0)
lua_pop(L, 1);
return 1; return 1;
}
} }
return 0; /* else... */ return 0; /* else... */
} }
@@ -489,9 +507,9 @@ static int pushline (lua_State *L, int firstline) {
size_t l; size_t l;
const char *prmt = get_prompt(L, firstline); const char *prmt = get_prompt(L, firstline);
int readstatus = lua_readline(L, b, prmt); int readstatus = lua_readline(L, b, prmt);
if (readstatus == 0)
return 0; /* no input (prompt will be popped by caller) */
lua_pop(L, 1); /* remove prompt */ lua_pop(L, 1); /* remove prompt */
if (readstatus == 0)
return 0; /* no input */
l = strlen(b); l = strlen(b);
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
b[--l] = '\0'; /* remove it */ b[--l] = '\0'; /* remove it */
@@ -533,8 +551,9 @@ static int multiline (lua_State *L) {
int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */ int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */
if (!incomplete(L, status) || !pushline(L, 0)) { if (!incomplete(L, status) || !pushline(L, 0)) {
lua_saveline(L, line); /* keep history */ lua_saveline(L, line); /* keep history */
return status; /* cannot or should not try to add continuation line */ return status; /* should not or cannot try to add continuation line */
} }
lua_remove(L, -2); /* remove error message (from incomplete line) */
lua_pushliteral(L, "\n"); /* add newline... */ lua_pushliteral(L, "\n"); /* add newline... */
lua_insert(L, -2); /* ...between the two lines */ lua_insert(L, -2); /* ...between the two lines */
lua_concat(L, 3); /* join them */ lua_concat(L, 3); /* join them */
@@ -609,8 +628,8 @@ static int pmain (lua_State *L) {
char **argv = (char **)lua_touserdata(L, 2); char **argv = (char **)lua_touserdata(L, 2);
int script; int script;
int args = collectargs(argv, &script); int args = collectargs(argv, &script);
int optlim = (script > 0) ? script : argc; /* first argv not an option */
luaL_checkversion(L); /* check that interpreter has correct version */ luaL_checkversion(L); /* check that interpreter has correct version */
if (argv[0] && argv[0][0]) progname = argv[0];
if (args == has_error) { /* bad arg? */ if (args == has_error) { /* bad arg? */
print_usage(argv[script]); /* 'script' has index of bad arg. */ print_usage(argv[script]); /* 'script' has index of bad arg. */
return 0; return 0;
@@ -623,19 +642,21 @@ static int pmain (lua_State *L) {
} }
luaL_openlibs(L); /* open standard libraries */ luaL_openlibs(L); /* open standard libraries */
createargtable(L, argv, argc, script); /* create table 'arg' */ createargtable(L, argv, argc, script); /* create table 'arg' */
lua_gc(L, LUA_GCGEN, 0, 0); /* GC in generational mode */ lua_gc(L, LUA_GCRESTART); /* start GC... */
lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */
if (!(args & has_E)) { /* no option '-E'? */ if (!(args & has_E)) { /* no option '-E'? */
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */ if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
return 0; /* error running LUA_INIT */ return 0; /* error running LUA_INIT */
} }
if (!runargs(L, argv, script)) /* execute arguments -e and -l */ if (!runargs(L, argv, optlim)) /* execute arguments -e and -l */
return 0; /* something failed */ return 0; /* something failed */
if (script < argc && /* execute main script (if there is one) */ if (script > 0) { /* execute main script (if there is one) */
handle_script(L, argv + script) != LUA_OK) if (handle_script(L, argv + script) != LUA_OK)
return 0; return 0; /* interrupt in case of error */
}
if (args & has_i) /* -i option? */ if (args & has_i) /* -i option? */
doREPL(L); /* do read-eval-print loop */ doREPL(L); /* do read-eval-print loop */
else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */ else if (script < 1 && !(args & (has_e | has_v))) { /* no active option? */
if (lua_stdin_is_tty()) { /* running in interactive mode? */ if (lua_stdin_is_tty()) { /* running in interactive mode? */
print_version(); print_version();
doREPL(L); /* do read-eval-print loop */ doREPL(L); /* do read-eval-print loop */
@@ -654,6 +675,7 @@ int main (int argc, char **argv) {
l_message(argv[0], "cannot create state: not enough memory"); l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
lua_gc(L, LUA_GCSTOP); /* stop GC while building state */
lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */ lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */
lua_pushinteger(L, argc); /* 1st argument */ lua_pushinteger(L, argc); /* 1st argument */
lua_pushlightuserdata(L, argv); /* 2nd argument */ lua_pushlightuserdata(L, argv); /* 2nd argument */
+16 -11
View File
@@ -18,14 +18,14 @@
#define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "4" #define LUA_VERSION_MINOR "4"
#define LUA_VERSION_RELEASE "4" #define LUA_VERSION_RELEASE "8"
#define LUA_VERSION_NUM 504 #define LUA_VERSION_NUM 504
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 4) #define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 8)
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2022 Lua.org, PUC-Rio" #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2025 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -131,6 +131,16 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont); typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
/*
** Type used by the debug API to collect debug information
*/
typedef struct lua_Debug lua_Debug;
/*
** Functions to be called by the debugger in specific events
*/
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
/* /*
@@ -153,7 +163,8 @@ extern const char lua_ident[];
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L); LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L); LUA_API lua_State *(lua_newthread) (lua_State *L);
LUA_API int (lua_resetthread) (lua_State *L); LUA_API int (lua_closethread) (lua_State *L, lua_State *from);
LUA_API int (lua_resetthread) (lua_State *L); /* Deprecated! */
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
@@ -442,12 +453,6 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
#define LUA_MASKLINE (1 << LUA_HOOKLINE) #define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) #define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
typedef struct lua_Debug lua_Debug; /* activation record */
/* Functions to be called by the debugger in specific events */
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
@@ -492,7 +497,7 @@ struct lua_Debug {
/****************************************************************************** /******************************************************************************
* Copyright (C) 1994-2022 Lua.org, PUC-Rio. * Copyright (C) 1994-2025 Lua.org, PUC-Rio.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
+19 -3
View File
@@ -70,6 +70,12 @@
#endif #endif
#if defined(LUA_USE_IOS)
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN
#endif
/* /*
@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits. @@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits.
*/ */
@@ -251,6 +257,15 @@
#endif #endif
/*
** LUA_IGMARK is a mark to ignore all after it when building the
** module name (e.g., used to build the luaopen_ function name).
** Typically, the suffix after the mark is the module version,
** as in "mod-v1.2.so".
*/
#define LUA_IGMARK "-"
/* }================================================================== */ /* }================================================================== */
@@ -728,7 +743,7 @@
** CHANGE it if you need a different limit. This limit is arbitrary; ** CHANGE it if you need a different limit. This limit is arbitrary;
** its only purpose is to stop Lua from consuming unlimited stack ** its only purpose is to stop Lua from consuming unlimited stack
** space (and to reserve some numbers for pseudo-indices). ** space (and to reserve some numbers for pseudo-indices).
** (It must fit into max(size_t)/32.) ** (It must fit into max(size_t)/32 and max(int)/2.)
*/ */
#if LUAI_IS32INT #if LUAI_IS32INT
#define LUAI_MAXSTACK 1000000 #define LUAI_MAXSTACK 1000000
@@ -747,14 +762,15 @@
/* /*
@@ LUA_IDSIZE gives the maximum size for the description of the source @@ LUA_IDSIZE gives the maximum size for the description of the source
@@ of a function in debug information. ** of a function in debug information.
** CHANGE it if you want a different size. ** CHANGE it if you want a different size.
*/ */
#define LUA_IDSIZE 60 #define LUA_IDSIZE 60
/* /*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. @@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib
** buffer system.
*/ */
#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number))) #define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))
+7 -5
View File
@@ -81,7 +81,7 @@ static size_t loadUnsigned (LoadState *S, size_t limit) {
static size_t loadSize (LoadState *S) { static size_t loadSize (LoadState *S) {
return loadUnsigned(S, ~(size_t)0); return loadUnsigned(S, MAX_SIZET);
} }
@@ -120,10 +120,10 @@ static TString *loadStringN (LoadState *S, Proto *p) {
} }
else { /* long string */ else { /* long string */
ts = luaS_createlngstrobj(L, size); /* create string */ ts = luaS_createlngstrobj(L, size); /* create string */
setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */ setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */
luaD_inctop(L); luaD_inctop(L);
loadVector(S, getstr(ts), size); /* load directly in final place */ loadVector(S, getlngstr(ts), size); /* load directly in final place */
L->top--; /* pop string */ L->top.p--; /* pop string */
} }
luaC_objbarrier(L, p, ts); luaC_objbarrier(L, p, ts);
return ts; return ts;
@@ -248,6 +248,8 @@ static void loadDebug (LoadState *S, Proto *f) {
f->locvars[i].endpc = loadInt(S); f->locvars[i].endpc = loadInt(S);
} }
n = loadInt(S); n = loadInt(S);
if (n != 0) /* does it have debug information? */
n = f->sizeupvalues; /* must be this many */
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
f->upvalues[i].name = loadStringN(S, f); f->upvalues[i].name = loadStringN(S, f);
} }
@@ -321,7 +323,7 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
S.Z = Z; S.Z = Z;
checkHeader(&S); checkHeader(&S);
cl = luaF_newLclosure(L, loadByte(&S)); cl = luaF_newLclosure(L, loadByte(&S));
setclLvalue2s(L, L->top, cl); setclLvalue2s(L, L->top.p, cl);
luaD_inctop(L); luaD_inctop(L);
cl->p = luaF_newproto(L); cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p); luaC_objbarrier(L, cl, cl->p);
+1 -2
View File
@@ -21,8 +21,7 @@
/* /*
** Encode major-minor version in one byte, one nibble for each ** Encode major-minor version in one byte, one nibble for each
*/ */
#define MYINT(s) (s[0]-'0') /* assume one-digit numerals */ #define LUAC_VERSION (((LUA_VERSION_NUM / 100) * 16) + LUA_VERSION_NUM % 100)
#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR))
#define LUAC_FORMAT 0 /* this is the official format */ #define LUAC_FORMAT 0 /* this is the official format */
+16 -11
View File
@@ -25,6 +25,9 @@
#define MAXUTF 0x7FFFFFFFu #define MAXUTF 0x7FFFFFFFu
#define MSGInvalid "invalid UTF-8 code"
/* /*
** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits. ** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
*/ */
@@ -35,7 +38,8 @@ typedef unsigned long utfint;
#endif #endif
#define iscont(p) ((*(p) & 0xC0) == 0x80) #define iscont(c) (((c) & 0xC0) == 0x80)
#define iscontp(p) iscont(*(p))
/* from strlib */ /* from strlib */
@@ -65,7 +69,7 @@ static const char *utf8_decode (const char *s, utfint *val, int strict) {
int count = 0; /* to count number of continuation bytes */ int count = 0; /* to count number of continuation bytes */
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */ for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
unsigned int cc = (unsigned char)s[++count]; /* read next byte */ unsigned int cc = (unsigned char)s[++count]; /* read next byte */
if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ if (!iscont(cc)) /* not a continuation byte? */
return NULL; /* invalid byte sequence */ return NULL; /* invalid byte sequence */
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
} }
@@ -140,7 +144,7 @@ static int codepoint (lua_State *L) {
utfint code; utfint code;
s = utf8_decode(s, &code, !lax); s = utf8_decode(s, &code, !lax);
if (s == NULL) if (s == NULL)
return luaL_error(L, "invalid UTF-8 code"); return luaL_error(L, MSGInvalid);
lua_pushinteger(L, code); lua_pushinteger(L, code);
n++; n++;
} }
@@ -190,16 +194,16 @@ static int byteoffset (lua_State *L) {
"position out of bounds"); "position out of bounds");
if (n == 0) { if (n == 0) {
/* find beginning of current byte sequence */ /* find beginning of current byte sequence */
while (posi > 0 && iscont(s + posi)) posi--; while (posi > 0 && iscontp(s + posi)) posi--;
} }
else { else {
if (iscont(s + posi)) if (iscontp(s + posi))
return luaL_error(L, "initial position is a continuation byte"); return luaL_error(L, "initial position is a continuation byte");
if (n < 0) { if (n < 0) {
while (n < 0 && posi > 0) { /* move back */ while (n < 0 && posi > 0) { /* move back */
do { /* find beginning of previous character */ do { /* find beginning of previous character */
posi--; posi--;
} while (posi > 0 && iscont(s + posi)); } while (posi > 0 && iscontp(s + posi));
n++; n++;
} }
} }
@@ -208,7 +212,7 @@ static int byteoffset (lua_State *L) {
while (n > 0 && posi < (lua_Integer)len) { while (n > 0 && posi < (lua_Integer)len) {
do { /* find beginning of next character */ do { /* find beginning of next character */
posi++; posi++;
} while (iscont(s + posi)); /* (cannot pass final '\0') */ } while (iscontp(s + posi)); /* (cannot pass final '\0') */
n--; n--;
} }
} }
@@ -226,15 +230,15 @@ static int iter_aux (lua_State *L, int strict) {
const char *s = luaL_checklstring(L, 1, &len); const char *s = luaL_checklstring(L, 1, &len);
lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2); lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
if (n < len) { if (n < len) {
while (iscont(s + n)) n++; /* skip continuation bytes */ while (iscontp(s + n)) n++; /* go to next character */
} }
if (n >= len) /* (also handles original 'n' being negative) */ if (n >= len) /* (also handles original 'n' being negative) */
return 0; /* no more codepoints */ return 0; /* no more codepoints */
else { else {
utfint code; utfint code;
const char *next = utf8_decode(s + n, &code, strict); const char *next = utf8_decode(s + n, &code, strict);
if (next == NULL) if (next == NULL || iscontp(next))
return luaL_error(L, "invalid UTF-8 code"); return luaL_error(L, MSGInvalid);
lua_pushinteger(L, n + 1); lua_pushinteger(L, n + 1);
lua_pushinteger(L, code); lua_pushinteger(L, code);
return 2; return 2;
@@ -253,7 +257,8 @@ static int iter_auxlax (lua_State *L) {
static int iter_codes (lua_State *L) { static int iter_codes (lua_State *L) {
int lax = lua_toboolean(L, 2); int lax = lua_toboolean(L, 2);
luaL_checkstring(L, 1); const char *s = luaL_checkstring(L, 1);
luaL_argcheck(L, !iscontp(s), 1, MSGInvalid);
lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict); lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
lua_pushinteger(L, 0); lua_pushinteger(L, 0);
+187 -125
View File
@@ -91,8 +91,10 @@ static int l_strton (const TValue *obj, TValue *result) {
lua_assert(obj != result); lua_assert(obj != result);
if (!cvt2num(obj)) /* is object not a string? */ if (!cvt2num(obj)) /* is object not a string? */
return 0; return 0;
else else {
return (luaO_str2num(svalue(obj), result) == vslen(obj) + 1); TString *st = tsvalue(obj);
return (luaO_str2num(getstr(st), result) == tsslen(st) + 1);
}
} }
@@ -337,7 +339,10 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
lua_assert(isempty(slot)); /* slot must be empty */ lua_assert(isempty(slot)); /* slot must be empty */
tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
if (tm == NULL) { /* no metamethod? */ if (tm == NULL) { /* no metamethod? */
sethvalue2s(L, L->top.p, h); /* anchor 't' */
L->top.p++; /* assume EXTRA_STACK */
luaH_finishset(L, h, key, slot, val); /* set new value */ luaH_finishset(L, h, key, slot, val); /* set new value */
L->top.p--;
invalidateTMcache(h); invalidateTMcache(h);
luaC_barrierback(L, obj2gco(h), val); luaC_barrierback(L, obj2gco(h), val);
return; return;
@@ -366,30 +371,32 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
/* /*
** Compare two strings 'ls' x 'rs', returning an integer less-equal- ** Compare two strings 'ts1' x 'ts2', returning an integer less-equal-
** -greater than zero if 'ls' is less-equal-greater than 'rs'. ** -greater than zero if 'ts1' is less-equal-greater than 'ts2'.
** The code is a little tricky because it allows '\0' in the strings ** The code is a little tricky because it allows '\0' in the strings
** and it uses 'strcoll' (to respect locales) for each segments ** and it uses 'strcoll' (to respect locales) for each segment
** of the strings. ** of the strings. Note that segments can compare equal but still
** have different lengths.
*/ */
static int l_strcmp (const TString *ls, const TString *rs) { static int l_strcmp (const TString *ts1, const TString *ts2) {
const char *l = getstr(ls); const char *s1 = getstr(ts1);
size_t ll = tsslen(ls); size_t rl1 = tsslen(ts1); /* real length */
const char *r = getstr(rs); const char *s2 = getstr(ts2);
size_t lr = tsslen(rs); size_t rl2 = tsslen(ts2);
for (;;) { /* for each segment */ for (;;) { /* for each segment */
int temp = strcoll(l, r); int temp = strcoll(s1, s2);
if (temp != 0) /* not equal? */ if (temp != 0) /* not equal? */
return temp; /* done */ return temp; /* done */
else { /* strings are equal up to a '\0' */ else { /* strings are equal up to a '\0' */
size_t len = strlen(l); /* index of first '\0' in both strings */ size_t zl1 = strlen(s1); /* index of first '\0' in 's1' */
if (len == lr) /* 'rs' is finished? */ size_t zl2 = strlen(s2); /* index of first '\0' in 's2' */
return (len == ll) ? 0 : 1; /* check 'ls' */ if (zl2 == rl2) /* 's2' is finished? */
else if (len == ll) /* 'ls' is finished? */ return (zl1 == rl1) ? 0 : 1; /* check 's1' */
return -1; /* 'ls' is less than 'rs' ('rs' is not finished) */ else if (zl1 == rl1) /* 's1' is finished? */
/* both strings longer than 'len'; go on comparing after the '\0' */ return -1; /* 's1' is less than 's2' ('s2' is not finished) */
len++; /* both strings longer than 'zl'; go on comparing after the '\0' */
l += len; ll -= len; r += len; lr -= len; zl1++; zl2++;
s1 += zl1; rl1 -= zl1; s2 += zl2; rl2 -= zl2;
} }
} }
} }
@@ -608,8 +615,8 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
if (tm == NULL) /* no TM? */ if (tm == NULL) /* no TM? */
return 0; /* objects are different */ return 0; /* objects are different */
else { else {
luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */ luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */
return !l_isfalse(s2v(L->top)); return !l_isfalse(s2v(L->top.p));
} }
} }
@@ -624,8 +631,9 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
static void copy2buff (StkId top, int n, char *buff) { static void copy2buff (StkId top, int n, char *buff) {
size_t tl = 0; /* size already copied */ size_t tl = 0; /* size already copied */
do { do {
size_t l = vslen(s2v(top - n)); /* length of string being copied */ TString *st = tsvalue(s2v(top - n));
memcpy(buff + tl, svalue(s2v(top - n)), l * sizeof(char)); size_t l = tsslen(st); /* length of string being copied */
memcpy(buff + tl, getstr(st), l * sizeof(char));
tl += l; tl += l;
} while (--n > 0); } while (--n > 0);
} }
@@ -633,17 +641,17 @@ static void copy2buff (StkId top, int n, char *buff) {
/* /*
** Main operation for concatenation: concat 'total' values in the stack, ** Main operation for concatenation: concat 'total' values in the stack,
** from 'L->top - total' up to 'L->top - 1'. ** from 'L->top.p - total' up to 'L->top.p - 1'.
*/ */
void luaV_concat (lua_State *L, int total) { void luaV_concat (lua_State *L, int total) {
if (total == 1) if (total == 1)
return; /* "all" values already concatenated */ return; /* "all" values already concatenated */
do { do {
StkId top = L->top; StkId top = L->top.p;
int n = 2; /* number of elements handled in this pass (at least 2) */ int n = 2; /* number of elements handled in this pass (at least 2) */
if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) || if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) ||
!tostring(L, s2v(top - 1))) !tostring(L, s2v(top - 1)))
luaT_tryconcatTM(L); luaT_tryconcatTM(L); /* may invalidate 'top' */
else if (isemptystr(s2v(top - 1))) /* second operand is empty? */ else if (isemptystr(s2v(top - 1))) /* second operand is empty? */
cast_void(tostring(L, s2v(top - 2))); /* result is first operand */ cast_void(tostring(L, s2v(top - 2))); /* result is first operand */
else if (isemptystr(s2v(top - 2))) { /* first operand is empty string? */ else if (isemptystr(s2v(top - 2))) { /* first operand is empty string? */
@@ -651,13 +659,15 @@ void luaV_concat (lua_State *L, int total) {
} }
else { else {
/* at least two non-empty string values; get as many as possible */ /* at least two non-empty string values; get as many as possible */
size_t tl = vslen(s2v(top - 1)); size_t tl = tsslen(tsvalue(s2v(top - 1)));
TString *ts; TString *ts;
/* collect total length and number of strings */ /* collect total length and number of strings */
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) { for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
size_t l = vslen(s2v(top - n - 1)); size_t l = tsslen(tsvalue(s2v(top - n - 1)));
if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) if (l_unlikely(l >= MAX_SIZE - sizeof(TString) - tl)) {
L->top.p = top - total; /* pop strings to avoid wasting stack */
luaG_runerror(L, "string length overflow"); luaG_runerror(L, "string length overflow");
}
tl += l; tl += l;
} }
if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */ if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
@@ -667,12 +677,12 @@ void luaV_concat (lua_State *L, int total) {
} }
else { /* long string; copy strings directly to final result */ else { /* long string; copy strings directly to final result */
ts = luaS_createlngstrobj(L, tl); ts = luaS_createlngstrobj(L, tl);
copy2buff(top, n, getstr(ts)); copy2buff(top, n, getlngstr(ts));
} }
setsvalue2s(L, top - n, ts); /* create result */ setsvalue2s(L, top - n, ts); /* create result */
} }
total -= n-1; /* got 'n' strings to create 1 new */ total -= n - 1; /* got 'n' strings to create one new */
L->top -= n-1; /* popped 'n' strings and pushed one */ L->top.p -= n - 1; /* popped 'n' strings and pushed one */
} while (total > 1); /* repeat until only 1 result left */ } while (total > 1); /* repeat until only 1 result left */
} }
@@ -763,12 +773,10 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) {
/* number of bits in an integer */ /* number of bits in an integer */
#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT) #define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT)
/* /*
** Shift left operation. (Shift right just negates 'y'.) ** Shift left operation. (Shift right just negates 'y'.)
*/ */
#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
if (y < 0) { /* shift right? */ if (y < 0) { /* shift right? */
if (y <= -NBITS) return 0; if (y <= -NBITS) return 0;
@@ -808,26 +816,26 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
*/ */
void luaV_finishOp (lua_State *L) { void luaV_finishOp (lua_State *L) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
StkId base = ci->func + 1; StkId base = ci->func.p + 1;
Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */
OpCode op = GET_OPCODE(inst); OpCode op = GET_OPCODE(inst);
switch (op) { /* finish its execution */ switch (op) { /* finish its execution */
case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: { case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top); setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top.p);
break; break;
} }
case OP_UNM: case OP_BNOT: case OP_LEN: case OP_UNM: case OP_BNOT: case OP_LEN:
case OP_GETTABUP: case OP_GETTABLE: case OP_GETI: case OP_GETTABUP: case OP_GETTABLE: case OP_GETI:
case OP_GETFIELD: case OP_SELF: { case OP_GETFIELD: case OP_SELF: {
setobjs2s(L, base + GETARG_A(inst), --L->top); setobjs2s(L, base + GETARG_A(inst), --L->top.p);
break; break;
} }
case OP_LT: case OP_LE: case OP_LT: case OP_LE:
case OP_LTI: case OP_LEI: case OP_LTI: case OP_LEI:
case OP_GTI: case OP_GEI: case OP_GTI: case OP_GEI:
case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */ case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */
int res = !l_isfalse(s2v(L->top - 1)); int res = !l_isfalse(s2v(L->top.p - 1));
L->top--; L->top.p--;
#if defined(LUA_COMPAT_LT_LE) #if defined(LUA_COMPAT_LT_LE)
if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
ci->callstatus ^= CIST_LEQ; /* clear mark */ ci->callstatus ^= CIST_LEQ; /* clear mark */
@@ -840,11 +848,11 @@ void luaV_finishOp (lua_State *L) {
break; break;
} }
case OP_CONCAT: { case OP_CONCAT: {
StkId top = L->top - 1; /* top when 'luaT_tryconcatTM' was called */ StkId top = L->top.p - 1; /* top when 'luaT_tryconcatTM' was called */
int a = GETARG_A(inst); /* first element to concatenate */ int a = GETARG_A(inst); /* first element to concatenate */
int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */ int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */
setobjs2s(L, top - 2, top); /* put TM result in proper position */ setobjs2s(L, top - 2, top); /* put TM result in proper position */
L->top = top - 1; /* top is one after last element (at top-2) */ L->top.p = top - 1; /* top is one after last element (at top-2) */
luaV_concat(L, total); /* concat them (may yield again) */ luaV_concat(L, total); /* concat them (may yield again) */
break; break;
} }
@@ -856,7 +864,7 @@ void luaV_finishOp (lua_State *L) {
StkId ra = base + GETARG_A(inst); StkId ra = base + GETARG_A(inst);
/* adjust top to signal correct number of returns, in case the /* adjust top to signal correct number of returns, in case the
return is "up to top" ('isIT') */ return is "up to top" ('isIT') */
L->top = ra + ci->u2.nres; L->top.p = ra + ci->u2.nres;
/* repeat instruction to close other vars. and complete the return */ /* repeat instruction to close other vars. and complete the return */
ci->u.l.savedpc--; ci->u.l.savedpc--;
break; break;
@@ -898,6 +906,7 @@ void luaV_finishOp (lua_State *L) {
** operation, 'fop' is the float operation. ** operation, 'fop' is the float operation.
*/ */
#define op_arithI(L,iop,fop) { \ #define op_arithI(L,iop,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
int imm = GETARG_sC(i); \ int imm = GETARG_sC(i); \
if (ttisinteger(v1)) { \ if (ttisinteger(v1)) { \
@@ -926,6 +935,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over floats and others with register operands. ** Arithmetic operations over floats and others with register operands.
*/ */
#define op_arithf(L,fop) { \ #define op_arithf(L,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \ TValue *v2 = vRC(i); \
op_arithf_aux(L, v1, v2, fop); } op_arithf_aux(L, v1, v2, fop); }
@@ -935,6 +945,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations with K operands for floats. ** Arithmetic operations with K operands for floats.
*/ */
#define op_arithfK(L,fop) { \ #define op_arithfK(L,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \ TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
op_arithf_aux(L, v1, v2, fop); } op_arithf_aux(L, v1, v2, fop); }
@@ -944,6 +955,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over integers and floats. ** Arithmetic operations over integers and floats.
*/ */
#define op_arith_aux(L,v1,v2,iop,fop) { \ #define op_arith_aux(L,v1,v2,iop,fop) { \
StkId ra = RA(i); \
if (ttisinteger(v1) && ttisinteger(v2)) { \ if (ttisinteger(v1) && ttisinteger(v2)) { \
lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \ lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \
pc++; setivalue(s2v(ra), iop(L, i1, i2)); \ pc++; setivalue(s2v(ra), iop(L, i1, i2)); \
@@ -973,6 +985,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with constant operand. ** Bitwise operations with constant operand.
*/ */
#define op_bitwiseK(L,op) { \ #define op_bitwiseK(L,op) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
TValue *v2 = KC(i); \ TValue *v2 = KC(i); \
lua_Integer i1; \ lua_Integer i1; \
@@ -986,6 +999,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with register operands. ** Bitwise operations with register operands.
*/ */
#define op_bitwise(L,op) { \ #define op_bitwise(L,op) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \ TValue *v2 = vRC(i); \
lua_Integer i1; lua_Integer i2; \ lua_Integer i1; lua_Integer i2; \
@@ -1000,18 +1014,19 @@ void luaV_finishOp (lua_State *L) {
** integers. ** integers.
*/ */
#define op_order(L,opi,opn,other) { \ #define op_order(L,opi,opn,other) { \
int cond; \ StkId ra = RA(i); \
TValue *rb = vRB(i); \ int cond; \
if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \ TValue *rb = vRB(i); \
lua_Integer ia = ivalue(s2v(ra)); \ if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
lua_Integer ib = ivalue(rb); \ lua_Integer ia = ivalue(s2v(ra)); \
cond = opi(ia, ib); \ lua_Integer ib = ivalue(rb); \
} \ cond = opi(ia, ib); \
else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \ } \
cond = opn(s2v(ra), rb); \ else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \
else \ cond = opn(s2v(ra), rb); \
Protect(cond = other(L, s2v(ra), rb)); \ else \
docondjump(); } Protect(cond = other(L, s2v(ra), rb)); \
docondjump(); }
/* /*
@@ -1019,20 +1034,21 @@ void luaV_finishOp (lua_State *L) {
** always small enough to have an exact representation as a float.) ** always small enough to have an exact representation as a float.)
*/ */
#define op_orderI(L,opi,opf,inv,tm) { \ #define op_orderI(L,opi,opf,inv,tm) { \
int cond; \ StkId ra = RA(i); \
int im = GETARG_sB(i); \ int cond; \
if (ttisinteger(s2v(ra))) \ int im = GETARG_sB(i); \
cond = opi(ivalue(s2v(ra)), im); \ if (ttisinteger(s2v(ra))) \
else if (ttisfloat(s2v(ra))) { \ cond = opi(ivalue(s2v(ra)), im); \
lua_Number fa = fltvalue(s2v(ra)); \ else if (ttisfloat(s2v(ra))) { \
lua_Number fim = cast_num(im); \ lua_Number fa = fltvalue(s2v(ra)); \
cond = opf(fa, fim); \ lua_Number fim = cast_num(im); \
} \ cond = opf(fa, fim); \
else { \ } \
int isf = GETARG_C(i); \ else { \
Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \ int isf = GETARG_C(i); \
} \ Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \
docondjump(); } } \
docondjump(); }
/* }================================================================== */ /* }================================================================== */
@@ -1061,7 +1077,7 @@ void luaV_finishOp (lua_State *L) {
#define updatetrap(ci) (trap = ci->u.l.trap) #define updatetrap(ci) (trap = ci->u.l.trap)
#define updatebase(ci) (base = ci->func + 1) #define updatebase(ci) (base = ci->func.p + 1)
#define updatestack(ci) \ #define updatestack(ci) \
@@ -1096,7 +1112,7 @@ void luaV_finishOp (lua_State *L) {
** Whenever code can raise errors, the global 'pc' and the global ** Whenever code can raise errors, the global 'pc' and the global
** 'top' must be correct to report occasional errors. ** 'top' must be correct to report occasional errors.
*/ */
#define savestate(L,ci) (savepc(L), L->top = ci->top) #define savestate(L,ci) (savepc(L), L->top.p = ci->top.p)
/* /*
@@ -1116,7 +1132,7 @@ void luaV_finishOp (lua_State *L) {
/* 'c' is the limit of live values in the stack */ /* 'c' is the limit of live values in the stack */
#define checkGC(L,c) \ #define checkGC(L,c) \
{ luaC_condGC(L, (savepc(L), L->top = (c)), \ { luaC_condGC(L, (savepc(L), L->top.p = (c)), \
updatetrap(ci)); \ updatetrap(ci)); \
luai_threadyield(L); } luai_threadyield(L); }
@@ -1128,7 +1144,6 @@ void luaV_finishOp (lua_State *L) {
updatebase(ci); /* correct stack */ \ updatebase(ci); /* correct stack */ \
} \ } \
i = *(pc++); \ i = *(pc++); \
ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
} }
#define vmdispatch(o) switch(o) #define vmdispatch(o) switch(o)
@@ -1148,72 +1163,73 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
startfunc: startfunc:
trap = L->hookmask; trap = L->hookmask;
returning: /* trap already set */ returning: /* trap already set */
cl = clLvalue(s2v(ci->func)); cl = ci_func(ci);
k = cl->p->k; k = cl->p->k;
pc = ci->u.l.savedpc; pc = ci->u.l.savedpc;
if (l_unlikely(trap)) { if (l_unlikely(trap))
if (pc == cl->p->code) { /* first instruction (not resuming)? */ trap = luaG_tracecall(L);
if (cl->p->is_vararg) base = ci->func.p + 1;
trap = 0; /* hooks will start after VARARGPREP instruction */
else /* check 'call' hook */
luaD_hookcall(L, ci);
}
ci->u.l.trap = 1; /* assume trap is on, for now */
}
base = ci->func + 1;
/* main loop of interpreter */ /* main loop of interpreter */
for (;;) { for (;;) {
Instruction i; /* instruction being executed */ Instruction i; /* instruction being executed */
StkId ra; /* instruction's A register */
vmfetch(); vmfetch();
#if 0 #if 0
/* low-level line tracing for debugging Lua */ /* low-level line tracing for debugging Lua */
printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p))); printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
#endif #endif
lua_assert(base == ci->func + 1); lua_assert(base == ci->func.p + 1);
lua_assert(base <= L->top && L->top < L->stack_last); lua_assert(base <= L->top.p && L->top.p <= L->stack_last.p);
/* invalidate top for instructions not expecting it */ /* invalidate top for instructions not expecting it */
lua_assert(isIT(i) || (cast_void(L->top = base), 1)); lua_assert(isIT(i) || (cast_void(L->top.p = base), 1));
vmdispatch (GET_OPCODE(i)) { vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) { vmcase(OP_MOVE) {
StkId ra = RA(i);
setobjs2s(L, ra, RB(i)); setobjs2s(L, ra, RB(i));
vmbreak; vmbreak;
} }
vmcase(OP_LOADI) { vmcase(OP_LOADI) {
StkId ra = RA(i);
lua_Integer b = GETARG_sBx(i); lua_Integer b = GETARG_sBx(i);
setivalue(s2v(ra), b); setivalue(s2v(ra), b);
vmbreak; vmbreak;
} }
vmcase(OP_LOADF) { vmcase(OP_LOADF) {
StkId ra = RA(i);
int b = GETARG_sBx(i); int b = GETARG_sBx(i);
setfltvalue(s2v(ra), cast_num(b)); setfltvalue(s2v(ra), cast_num(b));
vmbreak; vmbreak;
} }
vmcase(OP_LOADK) { vmcase(OP_LOADK) {
StkId ra = RA(i);
TValue *rb = k + GETARG_Bx(i); TValue *rb = k + GETARG_Bx(i);
setobj2s(L, ra, rb); setobj2s(L, ra, rb);
vmbreak; vmbreak;
} }
vmcase(OP_LOADKX) { vmcase(OP_LOADKX) {
StkId ra = RA(i);
TValue *rb; TValue *rb;
rb = k + GETARG_Ax(*pc); pc++; rb = k + GETARG_Ax(*pc); pc++;
setobj2s(L, ra, rb); setobj2s(L, ra, rb);
vmbreak; vmbreak;
} }
vmcase(OP_LOADFALSE) { vmcase(OP_LOADFALSE) {
StkId ra = RA(i);
setbfvalue(s2v(ra)); setbfvalue(s2v(ra));
vmbreak; vmbreak;
} }
vmcase(OP_LFALSESKIP) { vmcase(OP_LFALSESKIP) {
StkId ra = RA(i);
setbfvalue(s2v(ra)); setbfvalue(s2v(ra));
pc++; /* skip next instruction */ pc++; /* skip next instruction */
vmbreak; vmbreak;
} }
vmcase(OP_LOADTRUE) { vmcase(OP_LOADTRUE) {
StkId ra = RA(i);
setbtvalue(s2v(ra)); setbtvalue(s2v(ra));
vmbreak; vmbreak;
} }
vmcase(OP_LOADNIL) { vmcase(OP_LOADNIL) {
StkId ra = RA(i);
int b = GETARG_B(i); int b = GETARG_B(i);
do { do {
setnilvalue(s2v(ra++)); setnilvalue(s2v(ra++));
@@ -1221,21 +1237,24 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_GETUPVAL) { vmcase(OP_GETUPVAL) {
StkId ra = RA(i);
int b = GETARG_B(i); int b = GETARG_B(i);
setobj2s(L, ra, cl->upvals[b]->v); setobj2s(L, ra, cl->upvals[b]->v.p);
vmbreak; vmbreak;
} }
vmcase(OP_SETUPVAL) { vmcase(OP_SETUPVAL) {
StkId ra = RA(i);
UpVal *uv = cl->upvals[GETARG_B(i)]; UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, s2v(ra)); setobj(L, uv->v.p, s2v(ra));
luaC_barrier(L, uv, s2v(ra)); luaC_barrier(L, uv, s2v(ra));
vmbreak; vmbreak;
} }
vmcase(OP_GETTABUP) { vmcase(OP_GETTABUP) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *upval = cl->upvals[GETARG_B(i)]->v; TValue *upval = cl->upvals[GETARG_B(i)]->v.p;
TValue *rc = KC(i); TValue *rc = KC(i);
TString *key = tsvalue(rc); /* key must be a string */ TString *key = tsvalue(rc); /* key must be a short string */
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
setobj2s(L, ra, slot); setobj2s(L, ra, slot);
} }
@@ -1244,6 +1263,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_GETTABLE) { vmcase(OP_GETTABLE) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = vRB(i); TValue *rb = vRB(i);
TValue *rc = vRC(i); TValue *rc = vRC(i);
@@ -1258,6 +1278,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_GETI) { vmcase(OP_GETI) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = vRB(i); TValue *rb = vRB(i);
int c = GETARG_C(i); int c = GETARG_C(i);
@@ -1272,10 +1293,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_GETFIELD) { vmcase(OP_GETFIELD) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = vRB(i); TValue *rb = vRB(i);
TValue *rc = KC(i); TValue *rc = KC(i);
TString *key = tsvalue(rc); /* key must be a string */ TString *key = tsvalue(rc); /* key must be a short string */
if (luaV_fastget(L, rb, key, slot, luaH_getshortstr)) { if (luaV_fastget(L, rb, key, slot, luaH_getshortstr)) {
setobj2s(L, ra, slot); setobj2s(L, ra, slot);
} }
@@ -1285,10 +1307,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
} }
vmcase(OP_SETTABUP) { vmcase(OP_SETTABUP) {
const TValue *slot; const TValue *slot;
TValue *upval = cl->upvals[GETARG_A(i)]->v; TValue *upval = cl->upvals[GETARG_A(i)]->v.p;
TValue *rb = KB(i); TValue *rb = KB(i);
TValue *rc = RKC(i); TValue *rc = RKC(i);
TString *key = tsvalue(rb); /* key must be a string */ TString *key = tsvalue(rb); /* key must be a short string */
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
luaV_finishfastset(L, upval, slot, rc); luaV_finishfastset(L, upval, slot, rc);
} }
@@ -1297,6 +1319,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SETTABLE) { vmcase(OP_SETTABLE) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = vRB(i); /* key (table is in 'ra') */ TValue *rb = vRB(i); /* key (table is in 'ra') */
TValue *rc = RKC(i); /* value */ TValue *rc = RKC(i); /* value */
@@ -1311,6 +1334,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SETI) { vmcase(OP_SETI) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
int c = GETARG_B(i); int c = GETARG_B(i);
TValue *rc = RKC(i); TValue *rc = RKC(i);
@@ -1325,10 +1349,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SETFIELD) { vmcase(OP_SETFIELD) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = KB(i); TValue *rb = KB(i);
TValue *rc = RKC(i); TValue *rc = RKC(i);
TString *key = tsvalue(rb); /* key must be a string */ TString *key = tsvalue(rb); /* key must be a short string */
if (luaV_fastget(L, s2v(ra), key, slot, luaH_getshortstr)) { if (luaV_fastget(L, s2v(ra), key, slot, luaH_getshortstr)) {
luaV_finishfastset(L, s2v(ra), slot, rc); luaV_finishfastset(L, s2v(ra), slot, rc);
} }
@@ -1337,6 +1362,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_NEWTABLE) { vmcase(OP_NEWTABLE) {
StkId ra = RA(i);
int b = GETARG_B(i); /* log2(hash size) + 1 */ int b = GETARG_B(i); /* log2(hash size) + 1 */
int c = GETARG_C(i); /* array size */ int c = GETARG_C(i); /* array size */
Table *t; Table *t;
@@ -1346,7 +1372,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
if (TESTARG_k(i)) /* non-zero extra argument? */ if (TESTARG_k(i)) /* non-zero extra argument? */
c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */ c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */
pc++; /* skip extra argument */ pc++; /* skip extra argument */
L->top = ra + 1; /* correct top in case of emergency GC */ L->top.p = ra + 1; /* correct top in case of emergency GC */
t = luaH_new(L); /* memory allocation */ t = luaH_new(L); /* memory allocation */
sethvalue2s(L, ra, t); sethvalue2s(L, ra, t);
if (b != 0 || c != 0) if (b != 0 || c != 0)
@@ -1355,6 +1381,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SELF) { vmcase(OP_SELF) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = vRB(i); TValue *rb = vRB(i);
TValue *rc = RKC(i); TValue *rc = RKC(i);
@@ -1384,6 +1411,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_MODK) { vmcase(OP_MODK) {
savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_mod, luaV_modf); op_arithK(L, luaV_mod, luaV_modf);
vmbreak; vmbreak;
} }
@@ -1396,6 +1424,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_IDIVK) { vmcase(OP_IDIVK) {
savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_idiv, luai_numidiv); op_arithK(L, luaV_idiv, luai_numidiv);
vmbreak; vmbreak;
} }
@@ -1412,6 +1441,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SHRI) { vmcase(OP_SHRI) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
int ic = GETARG_sC(i); int ic = GETARG_sC(i);
lua_Integer ib; lua_Integer ib;
@@ -1421,6 +1451,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SHLI) { vmcase(OP_SHLI) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
int ic = GETARG_sC(i); int ic = GETARG_sC(i);
lua_Integer ib; lua_Integer ib;
@@ -1442,6 +1473,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_MOD) { vmcase(OP_MOD) {
savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_mod, luaV_modf); op_arith(L, luaV_mod, luaV_modf);
vmbreak; vmbreak;
} }
@@ -1454,6 +1486,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_IDIV) { /* floor division */ vmcase(OP_IDIV) { /* floor division */
savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_idiv, luai_numidiv); op_arith(L, luaV_idiv, luai_numidiv);
vmbreak; vmbreak;
} }
@@ -1478,6 +1511,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_MMBIN) { vmcase(OP_MMBIN) {
StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */ Instruction pi = *(pc - 2); /* original arith. expression */
TValue *rb = vRB(i); TValue *rb = vRB(i);
TMS tm = (TMS)GETARG_C(i); TMS tm = (TMS)GETARG_C(i);
@@ -1487,6 +1521,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_MMBINI) { vmcase(OP_MMBINI) {
StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */ Instruction pi = *(pc - 2); /* original arith. expression */
int imm = GETARG_sB(i); int imm = GETARG_sB(i);
TMS tm = (TMS)GETARG_C(i); TMS tm = (TMS)GETARG_C(i);
@@ -1496,6 +1531,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_MMBINK) { vmcase(OP_MMBINK) {
StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */ Instruction pi = *(pc - 2); /* original arith. expression */
TValue *imm = KB(i); TValue *imm = KB(i);
TMS tm = (TMS)GETARG_C(i); TMS tm = (TMS)GETARG_C(i);
@@ -1505,6 +1541,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_UNM) { vmcase(OP_UNM) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
lua_Number nb; lua_Number nb;
if (ttisinteger(rb)) { if (ttisinteger(rb)) {
@@ -1519,6 +1556,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_BNOT) { vmcase(OP_BNOT) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
lua_Integer ib; lua_Integer ib;
if (tointegerns(rb, &ib)) { if (tointegerns(rb, &ib)) {
@@ -1529,6 +1567,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_NOT) { vmcase(OP_NOT) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
if (l_isfalse(rb)) if (l_isfalse(rb))
setbtvalue(s2v(ra)); setbtvalue(s2v(ra));
@@ -1537,21 +1576,25 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_LEN) { vmcase(OP_LEN) {
StkId ra = RA(i);
Protect(luaV_objlen(L, ra, vRB(i))); Protect(luaV_objlen(L, ra, vRB(i)));
vmbreak; vmbreak;
} }
vmcase(OP_CONCAT) { vmcase(OP_CONCAT) {
StkId ra = RA(i);
int n = GETARG_B(i); /* number of elements to concatenate */ int n = GETARG_B(i); /* number of elements to concatenate */
L->top = ra + n; /* mark the end of concat operands */ L->top.p = ra + n; /* mark the end of concat operands */
ProtectNT(luaV_concat(L, n)); ProtectNT(luaV_concat(L, n));
checkGC(L, L->top); /* 'luaV_concat' ensures correct top */ checkGC(L, L->top.p); /* 'luaV_concat' ensures correct top */
vmbreak; vmbreak;
} }
vmcase(OP_CLOSE) { vmcase(OP_CLOSE) {
StkId ra = RA(i);
Protect(luaF_close(L, ra, LUA_OK, 1)); Protect(luaF_close(L, ra, LUA_OK, 1));
vmbreak; vmbreak;
} }
vmcase(OP_TBC) { vmcase(OP_TBC) {
StkId ra = RA(i);
/* create new to-be-closed upvalue */ /* create new to-be-closed upvalue */
halfProtect(luaF_newtbcupval(L, ra)); halfProtect(luaF_newtbcupval(L, ra));
vmbreak; vmbreak;
@@ -1561,6 +1604,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_EQ) { vmcase(OP_EQ) {
StkId ra = RA(i);
int cond; int cond;
TValue *rb = vRB(i); TValue *rb = vRB(i);
Protect(cond = luaV_equalobj(L, s2v(ra), rb)); Protect(cond = luaV_equalobj(L, s2v(ra), rb));
@@ -1576,6 +1620,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_EQK) { vmcase(OP_EQK) {
StkId ra = RA(i);
TValue *rb = KB(i); TValue *rb = KB(i);
/* basic types do not use '__eq'; we can use raw equality */ /* basic types do not use '__eq'; we can use raw equality */
int cond = luaV_rawequalobj(s2v(ra), rb); int cond = luaV_rawequalobj(s2v(ra), rb);
@@ -1583,6 +1628,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_EQI) { vmcase(OP_EQI) {
StkId ra = RA(i);
int cond; int cond;
int im = GETARG_sB(i); int im = GETARG_sB(i);
if (ttisinteger(s2v(ra))) if (ttisinteger(s2v(ra)))
@@ -1611,11 +1657,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_TEST) { vmcase(OP_TEST) {
StkId ra = RA(i);
int cond = !l_isfalse(s2v(ra)); int cond = !l_isfalse(s2v(ra));
docondjump(); docondjump();
vmbreak; vmbreak;
} }
vmcase(OP_TESTSET) { vmcase(OP_TESTSET) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
if (l_isfalse(rb) == GETARG_k(i)) if (l_isfalse(rb) == GETARG_k(i))
pc++; pc++;
@@ -1626,11 +1674,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_CALL) { vmcase(OP_CALL) {
StkId ra = RA(i);
CallInfo *newci; CallInfo *newci;
int b = GETARG_B(i); int b = GETARG_B(i);
int nresults = GETARG_C(i) - 1; int nresults = GETARG_C(i) - 1;
if (b != 0) /* fixed number of arguments? */ if (b != 0) /* fixed number of arguments? */
L->top = ra + b; /* top signals number of arguments */ L->top.p = ra + b; /* top signals number of arguments */
/* else previous instruction set top */ /* else previous instruction set top */
savepc(L); /* in case of errors */ savepc(L); /* in case of errors */
if ((newci = luaD_precall(L, ra, nresults)) == NULL) if ((newci = luaD_precall(L, ra, nresults)) == NULL)
@@ -1642,54 +1691,57 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_TAILCALL) { vmcase(OP_TAILCALL) {
StkId ra = RA(i);
int b = GETARG_B(i); /* number of arguments + 1 (function) */ int b = GETARG_B(i); /* number of arguments + 1 (function) */
int n; /* number of results when calling a C function */ int n; /* number of results when calling a C function */
int nparams1 = GETARG_C(i); int nparams1 = GETARG_C(i);
/* delta is virtual 'func' - real 'func' (vararg functions) */ /* delta is virtual 'func' - real 'func' (vararg functions) */
int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0; int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
if (b != 0) if (b != 0)
L->top = ra + b; L->top.p = ra + b;
else /* previous instruction set top */ else /* previous instruction set top */
b = cast_int(L->top - ra); b = cast_int(L->top.p - ra);
savepc(ci); /* several calls here can raise errors */ savepc(ci); /* several calls here can raise errors */
if (TESTARG_k(i)) { if (TESTARG_k(i)) {
luaF_closeupval(L, base); /* close upvalues from current call */ luaF_closeupval(L, base); /* close upvalues from current call */
lua_assert(L->tbclist < base); /* no pending tbc variables */ lua_assert(L->tbclist.p < base); /* no pending tbc variables */
lua_assert(base == ci->func + 1); lua_assert(base == ci->func.p + 1);
} }
if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */ if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */
goto startfunc; /* execute the callee */ goto startfunc; /* execute the callee */
else { /* C function? */ else { /* C function? */
ci->func -= delta; /* restore 'func' (if vararg) */ ci->func.p -= delta; /* restore 'func' (if vararg) */
luaD_poscall(L, ci, n); /* finish caller */ luaD_poscall(L, ci, n); /* finish caller */
updatetrap(ci); /* 'luaD_poscall' can change hooks */ updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret; /* caller returns after the tail call */ goto ret; /* caller returns after the tail call */
} }
} }
vmcase(OP_RETURN) { vmcase(OP_RETURN) {
StkId ra = RA(i);
int n = GETARG_B(i) - 1; /* number of results */ int n = GETARG_B(i) - 1; /* number of results */
int nparams1 = GETARG_C(i); int nparams1 = GETARG_C(i);
if (n < 0) /* not fixed? */ if (n < 0) /* not fixed? */
n = cast_int(L->top - ra); /* get what is available */ n = cast_int(L->top.p - ra); /* get what is available */
savepc(ci); savepc(ci);
if (TESTARG_k(i)) { /* may there be open upvalues? */ if (TESTARG_k(i)) { /* may there be open upvalues? */
ci->u2.nres = n; /* save number of returns */ ci->u2.nres = n; /* save number of returns */
if (L->top < ci->top) if (L->top.p < ci->top.p)
L->top = ci->top; L->top.p = ci->top.p;
luaF_close(L, base, CLOSEKTOP, 1); luaF_close(L, base, CLOSEKTOP, 1);
updatetrap(ci); updatetrap(ci);
updatestack(ci); updatestack(ci);
} }
if (nparams1) /* vararg function? */ if (nparams1) /* vararg function? */
ci->func -= ci->u.l.nextraargs + nparams1; ci->func.p -= ci->u.l.nextraargs + nparams1;
L->top = ra + n; /* set call for 'luaD_poscall' */ L->top.p = ra + n; /* set call for 'luaD_poscall' */
luaD_poscall(L, ci, n); luaD_poscall(L, ci, n);
updatetrap(ci); /* 'luaD_poscall' can change hooks */ updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret; goto ret;
} }
vmcase(OP_RETURN0) { vmcase(OP_RETURN0) {
if (l_unlikely(L->hookmask)) { if (l_unlikely(L->hookmask)) {
L->top = ra; StkId ra = RA(i);
L->top.p = ra;
savepc(ci); savepc(ci);
luaD_poscall(L, ci, 0); /* no hurry... */ luaD_poscall(L, ci, 0); /* no hurry... */
trap = 1; trap = 1;
@@ -1697,15 +1749,16 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
else { /* do the 'poscall' here */ else { /* do the 'poscall' here */
int nres; int nres;
L->ci = ci->previous; /* back to caller */ L->ci = ci->previous; /* back to caller */
L->top = base - 1; L->top.p = base - 1;
for (nres = ci->nresults; l_unlikely(nres > 0); nres--) for (nres = ci->nresults; l_unlikely(nres > 0); nres--)
setnilvalue(s2v(L->top++)); /* all results are nil */ setnilvalue(s2v(L->top.p++)); /* all results are nil */
} }
goto ret; goto ret;
} }
vmcase(OP_RETURN1) { vmcase(OP_RETURN1) {
if (l_unlikely(L->hookmask)) { if (l_unlikely(L->hookmask)) {
L->top = ra + 1; StkId ra = RA(i);
L->top.p = ra + 1;
savepc(ci); savepc(ci);
luaD_poscall(L, ci, 1); /* no hurry... */ luaD_poscall(L, ci, 1); /* no hurry... */
trap = 1; trap = 1;
@@ -1714,12 +1767,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
int nres = ci->nresults; int nres = ci->nresults;
L->ci = ci->previous; /* back to caller */ L->ci = ci->previous; /* back to caller */
if (nres == 0) if (nres == 0)
L->top = base - 1; /* asked for no results */ L->top.p = base - 1; /* asked for no results */
else { else {
StkId ra = RA(i);
setobjs2s(L, base - 1, ra); /* at least this result */ setobjs2s(L, base - 1, ra); /* at least this result */
L->top = base; L->top.p = base;
for (; l_unlikely(nres > 1); nres--) for (; l_unlikely(nres > 1); nres--)
setnilvalue(s2v(L->top++)); /* complete missing results */ setnilvalue(s2v(L->top.p++)); /* complete missing results */
} }
} }
ret: /* return from a Lua function */ ret: /* return from a Lua function */
@@ -1731,6 +1785,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
} }
} }
vmcase(OP_FORLOOP) { vmcase(OP_FORLOOP) {
StkId ra = RA(i);
if (ttisinteger(s2v(ra + 2))) { /* integer loop? */ if (ttisinteger(s2v(ra + 2))) { /* integer loop? */
lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1))); lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1)));
if (count > 0) { /* still more iterations? */ if (count > 0) { /* still more iterations? */
@@ -1749,12 +1804,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_FORPREP) { vmcase(OP_FORPREP) {
StkId ra = RA(i);
savestate(L, ci); /* in case of errors */ savestate(L, ci); /* in case of errors */
if (forprep(L, ra)) if (forprep(L, ra))
pc += GETARG_Bx(i) + 1; /* skip the loop */ pc += GETARG_Bx(i) + 1; /* skip the loop */
vmbreak; vmbreak;
} }
vmcase(OP_TFORPREP) { vmcase(OP_TFORPREP) {
StkId ra = RA(i);
/* create to-be-closed upvalue (if needed) */ /* create to-be-closed upvalue (if needed) */
halfProtect(luaF_newtbcupval(L, ra + 3)); halfProtect(luaF_newtbcupval(L, ra + 3));
pc += GETARG_Bx(i); pc += GETARG_Bx(i);
@@ -1763,7 +1820,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
goto l_tforcall; goto l_tforcall;
} }
vmcase(OP_TFORCALL) { vmcase(OP_TFORCALL) {
l_tforcall: l_tforcall: {
StkId ra = RA(i);
/* 'ra' has the iterator function, 'ra + 1' has the state, /* 'ra' has the iterator function, 'ra + 1' has the state,
'ra + 2' has the control variable, and 'ra + 3' has the 'ra + 2' has the control variable, and 'ra + 3' has the
to-be-closed variable. The call will use the stack after to-be-closed variable. The call will use the stack after
@@ -1771,29 +1829,31 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
*/ */
/* push function, state, and control variable */ /* push function, state, and control variable */
memcpy(ra + 4, ra, 3 * sizeof(*ra)); memcpy(ra + 4, ra, 3 * sizeof(*ra));
L->top = ra + 4 + 3; L->top.p = ra + 4 + 3;
ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */ ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */
updatestack(ci); /* stack may have changed */ updatestack(ci); /* stack may have changed */
i = *(pc++); /* go to next instruction */ i = *(pc++); /* go to next instruction */
lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i)); lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));
goto l_tforloop; goto l_tforloop;
} }}
vmcase(OP_TFORLOOP) { vmcase(OP_TFORLOOP) {
l_tforloop: l_tforloop: {
StkId ra = RA(i);
if (!ttisnil(s2v(ra + 4))) { /* continue loop? */ if (!ttisnil(s2v(ra + 4))) { /* continue loop? */
setobjs2s(L, ra + 2, ra + 4); /* save control variable */ setobjs2s(L, ra + 2, ra + 4); /* save control variable */
pc -= GETARG_Bx(i); /* jump back */ pc -= GETARG_Bx(i); /* jump back */
} }
vmbreak; vmbreak;
} }}
vmcase(OP_SETLIST) { vmcase(OP_SETLIST) {
StkId ra = RA(i);
int n = GETARG_B(i); int n = GETARG_B(i);
unsigned int last = GETARG_C(i); unsigned int last = GETARG_C(i);
Table *h = hvalue(s2v(ra)); Table *h = hvalue(s2v(ra));
if (n == 0) if (n == 0)
n = cast_int(L->top - ra) - 1; /* get up to the top */ n = cast_int(L->top.p - ra) - 1; /* get up to the top */
else else
L->top = ci->top; /* correct top in case of emergency GC */ L->top.p = ci->top.p; /* correct top in case of emergency GC */
last += n; last += n;
if (TESTARG_k(i)) { if (TESTARG_k(i)) {
last += GETARG_Ax(*pc) * (MAXARG_C + 1); last += GETARG_Ax(*pc) * (MAXARG_C + 1);
@@ -1810,12 +1870,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_CLOSURE) { vmcase(OP_CLOSURE) {
StkId ra = RA(i);
Proto *p = cl->p->p[GETARG_Bx(i)]; Proto *p = cl->p->p[GETARG_Bx(i)];
halfProtect(pushclosure(L, p, cl->upvals, base, ra)); halfProtect(pushclosure(L, p, cl->upvals, base, ra));
checkGC(L, ra + 1); checkGC(L, ra + 1);
vmbreak; vmbreak;
} }
vmcase(OP_VARARG) { vmcase(OP_VARARG) {
StkId ra = RA(i);
int n = GETARG_C(i) - 1; /* required results */ int n = GETARG_C(i) - 1; /* required results */
Protect(luaT_getvarargs(L, ci, ra, n)); Protect(luaT_getvarargs(L, ci, ra, n));
vmbreak; vmbreak;
+5
View File
@@ -110,6 +110,11 @@ typedef enum {
luaC_barrierback(L, gcvalue(t), v); } luaC_barrierback(L, gcvalue(t), v); }
/*
** Shift right is the same as shift left with a negative 'y'
*/
#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
+7 -3
View File
@@ -8,7 +8,6 @@ CWARNSCPP= \
-Wfatal-errors \ -Wfatal-errors \
-Wextra \ -Wextra \
-Wshadow \ -Wshadow \
-Wsign-compare \
-Wundef \ -Wundef \
-Wwrite-strings \ -Wwrite-strings \
-Wredundant-decls \ -Wredundant-decls \
@@ -57,8 +56,13 @@ CWARNS= $(CWARNSCPP) $(CWARNSC) $(CWARNGCC)
# -pg -malign-double # -pg -malign-double
# -DLUA_USE_CTYPE -DLUA_USE_APICHECK # -DLUA_USE_CTYPE -DLUA_USE_APICHECK
# ('-ftrapv' for runtime checks of integer overflows)
# -fsanitize=undefined -ftrapv -fno-inline # The following options help detect "undefined behavior"s that seldom
# create problems; some are only available in newer gcc versions. To
# use some of them, we also have to define an environment variable
# ASAN_OPTIONS="detect_invalid_pointer_pairs=2".
# -fsanitize=undefined
# -fsanitize=pointer-subtract -fsanitize=address -fsanitize=pointer-compare
# TESTS= -DLUA_USER_H='"ltests.h"' -O0 -g # TESTS= -DLUA_USER_H='"ltests.h"' -O0 -g
+1 -1
View File
@@ -30,7 +30,7 @@ by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
<p> <p>
<small> <small>
<a href="http://www.lua.org/copyright.html">Copyright</a> <a href="http://www.lua.org/copyright.html">Copyright</a>
&copy; 2022 Lua.org, PUC-Rio. All rights reserved. &copy; 2025 Lua.org, PUC-Rio. All rights reserved.
</small> </small>
<hr> <hr>
+195 -111
View File
@@ -20,7 +20,7 @@ making it ideal for configuration, scripting,
and rapid prototyping. and rapid prototyping.
Lua is implemented as a library, written in @emphx{clean C}, Lua is implemented as a library, written in @emphx{clean C},
the common subset of @N{Standard C} and C++. the common subset of @N{standard C} and C++.
The Lua distribution includes a host program called @id{lua}, The Lua distribution includes a host program called @id{lua},
which uses the Lua library to offer a complete, which uses the Lua library to offer a complete,
standalone Lua interpreter, standalone Lua interpreter,
@@ -289,7 +289,7 @@ Whenever there is an error,
an @def{error object} an @def{error object}
is propagated with information about the error. is propagated with information about the error.
Lua itself only generates errors whose error object is a string, Lua itself only generates errors whose error object is a string,
but programs may generate errors with but programs can generate errors with
any value as the error object. any value as the error object.
It is up to the Lua program or its host to handle such error objects. It is up to the Lua program or its host to handle such error objects.
For historical reasons, For historical reasons,
@@ -298,7 +298,7 @@ even though it does not have to be a string.
When you use @Lid{xpcall} (or @Lid{lua_pcall}, in C) When you use @Lid{xpcall} (or @Lid{lua_pcall}, in C)
you may give a @def{message handler} you can give a @def{message handler}
to be called in case of errors. to be called in case of errors.
This function is called with the original error object This function is called with the original error object
and returns a new error object. and returns a new error object.
@@ -343,7 +343,7 @@ which is then called a @def{metamethod}.
In the previous example, the key is the string @St{__add} In the previous example, the key is the string @St{__add}
and the metamethod is the function that performs the addition. and the metamethod is the function that performs the addition.
Unless stated otherwise, Unless stated otherwise,
a metamethod may in fact be any @x{callable value}, a metamethod can in fact be any @x{callable value},
which is either a function or a value with a @idx{__call} metamethod. which is either a function or a value with a @idx{__call} metamethod.
You can query the metatable of any value You can query the metatable of any value
@@ -1144,7 +1144,9 @@ Lua also accepts @x{hexadecimal constants},
which start with @T{0x} or @T{0X}. which start with @T{0x} or @T{0X}.
Hexadecimal constants also accept an optional fractional part Hexadecimal constants also accept an optional fractional part
plus an optional binary exponent, plus an optional binary exponent,
marked by a letter @Char{p} or @Char{P}. marked by a letter @Char{p} or @Char{P} and written in decimal.
(For instance, @T{0x1.fp10} denotes 1984,
which is @M{0x1f / 16} multiplied by @M{2@sp{10}}.)
A numeric constant with a radix point or an exponent A numeric constant with a radix point or an exponent
denotes a float; denotes a float;
@@ -1333,19 +1335,11 @@ Expressions are discussed in @See{expressions}.
Before the assignment, Before the assignment,
the list of values is @emph{adjusted} to the length of the list of values is @emph{adjusted} to the length of
the list of variables.@index{adjustment} the list of variables @see{multires}.
If there are more values than needed,
the excess values are thrown away.
If there are fewer values than needed,
the list is extended with @nil's.
If the list of expressions ends with a function call,
then all values returned by that call enter the list of values,
before the adjustment
(except when the call is enclosed in parentheses; see @See{expressions}).
If a variable is both assigned and read If a variable is both assigned and read
inside a multiple assignment, inside a multiple assignment,
Lua ensures all reads get the value of the variable Lua ensures that all reads get the value of the variable
before the assignment. before the assignment.
Thus the code Thus the code
@verbatim{ @verbatim{
@@ -1423,15 +1417,12 @@ labels in Lua are considered statements too:
A label is visible in the entire block where it is defined, A label is visible in the entire block where it is defined,
except inside nested functions. except inside nested functions.
A goto may jump to any visible label as long as it does not A goto can jump to any visible label as long as it does not
enter into the scope of a local variable. enter into the scope of a local variable.
A label should not be declared A label should not be declared
where a label with the same name is visible, where a label with the same name is visible,
even if this other label has been declared in an enclosing block. even if this other label has been declared in an enclosing block.
Labels and empty statements are called @def{void statements},
as they perform no actions.
The @Rw{break} statement terminates the execution of a The @Rw{break} statement terminates the execution of a
@Rw{while}, @Rw{repeat}, or @Rw{for} loop, @Rw{while}, @Rw{repeat}, or @Rw{for} loop,
skipping to the next statement after the loop: skipping to the next statement after the loop:
@@ -1684,9 +1675,10 @@ function calls are explained in @See{functioncall};
table constructors are explained in @See{tableconstructor}. table constructors are explained in @See{tableconstructor}.
Vararg expressions, Vararg expressions,
denoted by three dots (@Char{...}), can only be used when denoted by three dots (@Char{...}), can only be used when
directly inside a vararg function; directly inside a variadic function;
they are explained in @See{func-def}. they are explained in @See{func-def}.
Binary operators comprise arithmetic operators @see{arith}, Binary operators comprise arithmetic operators @see{arith},
bitwise operators @see{bitwise}, bitwise operators @see{bitwise},
relational operators @see{rel-ops}, logical operators @see{logic}, relational operators @see{rel-ops}, logical operators @see{logic},
@@ -1696,47 +1688,8 @@ the unary bitwise NOT @see{bitwise},
the unary logical @Rw{not} @see{logic}, the unary logical @Rw{not} @see{logic},
and the unary @def{length operator} @see{len-op}. and the unary @def{length operator} @see{len-op}.
Both function calls and vararg expressions can result in multiple values.
If a function call is used as a statement @see{funcstat},
then its return list is adjusted to zero elements,
thus discarding all returned values.
If an expression is used as the last (or the only) element
of a list of expressions,
then no adjustment is made
(unless the expression is enclosed in parentheses).
In all other contexts,
Lua adjusts the result list to one element,
either discarding all values except the first one
or adding a single @nil if there are no values.
Here are some examples:
@verbatim{
f() -- adjusted to 0 results
g(f(), x) -- f() is adjusted to 1 result
g(x, f()) -- g gets x plus all results from f()
a,b,c = f(), x -- f() is adjusted to 1 result (c gets nil)
a,b = ... -- a gets the first vararg argument, b gets
-- the second (both a and b can get nil if there
-- is no corresponding vararg argument)
a,b,c = x, f() -- f() is adjusted to 2 results
a,b,c = f() -- f() is adjusted to 3 results
return f() -- returns all results from f()
return ... -- returns all received vararg arguments
return x,y,f() -- returns x, y, and all results from f()
{f()} -- creates a list with all results from f()
{...} -- creates a list with all vararg arguments
{f(), nil} -- f() is adjusted to 1 result
} }
Any expression enclosed in parentheses always results in only one value.
Thus,
@T{(f(x,y,z))} is always a single value,
even if @id{f} returns several values.
(The value of @T{(f(x,y,z))} is the first value returned by @id{f}
or @nil if @id{f} does not return any values.)
}
@sect3{arith| @title{Arithmetic Operators} @sect3{arith| @title{Arithmetic Operators}
@@ -1843,8 +1796,9 @@ the library calls the metamethod of the other operand
(if present) or it raises an error. (if present) or it raises an error.
Note that bitwise operators do not do this coercion. Note that bitwise operators do not do this coercion.
Nonetheless, it is always a good practice not to rely on these It is always a good practice not to rely on the
implicit coercions, as they are not always applied; implicit coercions from strings to numbers,
as they are not always applied;
in particular, @T{"1"==1} is false and @T{"1"<1} raises an error in particular, @T{"1"==1} is false and @T{"1"<1} raises an error
@see{rel-ops}. @see{rel-ops}.
These coercions exist mainly for compatibility and may be removed These coercions exist mainly for compatibility and may be removed
@@ -2095,9 +2049,9 @@ The order of the assignments in a constructor is undefined.
(This order would be relevant only when there are repeated keys.) (This order would be relevant only when there are repeated keys.)
If the last field in the list has the form @id{exp} If the last field in the list has the form @id{exp}
and the expression is a function call or a vararg expression, and the expression is a multires expression,
then all values returned by this expression enter the list consecutively then all values returned by this expression enter the list consecutively
@see{functioncall}. @see{multires}.
The field list can have an optional trailing separator, The field list can have an optional trailing separator,
as a convenience for machine-generated code. as a convenience for machine-generated code.
@@ -2148,7 +2102,7 @@ A call of the form @T{return @rep{functioncall}} not in the
scope of a to-be-closed variable is called a @def{tail call}. scope of a to-be-closed variable is called a @def{tail call}.
Lua implements @def{proper tail calls} Lua implements @def{proper tail calls}
(or @def{proper tail recursion}): (or @def{proper tail recursion}):
in a tail call, In a tail call,
the called function reuses the stack entry of the calling function. the called function reuses the stack entry of the calling function.
Therefore, there is no limit on the number of nested tail calls that Therefore, there is no limit on the number of nested tail calls that
a program can execute. a program can execute.
@@ -2234,22 +2188,16 @@ initialized with the argument values:
} }
When a Lua function is called, When a Lua function is called,
it adjusts its list of @x{arguments} to it adjusts its list of @x{arguments} to
the length of its list of parameters, the length of its list of parameters @see{multires},
unless the function is a @def{vararg function}, unless the function is a @def{variadic function},
which is indicated by three dots (@Char{...}) which is indicated by three dots (@Char{...})
at the end of its parameter list. at the end of its parameter list.
A vararg function does not adjust its argument list; A variadic function does not adjust its argument list;
instead, it collects all extra arguments and supplies them instead, it collects all extra arguments and supplies them
to the function through a @def{vararg expression}, to the function through a @def{vararg expression},
which is also written as three dots. which is also written as three dots.
The value of this expression is a list of all actual extra arguments, The value of this expression is a list of all actual extra arguments,
similar to a function with multiple results. similar to a function with multiple results @see{multires}.
If a vararg expression is used inside another expression
or in the middle of a list of expressions,
then its return list is adjusted to one element.
If the expression is used as the last element of a list of expressions,
then no adjustment is made
(unless that last expression is enclosed in parentheses).
As an example, consider the following definitions: As an example, consider the following definitions:
@@ -2299,6 +2247,108 @@ t.a.b.c.f = function (self, @rep{params}) @rep{body} end
} }
@sect3{multires| @title{Lists of expressions, multiple results,
and adjustment}
Both function calls and vararg expressions can result in multiple values.
These expressions are called @def{multires expressions}.
When a multires expression is used as the last element
of a list of expressions,
all results from the expression are added to the
list of values produced by the list of expressions.
Note that a single expression
in a place that expects a list of expressions
is the last expression in that (singleton) list.
These are the places where Lua expects a list of expressions:
@description{
@item{A @rw{return} statement,
for instance @T{return e1, e2, e3} @see{control}.}
@item{A table constructor,
for instance @T{{e1, e2, e3}} @see{tableconstructor}.}
@item{The arguments of a function call,
for instance @T{foo(e1, e2, e3)} @see{functioncall}.}
@item{A multiple assignment,
for instance @T{a , b, c = e1, e2, e3} @see{assignment}.}
@item{A local declaration,
for instance @T{local a , b, c = e1, e2, e3} @see{localvar}.}
@item{The initial values in a generic @rw{for} loop,
for instance @T{for k in e1, e2, e3 do ... end} @see{for}.}
}
In the last four cases,
the list of values from the list of expressions
must be @emph{adjusted} to a specific length:
the number of parameters in a call to a non-variadic function
@see{func-def},
the number of variables in a multiple assignment or
a local declaration,
and exactly four values for a generic @rw{for} loop.
The @def{adjustment} follows these rules:
If there are more values than needed,
the extra values are thrown away;
if there are fewer values than needed,
the list is extended with @nil's.
When the list of expressions ends with a multires expression,
all results from that expression enter the list of values
before the adjustment.
When a multires expression is used
in a list of expressions without being the last element,
or in a place where the syntax expects a single expression,
Lua adjusts the result list of that expression to one element.
As a particular case,
the syntax expects a single expression inside a parenthesized expression;
therefore, adding parentheses around a multires expression
forces it to produce exactly one result.
We seldom need to use a vararg expression in a place
where the syntax expects a single expression.
(Usually it is simpler to add a regular parameter before
the variadic part and use that parameter.)
When there is such a need,
we recommend assigning the vararg expression
to a single variable and using that variable
in its place.
Here are some examples of uses of mutlres expressions.
In all cases, when the construction needs
@Q{the n-th result} and there is no such result,
it uses a @nil.
@verbatim{
print(x, f()) -- prints x and all results from f().
print(x, (f())) -- prints x and the first result from f().
print(f(), x) -- prints the first result from f() and x.
print(1 + f()) -- prints 1 added to the first result from f().
local x = ... -- x gets the first vararg argument.
x,y = ... -- x gets the first vararg argument,
-- y gets the second vararg argument.
x,y,z = w, f() -- x gets w, y gets the first result from f(),
-- z gets the second result from f().
x,y,z = f() -- x gets the first result from f(),
-- y gets the second result from f(),
-- z gets the third result from f().
x,y,z = f(), g() -- x gets the first result from f(),
-- y gets the first result from g(),
-- z gets the second result from g().
x,y,z = (f()) -- x gets the first result from f(), y and z get nil.
return f() -- returns all results from f().
return x, ... -- returns x and all received vararg arguments.
return x,y,f() -- returns x, y, and all results from f().
{f()} -- creates a list with all results from f().
{...} -- creates a list with all vararg arguments.
{f(), 5} -- creates a list with the first result from f() and 5.
}
}
} }
@sect2{visibility| @title{Visibility Rules} @sect2{visibility| @title{Visibility Rules}
@@ -2308,6 +2358,7 @@ Lua is a lexically scoped language.
The scope of a local variable begins at the first statement after The scope of a local variable begins at the first statement after
its declaration and lasts until the last non-void statement its declaration and lasts until the last non-void statement
of the innermost block that includes the declaration. of the innermost block that includes the declaration.
(@emph{Void statements} are labels and empty statements.)
Consider the following example: Consider the following example:
@verbatim{ @verbatim{
x = 10 -- global variable x = 10 -- global variable
@@ -2521,7 +2572,7 @@ In general,
Lua's garbage collection can free or move internal memory Lua's garbage collection can free or move internal memory
and then invalidate pointers to internal strings. and then invalidate pointers to internal strings.
To allow a safe use of these pointers, To allow a safe use of these pointers,
The API guarantees that any pointer to a string in a stack index the API guarantees that any pointer to a string in a stack index
is valid while the string value at that index is not removed from the stack. is valid while the string value at that index is not removed from the stack.
(It can be moved to another index, though.) (It can be moved to another index, though.)
When the index is a pseudo-index (referring to an upvalue), When the index is a pseudo-index (referring to an upvalue),
@@ -2912,7 +2963,7 @@ static void *l_alloc (void *ud, void *ptr, size_t osize,
return realloc(ptr, nsize); return realloc(ptr, nsize);
} }
} }
Note that @N{Standard C} ensures Note that @N{ISO C} ensures
that @T{free(NULL)} has no effect and that that @T{free(NULL)} has no effect and that
@T{realloc(NULL,size)} is equivalent to @T{malloc(size)}. @T{realloc(NULL,size)} is equivalent to @T{malloc(size)}.
@@ -3112,8 +3163,28 @@ The index must be the last index previously marked to be closed
A @idx{__close} metamethod cannot yield A @idx{__close} metamethod cannot yield
when called through this function. when called through this function.
(Exceptionally, this function was introduced in release 5.4.3. (This function was introduced in @N{release 5.4.3}.)
It is not present in previous 5.4 releases.)
}
@APIEntry{int lua_closethread (lua_State *L, lua_State *from);|
@apii{0,?,-}
Resets a thread, cleaning its call stack and closing all pending
to-be-closed variables.
Returns a status code:
@Lid{LUA_OK} 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.
The parameter @id{from} represents the coroutine that is resetting @id{L}.
If there is no such coroutine,
this parameter can be @id{NULL}.
(This function was introduced in @N{release 5.4.6}.)
} }
@@ -3660,7 +3731,7 @@ Pops a key from the stack,
and pushes a key@En{}value pair from the table at the given index, and pushes a key@En{}value pair from the table at the given index,
the @Q{next} pair after the given key. the @Q{next} pair after the given key.
If there are no more elements in the table, If there are no more elements in the table,
then @Lid{lua_next} returns 0 and pushes nothing. then @Lid{lua_next} @N{returns 0} and pushes nothing.
A typical table traversal looks like this: A typical table traversal looks like this:
@verbatim{ @verbatim{
@@ -3981,6 +4052,7 @@ Also @N{returns 0} if any of the indices are not valid.
Similar to @Lid{lua_gettable}, but does a raw access Similar to @Lid{lua_gettable}, but does a raw access
(i.e., without metamethods). (i.e., without metamethods).
The value at @id{index} must be a table.
} }
@@ -4027,6 +4099,7 @@ For other values, this call @N{returns 0}.
Similar to @Lid{lua_settable}, but does a raw assignment Similar to @Lid{lua_settable}, but does a raw assignment
(i.e., without metamethods). (i.e., without metamethods).
The value at @id{index} must be a table.
} }
@@ -4111,15 +4184,9 @@ and then pops the top element.
@APIEntry{int lua_resetthread (lua_State *L);| @APIEntry{int lua_resetthread (lua_State *L);|
@apii{0,?,-} @apii{0,?,-}
Resets a thread, cleaning its call stack and closing all pending This function is deprecated;
to-be-closed variables. it is equivalent to @Lid{lua_closethread} with
Returns a status code: @id{from} being @id{NULL}.
@Lid{LUA_OK} 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.
} }
@@ -4349,7 +4416,7 @@ otherwise, returns @id{NULL}.
} }
@APIEntry{void lua_toclose (lua_State *L, int index);| @APIEntry{void lua_toclose (lua_State *L, int index);|
@apii{0,0,m} @apii{0,0,v}
Marks the given index in the stack as a Marks the given index in the stack as a
to-be-closed slot @see{to-be-closed}. to-be-closed slot @see{to-be-closed}.
@@ -4366,6 +4433,9 @@ A slot marked as to-be-closed should not be removed from the stack
by any other function in the API except @Lid{lua_settop} or @Lid{lua_pop}, by any other function in the API except @Lid{lua_settop} or @Lid{lua_pop},
unless previously deactivated by @Lid{lua_closeslot}. unless previously deactivated by @Lid{lua_closeslot}.
This function raises an error if the value at the given slot
neither has a @idx{__close} metamethod nor is a false value.
This function should not be called for an index This function should not be called for an index
that is equal to or below an active to-be-closed slot. that is equal to or below an active to-be-closed slot.
@@ -4419,6 +4489,10 @@ This string always has a zero (@Char{\0})
after its last character (as @N{in C}), after its last character (as @N{in C}),
but can contain other zeros in its body. but can contain other zeros in its body.
This function can raise memory errors only
when converting a number to a string
(as then it may create a new string).
} }
@APIEntry{lua_Number lua_tonumber (lua_State *L, int index);| @APIEntry{lua_Number lua_tonumber (lua_State *L, int index);|
@@ -4778,7 +4852,7 @@ the number of parameters of the function
} }
@item{@id{isvararg}| @item{@id{isvararg}|
true if the function is a vararg function true if the function is a variadic function
(always true for @N{C functions}). (always true for @N{C functions}).
} }
@@ -5347,7 +5421,7 @@ Equivalent to the sequence
@APIEntry{void luaL_buffsub (luaL_Buffer *B, int n);| @APIEntry{void luaL_buffsub (luaL_Buffer *B, int n);|
@apii{?,?,-} @apii{?,?,-}
Removes @id{n} bytes from the the buffer @id{B} Removes @id{n} bytes from the buffer @id{B}
@seeC{luaL_Buffer}. @seeC{luaL_Buffer}.
The buffer must have at least that many bytes. The buffer must have at least that many bytes.
@@ -5484,8 +5558,8 @@ It is defined as the following macro:
@verbatim{ @verbatim{
(luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0)) (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))
} }
It returns @Lid{LUA_OK} if there are no errors, It @N{returns 0} (@Lid{LUA_OK}) if there are no errors,
or an error code in case of errors @see{statuscodes}. or 1 in case of errors.
} }
@@ -5497,8 +5571,8 @@ It is defined as the following macro:
@verbatim{ @verbatim{
(luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0)) (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))
} }
It returns @Lid{LUA_OK} if there are no errors, It @N{returns 0} (@Lid{LUA_OK}) if there are no errors,
or an error code in case of errors @see{statuscodes}. or 1 in case of errors.
} }
@@ -5723,7 +5797,7 @@ with @id{tname} in the registry.
Creates a new Lua state. Creates a new Lua state.
It calls @Lid{lua_newstate} with an It calls @Lid{lua_newstate} with an
allocator based on the @N{standard C} allocation functions allocator based on the @N{ISO C} allocation functions
and then sets a warning function and a panic function @see{C-error} and then sets a warning function and a panic function @see{C-error}
that print messages to the standard error output. that print messages to the standard error output.
@@ -6015,9 +6089,7 @@ to start the traceback.
} }
@APIEntry{const char *luaL_typeerror (lua_State *L, @APIEntry{int luaL_typeerror (lua_State *L, int arg, const char *tname);|
int arg,
const char *tname);|
@apii{0,0,v} @apii{0,0,v}
Raises a type error for the argument @id{arg} Raises a type error for the argument @id{arg}
@@ -6814,6 +6886,8 @@ When you require a module @id{modname} and
This variable is only a reference to the real table; This variable is only a reference to the real table;
assignments to this variable do not change the assignments to this variable do not change the
table used by @Lid{require}. table used by @Lid{require}.
The real table is stored in the C registry @see{registry},
indexed by the key @defid{LUA_LOADED_TABLE}, a string.
} }
@@ -6841,7 +6915,7 @@ including if necessary a path and an extension.
@id{funcname} must be the exact name exported by the @N{C library} @id{funcname} must be the exact name exported by the @N{C library}
(which may depend on the @N{C compiler} and linker used). (which may depend on the @N{C compiler} and linker used).
This function is not supported by @N{Standard C}. This functionality is not supported by @N{ISO C}.
As such, it is only available on some platforms As such, it is only available on some platforms
(Windows, Linux, Mac OS X, Solaris, BSD, (Windows, Linux, Mac OS X, Solaris, BSD,
plus other Unix systems that support the @id{dlfcn} standard). plus other Unix systems that support the @id{dlfcn} standard).
@@ -6881,6 +6955,8 @@ A table to store loaders for specific modules
This variable is only a reference to the real table; This variable is only a reference to the real table;
assignments to this variable do not change the assignments to this variable do not change the
table used by @Lid{require}. table used by @Lid{require}.
The real table is stored in the C registry @see{registry},
indexed by the key @defid{LUA_PRELOAD_TABLE}, a string.
} }
@@ -7280,7 +7356,7 @@ according to the format string @id{fmt} @see{pack}.
@LibEntry{string.packsize (fmt)| @LibEntry{string.packsize (fmt)|
Returns the size of a string resulting from @Lid{string.pack} Returns the length of a string resulting from @Lid{string.pack}
with the given format. with the given format.
The format string cannot have the variable-length options The format string cannot have the variable-length options
@Char{s} or @Char{z} @see{pack}. @Char{s} or @Char{z} @see{pack}.
@@ -7902,9 +7978,9 @@ Returns the arc sine of @id{x} (in radians).
@LibEntry{math.atan (y [, x])| @LibEntry{math.atan (y [, x])|
@index{atan2} @index{atan} @index{atan2}
Returns the arc tangent of @T{y/x} (in radians), Returns the arc tangent of @T{y/x} (in radians),
but uses the signs of both arguments to find the using the signs of both arguments to find the
quadrant of the result. quadrant of the result.
It also handles correctly the case of @id{x} being zero. It also handles correctly the case of @id{x} being zero.
@@ -8520,7 +8596,7 @@ the returned status is this number.
The default value for @id{code} is @true. The default value for @id{code} is @true.
If the optional second argument @id{close} is true, If the optional second argument @id{close} is true,
closes the Lua state before exiting. the function closes the Lua state before exiting @seeF{lua_close}.
} }
@@ -8700,13 +8776,13 @@ The returned table can contain all the fields returned by @Lid{lua_getinfo},
with the string @id{what} describing which fields to fill in. with the string @id{what} describing which fields to fill in.
The default for @id{what} is to get all information available, The default for @id{what} is to get all information available,
except the table of valid lines. except the table of valid lines.
If present, The option @Char{f}
the option @Char{f}
adds a field named @id{func} with the function itself. adds a field named @id{func} with the function itself.
If present, The option @Char{L} adds a field named @id{activelines}
the option @Char{L} with the table of valid lines,
adds a field named @id{activelines} with the table of provided the function is a Lua function.
valid lines. If the function has no debug information,
the table is empty.
For instance, the expression @T{debug.getinfo(1,"n").name} returns For instance, the expression @T{debug.getinfo(1,"n").name} returns
a name for the current function, a name for the current function,
@@ -8928,12 +9004,16 @@ The options are:
@item{@T{-i}| enter interactive mode after running @rep{script};} @item{@T{-i}| enter interactive mode after running @rep{script};}
@item{@T{-l @rep{mod}}| @Q{require} @rep{mod} and assign the @item{@T{-l @rep{mod}}| @Q{require} @rep{mod} and assign the
result to global @rep{mod};} result to global @rep{mod};}
@item{@T{-l @rep{g=mod}}| @Q{require} @rep{mod} and assign the
result to global @rep{g};}
@item{@T{-v}| print version information;} @item{@T{-v}| print version information;}
@item{@T{-E}| ignore environment variables;} @item{@T{-E}| ignore environment variables;}
@item{@T{-W}| turn warnings on;} @item{@T{-W}| turn warnings on;}
@item{@T{--}| stop handling options;} @item{@T{--}| stop handling options;}
@item{@T{-}| execute @id{stdin} as a file and stop handling options.} @item{@T{-}| execute @id{stdin} as a file and stop handling options.}
} }
(The form @T{-l @rep{g=mod}} was introduced in @N{release 5.4.4}.)
After handling its options, @id{lua} runs the given @emph{script}. After handling its options, @id{lua} runs the given @emph{script}.
When called without arguments, When called without arguments,
@id{lua} behaves as @T{lua -v -i} @id{lua} behaves as @T{lua -v -i}
@@ -8953,6 +9033,10 @@ Lua does not consult any environment variables.
In particular, In particular,
the values of @Lid{package.path} and @Lid{package.cpath} the values of @Lid{package.path} and @Lid{package.cpath}
are set with the default paths defined in @id{luaconf.h}. are set with the default paths defined in @id{luaconf.h}.
To signal to the libraries that this option is on,
the stand-alone interpreter sets the field
@idx{"LUA_NOENV"} in the registry to a true value.
Other libraries may consult this field for the same purpose.
The options @T{-e}, @T{-l}, and @T{-W} are handled in The options @T{-e}, @T{-l}, and @T{-W} are handled in
the order they appear. the order they appear.
@@ -8995,7 +9079,7 @@ If there is a script,
the script is called with arguments the script is called with arguments
@T{arg[1]}, @Cdots, @T{arg[#arg]}. @T{arg[1]}, @Cdots, @T{arg[#arg]}.
Like all chunks in Lua, Like all chunks in Lua,
the script is compiled as a vararg function. the script is compiled as a variadic function.
In interactive mode, In interactive mode,
Lua repeatedly prompts and waits for a line. Lua repeatedly prompts and waits for a line.
+17 -3
View File
@@ -1,5 +1,14 @@
/* /*
* one.c -- Lua core, libraries, and interpreter in a single file ** Lua core, libraries, and interpreter in a single file.
** Compiling just this file generates a complete Lua stand-alone
** program:
**
** $ gcc -O2 -std=c99 -o lua onelua.c -lm
**
** or
**
** $ gcc -O2 -std=c89 -DLUA_USE_C89 -o lua onelua.c -lm
**
*/ */
/* default is to build the full interpreter */ /* default is to build the full interpreter */
@@ -11,8 +20,12 @@
#endif #endif
#endif #endif
/* choose suitable platform-specific features */
/* some of these may need extra libraries such as -ldl -lreadline -lncurses */ /*
** Choose suitable platform-specific features. Default is no
** platform-specific features. Some of these options may need extra
** libraries such as -ldl -lreadline -lncurses
*/
#if 0 #if 0
#define LUA_USE_LINUX #define LUA_USE_LINUX
#define LUA_USE_MACOSX #define LUA_USE_MACOSX
@@ -20,6 +33,7 @@
#define LUA_ANSI #define LUA_ANSI
#endif #endif
/* no need to change anything below this line ----------------------------- */ /* no need to change anything below this line ----------------------------- */
#include "lprefix.h" #include "lprefix.h"
+2 -1
View File
@@ -163,6 +163,7 @@ f()
dofile('db.lua') dofile('db.lua')
assert(dofile('calls.lua') == deep and deep) assert(dofile('calls.lua') == deep and deep)
_G.deep = nil
olddofile('strings.lua') olddofile('strings.lua')
olddofile('literals.lua') olddofile('literals.lua')
dofile('tpack.lua') dofile('tpack.lua')
@@ -286,7 +287,7 @@ print("final OK !!!")
--[[ --[[
***************************************************************************** *****************************************************************************
* Copyright (C) 1994-2016 Lua.org, PUC-Rio. * Copyright (C) 1994-2025 Lua.org, PUC-Rio.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
+65 -51
View File
@@ -14,7 +14,7 @@ local pack = table.pack
-- standard error message for memory errors -- standard error message for memory errors
local MEMERRMSG = "not enough memory" local MEMERRMSG = "not enough memory"
function tcheck (t1, t2) local function tcheck (t1, t2)
assert(t1.n == (t2.n or #t2) + 1) assert(t1.n == (t2.n or #t2) + 1)
for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end
end end
@@ -28,7 +28,7 @@ end
print('testing C API') print('testing C API')
a = T.testC("pushvalue R; return 1") local a = T.testC("pushvalue R; return 1")
assert(a == debug.getregistry()) assert(a == debug.getregistry())
@@ -43,10 +43,10 @@ a = T.d2s(12458954321123.0)
assert(a == string.pack("d", 12458954321123.0)) assert(a == string.pack("d", 12458954321123.0))
assert(T.s2d(a) == 12458954321123.0) assert(T.s2d(a) == 12458954321123.0)
a,b,c = T.testC("pushnum 1; pushnum 2; pushnum 3; return 2") local a,b,c = T.testC("pushnum 1; pushnum 2; pushnum 3; return 2")
assert(a == 2 and b == 3 and not c) assert(a == 2 and b == 3 and not c)
f = T.makeCfunc("pushnum 1; pushnum 2; pushnum 3; return 2") local f = T.makeCfunc("pushnum 1; pushnum 2; pushnum 3; return 2")
a,b,c = f() a,b,c = f()
assert(a == 2 and b == 3 and not c) assert(a == 2 and b == 3 and not c)
@@ -61,7 +61,7 @@ assert(a==false and b==true and c==false)
a,b,c = T.testC("gettop; return 2", 10, 20, 30, 40) a,b,c = T.testC("gettop; return 2", 10, 20, 30, 40)
assert(a == 40 and b == 5 and not c) assert(a == 40 and b == 5 and not c)
t = pack(T.testC("settop 5; return *", 2, 3)) local t = pack(T.testC("settop 5; return *", 2, 3))
tcheck(t, {n=4,2,3}) tcheck(t, {n=4,2,3})
t = pack(T.testC("settop 0; settop 15; return 10", 3, 1, 23)) t = pack(T.testC("settop 0; settop 15; return 10", 3, 1, 23))
@@ -166,16 +166,17 @@ end
-- testing globals -- testing globals
_G.a = 14; _G.b = "a31" _G.AA = 14; _G.BB = "a31"
local a = {T.testC[[ local a = {T.testC[[
getglobal a; getglobal AA;
getglobal b; getglobal BB;
getglobal b; getglobal BB;
setglobal a; setglobal AA;
return * return *
]]} ]]}
assert(a[2] == 14 and a[3] == "a31" and a[4] == nil and _G.a == "a31") assert(a[2] == 14 and a[3] == "a31" and a[4] == nil and _G.AA == "a31")
_G.AA, _G.BB = nil
-- testing arith -- testing arith
assert(T.testC("pushnum 10; pushnum 20; arith /; return 1") == 0.5) assert(T.testC("pushnum 10; pushnum 20; arith /; return 1") == 0.5)
@@ -199,13 +200,14 @@ a,b,c = T.testC([[pushnum 1;
pushstring 10; arith _; pushstring 10; arith _;
pushstring 5; return 3]]) pushstring 5; return 3]])
assert(a == 1 and b == -10 and c == "5") assert(a == 1 and b == -10 and c == "5")
mt = {__add = function (a,b) return setmetatable({a[1] + b[1]}, mt) end, local mt = {
__add = function (a,b) return setmetatable({a[1] + b[1]}, mt) end,
__mod = function (a,b) return setmetatable({a[1] % b[1]}, mt) end, __mod = function (a,b) return setmetatable({a[1] % b[1]}, mt) end,
__unm = function (a) return setmetatable({a[1]* 2}, mt) end} __unm = function (a) return setmetatable({a[1]* 2}, mt) end}
a,b,c = setmetatable({4}, mt), a,b,c = setmetatable({4}, mt),
setmetatable({8}, mt), setmetatable({8}, mt),
setmetatable({-3}, mt) setmetatable({-3}, mt)
x,y,z = T.testC("arith +; return 2", 10, a, b) local x,y,z = T.testC("arith +; return 2", 10, a, b)
assert(x == 10 and y[1] == 12 and z == nil) assert(x == 10 and y[1] == 12 and z == nil)
assert(T.testC("arith %; return 1", a, c)[1] == 4%-3) assert(T.testC("arith %; return 1", a, c)[1] == 4%-3)
assert(T.testC("arith _; arith +; arith %; return 1", b, a, c)[1] == assert(T.testC("arith _; arith +; arith %; return 1", b, a, c)[1] ==
@@ -312,9 +314,9 @@ assert(T.testC("concat 1; return 1", "xuxu") == "xuxu")
-- testing lua_is -- testing lua_is
function B(x) return x and 1 or 0 end local function B (x) return x and 1 or 0 end
function count (x, n) local function count (x, n)
n = n or 2 n = n or 2
local prog = [[ local prog = [[
isnumber %d; isnumber %d;
@@ -345,7 +347,7 @@ assert(count(nil, 15) == 100)
-- testing lua_to... -- testing lua_to...
function to (s, x, n) local function to (s, x, n)
n = n or 2 n = n or 2
return T.testC(string.format("%s %d; return 1", s, n), x) return T.testC(string.format("%s %d; return 1", s, n), x)
end end
@@ -397,6 +399,10 @@ do
-- trivial error -- trivial error
assert(T.checkpanic("pushstring hi; error") == "hi") assert(T.checkpanic("pushstring hi; error") == "hi")
-- thread status inside panic (bug in 5.4.4)
assert(T.checkpanic("pushstring hi; error", "threadstatus; return 2") ==
"ERRRUN")
-- using the stack inside panic -- using the stack inside panic
assert(T.checkpanic("pushstring hi; error;", assert(T.checkpanic("pushstring hi; error;",
[[checkstack 5 XX [[checkstack 5 XX
@@ -486,11 +492,12 @@ a = T.testC([[
pushvalue 3; insert -2; pcall 1 1 0; pushvalue 3; insert -2; pcall 1 1 0;
pcall 0 0 0; pcall 0 0 0;
return 1 return 1
]], "x=150", function (a) assert(a==nil); return 3 end) ]], "XX=150", function (a) assert(a==nil); return 3 end)
assert(type(a) == 'string' and x == 150) assert(type(a) == 'string' and XX == 150)
_G.XX = nil
function check3(p, ...) local function check3(p, ...)
local arg = {...} local arg = {...}
assert(#arg == 3) assert(#arg == 3)
assert(string.find(arg[3], p)) assert(string.find(arg[3], p))
@@ -500,7 +507,7 @@ check3("%.", T.testC("loadfile 2; return *", "."))
check3("xxxx", T.testC("loadfile 2; return *", "xxxx")) check3("xxxx", T.testC("loadfile 2; return *", "xxxx"))
-- test errors in non protected threads -- test errors in non protected threads
function checkerrnopro (code, msg) local function checkerrnopro (code, msg)
local th = coroutine.create(function () end) -- create new thread local th = coroutine.create(function () end) -- create new thread
local stt, err = pcall(T.testC, th, code) -- run code there local stt, err = pcall(T.testC, th, code) -- run code there
assert(not stt and string.find(err, msg)) assert(not stt and string.find(err, msg))
@@ -510,8 +517,9 @@ if not _soft then
collectgarbage("stop") -- avoid __gc with full stack collectgarbage("stop") -- avoid __gc with full stack
checkerrnopro("pushnum 3; call 0 0", "attempt to call") checkerrnopro("pushnum 3; call 0 0", "attempt to call")
print"testing stack overflow in unprotected thread" print"testing stack overflow in unprotected thread"
function f () f() end function F () F() end
checkerrnopro("getglobal 'f'; call 0 0;", "stack overflow") checkerrnopro("getglobal 'F'; call 0 0;", "stack overflow")
F = nil
collectgarbage("restart") collectgarbage("restart")
end end
print"+" print"+"
@@ -588,7 +596,7 @@ assert(a[a] == "x")
b = setmetatable({p = a}, {}) b = setmetatable({p = a}, {})
getmetatable(b).__index = function (t, i) return t.p[i] end getmetatable(b).__index = function (t, i) return t.p[i] end
k, x = T.testC("gettable 3, return 2", 4, b, 20, 35, "x") local k, x = T.testC("gettable 3, return 2", 4, b, 20, 35, "x")
assert(x == 15 and k == 35) assert(x == 15 and k == 35)
k = T.testC("getfield 2 y, return 1", b) k = T.testC("getfield 2 y, return 1", b)
assert(k == 12) assert(k == 12)
@@ -748,8 +756,8 @@ local i = T.ref{}
T.unref(i) T.unref(i)
assert(T.ref{} == i) assert(T.ref{} == i)
Arr = {} local Arr = {}
Lim = 100 local Lim = 100
for i=1,Lim do -- lock many objects for i=1,Lim do -- lock many objects
Arr[i] = T.ref({}) Arr[i] = T.ref({})
end end
@@ -761,7 +769,7 @@ for i=1,Lim do -- unlock all them
T.unref(Arr[i]) T.unref(Arr[i])
end end
function printlocks () local function printlocks ()
local f = T.makeCfunc("gettable R; return 1") local f = T.makeCfunc("gettable R; return 1")
local n = f("n") local n = f("n")
print("n", n) print("n", n)
@@ -793,8 +801,8 @@ assert(type(T.getref(a)) == 'table')
-- colect in cl the `val' of all collected userdata -- colect in cl the `val' of all collected userdata
tt = {} local tt = {}
cl = {n=0} local cl = {n=0}
A = nil; B = nil A = nil; B = nil
local F local F
F = function (x) F = function (x)
@@ -817,6 +825,7 @@ F = function (x)
end end
tt.__gc = F tt.__gc = F
-- test whether udate collection frees memory in the right time -- test whether udate collection frees memory in the right time
do do
collectgarbage(); collectgarbage();
@@ -853,9 +862,9 @@ end
collectgarbage("stop") collectgarbage("stop")
-- create 3 userdatas with tag `tt' -- create 3 userdatas with tag `tt'
a = T.newuserdata(0); debug.setmetatable(a, tt); na = T.udataval(a) a = T.newuserdata(0); debug.setmetatable(a, tt); local na = T.udataval(a)
b = T.newuserdata(0); debug.setmetatable(b, tt); nb = T.udataval(b) b = T.newuserdata(0); debug.setmetatable(b, tt); local nb = T.udataval(b)
c = T.newuserdata(0); debug.setmetatable(c, tt); nc = T.udataval(c) c = T.newuserdata(0); debug.setmetatable(c, tt); local nc = T.udataval(c)
-- create userdata without meta table -- create userdata without meta table
x = T.newuserdata(4) x = T.newuserdata(4)
@@ -866,9 +875,9 @@ checkerr("FILE%* expected, got userdata", io.input, x)
assert(debug.getmetatable(x) == nil and debug.getmetatable(y) == nil) assert(debug.getmetatable(x) == nil and debug.getmetatable(y) == nil)
d=T.ref(a); local d = T.ref(a);
e=T.ref(b); local e = T.ref(b);
f=T.ref(c); local f = T.ref(c);
t = {T.getref(d), T.getref(e), T.getref(f)} t = {T.getref(d), T.getref(e), T.getref(f)}
assert(t[1] == a and t[2] == b and t[3] == c) assert(t[1] == a and t[2] == b and t[3] == c)
@@ -888,7 +897,7 @@ tt=nil -- frees tt for GC
A = nil A = nil
b = nil b = nil
T.unref(d); T.unref(d);
n5 = T.newuserdata(0) local n5 = T.newuserdata(0)
debug.setmetatable(n5, {__gc=F}) debug.setmetatable(n5, {__gc=F})
n5 = T.udataval(n5) n5 = T.udataval(n5)
collectgarbage() collectgarbage()
@@ -959,11 +968,11 @@ print'+'
-- testing changing hooks during hooks -- testing changing hooks during hooks
_G.t = {} _G.TT = {}
T.sethook([[ T.sethook([[
# set a line hook after 3 count hooks # set a line hook after 3 count hooks
sethook 4 0 ' sethook 4 0 '
getglobal t; getglobal TT;
pushvalue -3; append -2 pushvalue -3; append -2
pushvalue -2; append -2 pushvalue -2; append -2
']], "c", 3) ']], "c", 3)
@@ -973,12 +982,13 @@ a = 1 -- count hook (set line hook)
a = 1 -- line hook a = 1 -- line hook
a = 1 -- line hook a = 1 -- line hook
debug.sethook() debug.sethook()
t = _G.t local t = _G.TT
assert(t[1] == "line") assert(t[1] == "line")
line = t[2] local line = t[2]
assert(t[3] == "line" and t[4] == line + 1) assert(t[3] == "line" and t[4] == line + 1)
assert(t[5] == "line" and t[6] == line + 2) assert(t[5] == "line" and t[6] == line + 2)
assert(t[7] == nil) assert(t[7] == nil)
_G.TT = nil
------------------------------------------------------------------------- -------------------------------------------------------------------------
@@ -1003,6 +1013,7 @@ do -- testing errors during GC
collectgarbage("restart") collectgarbage("restart")
warn("@on") warn("@on")
end end
_G.A = nil
------------------------------------------------------------------------- -------------------------------------------------------------------------
-- test for userdata vals -- test for userdata vals
do do
@@ -1032,8 +1043,8 @@ assert(a == 'alo' and b == '3')
T.doremote(L1, "_ERRORMESSAGE = nil") T.doremote(L1, "_ERRORMESSAGE = nil")
-- error: `sin' is not defined -- error: `sin' is not defined
a, _, b = T.doremote(L1, "return sin(1)") a, b, c = T.doremote(L1, "return sin(1)")
assert(a == nil and b == 2) -- 2 == run-time error assert(a == nil and c == 2) -- 2 == run-time error
-- error: syntax error -- error: syntax error
a, b, c = T.doremote(L1, "return a+") a, b, c = T.doremote(L1, "return a+")
@@ -1204,7 +1215,7 @@ T.alloccount() -- remove limit
-- o that we get memory errors in all allocations of a given -- o that we get memory errors in all allocations of a given
-- task, until there is enough memory to complete the task without -- task, until there is enough memory to complete the task without
-- errors. -- errors.
function testbytes (s, f) local function testbytes (s, f)
collectgarbage() collectgarbage()
local M = T.totalmem() local M = T.totalmem()
local oldM = M local oldM = M
@@ -1229,7 +1240,7 @@ end
-- task, until there is enough allocations to complete the task without -- task, until there is enough allocations to complete the task without
-- errors. -- errors.
function testalloc (s, f) local function testalloc (s, f)
collectgarbage() collectgarbage()
local M = 0 local M = 0
local a,b = nil local a,b = nil
@@ -1296,12 +1307,12 @@ end)
-- testing threads -- testing threads
-- get main thread from registry (at index LUA_RIDX_MAINTHREAD == 1) -- get main thread from registry (at index LUA_RIDX_MAINTHREAD == 1)
mt = T.testC("rawgeti R 1; return 1") local mt = T.testC("rawgeti R 1; return 1")
assert(type(mt) == "thread" and coroutine.running() == mt) assert(type(mt) == "thread" and coroutine.running() == mt)
function expand (n,s) local function expand (n,s)
if n==0 then return "" end if n==0 then return "" end
local e = string.rep("=", n) local e = string.rep("=", n)
return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n", return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n",
@@ -1311,9 +1322,10 @@ end
G=0; collectgarbage(); a =collectgarbage("count") G=0; collectgarbage(); a =collectgarbage("count")
load(expand(20,"G=G+1"))() load(expand(20,"G=G+1"))()
assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1) assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1)
G = nil
testamem("running code on new thread", function () testamem("running code on new thread", function ()
return T.doonnewstack("x=1") == 0 -- try to create thread return T.doonnewstack("local x=1") == 0 -- try to create thread
end) end)
@@ -1327,13 +1339,13 @@ end)
local testprog = [[ local testprog = [[
local function foo () return end local function foo () return end
local t = {"x"} local t = {"x"}
a = "aaa" AA = "aaa"
for i = 1, #t do a=a..t[i] end for i = 1, #t do AA = AA .. t[i] end
return true return true
]] ]]
-- testing memory x dofile -- testing memory x dofile
_G.a = nil _G.AA = nil
local t =os.tmpname() local t =os.tmpname()
local f = assert(io.open(t, "w")) local f = assert(io.open(t, "w"))
f:write(testprog) f:write(testprog)
@@ -1343,7 +1355,7 @@ testamem("dofile", function ()
return a and a() return a and a()
end) end)
assert(os.remove(t)) assert(os.remove(t))
assert(_G.a == "aaax") assert(_G.AA == "aaax")
-- other generic tests -- other generic tests
@@ -1360,6 +1372,8 @@ testamem("dump/undump", function ()
return a and a() return a and a()
end) end)
_G.AA = nil
local t = os.tmpname() local t = os.tmpname()
testamem("file creation", function () testamem("file creation", function ()
local f = assert(io.open(t, 'w')) local f = assert(io.open(t, 'w'))
@@ -1381,7 +1395,7 @@ testamem("constructors", function ()
end) end)
local a = 1 local a = 1
close = nil local close = nil
testamem("closure creation", function () testamem("closure creation", function ()
function close (b) function close (b)
return function (x) return b + x end return function (x) return b + x end
+23 -11
View File
@@ -85,7 +85,7 @@ local DIR = "libs" .. dirsep
-- prepend DIR to a name and correct directory separators -- prepend DIR to a name and correct directory separators
local function D (x) local function D (x)
x = string.gsub(x, "/", dirsep) local x = string.gsub(x, "/", dirsep)
return DIR .. x return DIR .. x
end end
@@ -106,7 +106,7 @@ local function createfiles (files, preextras, posextras)
end end
end end
function removefiles (files) local function removefiles (files)
for n in pairs(files) do for n in pairs(files) do
os.remove(D(n)) os.remove(D(n))
end end
@@ -154,10 +154,9 @@ local try = function (p, n, r, ext)
assert(ext == x) assert(ext == x)
end end
a = require"names" local a = require"names"
assert(a[1] == "names" and a[2] == D"names.lua") assert(a[1] == "names" and a[2] == D"names.lua")
_G.a = nil
local st, msg = pcall(require, "err") local st, msg = pcall(require, "err")
assert(not st and string.find(msg, "arithmetic") and B == 15) assert(not st and string.find(msg, "arithmetic") and B == 15)
st, msg = pcall(require, "synerr") st, msg = pcall(require, "synerr")
@@ -191,6 +190,7 @@ try("X", "XXxX", AA, "libs/XXxX")
removefiles(files) removefiles(files)
NAME, REQUIRED, AA, B = nil
-- testing require of sub-packages -- testing require of sub-packages
@@ -223,7 +223,7 @@ assert(require"P1" == m and m.AA == 10)
removefiles(files) removefiles(files)
AA = nil
package.path = "" package.path = ""
assert(not pcall(require, "file_does_not_exist")) assert(not pcall(require, "file_does_not_exist"))
@@ -305,6 +305,7 @@ else
assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1") assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1")
assert(string.find(ext, "libs/lib1", 1, true)) assert(string.find(ext, "libs/lib1", 1, true))
assert(fs.id(45) == 45) assert(fs.id(45) == 45)
_ENV.x, _ENV.y = nil
end end
_ENV = _G _ENV = _G
@@ -338,10 +339,10 @@ print("testing assignments, logical operators, and constructors")
local res, res2 = 27 local res, res2 = 27
a, b = 1, 2+3 local a, b = 1, 2+3
assert(a==1 and b==5) assert(a==1 and b==5)
a={} a={}
function f() return 10, 11, 12 end local function f() return 10, 11, 12 end
a.x, b, a[1] = 1, 2, f() a.x, b, a[1] = 1, 2, f()
assert(a.x==1 and b==2 and a[1]==10) assert(a.x==1 and b==2 and a[1]==10)
a[f()], b, a[f()+3] = f(), a, 'x' a[f()], b, a[f()+3] = f(), a, 'x'
@@ -353,15 +354,15 @@ do
local a,b,c local a,b,c
a,b = 0, f(1) a,b = 0, f(1)
assert(a == 0 and b == 1) assert(a == 0 and b == 1)
A,b = 0, f(1) a,b = 0, f(1)
assert(A == 0 and b == 1) assert(a == 0 and b == 1)
a,b,c = 0,5,f(4) a,b,c = 0,5,f(4)
assert(a==0 and b==5 and c==1) assert(a==0 and b==5 and c==1)
a,b,c = 0,5,f(0) a,b,c = 0,5,f(0)
assert(a==0 and b==5 and c==nil) assert(a==0 and b==5 and c==nil)
end end
a, b, c, d = 1 and nil, 1 or nil, (1 and (nil or 1)), 6 local a, b, c, d = 1 and nil, 1 or nil, (1 and (nil or 1)), 6
assert(not a and b and c and d==6) assert(not a and b and c and d==6)
d = 20 d = 20
@@ -419,6 +420,7 @@ assert(not pcall(function () local a = {[nil] = 10} end))
assert(a[nil] == undef) assert(a[nil] == undef)
a = nil a = nil
local a, b, c
a = {10,9,8,7,6,5,4,3,2; [-3]='a', [f]=print, a='a', b='ab'} a = {10,9,8,7,6,5,4,3,2; [-3]='a', [f]=print, a='a', b='ab'}
a, a.x, a.y = a, a[-3] a, a.x, a.y = a, a[-3]
assert(a[1]==10 and a[-3]==a.a and a[f]==print and a.x=='a' and not a.y) assert(a[1]==10 and a[-3]==a.a and a[f]==print and a.x=='a' and not a.y)
@@ -434,6 +436,16 @@ a.aVeryLongName012345678901234567890123456789012345678901234567890123456789 ==
10) 10)
do
-- _ENV constant
local function foo ()
local _ENV <const> = 11
X = "hi"
end
local st, msg = pcall(foo)
assert(not st and string.find(msg, "number"))
end
-- test of large float/integer indices -- test of large float/integer indices
@@ -445,7 +457,7 @@ while maxint ~= (maxint + 0.0) or (maxint - 1) ~= (maxint - 1.0) do
maxint = maxint // 2 maxint = maxint // 2
end end
maxintF = maxint + 0.0 -- float version local maxintF = maxint + 0.0 -- float version
assert(maxintF == maxint and math.type(maxintF) == "float" and assert(maxintF == maxint and math.type(maxintF) == "float" and
maxintF >= 2.0^14) maxintF >= 2.0^14)
+1 -1
View File
@@ -32,7 +32,7 @@ setmetatable(env, {
}) })
X = nil X = nil
co = coroutine.wrap(f) local co = coroutine.wrap(f)
assert(co() == 's') assert(co() == 's')
assert(co() == 'g') assert(co() == 'g')
assert(co() == 'g') assert(co() == 'g')
+12
View File
@@ -38,6 +38,18 @@ d = d << 32
assert(a | b ~ c & d == 0xF4000000 << 32) assert(a | b ~ c & d == 0xF4000000 << 32)
assert(~~a == a and ~a == -1 ~ a and -d == ~d + 1) assert(~~a == a and ~a == -1 ~ a and -d == ~d + 1)
do -- constant folding
local code = string.format("return -1 >> %d", math.maxinteger)
assert(load(code)() == 0)
local code = string.format("return -1 >> %d", math.mininteger)
assert(load(code)() == 0)
local code = string.format("return -1 << %d", math.maxinteger)
assert(load(code)() == 0)
local code = string.format("return -1 << %d", math.mininteger)
assert(load(code)() == 0)
end
assert(-1 >> 1 == (1 << (numbits - 1)) - 1 and 1 << 31 == 0x80000000) assert(-1 >> 1 == (1 << (numbits - 1)) - 1 and 1 << 31 == 0x80000000)
assert(-1 >> (numbits - 1) == 1) assert(-1 >> (numbits - 1) == 1)
assert(-1 >> numbits == 0 and assert(-1 >> numbits == 0 and
+35 -19
View File
@@ -16,7 +16,7 @@ assert(type(nil) == 'nil'
and type(type) == 'function') and type(type) == 'function')
assert(type(assert) == type(print)) assert(type(assert) == type(print))
function f (x) return a:x (x) end local function f (x) return a:x (x) end
assert(type(f) == 'function') assert(type(f) == 'function')
assert(not pcall(type)) assert(not pcall(type))
@@ -33,10 +33,11 @@ do
assert(fact(5) == 120) assert(fact(5) == 120)
end end
assert(fact == false) assert(fact == false)
fact = nil
-- testing declarations -- testing declarations
a = {i = 10} local a = {i = 10}
self = 20 local self = 20
function a:x (x) return x+self.i end function a:x (x) return x+self.i end
function a.y (x) return x+self end function a.y (x) return x+self end
@@ -72,6 +73,8 @@ f(1,2, -- this one too
3,4) 3,4)
assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 'a') assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 'a')
t = nil -- delete 't'
function fat(x) function fat(x)
if x <= 1 then return 1 if x <= 1 then return 1
else return x*load("return fat(" .. x-1 .. ")", "")() else return x*load("return fat(" .. x-1 .. ")", "")()
@@ -80,26 +83,29 @@ end
assert(load "load 'assert(fat(6)==720)' () ")() assert(load "load 'assert(fat(6)==720)' () ")()
a = load('return fat(5), 3') a = load('return fat(5), 3')
a,b = a() local a,b = a()
assert(a == 120 and b == 3) assert(a == 120 and b == 3)
fat = nil
print('+') print('+')
function err_on_n (n) local function err_on_n (n)
if n==0 then error(); exit(1); if n==0 then error(); exit(1);
else err_on_n (n-1); exit(1); else err_on_n (n-1); exit(1);
end end
end end
do do
function dummy (n) local function dummy (n)
if n > 0 then if n > 0 then
assert(not pcall(err_on_n, n)) assert(not pcall(err_on_n, n))
dummy(n-1) dummy(n-1)
end end
end end
dummy(10)
end end
dummy(10) _G.deep = nil -- "declaration" (used by 'all.lua')
function deep (n) function deep (n)
if n>0 then deep(n-1) end if n>0 then deep(n-1) end
@@ -151,6 +157,16 @@ do -- tail calls x varargs
end end
do -- C-stack overflow while handling C-stack overflow
local function loop ()
assert(pcall(loop))
end
local err, msg = xpcall(loop, loop)
assert(not err and string.find(msg, "error"))
end
do -- tail calls x chain of __call do -- tail calls x chain of __call
local n = 10000 -- depth local n = 10000 -- depth
@@ -199,7 +215,7 @@ assert(a == 23 and (function (x) return x*2 end)(20) == 40)
-- testing closures -- testing closures
-- fixed-point operator -- fixed-point operator
Z = function (le) local Z = function (le)
local function a (f) local function a (f)
return le(function (x) return f(f)(x) end) return le(function (x) return f(f)(x) end)
end end
@@ -209,14 +225,14 @@ Z = function (le)
-- non-recursive factorial -- non-recursive factorial
F = function (f) local F = function (f)
return function (n) return function (n)
if n == 0 then return 1 if n == 0 then return 1
else return n*f(n-1) end else return n*f(n-1) end
end end
end end
fat = Z(F) local fat = Z(F)
assert(fat(0) == 1 and fat(4) == 24 and Z(F)(5)==5*Z(F)(4)) assert(fat(0) == 1 and fat(4) == 24 and Z(F)(5)==5*Z(F)(4))
@@ -227,22 +243,21 @@ local function g (z)
return f(z,z+1,z+2,z+3) return f(z,z+1,z+2,z+3)
end end
f = g(10) local f = g(10)
assert(f(9, 16) == 10+11+12+13+10+9+16+10) assert(f(9, 16) == 10+11+12+13+10+9+16+10)
Z, F, f = nil
print('+') print('+')
-- testing multiple returns -- testing multiple returns
function unlpack (t, i) local function unlpack (t, i)
i = i or 1 i = i or 1
if (i <= #t) then if (i <= #t) then
return t[i], unlpack(t, i+1) return t[i], unlpack(t, i+1)
end end
end end
function equaltab (t1, t2) local function equaltab (t1, t2)
assert(#t1 == #t2) assert(#t1 == #t2)
for i = 1, #t1 do for i = 1, #t1 do
assert(t1[i] == t2[i]) assert(t1[i] == t2[i])
@@ -251,8 +266,8 @@ end
local pack = function (...) return (table.pack(...)) end local pack = function (...) return (table.pack(...)) end
function f() return 1,2,30,4 end local function f() return 1,2,30,4 end
function ret2 (a,b) return a,b end local function ret2 (a,b) return a,b end
local a,b,c,d = unlpack{1,2,3} local a,b,c,d = unlpack{1,2,3}
assert(a==1 and b==2 and c==3 and d==nil) assert(a==1 and b==2 and c==3 and d==nil)
@@ -281,7 +296,7 @@ table.sort({10,9,8,4,19,23,0,0}, function (a,b) return a<b end, "extra arg")
local x = "-- a comment\0\0\0\n x = 10 + \n23; \ local x = "-- a comment\0\0\0\n x = 10 + \n23; \
local a = function () x = 'hi' end; \ local a = function () x = 'hi' end; \
return '\0'" return '\0'"
function read1 (x) local function read1 (x)
local i = 0 local i = 0
return function () return function ()
collectgarbage() collectgarbage()
@@ -290,7 +305,7 @@ function read1 (x)
end end
end end
function cannotload (msg, a,b) local function cannotload (msg, a,b)
assert(not a and string.find(b, msg)) assert(not a and string.find(b, msg))
end end
@@ -332,6 +347,7 @@ a = assert(load(read1(x), nil, "b"))
assert(a() == 1 and _G.x == 1) assert(a() == 1 and _G.x == 1)
cannotload("attempt to load a binary chunk", load(read1(x), nil, "t")) cannotload("attempt to load a binary chunk", load(read1(x), nil, "t"))
cannotload("attempt to load a binary chunk", load(x, nil, "t")) cannotload("attempt to load a binary chunk", load(x, nil, "t"))
_G.x = nil
assert(not pcall(string.dump, print)) -- no dump of C functions assert(not pcall(string.dump, print)) -- no dump of C functions
@@ -356,7 +372,7 @@ debug.setupvalue(x, 2, _G)
assert(x() == 123) assert(x() == 123)
assert(assert(load("return XX + ...", nil, nil, {XX = 13}))(4) == 17) assert(assert(load("return XX + ...", nil, nil, {XX = 13}))(4) == 17)
XX = nil
-- test generic load with nested functions -- test generic load with nested functions
x = [[ x = [[
+12 -2
View File
@@ -3,8 +3,16 @@
print "testing closures" print "testing closures"
do -- bug in 5.4.7
_ENV[true] = 10
local function aux () return _ENV[1 < 2] end
assert(aux() == 10)
_ENV[true] = nil
end
local A,B = 0,{g=10} local A,B = 0,{g=10}
function f(x) local function f(x)
local a = {} local a = {}
for i=1,1000 do for i=1,1000 do
local y = 0 local y = 0
@@ -89,6 +97,7 @@ assert(r == "a" and s == "b")
-- testing closures with 'for' control variable x break -- testing closures with 'for' control variable x break
local f
for i=1,3 do for i=1,3 do
f = function () return i end f = function () return i end
break break
@@ -139,7 +148,7 @@ assert(b('get') == 'xuxu')
b('set', 10); assert(b('get') == 14) b('set', 10); assert(b('get') == 14)
local w local y, w
-- testing multi-level closure -- testing multi-level closure
function f(x) function f(x)
return function (y) return function (y)
@@ -230,6 +239,7 @@ t()
-- test for debug manipulation of upvalues -- test for debug manipulation of upvalues
local debug = require'debug' local debug = require'debug'
local foo1, foo2, foo3
do do
local a , b, c = 3, 5, 7 local a , b, c = 3, 5, 7
foo1 = function () return a+b end; foo1 = function () return a+b end;
+3 -3
View File
@@ -86,7 +86,7 @@ checkKlist(foo, {1, 1.0, 2, 2.0, 0, 0.0})
-- testing opcodes -- testing opcodes
-- check that 'f' opcodes match '...' -- check that 'f' opcodes match '...'
function check (f, ...) local function check (f, ...)
local arg = {...} local arg = {...}
local c = T.listcode(f) local c = T.listcode(f)
for i=1, #arg do for i=1, #arg do
@@ -99,7 +99,7 @@ end
-- check that 'f' opcodes match '...' and that 'f(p) == r'. -- check that 'f' opcodes match '...' and that 'f(p) == r'.
function checkR (f, p, r, ...) local function checkR (f, p, r, ...)
local r1 = f(p) local r1 = f(p)
assert(r == r1 and math.type(r) == math.type(r1)) assert(r == r1 and math.type(r) == math.type(r1))
check(f, ...) check(f, ...)
@@ -107,7 +107,7 @@ end
-- check that 'a' and 'b' has the same opcodes -- check that 'a' and 'b' has the same opcodes
function checkequal (a, b) local function checkequal (a, b)
a = T.listcode(a) a = T.listcode(a)
b = T.listcode(b) b = T.listcode(b)
assert(#a == #b) assert(#a == #b)
+45 -16
View File
@@ -11,6 +11,7 @@ local function checkload (s, msg)
end end
-- testing semicollons -- testing semicollons
local a
do ;;; end do ;;; end
; do ; a = 3; assert(a == 3) end; ; do ; a = 3; assert(a == 3) end;
; ;
@@ -49,10 +50,10 @@ assert((((nil and true) or false) and true) == false)
local a,b = 1,nil; local a,b = 1,nil;
assert(-(1 or 2) == -1 and (1 and 2)+(-1.25 or -4) == 0.75); assert(-(1 or 2) == -1 and (1 and 2)+(-1.25 or -4) == 0.75);
x = ((b or a)+1 == 2 and (10 or a)+1 == 11); assert(x); local x = ((b or a)+1 == 2 and (10 or a)+1 == 11); assert(x);
x = (((2<3) or 1) == true and (2<3 and 4) == 4); assert(x); x = (((2<3) or 1) == true and (2<3 and 4) == 4); assert(x);
x,y=1,2; local x, y = 1, 2;
assert((x>y) and x or y == 2); assert((x>y) and x or y == 2);
x,y=2,1; x,y=2,1;
assert((x>y) and x or y == 2); assert((x>y) and x or y == 2);
@@ -77,13 +78,13 @@ do -- testing operators with diffent kinds of constants
local gab = f(o1, o2) local gab = f(o1, o2)
_ENV.XX = o1 _ENV.XX = o1
code = string.format("return XX %s %s", op, o2) local code = string.format("return XX %s %s", op, o2)
res = assert(load(code))() local res = assert(load(code))()
assert(res == gab) assert(res == gab)
_ENV.XX = o2 _ENV.XX = o2
local code = string.format("return (%s) %s XX", o1, op) code = string.format("return (%s) %s XX", o1, op)
local res = assert(load(code))() res = assert(load(code))()
assert(res == gab) assert(res == gab)
code = string.format("return (%s) %s %s", o1, op, o2) code = string.format("return (%s) %s %s", o1, op, o2)
@@ -92,6 +93,7 @@ do -- testing operators with diffent kinds of constants
end end
end end
end end
_ENV.XX = nil
end end
@@ -100,10 +102,35 @@ repeat until 1; repeat until true;
while false do end; while nil do end; while false do end; while nil do end;
do -- test old bug (first name could not be an `upvalue') do -- test old bug (first name could not be an `upvalue')
local a; function f(x) x={a=1}; x={x=1}; x={G=1} end local a; local function f(x) x={a=1}; x={x=1}; x={G=1} end
end end
function f (i)
do -- bug since 5.4.0
-- create code with a table using more than 256 constants
local code = {"local x = {"}
for i = 1, 257 do
code[#code + 1] = i .. ".1,"
end
code[#code + 1] = "};"
code = table.concat(code)
-- add "ret" to the end of that code and checks that
-- it produces the expected value "val"
local function check (ret, val)
local code = code .. ret
code = load(code)
assert(code() == val)
end
check("return (1 ~ (2 or 3))", 1 ~ 2)
check("return (1 | (2 or 3))", 1 | 2)
check("return (1 + (2 or 3))", 1 + 2)
check("return (1 << (2 or 3))", 1 << 2)
end
local function f (i)
if type(i) ~= 'number' then return i,'jojo'; end; if type(i) ~= 'number' then return i,'jojo'; end;
if i > 0 then return i, f(i-1); end; if i > 0 then return i, f(i-1); end;
end end
@@ -129,10 +156,10 @@ end
assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == nil) assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == nil)
for i=1,1000 do break; end; for i=1,1000 do break; end;
n=100; local n=100;
i=3; local i=3;
t = {}; local t = {};
a=nil local a=nil
while not a do while not a do
a=0; for i=1,n do for i=i,1,-1 do a=a+1; t[i]=1; end; end; a=0; for i=1,n do for i=i,1,-1 do a=a+1; t[i]=1; end; end;
end end
@@ -175,14 +202,14 @@ a={y=1}
x = {a.y} x = {a.y}
assert(x[1] == 1) assert(x[1] == 1)
function f(i) local function f (i)
while 1 do while 1 do
if i>0 then i=i-1; if i>0 then i=i-1;
else return; end; else return; end;
end; end;
end; end;
function g(i) local function g(i)
while 1 do while 1 do
if i>0 then i=i-1 if i>0 then i=i-1
else return end else return end
@@ -247,7 +274,7 @@ function g (a,b,c,d,e)
if not (a>=b or c or d and e or nil) then return 0; else return 1; end; if not (a>=b or c or d and e or nil) then return 0; else return 1; end;
end end
function h (a,b,c,d,e) local function h (a,b,c,d,e)
while (a>=b or c or (d and e) or nil) do return 1; end; while (a>=b or c or (d and e) or nil) do return 1; end;
return 0; return 0;
end; end;
@@ -275,7 +302,7 @@ do
assert(a==2) assert(a==2)
end end
function F(a) local function F (a)
assert(debug.getinfo(1, "n").name == 'F') assert(debug.getinfo(1, "n").name == 'F')
return a,2,3 return a,2,3
end end
@@ -368,6 +395,8 @@ for n = 1, level do
if i % 60000 == 0 then print('+') end if i % 60000 == 0 then print('+') end
end end
end end
IX = nil
_G.GLOB1 = nil
------------------------------------------------------------------ ------------------------------------------------------------------
-- testing some syntax errors (chosen through 'gcov') -- testing some syntax errors (chosen through 'gcov')
+65 -33
View File
@@ -30,7 +30,8 @@ local function eqtab (t1, t2)
end end
_G.x = nil -- declare x _G.x = nil -- declare x
function foo (a, ...) _G.f = nil -- declare f
local function foo (a, ...)
local x, y = coroutine.running() local x, y = coroutine.running()
assert(x == f and y == false) assert(x == f and y == false)
-- next call should not corrupt coroutine (but must fail, -- next call should not corrupt coroutine (but must fail,
@@ -67,10 +68,11 @@ assert(coroutine.status(f) == "dead")
s, a = coroutine.resume(f, "xuxu") s, a = coroutine.resume(f, "xuxu")
assert(not s and string.find(a, "dead") and coroutine.status(f) == "dead") assert(not s and string.find(a, "dead") and coroutine.status(f) == "dead")
_G.f = nil
-- yields in tail calls -- yields in tail calls
local function foo (i) return coroutine.yield(i) end local function foo (i) return coroutine.yield(i) end
f = coroutine.wrap(function () local f = coroutine.wrap(function ()
for i=1,10 do for i=1,10 do
assert(foo(i) == _G.x) assert(foo(i) == _G.x)
end end
@@ -79,8 +81,10 @@ end)
for i=1,10 do _G.x = i; assert(f(i) == i) end for i=1,10 do _G.x = i; assert(f(i) == i) end
_G.x = 'xuxu'; assert(f('xuxu') == 'a') _G.x = 'xuxu'; assert(f('xuxu') == 'a')
_G.x = nil
-- recursive -- recursive
function pf (n, i) local function pf (n, i)
coroutine.yield(n) coroutine.yield(n)
pf(n*i, i+1) pf(n*i, i+1)
end end
@@ -93,14 +97,14 @@ for i=1,10 do
end end
-- sieve -- sieve
function gen (n) local function gen (n)
return coroutine.wrap(function () return coroutine.wrap(function ()
for i=2,n do coroutine.yield(i) end for i=2,n do coroutine.yield(i) end
end) end)
end end
function filter (p, g) local function filter (p, g)
return coroutine.wrap(function () return coroutine.wrap(function ()
while 1 do while 1 do
local n = g() local n = g()
@@ -221,14 +225,14 @@ do
-- <close> versus pcall in coroutines -- <close> versus pcall in coroutines
local X = false local X = false
local Y = false local Y = false
function foo () local function foo ()
local x <close> = func2close(function (self, err) local x <close> = func2close(function (self, err)
Y = debug.getinfo(2) Y = debug.getinfo(2)
X = err X = err
end) end)
error(43) error(43)
end end
co = coroutine.create(function () return pcall(foo) end) local co = coroutine.create(function () return pcall(foo) end)
local st1, st2, err = coroutine.resume(co) local st1, st2, err = coroutine.resume(co)
assert(st1 and not st2 and err == 43) assert(st1 and not st2 and err == 43)
assert(X == 43 and Y.what == "C") assert(X == 43 and Y.what == "C")
@@ -275,7 +279,7 @@ end
-- yielding across C boundaries -- yielding across C boundaries
co = coroutine.wrap(function() local co = coroutine.wrap(function()
assert(not pcall(table.sort,{1,2,3}, coroutine.yield)) assert(not pcall(table.sort,{1,2,3}, coroutine.yield))
assert(coroutine.isyieldable()) assert(coroutine.isyieldable())
coroutine.yield(20) coroutine.yield(20)
@@ -303,15 +307,15 @@ local r1, r2, v = f1(nil)
assert(r1 and not r2 and v[1] == (10 + 1)*10/2) assert(r1 and not r2 and v[1] == (10 + 1)*10/2)
function f (a, b) a = coroutine.yield(a); error{a + b} end local function f (a, b) a = coroutine.yield(a); error{a + b} end
function g(x) return x[1]*2 end local function g(x) return x[1]*2 end
co = coroutine.wrap(function () co = coroutine.wrap(function ()
coroutine.yield(xpcall(f, g, 10, 20)) coroutine.yield(xpcall(f, g, 10, 20))
end) end)
assert(co() == 10) assert(co() == 10)
r, msg = co(100) local r, msg = co(100)
assert(not r and msg == 240) assert(not r and msg == 240)
@@ -373,9 +377,10 @@ assert(not a and b == foo and coroutine.status(x) == "dead")
a,b = coroutine.resume(x) a,b = coroutine.resume(x)
assert(not a and string.find(b, "dead") and coroutine.status(x) == "dead") assert(not a and string.find(b, "dead") and coroutine.status(x) == "dead")
goo = nil
-- co-routines x for loop -- co-routines x for loop
function all (a, n, k) local function all (a, n, k)
if k == 0 then coroutine.yield(a) if k == 0 then coroutine.yield(a)
else else
for i=1,n do for i=1,n do
@@ -415,7 +420,7 @@ assert(f() == 43 and f() == 53)
-- old bug: attempt to resume itself -- old bug: attempt to resume itself
function co_func (current_co) local function co_func (current_co)
assert(coroutine.running() == current_co) assert(coroutine.running() == current_co)
assert(coroutine.resume(current_co) == false) assert(coroutine.resume(current_co) == false)
coroutine.yield(10, 20) coroutine.yield(10, 20)
@@ -488,18 +493,38 @@ assert(not pcall(a, a))
a = nil a = nil
do
-- bug in 5.4: thread can use message handler higher in the stack
-- than the variable being closed
local c = coroutine.create(function()
local clo <close> = setmetatable({}, {__close=function()
local x = 134 -- will overwrite message handler
error(x)
end})
-- yields coroutine but leaves a new message handler for it,
-- that would be used when closing the coroutine (except that it
-- will be overwritten)
xpcall(coroutine.yield, function() return "XXX" end)
end)
assert(coroutine.resume(c)) -- start coroutine
local st, msg = coroutine.close(c)
assert(not st and msg == 134)
end
-- access to locals of erroneous coroutines -- access to locals of erroneous coroutines
local x = coroutine.create (function () local x = coroutine.create (function ()
local a = 10 local a = 10
_G.f = function () a=a+1; return a end _G.F = function () a=a+1; return a end
error('x') error('x')
end) end)
assert(not coroutine.resume(x)) assert(not coroutine.resume(x))
-- overwrite previous position of local `a' -- overwrite previous position of local `a'
assert(not coroutine.resume(x, 1, 1, 1, 1, 1, 1, 1)) assert(not coroutine.resume(x, 1, 1, 1, 1, 1, 1, 1))
assert(_G.f() == 11) assert(_G.F() == 11)
assert(_G.f() == 12) assert(_G.F() == 12)
_G.F = nil
if not T then if not T then
@@ -510,7 +535,7 @@ else
local turn local turn
function fact (t, x) local function fact (t, x)
assert(turn == t) assert(turn == t)
if x == 0 then return 1 if x == 0 then return 1
else return x*fact(t, x-1) else return x*fact(t, x-1)
@@ -579,6 +604,7 @@ else
_G.X = nil; co(); assert(_G.X == line + 2 and _G.XX == nil) _G.X = nil; co(); assert(_G.X == line + 2 and _G.XX == nil)
_G.X = nil; co(); assert(_G.X == line + 3 and _G.XX == 20) _G.X = nil; co(); assert(_G.X == line + 3 and _G.XX == 20)
assert(co() == 10) assert(co() == 10)
_G.X = nil
-- testing yields in count hook -- testing yields in count hook
co = coroutine.wrap(function () co = coroutine.wrap(function ()
@@ -603,18 +629,20 @@ else
-- (bug in 5.2/5.3) -- (bug in 5.2/5.3)
c = coroutine.create(function (a, ...) c = coroutine.create(function (a, ...)
T.sethook("yield 0", "l") -- will yield on next two lines T.sethook("yield 0", "l") -- will yield on next two lines
assert(a == 10) local b = a
return ... return ...
end) end)
assert(coroutine.resume(c, 1, 2, 3)) -- start coroutine assert(coroutine.resume(c, 1, 2, 3)) -- start coroutine
local n,v = debug.getlocal(c, 0, 1) -- check its local local n,v = debug.getlocal(c, 0, 1) -- check its local
assert(n == "a" and v == 1) assert(n == "a" and v == 1 and debug.getlocal(c, 0, 2) ~= "b")
assert(debug.setlocal(c, 0, 1, 10)) -- test 'setlocal' assert(debug.setlocal(c, 0, 1, 10)) -- test 'setlocal'
local t = debug.getinfo(c, 0) -- test 'getinfo' local t = debug.getinfo(c, 0) -- test 'getinfo'
assert(t.currentline == t.linedefined + 1) assert(t.currentline == t.linedefined + 2)
assert(not debug.getinfo(c, 1)) -- no other level assert(not debug.getinfo(c, 1)) -- no other level
assert(coroutine.resume(c)) -- run next line assert(coroutine.resume(c)) -- run next line
local n,v = debug.getlocal(c, 0, 2) -- check next local
assert(n == "b" and v == 10)
v = {coroutine.resume(c)} -- finish coroutine v = {coroutine.resume(c)} -- finish coroutine
assert(v[1] == true and v[2] == 2 and v[3] == 3 and v[4] == undef) assert(v[1] == true and v[2] == 2 and v[3] == 3 and v[4] == undef)
assert(not coroutine.resume(c)) assert(not coroutine.resume(c))
@@ -656,6 +684,8 @@ else
assert(X == 'a a a' and Y == 'OK') assert(X == 'a a a' and Y == 'OK')
X, Y = nil
-- resuming running coroutine -- resuming running coroutine
C = coroutine.create(function () C = coroutine.create(function ()
@@ -701,7 +731,7 @@ else
X = function (x) coroutine.yield(x, 'BB'); return 'CC' end; X = function (x) coroutine.yield(x, 'BB'); return 'CC' end;
return 'ok']])) return 'ok']]))
t = table.pack(T.testC(state, [[ local t = table.pack(T.testC(state, [[
rawgeti R 1 # get main thread rawgeti R 1 # get main thread
pushstring 'XX' pushstring 'XX'
getglobal X # get function for body getglobal X # get function for body
@@ -730,31 +760,28 @@ end
-- leaving a pending coroutine open -- leaving a pending coroutine open
_X = coroutine.wrap(function () _G.TO_SURVIVE = coroutine.wrap(function ()
local a = 10 local a = 10
local x = function () a = a+1 end local x = function () a = a+1 end
coroutine.yield() coroutine.yield()
end) end)
_X() _G.TO_SURVIVE()
if not _soft then if not _soft then
-- bug (stack overflow) -- bug (stack overflow)
local j = 2^9 local lim = 1000000 -- stack limit; assume 32-bit machine
local lim = 1000000 -- (C stack limit; assume 32-bit machine) local t = {lim - 10, lim - 5, lim - 1, lim, lim + 1, lim + 5}
local t = {lim - 10, lim - 5, lim - 1, lim, lim + 1}
for i = 1, #t do for i = 1, #t do
local j = t[i] local j = t[i]
co = coroutine.create(function() local co = coroutine.create(function()
local t = {} return table.unpack({}, 1, j)
for i = 1, j do t[i] = i end
return table.unpack(t)
end) end)
local r, msg = coroutine.resume(co) local r, msg = coroutine.resume(co)
assert(not r) -- must fail for unpacking larger than stack limit
assert(j < lim or not r)
end end
co = nil
end end
@@ -938,7 +965,7 @@ assert(run(function ()
do local _ENV = _ENV do local _ENV = _ENV
f = function () AAA = BBB + 1; return AAA end f = function () AAA = BBB + 1; return AAA end
end end
g = new(10); g.k.BBB = 10; local g = new(10); g.k.BBB = 10;
debug.setupvalue(f, 1, g) debug.setupvalue(f, 1, g)
assert(run(f, {"idx", "nidx", "idx"}) == 11) assert(run(f, {"idx", "nidx", "idx"}) == 11)
assert(g.k.AAA == 11) assert(g.k.AAA == 11)
@@ -1078,6 +1105,8 @@ assert(#a == 3 and a[1] == a[2] and a[2] == a[3] and a[3] == 34)
-- testing yields with continuations -- testing yields with continuations
local y
co = coroutine.wrap(function (...) return co = coroutine.wrap(function (...) return
T.testC([[ # initial function T.testC([[ # initial function
yieldk 1 2 yieldk 1 2
@@ -1130,6 +1159,9 @@ assert(x == "YIELD" and y == 4)
assert(not pcall(co)) -- coroutine should be dead assert(not pcall(co)) -- coroutine should be dead
_G.ctx = nil
_G.status = nil
-- bug in nCcalls -- bug in nCcalls
local co = coroutine.wrap(function () local co = coroutine.wrap(function ()
+26
View File
@@ -84,6 +84,32 @@ do -- bug in 5.4.0
end end
do -- bug since 5.4.0
local count = 0
print("chain of 'coroutine.close'")
-- create N coroutines forming a list so that each one, when closed,
-- closes the previous one. (With a large enough N, previous Lua
-- versions crash in this test.)
local coro = false
for i = 1, 1000 do
local previous = coro
coro = coroutine.create(function()
local cc <close> = setmetatable({}, {__close=function()
count = count + 1
if previous then
assert(coroutine.close(previous))
end
end})
coroutine.yield() -- leaves 'cc' pending to be closed
end)
assert(coroutine.resume(coro)) -- start it and run until it yields
end
local st, msg = coroutine.close(coro)
assert(not st and string.find(msg, "C stack overflow"))
print("final count: ", count)
end
do do
print("nesting of resuming yielded coroutines") print("nesting of resuming yielded coroutines")
local count = 0 local count = 0
+31 -13
View File
@@ -16,7 +16,7 @@ end
assert(not debug.gethook()) assert(not debug.gethook())
local testline = 19 -- line where 'test' is defined local testline = 19 -- line where 'test' is defined
function test (s, l, p) -- this must be line 19 local function test (s, l, p) -- this must be line 19
collectgarbage() -- avoid gc during trace collectgarbage() -- avoid gc during trace
local function f (event, line) local function f (event, line)
assert(event == 'line') assert(event == 'line')
@@ -49,8 +49,17 @@ do
end end
-- bug in 5.4.4-5.4.6: activelines in vararg functions
-- without debug information
do
local func = load(string.dump(load("print(10)"), true))
local actl = debug.getinfo(func, "L").activelines
assert(#actl == 0) -- no line info
end
-- test file and string names truncation -- test file and string names truncation
a = "function f () end" local a = "function f () end"
local function dostring (s, x) return load(s, x)() end local function dostring (s, x) return load(s, x)() end
dostring(a) dostring(a)
assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a)) assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a))
@@ -72,7 +81,8 @@ dostring(a, string.format("=%s", string.rep('x', 500)))
assert(string.find(debug.getinfo(f).short_src, "^x*$")) assert(string.find(debug.getinfo(f).short_src, "^x*$"))
dostring(a, "=") dostring(a, "=")
assert(debug.getinfo(f).short_src == "") assert(debug.getinfo(f).short_src == "")
a = nil; f = nil; _G.a = nil; _G.f = nil;
_G[string.rep("p", 400)] = nil
repeat repeat
@@ -120,6 +130,7 @@ else
end end
]], {2,3,4,7}) ]], {2,3,4,7})
test([[ test([[
local function foo() local function foo()
end end
@@ -128,6 +139,7 @@ A = 1
A = 2 A = 2
A = 3 A = 3
]], {2, 3, 2, 4, 5, 6}) ]], {2, 3, 2, 4, 5, 6})
_G.A = nil
test([[-- test([[--
@@ -175,6 +187,8 @@ end
test([[for i=1,4 do a=1 end]], {1,1,1,1}) test([[for i=1,4 do a=1 end]], {1,1,1,1})
_G.a = nil
do -- testing line info/trace with large gaps in source do -- testing line info/trace with large gaps in source
@@ -194,6 +208,7 @@ do -- testing line info/trace with large gaps in source
end end
end end
end end
_G.a = nil
do -- testing active lines do -- testing active lines
@@ -287,7 +302,6 @@ foo(200, 3, 4)
local a = {} local a = {}
for i = 1, (_soft and 100 or 1000) do a[i] = i end for i = 1, (_soft and 100 or 1000) do a[i] = i end
foo(table.unpack(a)) foo(table.unpack(a))
a = nil
@@ -307,13 +321,14 @@ do -- test hook presence in debug info
debug.sethook() debug.sethook()
assert(count == 4) assert(count == 4)
end end
_ENV.a = nil
-- hook table has weak keys -- hook table has weak keys
assert(getmetatable(debug.getregistry()._HOOKKEY).__mode == 'k') assert(getmetatable(debug.getregistry()._HOOKKEY).__mode == 'k')
a = {}; L = nil a = {}; local L = nil
local glob = 1 local glob = 1
local oldglob = glob local oldglob = glob
debug.sethook(function (e,l) debug.sethook(function (e,l)
@@ -339,7 +354,7 @@ function f(a,b)
local _, y = debug.getlocal(1, 2) local _, y = debug.getlocal(1, 2)
assert(x == a and y == b) assert(x == a and y == b)
assert(debug.setlocal(2, 3, "pera") == "AA".."AA") assert(debug.setlocal(2, 3, "pera") == "AA".."AA")
assert(debug.setlocal(2, 4, "maçã") == "B") assert(debug.setlocal(2, 4, "manga") == "B")
x = debug.getinfo(2) x = debug.getinfo(2)
assert(x.func == g and x.what == "Lua" and x.name == 'g' and assert(x.func == g and x.what == "Lua" and x.name == 'g' and
x.nups == 2 and string.find(x.source, "^@.*db%.lua$")) x.nups == 2 and string.find(x.source, "^@.*db%.lua$"))
@@ -354,7 +369,7 @@ function foo()
end; foo() -- set L end; foo() -- set L
-- check line counting inside strings and empty lines -- check line counting inside strings and empty lines
_ = 'alo\ local _ = 'alo\
alo' .. [[ alo' .. [[
]] ]]
@@ -367,9 +382,9 @@ function g (...)
local arg = {...} local arg = {...}
do local a,b,c; a=math.sin(40); end do local a,b,c; a=math.sin(40); end
local feijao local feijao
local AAAA,B = "xuxu", "mamão" local AAAA,B = "xuxu", "abacate"
f(AAAA,B) f(AAAA,B)
assert(AAAA == "pera" and B == "maçã") assert(AAAA == "pera" and B == "manga")
do do
local B = 13 local B = 13
local x,y = debug.getlocal(1,5) local x,y = debug.getlocal(1,5)
@@ -403,6 +418,7 @@ function g(a,b) return (a+1) + f() end
assert(g(0,0) == 30) assert(g(0,0) == 30)
_G.f, _G.g = nil
debug.sethook(nil); debug.sethook(nil);
assert(not debug.gethook()) assert(not debug.gethook())
@@ -446,7 +462,7 @@ local function collectlocals (level)
end end
X = nil local X = nil
a = {} a = {}
function a:f (a, b, ...) local arg = {...}; local c = 13 end function a:f (a, b, ...) local arg = {...}; local c = 13 end
debug.sethook(function (e) debug.sethook(function (e)
@@ -469,6 +485,7 @@ a:f(1,2,3,4,5)
assert(X.self == a and X.a == 1 and X.b == 2 and X.c == nil) assert(X.self == a and X.a == 1 and X.b == 2 and X.c == nil)
assert(XX == 12) assert(XX == 12)
assert(not debug.gethook()) assert(not debug.gethook())
_G.XX = nil
-- testing access to local variables in return hook (bug in 5.2) -- testing access to local variables in return hook (bug in 5.2)
@@ -593,6 +610,7 @@ end
debug.sethook() debug.sethook()
local g, g1
-- tests for tail calls -- tests for tail calls
local function f (x) local function f (x)
@@ -638,7 +656,7 @@ h(false)
debug.sethook() debug.sethook()
assert(b == 2) -- two tail calls assert(b == 2) -- two tail calls
lim = _soft and 3000 or 30000 local lim = _soft and 3000 or 30000
local function foo (x) local function foo (x)
if x==0 then if x==0 then
assert(debug.getinfo(2).what == "main") assert(debug.getinfo(2).what == "main")
@@ -919,7 +937,7 @@ do
local cl = countlines(rest) local cl = countlines(rest)
-- at most 10 lines in first part, 11 in second, plus '...' -- at most 10 lines in first part, 11 in second, plus '...'
assert(cl <= 10 + 11 + 1) assert(cl <= 10 + 11 + 1)
local brk = string.find(rest, "%.%.%.") local brk = string.find(rest, "%.%.%.\t%(skip")
if brk then -- does message have '...'? if brk then -- does message have '...'?
local rest1 = string.sub(rest, 1, brk) local rest1 = string.sub(rest, 1, brk)
local rest2 = string.sub(rest, brk, #rest) local rest2 = string.sub(rest, brk, #rest)
@@ -940,7 +958,7 @@ end
print("testing debug functions on chunk without debug info") print("testing debug functions on chunk without debug info")
prog = [[-- program to be loaded without debug information (strip) local prog = [[-- program to be loaded without debug information (strip)
local debug = require'debug' local debug = require'debug'
local a = 12 -- a local variable local a = 12 -- a local variable
+80 -41
View File
@@ -91,7 +91,7 @@ end
if not T then if not T then
(Message or print) (Message or print)
('\n >>> testC not active: skipping memory message test <<<\n') ('\n >>> testC not active: skipping tests for messages in C <<<\n')
else else
print "testing memory error message" print "testing memory error message"
local a = {} local a = {}
@@ -104,6 +104,19 @@ else
end) end)
T.totalmem(0) T.totalmem(0)
assert(not st and msg == "not enough" .. " memory") assert(not st and msg == "not enough" .. " memory")
-- stack space for luaL_traceback (bug in 5.4.6)
local res = T.testC[[
# push 16 elements on the stack
pushnum 1; pushnum 1; pushnum 1; pushnum 1; pushnum 1;
pushnum 1; pushnum 1; pushnum 1; pushnum 1; pushnum 1;
pushnum 1; pushnum 1; pushnum 1; pushnum 1; pushnum 1;
pushnum 1;
# traceback should work with 4 remaining slots
traceback xuxu 1;
return 1
]]
assert(string.find(res, "xuxu.-main chunk"))
end end
@@ -114,12 +127,21 @@ checkmessage("a = {} | 1", "bitwise operation")
checkmessage("a = {} < 1", "attempt to compare") checkmessage("a = {} < 1", "attempt to compare")
checkmessage("a = {} <= 1", "attempt to compare") checkmessage("a = {} <= 1", "attempt to compare")
checkmessage("a=1; bbbb=2; a=math.sin(3)+bbbb(3)", "global 'bbbb'") checkmessage("aaa=1; bbbb=2; aaa=math.sin(3)+bbbb(3)", "global 'bbbb'")
checkmessage("a={}; do local a=1 end a:bbbb(3)", "method 'bbbb'") checkmessage("aaa={}; do local aaa=1 end aaa:bbbb(3)", "method 'bbbb'")
checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'") checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'")
assert(not string.find(doit"a={13}; local bbbb=1; a[bbbb](3)", "'bbbb'")) assert(not string.find(doit"aaa={13}; local bbbb=1; aaa[bbbb](3)", "'bbbb'"))
checkmessage("a={13}; local bbbb=1; a[bbbb](3)", "number") checkmessage("aaa={13}; local bbbb=1; aaa[bbbb](3)", "number")
checkmessage("a=(1)..{}", "a table value") checkmessage("aaa=(1)..{}", "a table value")
-- bug in 5.4.6
checkmessage("a = {_ENV = {}}; print(a._ENV.x + 1)", "field 'x'")
-- a similar bug in 5.4.7, since 5.4.0
checkmessage("print(('_ENV').x + 1)", "field 'x'")
_G.aaa, _G.bbbb = nil
-- calls -- calls
checkmessage("local a; a(13)", "local 'a'") checkmessage("local a; a(13)", "local 'a'")
@@ -134,12 +156,13 @@ checkmessage([[
-- tail calls -- tail calls
checkmessage("local a={}; return a.bbbb(3)", "field 'bbbb'") checkmessage("local a={}; return a.bbbb(3)", "field 'bbbb'")
checkmessage("a={}; do local a=1 end; return a:bbbb(3)", "method 'bbbb'") checkmessage("aaa={}; do local aaa=1 end; return aaa:bbbb(3)", "method 'bbbb'")
checkmessage("a = #print", "length of a function value") checkmessage("aaa = #print", "length of a function value")
checkmessage("a = #3", "length of a number value") checkmessage("aaa = #3", "length of a number value")
_G.aaa = nil
aaa = nil
checkmessage("aaa.bbb:ddd(9)", "global 'aaa'") checkmessage("aaa.bbb:ddd(9)", "global 'aaa'")
checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'") checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'")
checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'") checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'")
@@ -152,15 +175,16 @@ checkmessage("local a,b,cc; (function () a.x = 1 end)()", "upvalue 'a'")
checkmessage("local _ENV = {x={}}; a = a + 1", "global 'a'") checkmessage("local _ENV = {x={}}; a = a + 1", "global 'a'")
checkmessage("b=1; local aaa={}; x=aaa+b", "local 'aaa'") checkmessage("BB=1; local aaa={}; x=aaa+BB", "local 'aaa'")
checkmessage("aaa={}; x=3.3/aaa", "global 'aaa'") checkmessage("aaa={}; x=3.3/aaa", "global 'aaa'")
checkmessage("aaa=2; b=nil;x=aaa*b", "global 'b'") checkmessage("aaa=2; BB=nil;x=aaa*BB", "global 'BB'")
checkmessage("aaa={}; x=-aaa", "global 'aaa'") checkmessage("aaa={}; x=-aaa", "global 'aaa'")
-- short circuit -- short circuit
checkmessage("a=1; local a,bbbb=2,3; a = math.sin(1) and bbbb(3)", checkmessage("aaa=1; local aaa,bbbb=2,3; aaa = math.sin(1) and bbbb(3)",
"local 'bbbb'") "local 'bbbb'")
checkmessage("a=1; local a,bbbb=2,3; a = bbbb(1) or a(3)", "local 'bbbb'") checkmessage("aaa=1; local aaa,bbbb=2,3; aaa = bbbb(1) or aaa(3)",
"local 'bbbb'")
checkmessage("local a,b,c,f = 1,1,1; f((a and b) or c)", "local 'f'") checkmessage("local a,b,c,f = 1,1,1; f((a and b) or c)", "local 'f'")
checkmessage("local a,b,c = 1,1,1; ((a and b) or c)()", "call a number value") checkmessage("local a,b,c = 1,1,1; ((a and b) or c)()", "call a number value")
assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'")) assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'"))
@@ -187,8 +211,8 @@ checkmessage("return ~-3e40", "has no integer representation")
checkmessage("return ~-3.009", "has no integer representation") checkmessage("return ~-3.009", "has no integer representation")
checkmessage("return 3.009 & 1", "has no integer representation") checkmessage("return 3.009 & 1", "has no integer representation")
checkmessage("return 34 >> {}", "table value") checkmessage("return 34 >> {}", "table value")
checkmessage("a = 24 // 0", "divide by zero") checkmessage("aaa = 24 // 0", "divide by zero")
checkmessage("a = 1 % 0", "'n%0'") checkmessage("aaa = 1 % 0", "'n%0'")
-- type error for an object which is neither in an upvalue nor a register. -- type error for an object which is neither in an upvalue nor a register.
@@ -269,13 +293,13 @@ end
-- tests for field accesses after RK limit -- tests for field accesses after RK limit
local t = {} local t = {}
for i = 1, 1000 do for i = 1, 1000 do
t[i] = "a = x" .. i t[i] = "aaa = x" .. i
end end
local s = table.concat(t, "; ") local s = table.concat(t, "; ")
t = nil t = nil
checkmessage(s.."; a = bbb + 1", "global 'bbb'") checkmessage(s.."; aaa = bbb + 1", "global 'bbb'")
checkmessage("local _ENV=_ENV;"..s.."; a = bbb + 1", "global 'bbb'") checkmessage("local _ENV=_ENV;"..s.."; aaa = bbb + 1", "global 'bbb'")
checkmessage(s.."; local t = {}; a = t.bbb + 1", "field 'bbb'") checkmessage(s.."; local t = {}; aaa = t.bbb + 1", "field 'bbb'")
checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'") checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'")
checkmessage([[aaa=9 checkmessage([[aaa=9
@@ -324,14 +348,17 @@ main()
]], "global 'NoSuchName'") ]], "global 'NoSuchName'")
print'+' print'+'
a = {}; setmetatable(a, {__index = string}) aaa = {}; setmetatable(aaa, {__index = string})
checkmessage("a:sub()", "bad self") checkmessage("aaa:sub()", "bad self")
checkmessage("string.sub('a', {})", "#2") checkmessage("string.sub('a', {})", "#2")
checkmessage("('a'):sub{}", "#1") checkmessage("('a'):sub{}", "#1")
checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'") checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'")
checkmessage("string.gsub('s', 's', setmetatable)", "'setmetatable'") checkmessage("string.gsub('s', 's', setmetatable)", "'setmetatable'")
_G.aaa = nil
-- tests for errors in coroutines -- tests for errors in coroutines
local function f (n) local function f (n)
@@ -349,7 +376,7 @@ checkerr("yield across", f)
-- testing size of 'source' info; size of buffer for that info is -- testing size of 'source' info; size of buffer for that info is
-- LUA_IDSIZE, declared as 60 in luaconf. Get one position for '\0'. -- LUA_IDSIZE, declared as 60 in luaconf. Get one position for '\0'.
idsize = 60 - 1 local idsize = 60 - 1
local function checksize (source) local function checksize (source)
-- syntax error -- syntax error
local _, msg = load("x", source) local _, msg = load("x", source)
@@ -385,19 +412,19 @@ lineerror("a\n=\n-\n\nprint\n;", 3)
lineerror([[ lineerror([[
a a
( ( -- <<
23) 23)
]], 1) ]], 2)
lineerror([[ lineerror([[
local a = {x = 13} local a = {x = 13}
a a
. .
x x
( ( -- <<
23 23
) )
]], 2) ]], 5)
lineerror([[ lineerror([[
local a = {x = 13} local a = {x = 13}
@@ -411,13 +438,14 @@ x
local p = [[ local p = [[
function g() f() end function g() f() end
function f(x) error('a', X) end function f(x) error('a', XX) end
g() g()
]] ]]
X=3;lineerror((p), 3) XX=3;lineerror((p), 3)
X=0;lineerror((p), false) XX=0;lineerror((p), false)
X=1;lineerror((p), 2) XX=1;lineerror((p), 2)
X=2;lineerror((p), 1) XX=2;lineerror((p), 1)
_G.XX, _G.g, _G.f = nil
lineerror([[ lineerror([[
@@ -436,6 +464,14 @@ if not b then
end end
end]], 5) end]], 5)
-- bug in 5.4.0
lineerror([[
local a = 0
local b = 1
local c = b % a
]], 3)
do do
-- Force a negative estimate for base line. Error in instruction 2 -- Force a negative estimate for base line. Error in instruction 2
-- (after VARARGPREP, GETGLOBAL), with first absolute line information -- (after VARARGPREP, GETGLOBAL), with first absolute line information
@@ -449,11 +485,11 @@ if not _soft then
-- several tests that exaust the Lua stack -- several tests that exaust the Lua stack
collectgarbage() collectgarbage()
print"testing stack overflow" print"testing stack overflow"
C = 0 local C = 0
-- get line where stack overflow will happen -- get line where stack overflow will happen
local l = debug.getinfo(1, "l").currentline + 1 local l = debug.getinfo(1, "l").currentline + 1
local function auxy () C=C+1; auxy() end -- produce a stack overflow local function auxy () C=C+1; auxy() end -- produce a stack overflow
function y () function YY ()
collectgarbage("stop") -- avoid running finalizers without stack space collectgarbage("stop") -- avoid running finalizers without stack space
auxy() auxy()
collectgarbage("restart") collectgarbage("restart")
@@ -465,9 +501,11 @@ if not _soft then
return (string.find(m, "stack overflow")) return (string.find(m, "stack overflow"))
end end
-- repeated stack overflows (to check stack recovery) -- repeated stack overflows (to check stack recovery)
assert(checkstackmessage(doit('y()'))) assert(checkstackmessage(doit('YY()')))
assert(checkstackmessage(doit('y()'))) assert(checkstackmessage(doit('YY()')))
assert(checkstackmessage(doit('y()'))) assert(checkstackmessage(doit('YY()')))
_G.YY = nil
-- error lines in stack overflow -- error lines in stack overflow
@@ -561,7 +599,7 @@ do
end end
-- xpcall with arguments -- xpcall with arguments
a, b, c = xpcall(string.find, error, "alo", "al") local a, b, c = xpcall(string.find, error, "alo", "al")
assert(a and b == 1 and c == 2) assert(a and b == 1 and c == 2)
a, b, c = xpcall(string.find, function (x) return {} end, true, "al") a, b, c = xpcall(string.find, function (x) return {} end, true, "al")
assert(not a and type(b) == "table" and c == nil) assert(not a and type(b) == "table" and c == nil)
@@ -581,11 +619,12 @@ checksyntax("a\1a = 1", "", "<\\1>", 1)
-- test 255 as first char in a chunk -- test 255 as first char in a chunk
checksyntax("\255a = 1", "", "<\\255>", 1) checksyntax("\255a = 1", "", "<\\255>", 1)
doit('I = load("a=9+"); a=3') doit('I = load("a=9+"); aaa=3')
assert(a==3 and not I) assert(_G.aaa==3 and not _G.I)
_G.I,_G.aaa = nil
print('+') print('+')
lim = 1000 local lim = 1000
if _soft then lim = 100 end if _soft then lim = 100 end
for i=1,lim do for i=1,lim do
doit('a = ') doit('a = ')
+16
View File
@@ -370,6 +370,19 @@ x = 0 .."a".."b"..c..d.."e".."f".."g"
assert(x.val == "0abcdefg") assert(x.val == "0abcdefg")
do
-- bug since 5.4.1
local mt = setmetatable({__newindex={}}, {__mode='v'})
local t = setmetatable({}, mt)
if T then T.allocfailnext() end
-- seg. fault
for i=1, 10 do t[i] = 1 end
end
-- concat metamethod x numbers (bug in 5.1.1) -- concat metamethod x numbers (bug in 5.1.1)
c = {} c = {}
local x local x
@@ -420,6 +433,9 @@ assert(i == 3 and x[1] == 3 and x[3] == 5)
assert(_G.X == 20) assert(_G.X == 20)
_G.X, _G.B = nil
print'+' print'+'
local _g = _G local _g = _G
+17 -6
View File
@@ -92,8 +92,8 @@ assert(io.output():seek("end") == string.len("alo joao"))
assert(io.output():seek("set") == 0) assert(io.output():seek("set") == 0)
assert(io.write('"álo"', "{a}\n", "second line\n", "third line \n")) assert(io.write('"alo"', "{a}\n", "second line\n", "third line \n"))
assert(io.write('çfourth_line')) assert(io.write('Xfourth_line'))
io.output(io.stdout) io.output(io.stdout)
collectgarbage() -- file should be closed by GC collectgarbage() -- file should be closed by GC
assert(io.input() == io.stdin and rawequal(io.output(), io.stdout)) assert(io.input() == io.stdin and rawequal(io.output(), io.stdout))
@@ -300,14 +300,14 @@ do -- test error returns
end end
checkerr("invalid format", io.read, "x") checkerr("invalid format", io.read, "x")
assert(io.read(0) == "") -- not eof assert(io.read(0) == "") -- not eof
assert(io.read(5, 'l') == '"álo"') assert(io.read(5, 'l') == '"alo"')
assert(io.read(0) == "") assert(io.read(0) == "")
assert(io.read() == "second line") assert(io.read() == "second line")
local x = io.input():seek() local x = io.input():seek()
assert(io.read() == "third line ") assert(io.read() == "third line ")
assert(io.input():seek("set", x)) assert(io.input():seek("set", x))
assert(io.read('L') == "third line \n") assert(io.read('L') == "third line \n")
assert(io.read(1) == "ç") assert(io.read(1) == "X")
assert(io.read(string.len"fourth_line") == "fourth_line") assert(io.read(string.len"fourth_line") == "fourth_line")
assert(io.input():seek("cur", -string.len"fourth_line")) assert(io.input():seek("cur", -string.len"fourth_line"))
assert(io.read() == "fourth_line") assert(io.read() == "fourth_line")
@@ -507,15 +507,17 @@ load((io.lines(file, 1)))()
assert(_G.X == 4) assert(_G.X == 4)
load((io.lines(file, 3)))() load((io.lines(file, 3)))()
assert(_G.X == 8) assert(_G.X == 8)
_G.X = nil
print('+') print('+')
local x1 = "string\n\n\\com \"\"''coisas [[estranhas]] ]]'" local x1 = "string\n\n\\com \"\"''coisas [[estranhas]] ]]'"
io.output(file) io.output(file)
assert(io.write(string.format("x2 = %q\n-- comment without ending EOS", x1))) assert(io.write(string.format("X2 = %q\n-- comment without ending EOS", x1)))
io.close() io.close()
assert(loadfile(file))() assert(loadfile(file))()
assert(x1 == x2) assert(x1 == _G.X2)
_G.X2 = nil
print('+') print('+')
assert(os.remove(file)) assert(os.remove(file))
assert(not os.remove(file)) assert(not os.remove(file))
@@ -825,8 +827,17 @@ checkerr("missing", os.time, {hour = 12}) -- missing date
if string.packsize("i") == 4 then -- 4-byte ints if string.packsize("i") == 4 then -- 4-byte ints
checkerr("field 'year' is out-of-bound", os.time, checkerr("field 'year' is out-of-bound", os.time,
{year = -(1 << 31) + 1899, month = 1, day = 1}) {year = -(1 << 31) + 1899, month = 1, day = 1})
checkerr("field 'year' is out-of-bound", os.time,
{year = -(1 << 31), month = 1, day = 1})
if math.maxinteger > 2^31 then -- larger lua_integer?
checkerr("field 'year' is out-of-bound", os.time,
{year = (1 << 31) + 1900, month = 1, day = 1})
end
end end
if not _port then if not _port then
-- test Posix-specific modifiers -- test Posix-specific modifiers
assert(type(os.date("%Ex")) == 'string') assert(type(os.date("%Ex")) == 'string')
+32 -18
View File
@@ -125,7 +125,7 @@ do
end end
a:test() a:test()
_G.temp = nil
end end
@@ -134,7 +134,7 @@ do local f = function () end end
print("functions with errors") print("functions with errors")
prog = [[ local prog = [[
do do
a = 10; a = 10;
function foo(x,y) function foo(x,y)
@@ -153,22 +153,25 @@ do
end end
end end
end end
rawset(_G, "a", nil)
_G.x = nil
foo = nil do
print('long strings') foo = nil
x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789" print('long strings')
assert(string.len(x)==80) local x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
s = '' assert(string.len(x)==80)
k = math.min(300, (math.maxinteger // 80) // 2) local s = ''
for n = 1, k do s = s..x; j=tostring(n) end local k = math.min(300, (math.maxinteger // 80) // 2)
assert(string.len(s) == k*80) for n = 1, k do s = s..x; local j=tostring(n) end
s = string.sub(s, 1, 10000) assert(string.len(s) == k*80)
s, i = string.gsub(s, '(%d%d%d%d)', '') s = string.sub(s, 1, 10000)
assert(i==10000 // 4) local s, i = string.gsub(s, '(%d%d%d%d)', '')
s = nil assert(i==10000 // 4)
x = nil
assert(_G["while"] == 234) assert(_G["while"] == 234)
_G["while"] = nil
end
-- --
@@ -227,8 +230,8 @@ end
print("clearing tables") print("clearing tables")
lim = 15 local lim = 15
a = {} local a = {}
-- fill a with `collectable' indices -- fill a with `collectable' indices
for i=1,lim do a[{}] = i end for i=1,lim do a[{}] = i end
b = {} b = {}
@@ -298,6 +301,16 @@ collectgarbage()
assert(next(a) == string.rep('$', 11)) assert(next(a) == string.rep('$', 11))
if T then -- bug since 5.3: all-weak tables are not being revisited
T.gcstate("propagate")
local t = setmetatable({}, {__mode = "kv"})
T.gcstate("atomic") -- 't' was visited
setmetatable(t, {__mode = "kv"})
T.gcstate("pause") -- its new metatable is not being visited
assert(getmetatable(t).__mode == "kv")
end
-- 'bug' in 5.1 -- 'bug' in 5.1
a = {} a = {}
local t = {x = 10} local t = {x = 10}
@@ -552,6 +565,7 @@ do
for i=1,1000 do _ENV.a = {} end -- no collection during the loop for i=1,1000 do _ENV.a = {} end -- no collection during the loop
until gcinfo() > 2 * x until gcinfo() > 2 * x
collectgarbage"restart" collectgarbage"restart"
_ENV.a = nil
end end
+5 -5
View File
@@ -11,17 +11,17 @@ CFLAGS = -Wall -std=gnu99 -O2 -I$(LUA_DIR) -fPIC -shared
all: lib1.so lib11.so lib2.so lib21.so lib2-v2.so all: lib1.so lib11.so lib2.so lib21.so lib2-v2.so
touch all touch all
lib1.so: lib1.c $(LUA_DIR)/luaconf.h lib1.so: lib1.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib1.so lib1.c $(CC) $(CFLAGS) -o lib1.so lib1.c
lib11.so: lib11.c $(LUA_DIR)/luaconf.h lib11.so: lib11.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib11.so lib11.c $(CC) $(CFLAGS) -o lib11.so lib11.c
lib2.so: lib2.c $(LUA_DIR)/luaconf.h lib2.so: lib2.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib2.so lib2.c $(CC) $(CFLAGS) -o lib2.so lib2.c
lib21.so: lib21.c $(LUA_DIR)/luaconf.h lib21.so: lib21.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib21.so lib21.c $(CC) $(CFLAGS) -o lib21.so lib21.c
lib2-v2.so: lib21.c $(LUA_DIR)/luaconf.h lib2-v2.so: lib21.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib2-v2.so lib22.c $(CC) $(CFLAGS) -o lib2-v2.so lib22.c
+17 -16
View File
@@ -10,6 +10,7 @@ local function dostring (x) return assert(load(x), "")() end
dostring("x \v\f = \t\r 'a\0a' \v\f\f") dostring("x \v\f = \t\r 'a\0a' \v\f\f")
assert(x == 'a\0a' and string.len(x) == 3) assert(x == 'a\0a' and string.len(x) == 3)
_G.x = nil
-- escape sequences -- escape sequences
assert('\n\"\'\\' == [[ assert('\n\"\'\\' == [[
@@ -129,16 +130,16 @@ end
-- long variable names -- long variable names
var1 = string.rep('a', 15000) .. '1' local var1 = string.rep('a', 15000) .. '1'
var2 = string.rep('a', 15000) .. '2' local var2 = string.rep('a', 15000) .. '2'
prog = string.format([[ local prog = string.format([[
%s = 5 %s = 5
%s = %s + 1 %s = %s + 1
return function () return %s - %s end return function () return %s - %s end
]], var1, var2, var1, var1, var2) ]], var1, var2, var1, var1, var2)
local f = dostring(prog) local f = dostring(prog)
assert(_G[var1] == 5 and _G[var2] == 6 and f() == -1) assert(_G[var1] == 5 and _G[var2] == 6 and f() == -1)
var1, var2, f = nil _G[var1], _G[var2] = nil
print('+') print('+')
-- escapes -- -- escapes --
@@ -150,13 +151,13 @@ assert([[
$debug]] == "\n $debug") $debug]] == "\n $debug")
assert([[ [ ]] ~= [[ ] ]]) assert([[ [ ]] ~= [[ ] ]])
-- long strings -- -- long strings --
b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789" local b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
assert(string.len(b) == 960) assert(string.len(b) == 960)
prog = [=[ prog = [=[
print('+') print('+')
a1 = [["this is a 'string' with several 'quotes'"]] local a1 = [["this is a 'string' with several 'quotes'"]]
a2 = "'quotes'" local a2 = "'quotes'"
assert(string.find(a1, a2) == 34) assert(string.find(a1, a2) == 34)
print('+') print('+')
@@ -164,12 +165,13 @@ print('+')
a1 = [==[temp = [[an arbitrary value]]; ]==] a1 = [==[temp = [[an arbitrary value]]; ]==]
assert(load(a1))() assert(load(a1))()
assert(temp == 'an arbitrary value') assert(temp == 'an arbitrary value')
_G.temp = nil
-- long strings -- -- long strings --
b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789" local b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
assert(string.len(b) == 960) assert(string.len(b) == 960)
print('+') print('+')
a = [[00123456789012345678901234567890123456789123456789012345678901234567890123456789 local a = [[00123456789012345678901234567890123456789123456789012345678901234567890123456789
00123456789012345678901234567890123456789123456789012345678901234567890123456789 00123456789012345678901234567890123456789123456789012345678901234567890123456789
00123456789012345678901234567890123456789123456789012345678901234567890123456789 00123456789012345678901234567890123456789123456789012345678901234567890123456789
00123456789012345678901234567890123456789123456789012345678901234567890123456789 00123456789012345678901234567890123456789123456789012345678901234567890123456789
@@ -199,13 +201,11 @@ x = 1
]=] ]=]
print('+') print('+')
x = nil _G.x = nil
dostring(prog) dostring(prog)
assert(x) assert(x)
_G.x = nil
prog = nil
a = nil
b = nil
do -- reuse of long strings do -- reuse of long strings
@@ -234,8 +234,8 @@ end
-- testing line ends -- testing line ends
prog = [[ prog = [[
a = 1 -- a comment local a = 1 -- a comment
b = 2 local b = 2
x = [=[ x = [=[
@@ -252,10 +252,11 @@ for _, n in pairs{"\n", "\r", "\n\r", "\r\n"} do
assert(dostring(prog) == nn) assert(dostring(prog) == nn)
assert(_G.x == "hi\n" and _G.y == "\nhello\r\n\n") assert(_G.x == "hi\n" and _G.y == "\nhello\r\n\n")
end end
_G.x, _G.y = nil
-- testing comments and strings with long brackets -- testing comments and strings with long brackets
a = [==[]=]==] local a = [==[]=]==]
assert(a == "]=") assert(a == "]=")
a = [==[[===[[=[]]=][====[]]===]===]==] a = [==[[===[[=[]]=][====[]]===]===]==]
+47 -3
View File
@@ -37,7 +37,7 @@ end
f = nil f = nil
local f local f
x = 1 local x = 1
a = nil a = nil
load('local a = {}')() load('local a = {}')()
@@ -152,7 +152,7 @@ local dummy
local _ENV = (function (...) return ... end)(_G, dummy) -- { local _ENV = (function (...) return ... end)(_G, dummy) -- {
do local _ENV = {assert=assert}; assert(true) end do local _ENV = {assert=assert}; assert(true) end
mt = {_G = _G} local mt = {_G = _G}
local foo,x local foo,x
A = false -- "declare" A A = false -- "declare" A
do local _ENV = mt do local _ENV = mt
@@ -174,6 +174,8 @@ do local _ENV = {assert=assert, A=10};
end end
assert(x==20) assert(x==20)
A = nil
do -- constants do -- constants
local a<const>, b, c<const> = 10, 20, 30 local a<const>, b, c<const> = 10, 20, 30
@@ -360,6 +362,26 @@ do
end end
do
-- bug in 5.4.4: 'break' may generate wrong 'close' instruction when
-- leaving a loop block.
local closed = false
local o1 = setmetatable({}, {__close=function() closed = true end})
local function test()
for k, v in next, {}, nil, o1 do
local function f() return k end -- create an upvalue
break
end
assert(closed)
end
test()
end
do print("testing errors in __close") do print("testing errors in __close")
-- original error is in __close -- original error is in __close
@@ -592,6 +614,28 @@ end
if rawget(_G, "T") then if rawget(_G, "T") then
do
-- bug in 5.4.3
-- 'lua_settop' may use a pointer to stack invalidated by 'luaF_close'
-- reduce stack size
collectgarbage(); collectgarbage(); collectgarbage()
-- force a stack reallocation
local function loop (n)
if n < 400 then loop(n + 1) end
end
-- close metamethod will reallocate the stack
local o = setmetatable({}, {__close = function () loop(0) end})
local script = [[toclose 2; settop 1; return 1]]
assert(T.testC(script, o) == script)
end
-- memory error inside closing function -- memory error inside closing function
local function foo () local function foo ()
local y <close> = func2close(function () T.alloccount() end) local y <close> = func2close(function () T.alloccount() end)
@@ -669,7 +713,7 @@ if rawget(_G, "T") then
collectgarbage(); collectgarbage() collectgarbage(); collectgarbage()
m = T.totalmem() local m = T.totalmem()
collectgarbage("stop") collectgarbage("stop")
-- error in the first buffer allocation -- error in the first buffer allocation
+64 -22
View File
@@ -27,17 +27,19 @@ do
end end
print("progname: "..progname) print("progname: "..progname)
local prepfile = function (s, p)
p = p or prog local prepfile = function (s, mod, p)
io.output(p) mod = mod and "wb" or "w" -- mod true means binary files
io.write(s) p = p or prog -- file to write the program
assert(io.close()) local f = io.open(p, mod)
f:write(s)
assert(f:close())
end end
local function getoutput () local function getoutput ()
io.input(out) local f = io.open(out)
local t = io.read("a") local t = f:read("a")
io.input():close() f:close()
assert(os.remove(out)) assert(os.remove(out))
return t return t
end end
@@ -65,10 +67,11 @@ local function RUN (p, ...)
assert(os.execute(s)) assert(os.execute(s))
end end
local function NoRun (msg, p, ...) local function NoRun (msg, p, ...)
p = string.gsub(p, "lua", '"'..progname..'"', 1) p = string.gsub(p, "lua", '"'..progname..'"', 1)
local s = string.format(p, ...) local s = string.format(p, ...)
s = string.format("%s 2> %s", s, out) -- will send error to 'out' s = string.format("%s >%s 2>&1", s, out) -- send output and error to 'out'
assert(not os.execute(s)) assert(not os.execute(s))
assert(string.find(getoutput(), msg, 1, true)) -- check error message assert(string.find(getoutput(), msg, 1, true)) -- check error message
end end
@@ -87,13 +90,40 @@ prepfile[[
1, a 1, a
) )
]] ]]
RUN('lua - < %s > %s', prog, out) RUN('lua - -- < %s > %s', prog, out)
checkout("1\tnil\n") checkout("1\tnil\n")
RUN('echo "print(10)\nprint(2)\n" | lua > %s', out) RUN('echo "print(10)\nprint(2)\n" | lua > %s', out)
checkout("10\n2\n") checkout("10\n2\n")
-- testing BOM
prepfile("\xEF\xBB\xBF")
RUN('lua %s > %s', prog, out)
checkout("")
prepfile("\xEF\xBB\xBFprint(3)")
RUN('lua %s > %s', prog, out)
checkout("3\n")
prepfile("\xEF\xBB\xBF# comment!!\nprint(3)")
RUN('lua %s > %s', prog, out)
checkout("3\n")
-- bad BOMs
prepfile("\xEF", true)
NoRun("unexpected symbol", 'lua %s', prog)
prepfile("\xEF\xBB", true)
NoRun("unexpected symbol", 'lua %s', prog)
prepfile("\xEFprint(3)", true)
NoRun("unexpected symbol", 'lua %s', prog)
prepfile("\xEF\xBBprint(3)", true)
NoRun("unexpected symbol", 'lua %s', prog)
-- test option '-' -- test option '-'
RUN('echo "print(arg[1])" | lua - -h > %s', out) RUN('echo "print(arg[1])" | lua - -h > %s', out)
checkout("-h\n") checkout("-h\n")
@@ -103,7 +133,7 @@ checkout("-h\n")
prepfile("print(package.path)") prepfile("print(package.path)")
-- test LUA_PATH -- test LUA_PATH
RUN('env LUA_INIT= LUA_PATH=x lua %s > %s', prog, out) RUN('env LUA_INIT= LUA_PATH=x lua -- %s > %s', prog, out)
checkout("x\n") checkout("x\n")
-- test LUA_PATH_version -- test LUA_PATH_version
@@ -186,7 +216,7 @@ convert("a;b;;c")
-- test -l over multiple libraries -- test -l over multiple libraries
prepfile("print(1); a=2; return {x=15}") prepfile("print(1); a=2; return {x=15}")
prepfile(("print(a); print(_G['%s'].x)"):format(prog), otherprog) prepfile(("print(a); print(_G['%s'].x)"):format(prog), false, otherprog)
RUN('env LUA_PATH="?;;" lua -l %s -l%s -lstring -l io %s > %s', prog, otherprog, otherprog, out) RUN('env LUA_PATH="?;;" lua -l %s -l%s -lstring -l io %s > %s', prog, otherprog, otherprog, out)
checkout("1\n2\n15\n2\n15\n") checkout("1\n2\n15\n2\n15\n")
@@ -195,6 +225,13 @@ prepfile("print(str.upper'alo alo', m.max(10, 20))")
RUN("lua -l 'str=string' '-lm=math' -e 'print(m.sin(0))' %s > %s", prog, out) RUN("lua -l 'str=string' '-lm=math' -e 'print(m.sin(0))' %s > %s", prog, out)
checkout("0.0\nALO ALO\t20\n") checkout("0.0\nALO ALO\t20\n")
-- test module names with version sufix ("libs/lib2-v2")
RUN("env LUA_CPATH='./libs/?.so' lua -l lib2-v2 -e 'print(lib2.id())' > %s",
out)
checkout("true\n")
-- test 'arg' table -- test 'arg' table
local a = [[ local a = [[
assert(#arg == 3 and arg[1] == 'a' and assert(#arg == 3 and arg[1] == 'a' and
@@ -210,7 +247,7 @@ RUN('lua "-e " -- %s a b c', prog) -- "-e " runs an empty command
-- test 'arg' availability in libraries -- test 'arg' availability in libraries
prepfile"assert(arg)" prepfile"assert(arg)"
prepfile("assert(arg)", otherprog) prepfile("assert(arg)", false, otherprog)
RUN('env LUA_PATH="?;;" lua -l%s - < %s', prog, otherprog) RUN('env LUA_PATH="?;;" lua -l%s - < %s', prog, otherprog)
-- test messing up the 'arg' table -- test messing up the 'arg' table
@@ -309,10 +346,15 @@ RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
checkprogout("6\n10\n10\n\n") checkprogout("6\n10\n10\n\n")
prepfile("a = [[b\nc\nd\ne]]\n=a") prepfile("a = [[b\nc\nd\ne]]\n=a")
RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i -- < %s > %s]], prog, out)
checkprogout("b\nc\nd\ne\n\n") checkprogout("b\nc\nd\ne\n\n")
prompt = "alo" -- input interrupted in continuation line
prepfile("a.\n")
RUN([[lua -i < %s > /dev/null 2> %s]], prog, out)
checkprogout("near <eof>\n")
local prompt = "alo"
prepfile[[ -- prepfile[[ --
a = 2 a = 2
]] ]]
@@ -363,7 +405,7 @@ NoRun("error object is a table value", [[lua %s]], prog)
-- chunk broken in many lines -- chunk broken in many lines
s = [=[ -- local s = [=[ --
function f ( x ) function f ( x )
local a = [[ local a = [[
xuxu xuxu
@@ -385,12 +427,10 @@ checkprogout("101\n13\t22\n\n")
prepfile[[#comment in 1st line without \n at the end]] prepfile[[#comment in 1st line without \n at the end]]
RUN('lua %s', prog) RUN('lua %s', prog)
prepfile[[#test line number when file starts with comment line -- first-line comment with binary file
debug = require"debug" prepfile("#comment\n" .. string.dump(load("print(3)")), true)
print(debug.getinfo(1).currentline)
]]
RUN('lua %s > %s', prog, out) RUN('lua %s > %s', prog, out)
checkprogout('3\n') checkout('3\n')
-- close Lua with an open file -- close Lua with an open file
prepfile(string.format([[io.output(%q); io.write('alo')]], out)) prepfile(string.format([[io.output(%q); io.write('alo')]], out))
@@ -438,12 +478,14 @@ assert(not os.remove(out))
-- invalid options -- invalid options
NoRun("unrecognized option '-h'", "lua -h") NoRun("unrecognized option '-h'", "lua -h")
NoRun("unrecognized option '---'", "lua ---") NoRun("unrecognized option '---'", "lua ---")
NoRun("unrecognized option '-Ex'", "lua -Ex") NoRun("unrecognized option '-Ex'", "lua -Ex --")
NoRun("unrecognized option '-vv'", "lua -vv") NoRun("unrecognized option '-vv'", "lua -vv")
NoRun("unrecognized option '-iv'", "lua -iv") NoRun("unrecognized option '-iv'", "lua -iv")
NoRun("'-e' needs argument", "lua -e") NoRun("'-e' needs argument", "lua -e")
NoRun("syntax error", "lua -e a") NoRun("syntax error", "lua -e a")
NoRun("'-l' needs argument", "lua -l") NoRun("'-l' needs argument", "lua -l")
NoRun("-i", "lua -- -i") -- handles -i as a script name
if T then -- test library? if T then -- test library?
+3 -3
View File
@@ -50,7 +50,7 @@ end
local msgf2i = "number.* has no integer representation" local msgf2i = "number.* has no integer representation"
-- float equality -- float equality
function eq (a,b,limit) local function eq (a,b,limit)
if not limit then if not limit then
if floatbits >= 50 then limit = 1E-11 if floatbits >= 50 then limit = 1E-11
else limit = 1E-5 else limit = 1E-5
@@ -62,7 +62,7 @@ end
-- equality with types -- equality with types
function eqT (a,b) local function eqT (a,b)
return a == b and math.type(a) == math.type(b) return a == b and math.type(a) == math.type(b)
end end
@@ -83,7 +83,7 @@ end
do do
local x = -1 local x = -1
local mz = 0/x -- minus zero local mz = 0/x -- minus zero
t = {[0] = 10, 20, 30, 40, 50} local t = {[0] = 10, 20, 30, 40, 50}
assert(t[mz] == t[0] and t[-0] == t[0]) assert(t[mz] == t[0] and t[-0] == t[0])
end end
+30 -10
View File
@@ -9,6 +9,16 @@ local function checkerror (msg, f, ...)
end end
local function check (t, na, nh)
if not T then return end
local a, h = T.querytab(t)
if a ~= na or h ~= nh then
print(na, nh, a, h)
assert(nil)
end
end
local a = {} local a = {}
-- make sure table has lots of space in hash part -- make sure table has lots of space in hash part
@@ -20,6 +30,25 @@ for i=1,100 do
assert(#a == i) assert(#a == i)
end end
do -- rehash moving elements from array to hash
local a = {}
for i = 1, 100 do a[i] = i end
check(a, 128, 0)
for i = 5, 95 do a[i] = nil end
check(a, 128, 0)
a.x = 1 -- force a re-hash
check(a, 4, 8)
for i = 1, 4 do assert(a[i] == i) end
for i = 5, 95 do assert(a[i] == nil) end
for i = 96, 100 do assert(a[i] == i) end
assert(a.x == 1)
end
-- testing ipairs -- testing ipairs
local x = 0 local x = 0
for k,v in ipairs{10,20,30;x=12} do for k,v in ipairs{10,20,30;x=12} do
@@ -65,15 +94,6 @@ local function mp2 (n) -- minimum power of 2 >= n
end end
local function check (t, na, nh)
local a, h = T.querytab(t)
if a ~= na or h ~= nh then
print(na, nh, a, h)
assert(nil)
end
end
-- testing C library sizes -- testing C library sizes
do do
local s = 0 local s = 0
@@ -169,7 +189,7 @@ end
-- size tests for vararg -- size tests for vararg
lim = 35 lim = 35
function foo (n, ...) local function foo (n, ...)
local arg = {...} local arg = {...}
check(arg, n, 0) check(arg, n, 0)
assert(select('#', ...) == n) assert(select('#', ...) == n)
+52 -33
View File
@@ -1,6 +1,9 @@
-- $Id: testes/pm.lua $ -- $Id: testes/pm.lua $
-- See Copyright Notice in file all.lua -- See Copyright Notice in file all.lua
-- UTF-8 file
print('testing pattern matching') print('testing pattern matching')
local function checkerror (msg, f, ...) local function checkerror (msg, f, ...)
@@ -9,12 +12,12 @@ local function checkerror (msg, f, ...)
end end
function f(s, p) local function f (s, p)
local i,e = string.find(s, p) local i,e = string.find(s, p)
if i then return string.sub(s, i, e) end if i then return string.sub(s, i, e) end
end end
a,b = string.find('', '') -- empty patterns are tricky local a,b = string.find('', '') -- empty patterns are tricky
assert(a == 1 and b == 0); assert(a == 1 and b == 0);
a,b = string.find('alo', '') a,b = string.find('alo', '')
assert(a == 1 and b == 0) assert(a == 1 and b == 0)
@@ -50,6 +53,20 @@ assert(f('aLo_ALO', '%a*') == 'aLo')
assert(f(" \n\r*&\n\r xuxu \n\n", "%g%g%g+") == "xuxu") assert(f(" \n\r*&\n\r xuxu \n\n", "%g%g%g+") == "xuxu")
-- Adapt a pattern to UTF-8
local function PU (p)
-- reapply '?' into each individual byte of a character.
-- (For instance, "á?" becomes "\195?\161?".)
p = string.gsub(p, "(" .. utf8.charpattern .. ")%?", function (c)
return string.gsub(c, ".", "%0?")
end)
-- change '.' to utf-8 character patterns
p = string.gsub(p, "%.", utf8.charpattern)
return p
end
assert(f('aaab', 'a*') == 'aaa'); assert(f('aaab', 'a*') == 'aaa');
assert(f('aaa', '^.*$') == 'aaa'); assert(f('aaa', '^.*$') == 'aaa');
assert(f('aaa', 'b*') == ''); assert(f('aaa', 'b*') == '');
@@ -73,22 +90,22 @@ assert(f('aaa', '^.-$') == 'aaa')
assert(f('aabaaabaaabaaaba', 'b.*b') == 'baaabaaabaaab') assert(f('aabaaabaaabaaaba', 'b.*b') == 'baaabaaabaaab')
assert(f('aabaaabaaabaaaba', 'b.-b') == 'baaab') assert(f('aabaaabaaabaaaba', 'b.-b') == 'baaab')
assert(f('alo xo', '.o$') == 'xo') assert(f('alo xo', '.o$') == 'xo')
assert(f(' \n isto é assim', '%S%S*') == 'isto') assert(f(' \n isto é assim', '%S%S*') == 'isto')
assert(f(' \n isto é assim', '%S*$') == 'assim') assert(f(' \n isto é assim', '%S*$') == 'assim')
assert(f(' \n isto é assim', '[a-z]*$') == 'assim') assert(f(' \n isto é assim', '[a-z]*$') == 'assim')
assert(f('um caracter ? extra', '[^%sa-z]') == '?') assert(f('um caracter ? extra', '[^%sa-z]') == '?')
assert(f('', 'a?') == '') assert(f('', 'a?') == '')
assert(f('á', 'á?') == 'á') assert(f('á', PU'á?') == 'á')
assert(f('ábl', 'á?b?l?') == 'ábl') assert(f('ábl', PU'á?b?l?') == 'ábl')
assert(f(' ábl', 'á?b?l?') == '') assert(f(' ábl', PU'á?b?l?') == '')
assert(f('aa', '^aa?a?a') == 'aa') assert(f('aa', '^aa?a?a') == 'aa')
assert(f(']]]áb', '[^]]') == 'á') assert(f(']]]áb', '[^]]+') == 'áb')
assert(f("0alo alo", "%x*") == "0a") assert(f("0alo alo", "%x*") == "0a")
assert(f("alo alo", "%C+") == "alo alo") assert(f("alo alo", "%C+") == "alo alo")
print('+') print('+')
function f1(s, p) local function f1 (s, p)
p = string.gsub(p, "%%([0-9])", function (s) p = string.gsub(p, "%%([0-9])", function (s)
return "%" .. (tonumber(s)+1) return "%" .. (tonumber(s)+1)
end) end)
@@ -113,7 +130,7 @@ local abc = string.char(range(0, 127)) .. string.char(range(128, 255));
assert(string.len(abc) == 256) assert(string.len(abc) == 256)
function strset (p) local function strset (p)
local res = {s=''} local res = {s=''}
string.gsub(abc, p, function (c) res.s = res.s .. c end) string.gsub(abc, p, function (c) res.s = res.s .. c end)
return res.s return res.s
@@ -136,28 +153,28 @@ assert(string.match("alo xyzK", "(%w+)K") == "xyz")
assert(string.match("254 K", "(%d*)K") == "") assert(string.match("254 K", "(%d*)K") == "")
assert(string.match("alo ", "(%w*)$") == "") assert(string.match("alo ", "(%w*)$") == "")
assert(not string.match("alo ", "(%w+)$")) assert(not string.match("alo ", "(%w+)$"))
assert(string.find("(álo)", "%(á") == 1) assert(string.find("(álo)", "%(á") == 1)
local a, b, c, d, e = string.match("âlo alo", "^(((.).).* (%w*))$") local a, b, c, d, e = string.match("âlo alo", PU"^(((.).). (%w*))$")
assert(a == 'âlo alo' and b == 'âl' and c == 'â' and d == 'alo' and e == nil) assert(a == 'âlo alo' and b == 'âl' and c == 'â' and d == 'alo' and e == nil)
a, b, c, d = string.match('0123456789', '(.+(.?)())') a, b, c, d = string.match('0123456789', '(.+(.?)())')
assert(a == '0123456789' and b == '' and c == 11 and d == nil) assert(a == '0123456789' and b == '' and c == 11 and d == nil)
print('+') print('+')
assert(string.gsub('ülo ülo', 'ü', 'x') == 'xlo xlo') assert(string.gsub('ülo ülo', 'ü', 'x') == 'xlo xlo')
assert(string.gsub('alo úlo ', ' +$', '') == 'alo úlo') -- trim assert(string.gsub('alo úlo ', ' +$', '') == 'alo úlo') -- trim
assert(string.gsub(' alo alo ', '^%s*(.-)%s*$', '%1') == 'alo alo') -- double trim assert(string.gsub(' alo alo ', '^%s*(.-)%s*$', '%1') == 'alo alo') -- double trim
assert(string.gsub('alo alo \n 123\n ', '%s+', ' ') == 'alo alo 123 ') assert(string.gsub('alo alo \n 123\n ', '%s+', ' ') == 'alo alo 123 ')
t = "abç d" local t = "abç d"
a, b = string.gsub(t, '(.)', '%1@') a, b = string.gsub(t, PU'(.)', '%1@')
assert('@'..a == string.gsub(t, '', '@') and b == 5) assert(a == "a@b@ç@ @d@" and b == 5)
a, b = string.gsub('abçd', '(.)', '%0@', 2) a, b = string.gsub('abçd', PU'(.)', '%0@', 2)
assert(a == 'a@b@çd' and b == 2) assert(a == 'a@b@çd' and b == 2)
assert(string.gsub('alo alo', '()[al]', '%1') == '12o 56o') assert(string.gsub('alo alo', '()[al]', '%1') == '12o 56o')
assert(string.gsub("abc=xyz", "(%w*)(%p)(%w+)", "%3%2%1-%0") == assert(string.gsub("abc=xyz", "(%w*)(%p)(%w+)", "%3%2%1-%0") ==
"xyz=abc-abc=xyz") "xyz=abc-abc=xyz")
assert(string.gsub("abc", "%w", "%1%0") == "aabbcc") assert(string.gsub("abc", "%w", "%1%0") == "aabbcc")
assert(string.gsub("abc", "%w+", "%0%1") == "abcabc") assert(string.gsub("abc", "%w+", "%0%1") == "abcabc")
assert(string.gsub('áéí', '$', '\0óú') == 'áéí\0óú') assert(string.gsub('áéí', '$', '\0óú') == 'áéí\0óú')
assert(string.gsub('', '^', 'r') == 'r') assert(string.gsub('', '^', 'r') == 'r')
assert(string.gsub('', '$', 'r') == 'r') assert(string.gsub('', '$', 'r') == 'r')
print('+') print('+')
@@ -184,31 +201,33 @@ do
local function setglobal (n,v) rawset(_G, n, v) end local function setglobal (n,v) rawset(_G, n, v) end
string.gsub("a=roberto,roberto=a", "(%w+)=(%w%w*)", setglobal) string.gsub("a=roberto,roberto=a", "(%w+)=(%w%w*)", setglobal)
assert(_G.a=="roberto" and _G.roberto=="a") assert(_G.a=="roberto" and _G.roberto=="a")
_G.a = nil; _G.roberto = nil
end end
function f(a,b) return string.gsub(a,'.',b) end function f(a,b) return string.gsub(a,'.',b) end
assert(string.gsub("trocar tudo em |teste|b| é |beleza|al|", "|([^|]*)|([^|]*)|", f) == assert(string.gsub("trocar tudo em |teste|b| é |beleza|al|", "|([^|]*)|([^|]*)|", f) ==
"trocar tudo em bbbbb é alalalalalal") "trocar tudo em bbbbb é alalalalalal")
local function dostring (s) return load(s, "")() or "" end local function dostring (s) return load(s, "")() or "" end
assert(string.gsub("alo $a='x'$ novamente $return a$", assert(string.gsub("alo $a='x'$ novamente $return a$",
"$([^$]*)%$", "$([^$]*)%$",
dostring) == "alo novamente x") dostring) == "alo novamente x")
x = string.gsub("$x=string.gsub('alo', '.', string.upper)$ assim vai para $return x$", local x = string.gsub("$x=string.gsub('alo', '.', string.upper)$ assim vai para $return x$",
"$([^$]*)%$", dostring) "$([^$]*)%$", dostring)
assert(x == ' assim vai para ALO') assert(x == ' assim vai para ALO')
_G.a, _G.x = nil
t = {} local t = {}
s = 'a alo jose joao' local s = 'a alo jose joao'
r = string.gsub(s, '()(%w+)()', function (a,w,b) local r = string.gsub(s, '()(%w+)()', function (a,w,b)
assert(string.len(w) == b-a); assert(string.len(w) == b-a);
t[a] = b-a; t[a] = b-a;
end) end)
assert(s == r and t[1] == 1 and t[3] == 3 and t[7] == 4 and t[13] == 4) assert(s == r and t[1] == 1 and t[3] == 3 and t[7] == 4 and t[13] == 4)
function isbalanced (s) local function isbalanced (s)
return not string.find(string.gsub(s, "%b()", ""), "[()]") return not string.find(string.gsub(s, "%b()", ""), "[()]")
end end
@@ -251,7 +270,7 @@ if not _soft then
end end
-- recursive nest of gsubs -- recursive nest of gsubs
function rev (s) local function rev (s)
return string.gsub(s, "(.)(.+)", function (c,s1) return rev(s1)..c end) return string.gsub(s, "(.)(.+)", function (c,s1) return rev(s1)..c end)
end end
+12 -11
View File
@@ -20,7 +20,7 @@ end
checkerror("wrong number of arguments", table.insert, {}, 2, 3, 4) checkerror("wrong number of arguments", table.insert, {}, 2, 3, 4)
local x,y,z,a,n local x,y,z,a,n
a = {}; lim = _soft and 200 or 2000 a = {}; local lim = _soft and 200 or 2000
for i=1, lim do a[i]=i end for i=1, lim do a[i]=i end
assert(select(lim, unpack(a)) == lim and select('#', unpack(a)) == lim) assert(select(lim, unpack(a)) == lim and select('#', unpack(a)) == lim)
x = unpack(a) x = unpack(a)
@@ -222,7 +222,7 @@ a = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
table.sort(a) table.sort(a)
check(a) check(a)
function perm (s, n) local function perm (s, n)
n = n or #s n = n or #s
if n == 1 then if n == 1 then
local t = {unpack(s)} local t = {unpack(s)}
@@ -248,7 +248,7 @@ perm{1,2,3,3,5}
perm{1,2,3,4,5,6} perm{1,2,3,4,5,6}
perm{2,2,3,3,5,6} perm{2,2,3,3,5,6}
function timesort (a, n, func, msg, pre) local function timesort (a, n, func, msg, pre)
local x = os.clock() local x = os.clock()
table.sort(a, func) table.sort(a, func)
x = (os.clock() - x) * 1000 x = (os.clock() - x) * 1000
@@ -257,7 +257,7 @@ function timesort (a, n, func, msg, pre)
check(a, func) check(a, func)
end end
limit = 50000 local limit = 50000
if _soft then limit = 5000 end if _soft then limit = 5000 end
a = {} a = {}
@@ -274,7 +274,7 @@ for i=1,limit do
a[i] = math.random() a[i] = math.random()
end end
x = os.clock(); i=0 local x = os.clock(); local i = 0
table.sort(a, function(x,y) i=i+1; return y<x end) table.sort(a, function(x,y) i=i+1; return y<x end)
x = (os.clock() - x) * 1000 x = (os.clock() - x) * 1000
print(string.format("Invert-sorting other %d elements in %.2f msec., with %i comparisons", print(string.format("Invert-sorting other %d elements in %.2f msec., with %i comparisons",
@@ -289,18 +289,19 @@ timesort(a, limit, function(x,y) return nil end, "equal")
for i,v in pairs(a) do assert(v == false) end for i,v in pairs(a) do assert(v == false) end
A = {"álo", "\0first :-)", "alo", "then this one", "45", "and a new"} AA = {"\xE1lo", "\0first :-)", "alo", "then this one", "45", "and a new"}
table.sort(A) table.sort(AA)
check(A) check(AA)
table.sort(A, function (x, y) table.sort(AA, function (x, y)
load(string.format("A[%q] = ''", x), "")() load(string.format("AA[%q] = ''", x), "")()
collectgarbage() collectgarbage()
return x<y return x<y
end) end)
_G.AA = nil
tt = {__lt = function (a,b) return a.val < b.val end} local tt = {__lt = function (a,b) return a.val < b.val end}
a = {} a = {}
for i=1,10 do a[i] = {val=math.random(100)}; setmetatable(a[i], tt); end for i=1,10 do a[i] = {val=math.random(100)}; setmetatable(a[i], tt); end
table.sort(a) table.sort(a)
+13 -5
View File
@@ -1,6 +1,9 @@
-- $Id: testes/strings.lua $ -- $Id: testes/strings.lua $
-- See Copyright Notice in file all.lua -- See Copyright Notice in file all.lua
-- ISO Latin encoding
print('testing strings and string library') print('testing strings and string library')
local maxi <const> = math.maxinteger local maxi <const> = math.maxinteger
@@ -52,7 +55,7 @@ assert(("\000123456789"):sub(8) == "789")
-- testing string.find -- testing string.find
assert(string.find("123456789", "345") == 3) assert(string.find("123456789", "345") == 3)
a,b = string.find("123456789", "345") local a,b = string.find("123456789", "345")
assert(string.sub("123456789", a, b) == "345") assert(string.sub("123456789", a, b) == "345")
assert(string.find("1234567890123456789", "345", 3) == 3) assert(string.find("1234567890123456789", "345", 3) == 3)
assert(string.find("1234567890123456789", "345", 4) == 13) assert(string.find("1234567890123456789", "345", 4) == 13)
@@ -192,7 +195,7 @@ do -- tests for '%p' format
end end
end end
x = '"ílo"\n\\' local x = '"ílo"\n\\'
assert(string.format('%q%s', x, x) == '"\\"ílo\\"\\\n\\\\""ílo"\n\\') assert(string.format('%q%s', x, x) == '"\\"ílo\\"\\\n\\\\""ílo"\n\\')
assert(string.format('%q', "\0") == [["\0"]]) assert(string.format('%q', "\0") == [["\0"]])
assert(load(string.format('return %q', x))() == x) assert(load(string.format('return %q', x))() == x)
@@ -346,13 +349,18 @@ assert(string.format("%013i", -100) == "-000000000100")
assert(string.format("%2.5d", -100) == "-00100") assert(string.format("%2.5d", -100) == "-00100")
assert(string.format("%.u", 0) == "") assert(string.format("%.u", 0) == "")
assert(string.format("%+#014.0f", 100) == "+000000000100.") assert(string.format("%+#014.0f", 100) == "+000000000100.")
assert(string.format("% 1.0E", 100) == " 1E+02")
assert(string.format("%-16c", 97) == "a ") assert(string.format("%-16c", 97) == "a ")
assert(string.format("%+.3G", 1.5) == "+1.5") assert(string.format("%+.3G", 1.5) == "+1.5")
assert(string.format("% .1g", 2^10) == " 1e+03")
assert(string.format("%.0s", "alo") == "") assert(string.format("%.0s", "alo") == "")
assert(string.format("%.s", "alo") == "") assert(string.format("%.s", "alo") == "")
-- ISO C89 says that "The exponent always contains at least two digits",
-- but unlike ISO C99 it does not ensure that it contains "only as many
-- more digits as necessary".
assert(string.match(string.format("% 1.0E", 100), "^ 1E%+0+2$"))
assert(string.match(string.format("% .1g", 2^10), "^ 1e%+0+3$"))
-- errors in format -- errors in format
local function check (fmt, msg) local function check (fmt, msg)
@@ -447,7 +455,7 @@ end
do do
local f = string.gmatch("1 2 3 4 5", "%d+") local f = string.gmatch("1 2 3 4 5", "%d+")
assert(f() == "1") assert(f() == "1")
co = coroutine.wrap(f) local co = coroutine.wrap(f)
assert(co() == "2") assert(co() == "2")
end end
+1 -1
View File
@@ -35,7 +35,7 @@ print("\talignment: " .. align)
-- check errors in arguments -- check errors in arguments
function checkerror (msg, f, ...) local function checkerror (msg, f, ...)
local status, err = pcall(f, ...) local status, err = pcall(f, ...)
-- print(status, err, msg) -- print(status, err, msg)
assert(not status and string.find(err, msg)) assert(not status and string.find(err, msg))
+14 -2
View File
@@ -1,6 +1,8 @@
-- $Id: testes/utf8.lua $ -- $Id: testes/utf8.lua $
-- See Copyright Notice in file all.lua -- See Copyright Notice in file all.lua
-- UTF-8 file
print "testing UTF-8 library" print "testing UTF-8 library"
local utf8 = require'utf8' local utf8 = require'utf8'
@@ -97,9 +99,15 @@ do -- error indication in utf8.len
assert(not a and b == p) assert(not a and b == p)
end end
check("abc\xE3def", 4) check("abc\xE3def", 4)
check("汉字\x80", #("汉字") + 1)
check("\xF4\x9F\xBF", 1) check("\xF4\x9F\xBF", 1)
check("\xF4\x9F\xBF\xBF", 1) check("\xF4\x9F\xBF\xBF", 1)
-- spurious continuation bytes
check("汉字\x80", #("汉字") + 1)
check("\x80hello", 1)
check("hel\x80lo", 4)
check("汉字\xBF", #("汉字") + 1)
check("\xBFhello", 1)
check("hel\xBFlo", 4)
end end
-- errors in utf8.codes -- errors in utf8.codes
@@ -112,12 +120,16 @@ do
end end
errorcodes("ab\xff") errorcodes("ab\xff")
errorcodes("\u{110000}") errorcodes("\u{110000}")
errorcodes("in\x80valid")
errorcodes("\xbfinvalid")
errorcodes("αλφ\xBFα")
-- calling interation function with invalid arguments -- calling interation function with invalid arguments
local f = utf8.codes("") local f = utf8.codes("")
assert(f("", 2) == nil) assert(f("", 2) == nil)
assert(f("", -1) == nil) assert(f("", -1) == nil)
assert(f("", math.mininteger) == nil) assert(f("", math.mininteger) == nil)
end end
-- error in initial position for offset -- error in initial position for offset
@@ -220,7 +232,7 @@ do
check(s, {0x10000, 0x1FFFFF}, true) check(s, {0x10000, 0x1FFFFF}, true)
end end
x = "日本語a-4\0éó" local x = "日本語a-4\0éó"
check(x, {26085, 26412, 35486, 97, 45, 52, 0, 233, 243}) check(x, {26085, 26412, 35486, 97, 45, 52, 0, 233, 243})
+9 -9
View File
@@ -3,13 +3,13 @@
print('testing vararg') print('testing vararg')
function f(a, ...) local function f (a, ...)
local x = {n = select('#', ...), ...} local x = {n = select('#', ...), ...}
for i = 1, x.n do assert(a[i] == x[i]) end for i = 1, x.n do assert(a[i] == x[i]) end
return x.n return x.n
end end
function c12 (...) local function c12 (...)
assert(arg == _G.arg) -- no local 'arg' assert(arg == _G.arg) -- no local 'arg'
local x = {...}; x.n = #x local x = {...}; x.n = #x
local res = (x.n==2 and x[1] == 1 and x[2] == 2) local res = (x.n==2 and x[1] == 1 and x[2] == 2)
@@ -17,7 +17,7 @@ function c12 (...)
return res, 2 return res, 2
end end
function vararg (...) return {n = select('#', ...), ...} end local function vararg (...) return {n = select('#', ...), ...} end
local call = function (f, args) return f(table.unpack(args, 1, args.n)) end local call = function (f, args) return f(table.unpack(args, 1, args.n)) end
@@ -29,7 +29,7 @@ assert(vararg().n == 0)
assert(vararg(nil, nil).n == 2) assert(vararg(nil, nil).n == 2)
assert(c12(1,2)==55) assert(c12(1,2)==55)
a,b = assert(call(c12, {1,2})) local a,b = assert(call(c12, {1,2}))
assert(a == 55 and b == 2) assert(a == 55 and b == 2)
a = call(c12, {1,2;n=2}) a = call(c12, {1,2;n=2})
assert(a == 55 and b == 2) assert(a == 55 and b == 2)
@@ -49,7 +49,7 @@ function t:f (...) local arg = {...}; return self[...]+#arg end
assert(t:f(1,4) == 3 and t:f(2) == 11) assert(t:f(1,4) == 3 and t:f(2) == 11)
print('+') print('+')
lim = 20 local lim = 20
local i, a = 1, {} local i, a = 1, {}
while i <= lim do a[i] = i+0.3; i=i+1 end while i <= lim do a[i] = i+0.3; i=i+1 end
@@ -59,7 +59,7 @@ function f(a, b, c, d, ...)
more[lim-4] == lim+0.3 and not more[lim-3]) more[lim-4] == lim+0.3 and not more[lim-3])
end end
function g(a,b,c) local function g (a,b,c)
assert(a == 1.3 and b == 2.3 and c == 3.3) assert(a == 1.3 and b == 2.3 and c == 3.3)
end end
@@ -76,7 +76,7 @@ print("+")
-- new-style varargs -- new-style varargs
function oneless (a, ...) return ... end local function oneless (a, ...) return ... end
function f (n, a, ...) function f (n, a, ...)
local b local b
@@ -99,8 +99,8 @@ assert(a==nil and b==nil and c==nil and d==nil and e==nil)
-- varargs for main chunks -- varargs for main chunks
f = load[[ return {...} ]] local f = load[[ return {...} ]]
x = f(2,3) local x = f(2,3)
assert(x[1] == 2 and x[2] == 3 and x[3] == undef) assert(x[1] == 2 and x[2] == 3 and x[3] == undef)
+6 -6
View File
@@ -52,7 +52,7 @@ if _soft then return 10 end
print "testing large programs (>64k)" print "testing large programs (>64k)"
-- template to create a very big test file -- template to create a very big test file
prog = [[$ local prog = [[$
local a,b local a,b
@@ -85,7 +85,7 @@ function b:xxx (a,b) return a+b end
assert(b:xxx(10, 12) == 22) -- pushself with non-constant index assert(b:xxx(10, 12) == 22) -- pushself with non-constant index
b["xxx"] = undef b["xxx"] = undef
s = 0; n=0 local s = 0; local n=0
for a,b in pairs(b) do s=s+b; n=n+1 end for a,b in pairs(b) do s=s+b; n=n+1 end
-- with 32-bit floats, exact value of 's' depends on summation order -- with 32-bit floats, exact value of 's' depends on summation order
assert(81800000.0 < s and s < 81860000 and n == 70001) assert(81800000.0 < s and s < 81860000 and n == 70001)
@@ -93,7 +93,7 @@ assert(81800000.0 < s and s < 81860000 and n == 70001)
a = nil; b = nil a = nil; b = nil
print'+' print'+'
function f(x) b=x end local function f(x) b=x end
a = f{$3$} or 10 a = f{$3$} or 10
@@ -118,7 +118,7 @@ local function sig (x)
return (x % 2 == 0) and '' or '-' return (x % 2 == 0) and '' or '-'
end end
F = { local F = {
function () -- $1$ function () -- $1$
for i=10,50009 do for i=10,50009 do
io.write('a', i, ' = ', sig(i), 5+((i-10)/2), ',\n') io.write('a', i, ' = ', sig(i), 5+((i-10)/2), ',\n')
@@ -138,14 +138,14 @@ function () -- $3$
end, end,
} }
file = os.tmpname() local file = os.tmpname()
io.output(file) io.output(file)
for s in string.gmatch(prog, "$([^$]+)") do for s in string.gmatch(prog, "$([^$]+)") do
local n = tonumber(s) local n = tonumber(s)
if not n then io.write(s) else F[n]() end if not n then io.write(s) else F[n]() end
end end
io.close() io.close()
result = dofile(file) local result = dofile(file)
assert(os.remove(file)) assert(os.remove(file))
print'OK' print'OK'
return result return result