mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
Squashed 'src/deps/src/luajit/' changes from 4182d6bf3..15f58c964
15f58c964 Merge branch 'v2.1' into v2.1-agentzh. 5b9f6b064 Merge branch 'v2.1' into v2.1-agentzh 7952882d9 feature: add s390x disassembler. d06beb048 Handle all types of errors during trace stitching. bcc5125a9 Fix recording of __concat metamethod. 913df6a94 Merge branch 'master' into v2.1 cae361187 Prevent down-recursion for side traces. 302366a33 Check frame size limit before returning to a lower frame. dda1ac273 FFI: Treat cdata finalizer table as a GC root. 88ed9fdbb Handle stack reallocation in debug.setmetatable() and lua_setmetatable(). 2445b59a8 Merge branch 'v2.1' into v2.1-agentzh 7a41f1593 optimize: [ppc64le] Aligned code as per other archs for next_1 function and relevant code changes. 0d313b243 Merge branch 'master' into v2.1 defe61a56 Rework stack overflow handling. 9cc2e42b1 Merge branch 'master' into v2.1 9cdd5a947 Preserve keys with dynamic values in template tables when saving bytecode. 5e5d542c9 Merge branch 'master' into v2.1 14987af80 Prevent include of luajit_rolling.h. 21a46723d Merge branch 'master' into v2.1 e6c0ade97 Fix documentation bug about '\z' string escape. 343ce0eda Fix zero stripping in %g number formatting. f2336c48f Merge branch 'master' into v2.1 85b4fed0b Fix unsinking of IR_FSTORE for NULL metatable. 3ca0a8071 DynASM/x86: Add endbr instruction. 2f35cb45f MIPS64 R2/R6: Fix FP to integer conversions. 4b90f6c4d Add cross-32/64 bit and deterministic bytecode generation. c525bcb90 DynASM/x86: Allow [&expr] operand. dbd363ca2 Merge branch 'master' into v2.1 658530562 Check for IR_HREF vs. IR_HREFK aliasing in non-nil store check. 293199c5e Merge branch 'master' into v2.1 7dbe54593 Respect jit.off() on pending trace exit. e02a20790 Merge branch 'master' into v2.1 c42c62e71 Simplify handling of instable types in TNEW/TDUP load forwarding. 29b0b282f Merge branch 'master' into v2.1 9bdfd34dc Only emit proper parent references in snapshot replay. ff204d035 Fix anchoring for string buffer set() method (again). 8d5ea4ceb Merge branch 'master' into v2.1 10cc759f2 ARM: Fix stack restore for FP slots. 420a9afa9 Merge branch 'master' into v2.1 1b38c7365 Document workaround for multilib vs. cross-compiler conflict. e02cb19b5 Fix anchoring for string buffer set() method. e4168fae5 Merge branch 'master' into v2.1 856423f5d Fix runtime library flags for MSVC debug builds. 487eaaf04 Merge branch 'master' into v2.1 dcf3627d7 Fix .debug_abbrev section in GDB JIT API. d1236a4ca Optimize table.new() with constant args to (sinkable) IR_TNEW. 7ad68a1fd Merge branch 'master' into v2.1 1761fd2ef Emit sunk IR_NEWREF only once per key on snapshot replay. git-subtree-dir: src/deps/src/luajit git-subtree-split: 15f58c9648ee40a3fb6617e22e2f3fdff80d66b8
This commit is contained in:
parent
6ed1ec58b1
commit
fb53d3ab4d
41 changed files with 2143 additions and 212 deletions
|
|
@ -160,13 +160,33 @@ passes any arguments after the error function to the function
|
|||
which is called in a protected context.
|
||||
</p>
|
||||
|
||||
<h3 id="load"><tt>loadfile()</tt> etc. handle UTF-8 source code</h3>
|
||||
<h3 id="load"><tt>load*()</tt> handle UTF-8 source code</h3>
|
||||
<p>
|
||||
Non-ASCII characters are handled transparently by the Lua source code parser.
|
||||
This allows the use of UTF-8 characters in identifiers and strings.
|
||||
A UTF-8 BOM is skipped at the start of the source code.
|
||||
</p>
|
||||
|
||||
<h3 id="load_mode"><tt>load*()</tt> add a mode parameter</h3>
|
||||
<p>
|
||||
As an extension from Lua 5.2, the functions <tt>loadstring()</tt>,
|
||||
<tt>loadfile()</tt> and (new) <tt>load()</tt> add an optional
|
||||
<tt>mode</tt> parameter.
|
||||
</p>
|
||||
<p>
|
||||
The default mode string is <tt>"bt"</tt>, which allows loading of both
|
||||
source code and bytecode. Use <tt>"t"</tt> to allow only source code
|
||||
or <tt>"b"</tt> to allow only bytecode to be loaded.
|
||||
</p>
|
||||
<p>
|
||||
By default, the <tt>load*</tt> functions generate the native bytecode format.
|
||||
For cross-compilation purposes, add <tt>W</tt> to the mode string to
|
||||
force the 32 bit format and <tt>X</tt> to force the 64 bit format.
|
||||
Add both to force the opposite format. Note that non-native bytecode
|
||||
generated by <tt>load*</tt> cannot be run, but can still be passed
|
||||
to <tt>string.dump</tt>.
|
||||
</p>
|
||||
|
||||
<h3 id="tostring"><tt>tostring()</tt> etc. canonicalize NaN and ±Inf</h3>
|
||||
<p>
|
||||
All number-to-string conversions consistently convert non-finite numbers
|
||||
|
|
@ -186,26 +206,33 @@ works independently of the current locale and it supports hex floating-point
|
|||
numbers (e.g. <tt>0x1.5p-3</tt>).
|
||||
</p>
|
||||
|
||||
<h3 id="string_dump"><tt>string.dump(f [,strip])</tt> generates portable bytecode</h3>
|
||||
<h3 id="string_dump"><tt>string.dump(f [,mode])</tt> generates portable bytecode</h3>
|
||||
<p>
|
||||
An extra argument has been added to <tt>string.dump()</tt>. If set to
|
||||
<tt>true</tt>, 'stripped' bytecode without debug information is
|
||||
generated. This speeds up later bytecode loading and reduces memory
|
||||
usage. See also the
|
||||
<tt>true</tt> or to a string which contains the character <tt>s</tt>,
|
||||
'stripped' bytecode without debug information is generated. This speeds
|
||||
up later bytecode loading and reduces memory usage. See also the
|
||||
<a href="running.html#opt_b"><tt>-b</tt> command line option</a>.
|
||||
</p>
|
||||
<p>
|
||||
The generated bytecode is portable and can be loaded on any architecture
|
||||
that LuaJIT supports, independent of word size or endianess. However, the
|
||||
bytecode compatibility versions must match. Bytecode stays compatible
|
||||
for dot releases (x.y.0 → x.y.1), but may change with major or
|
||||
minor releases (2.0 → 2.1) or between any beta release. Foreign
|
||||
bytecode (e.g. from Lua 5.1) is incompatible and cannot be loaded.
|
||||
that LuaJIT supports. However, the bytecode compatibility versions must
|
||||
match. Bytecode only stays compatible within a major+minor version
|
||||
(x.y.aaa → x.y.bbb), except for development branches. Foreign bytecode
|
||||
(e.g. from Lua 5.1) is incompatible and cannot be loaded.
|
||||
</p>
|
||||
<p>
|
||||
Note: <tt>LJ_GC64</tt> mode requires a different frame layout, which implies
|
||||
a different, incompatible bytecode format for all 64 bit ports. This may be
|
||||
rectified in the future.
|
||||
a different, incompatible bytecode format between 32 bit and 64 bit ports.
|
||||
This may be rectified in the future. In the meantime, use the <tt>W</tt>
|
||||
and </tt>X</tt> <a href="#load_mode">modes of the <tt>load*</tt> functions</a>
|
||||
for cross-compilation purposes.
|
||||
</p>
|
||||
<p>
|
||||
Due to VM hardening, bytecode is not deterministic. Add <tt>d</tt> to the
|
||||
mode string to dump it in a deterministic manner: identical source code
|
||||
always gives a byte-for-byte identical bytecode dump. This feature is
|
||||
mainly useful for reproducible builds.
|
||||
</p>
|
||||
|
||||
<h3 id="table_new"><tt>table.new(narray, nhash)</tt> allocates a pre-sized table</h3>
|
||||
|
|
@ -286,7 +313,7 @@ enabled:
|
|||
</p>
|
||||
<ul>
|
||||
<li><tt>goto</tt> and <tt>::labels::</tt>.</li>
|
||||
<li>Hex escapes <tt>'\x3F'</tt> and <tt>'\*'</tt> escape in strings.</li>
|
||||
<li>Hex escapes <tt>'\x3F'</tt> and <tt>'\z'</tt> escape in strings.</li>
|
||||
<li><tt>load(string|reader [, chunkname [,mode [,env]]])</tt>.</li>
|
||||
<li><tt>loadstring()</tt> is an alias for <tt>load()</tt>.</li>
|
||||
<li><tt>loadfile(filename [,mode [,env]])</tt>.</li>
|
||||
|
|
|
|||
|
|
@ -269,6 +269,7 @@ for any supported target:
|
|||
<li>Yes, you need a toolchain for both your host <em>and</em> your target!</li>
|
||||
<li>Both host and target architectures must have the same pointer size.</li>
|
||||
<li>E.g. if you want to cross-compile to a 32 bit target on a 64 bit host, you need to install the multilib development package (e.g. <tt>libc6-dev-i386</tt> on Debian/Ubuntu) and build a 32 bit host part (<tt>HOST_CC="gcc -m32"</tt>).</li>
|
||||
<li>On some distro versions, multilib conflicts with cross-compilers. The workaround is to install the x86 cross-compiler package <tt>gcc-i686-linux-gnu</tt> and use it to build the host part (<tt>HOST_CC=i686-linux-gnu-gcc</tt>).</li>
|
||||
<li>64 bit targets always require compilation on a 64 bit host.</li>
|
||||
</ul>
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -106,6 +106,9 @@ are accepted:
|
|||
<li><tt>-l</tt> — Only list bytecode.</li>
|
||||
<li><tt>-s</tt> — Strip debug info (this is the default).</li>
|
||||
<li><tt>-g</tt> — Keep debug info.</li>
|
||||
<li><tt>-W</tt> — Generate 32 bit (non-GC64) bytecode.</li>
|
||||
<li><tt>-X</tt> — Generate 64 bit (GC64) bytecode.</li>
|
||||
<li><tt>-d</tt> — Generate bytecode in deterministic manner.</li>
|
||||
<li><tt>-n name</tt> — Set module name (default: auto-detect from input name)</li>
|
||||
<li><tt>-t type</tt> — Set output file type (default: auto-detect from output name).</li>
|
||||
<li><tt>-a arch</tt> — Override architecture for object files (default: native).</li>
|
||||
|
|
|
|||
|
|
@ -627,7 +627,11 @@ local function wputmrmsib(t, imark, s, vsreg, psz, sk)
|
|||
werror("NYI: rip-relative displacement followed by immediate")
|
||||
end
|
||||
-- The previous byte in the action buffer cannot be 0xe9 or 0x80-0x8f.
|
||||
wputlabel("REL_", disp[1], 2)
|
||||
if disp[2] == "iPJ" then
|
||||
waction("REL_A", disp[1])
|
||||
else
|
||||
wputlabel("REL_", disp[1], 2)
|
||||
end
|
||||
else
|
||||
wputdarg(disp)
|
||||
end
|
||||
|
|
@ -744,9 +748,9 @@ local function dispexpr(expr)
|
|||
return imm*map_opsizenum[ops]
|
||||
end
|
||||
local mode, iexpr = immexpr(dispt)
|
||||
if mode == "iJ" then
|
||||
if mode == "iJ" or mode == "iPJ" then
|
||||
if c == "-" then werror("cannot invert label reference") end
|
||||
return { iexpr }
|
||||
return { iexpr, mode }
|
||||
end
|
||||
return expr -- Need to return original signed expression.
|
||||
end
|
||||
|
|
@ -1147,6 +1151,8 @@ local map_op = {
|
|||
rep_0 = "F3",
|
||||
repe_0 = "F3",
|
||||
repz_0 = "F3",
|
||||
endbr32_0 = "F30F1EFB",
|
||||
endbr64_0 = "F30F1EFA",
|
||||
-- F4: *hlt
|
||||
cmc_0 = "F5",
|
||||
-- F6: test... mb,i; div... mb
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ local function wline(line, needindent)
|
|||
g_synclineno = g_synclineno + 1
|
||||
end
|
||||
|
||||
-- Write assembler line as a comment, if requestd.
|
||||
-- Write assembler line as a comment, if requested.
|
||||
local function wcomment(aline)
|
||||
if g_opt.comment then
|
||||
wline(g_opt.comment..aline..g_opt.endcomment, true)
|
||||
|
|
|
|||
|
|
@ -138,65 +138,73 @@ local function fixup_dump(dump, fixup)
|
|||
return { dump = ndump, startbc = startbc, sizebc = sizebc }
|
||||
end
|
||||
|
||||
local function find_defs(src)
|
||||
local function find_defs(src, mode)
|
||||
local defs = {}
|
||||
for name, code in string.gmatch(src, "LJLIB_LUA%(([^)]*)%)%s*/%*(.-)%*/") do
|
||||
local env = {}
|
||||
local tcode, fixup = transform_lua(code)
|
||||
local func = assert(load(tcode, "", nil, env))()
|
||||
defs[name] = fixup_dump(string.dump(func, true), fixup)
|
||||
local func = assert(load(tcode, "", mode))
|
||||
defs[name] = fixup_dump(string.dump(func, mode), fixup)
|
||||
defs[#defs+1] = name
|
||||
end
|
||||
return defs
|
||||
end
|
||||
|
||||
local function gen_header(defs)
|
||||
local function gen_header(defs32, defs64)
|
||||
local t = {}
|
||||
local function w(x) t[#t+1] = x end
|
||||
w("/* This is a generated file. DO NOT EDIT! */\n\n")
|
||||
w("static const int libbc_endian = ") w(isbe and 1 or 0) w(";\n\n")
|
||||
local s, sb = "", ""
|
||||
for i,name in ipairs(defs) do
|
||||
local d = defs[name]
|
||||
s = s .. d.dump
|
||||
sb = sb .. string.char(i) .. ("\0"):rep(d.startbc - 1)
|
||||
.. (isbe and "\0\0\0\255" or "\255\0\0\0"):rep(d.sizebc)
|
||||
.. ("\0"):rep(#d.dump - d.startbc - d.sizebc*4)
|
||||
end
|
||||
w("static const uint8_t libbc_code[] = {\n")
|
||||
local n = 0
|
||||
for i=1,#s do
|
||||
local x = string.byte(s, i)
|
||||
local xb = string.byte(sb, i)
|
||||
if xb == 255 then
|
||||
local name = BCN[x]
|
||||
local m = #name + 4
|
||||
if n + m > 78 then n = 0; w("\n") end
|
||||
n = n + m
|
||||
w("BC_"); w(name)
|
||||
else
|
||||
local m = x < 10 and 2 or (x < 100 and 3 or 4)
|
||||
if xb == 0 then
|
||||
if n + m > 78 then n = 0; w("\n") end
|
||||
else
|
||||
local name = defs[xb]:gsub("_", ".")
|
||||
if n ~= 0 then w("\n") end
|
||||
w("/* "); w(name); w(" */ ")
|
||||
n = #name + 7
|
||||
end
|
||||
n = n + m
|
||||
w(x)
|
||||
for j,defs in ipairs{defs64, defs32} do
|
||||
local s, sb = "", ""
|
||||
for i,name in ipairs(defs) do
|
||||
local d = defs[name]
|
||||
s = s .. d.dump
|
||||
sb = sb .. string.char(i) .. ("\0"):rep(d.startbc - 1)
|
||||
.. (isbe and "\0\0\0\255" or "\255\0\0\0"):rep(d.sizebc)
|
||||
.. ("\0"):rep(#d.dump - d.startbc - d.sizebc*4)
|
||||
end
|
||||
if j == 1 then
|
||||
w("static const uint8_t libbc_code[] = {\n#if LJ_FR2\n")
|
||||
else
|
||||
w("\n#else\n")
|
||||
end
|
||||
local n = 0
|
||||
for i=1,#s do
|
||||
local x = string.byte(s, i)
|
||||
local xb = string.byte(sb, i)
|
||||
if xb == 255 then
|
||||
local name = BCN[x]
|
||||
local m = #name + 4
|
||||
if n + m > 78 then n = 0; w("\n") end
|
||||
n = n + m
|
||||
w("BC_"); w(name)
|
||||
else
|
||||
local m = x < 10 and 2 or (x < 100 and 3 or 4)
|
||||
if xb == 0 then
|
||||
if n + m > 78 then n = 0; w("\n") end
|
||||
else
|
||||
local name = defs[xb]:gsub("_", ".")
|
||||
if n ~= 0 then w("\n") end
|
||||
w("/* "); w(name); w(" */ ")
|
||||
n = #name + 7
|
||||
end
|
||||
n = n + m
|
||||
w(x)
|
||||
end
|
||||
w(",")
|
||||
end
|
||||
w(",")
|
||||
end
|
||||
w("\n0\n};\n\n")
|
||||
w("\n#endif\n0\n};\n\n")
|
||||
w("static const struct { const char *name; int ofs; } libbc_map[] = {\n")
|
||||
local m = 0
|
||||
for _,name in ipairs(defs) do
|
||||
w('{"'); w(name); w('",'); w(m) w('},\n')
|
||||
m = m + #defs[name].dump
|
||||
local m32, m64 = 0, 0
|
||||
for i,name in ipairs(defs32) do
|
||||
assert(name == defs64[i])
|
||||
w('{"'); w(name); w('",'); w(m32) w('},\n')
|
||||
m32 = m32 + #defs32[name].dump
|
||||
m64 = m64 + #defs64[name].dump
|
||||
assert(m32 == m64)
|
||||
end
|
||||
w("{NULL,"); w(m); w("}\n};\n\n")
|
||||
w("{NULL,"); w(m32); w("}\n};\n\n")
|
||||
return table.concat(t)
|
||||
end
|
||||
|
||||
|
|
@ -219,7 +227,8 @@ end
|
|||
|
||||
local outfile = parse_arg(arg)
|
||||
local src = read_files(arg)
|
||||
local defs = find_defs(src)
|
||||
local hdr = gen_header(defs)
|
||||
local defs32 = find_defs(src, "Wdts")
|
||||
local defs64 = find_defs(src, "Xdts")
|
||||
local hdr = gen_header(defs32, defs64)
|
||||
write_file(outfile, hdr)
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ local function file_write_mod(file, data)
|
|||
assert(fp:close())
|
||||
end
|
||||
|
||||
local text = file_read(FILE_ROLLING_H)
|
||||
local text = file_read(FILE_ROLLING_H):gsub("#error.-\n", "")
|
||||
local relver = file_read(FILE_RELVER_TXT):match("(%d+)")
|
||||
|
||||
if relver then
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ Save LuaJIT bytecode: luajit -b[options] input output
|
|||
-L Only list bytecode with lineinfo.
|
||||
-s Strip debug info (default).
|
||||
-g Keep debug info.
|
||||
-W Generate 32 bit (non-GC64) bytecode.
|
||||
-X Generate 64 bit (GC64) bytecode.
|
||||
-d Generate bytecode in deterministic manner.
|
||||
-n name Set module name (default: auto-detect from input name).
|
||||
-t type Set output file type (default: auto-detect from output name).
|
||||
-a arch Override architecture for object files (default: native).
|
||||
|
|
@ -52,8 +55,9 @@ local function check(ok, ...)
|
|||
end
|
||||
|
||||
local function readfile(ctx, input)
|
||||
if type(input) == "function" then return input end
|
||||
if ctx.filename then
|
||||
if ctx.string then
|
||||
return check(loadstring(input, nil, ctx.mode))
|
||||
elseif ctx.filename then
|
||||
local data
|
||||
if input == "-" then
|
||||
data = io.stdin:read("*a")
|
||||
|
|
@ -62,10 +66,10 @@ local function readfile(ctx, input)
|
|||
data = assert(fp:read("*a"))
|
||||
assert(fp:close())
|
||||
end
|
||||
return check(load(data, ctx.filename))
|
||||
return check(load(data, ctx.filename, ctx.mode))
|
||||
else
|
||||
if input == "-" then input = nil end
|
||||
return check(loadfile(input))
|
||||
return check(loadfile(input, ctx.mode))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -626,7 +630,7 @@ end
|
|||
|
||||
local function bcsave(ctx, input, output)
|
||||
local f = readfile(ctx, input)
|
||||
local s = string.dump(f, ctx.strip)
|
||||
local s = string.dump(f, ctx.mode)
|
||||
local t = ctx.type
|
||||
if not t then
|
||||
t = detecttype(output)
|
||||
|
|
@ -650,9 +654,11 @@ local function docmd(...)
|
|||
local list = false
|
||||
local lineinfo = false
|
||||
local ctx = {
|
||||
strip = true, arch = jit.arch, os = jit.os:lower(),
|
||||
type = false, modname = false,
|
||||
mode = "bt", arch = jit.arch, os = jit.os:lower(),
|
||||
type = false, modname = false, string = false,
|
||||
}
|
||||
local strip = "s"
|
||||
local gc64 = ""
|
||||
while n <= #arg do
|
||||
local a = arg[n]
|
||||
if type(a) == "string" and a:sub(1, 1) == "-" and a ~= "-" then
|
||||
|
|
@ -666,14 +672,18 @@ local function docmd(...)
|
|||
list = true
|
||||
lineinfo = true
|
||||
elseif opt == "s" then
|
||||
ctx.strip = true
|
||||
strip = "s"
|
||||
elseif opt == "g" then
|
||||
ctx.strip = false
|
||||
strip = ""
|
||||
elseif opt == "W" or opt == "X" then
|
||||
gc64 = opt
|
||||
elseif opt == "d" then
|
||||
ctx.mode = ctx.mode .. opt
|
||||
else
|
||||
if arg[n] == nil or m ~= #a then usage() end
|
||||
if opt == "e" then
|
||||
if n ~= 1 then usage() end
|
||||
arg[1] = check(loadstring(arg[1]))
|
||||
ctx.string = true
|
||||
elseif opt == "n" then
|
||||
ctx.modname = checkmodname(tremove(arg, n))
|
||||
elseif opt == "t" then
|
||||
|
|
@ -693,6 +703,7 @@ local function docmd(...)
|
|||
n = n + 1
|
||||
end
|
||||
end
|
||||
ctx.mode = ctx.mode .. strip .. gc64
|
||||
if list then
|
||||
if #arg == 0 or #arg > 2 then usage() end
|
||||
bclist(ctx, arg[1], arg[2] or "-", lineinfo)
|
||||
|
|
|
|||
1593
src/jit/dis_s390x.lua
Normal file
1593
src/jit/dis_s390x.lua
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -361,7 +361,11 @@ LJLIB_ASM_(xpcall) LJLIB_REC(.)
|
|||
static int load_aux(lua_State *L, int status, int envarg)
|
||||
{
|
||||
if (status == LUA_OK) {
|
||||
if (tvistab(L->base+envarg-1)) {
|
||||
/*
|
||||
** Set environment table for top-level function.
|
||||
** Don't do this for non-native bytecode, which returns a prototype.
|
||||
*/
|
||||
if (tvistab(L->base+envarg-1) && tvisfunc(L->top-1)) {
|
||||
GCfunc *fn = funcV(L->top-1);
|
||||
GCtab *t = tabV(L->base+envarg-1);
|
||||
setgcref(fn->c.env, obj2gco(t));
|
||||
|
|
|
|||
|
|
@ -221,24 +221,6 @@ LJLIB_PUSH(top-2) LJLIB_SET(version)
|
|||
|
||||
/* -- Reflection API for Lua functions ------------------------------------ */
|
||||
|
||||
/* Return prototype of first argument (Lua function or prototype object) */
|
||||
static GCproto *check_Lproto(lua_State *L, int nolua)
|
||||
{
|
||||
TValue *o = L->base;
|
||||
if (L->top > o) {
|
||||
if (tvisproto(o)) {
|
||||
return protoV(o);
|
||||
} else if (tvisfunc(o)) {
|
||||
if (isluafunc(funcV(o)))
|
||||
return funcproto(funcV(o));
|
||||
else if (nolua)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
lj_err_argt(L, 1, LUA_TFUNCTION);
|
||||
return NULL; /* unreachable */
|
||||
}
|
||||
|
||||
static void setintfield(lua_State *L, GCtab *t, const char *name, int32_t val)
|
||||
{
|
||||
setintV(lj_tab_setstr(L, t, lj_str_newz(L, name)), val);
|
||||
|
|
@ -247,7 +229,7 @@ static void setintfield(lua_State *L, GCtab *t, const char *name, int32_t val)
|
|||
/* local info = jit.util.funcinfo(func [,pc]) */
|
||||
LJLIB_CF(jit_util_funcinfo)
|
||||
{
|
||||
GCproto *pt = check_Lproto(L, 1);
|
||||
GCproto *pt = lj_lib_checkLproto(L, 1, 1);
|
||||
if (pt) {
|
||||
BCPos pc = (BCPos)lj_lib_optint(L, 2, 0);
|
||||
GCtab *t;
|
||||
|
|
@ -289,7 +271,7 @@ LJLIB_CF(jit_util_funcinfo)
|
|||
/* local ins, m = jit.util.funcbc(func, pc) */
|
||||
LJLIB_CF(jit_util_funcbc)
|
||||
{
|
||||
GCproto *pt = check_Lproto(L, 0);
|
||||
GCproto *pt = lj_lib_checkLproto(L, 1, 0);
|
||||
BCPos pc = (BCPos)lj_lib_checkint(L, 2);
|
||||
int lineinfo = lj_lib_optint(L, 3, 0);
|
||||
if (pc < pt->sizebc) {
|
||||
|
|
@ -312,7 +294,7 @@ LJLIB_CF(jit_util_funcbc)
|
|||
/* local k = jit.util.funck(func, idx) */
|
||||
LJLIB_CF(jit_util_funck)
|
||||
{
|
||||
GCproto *pt = check_Lproto(L, 0);
|
||||
GCproto *pt = lj_lib_checkLproto(L, 1, 0);
|
||||
ptrdiff_t idx = (ptrdiff_t)lj_lib_checkint(L, 2);
|
||||
if (idx >= 0) {
|
||||
if (idx < (ptrdiff_t)pt->sizekn) {
|
||||
|
|
@ -332,7 +314,7 @@ LJLIB_CF(jit_util_funck)
|
|||
/* local name = jit.util.funcuvname(func, idx) */
|
||||
LJLIB_CF(jit_util_funcuvname)
|
||||
{
|
||||
GCproto *pt = check_Lproto(L, 0);
|
||||
GCproto *pt = lj_lib_checkLproto(L, 1, 0);
|
||||
uint32_t idx = (uint32_t)lj_lib_checkint(L, 2);
|
||||
if (idx < pt->sizeuv) {
|
||||
setstrV(L, L->top-1, lj_str_newz(L, lj_debug_uvname(pt, idx)));
|
||||
|
|
|
|||
|
|
@ -122,11 +122,25 @@ static int writer_buf(lua_State *L, const void *p, size_t size, void *sb)
|
|||
|
||||
LJLIB_CF(string_dump)
|
||||
{
|
||||
GCfunc *fn = lj_lib_checkfunc(L, 1);
|
||||
int strip = L->base+1 < L->top && tvistruecond(L->base+1);
|
||||
SBuf *sb = lj_buf_tmp_(L); /* Assumes lj_bcwrite() doesn't use tmpbuf. */
|
||||
GCproto *pt = lj_lib_checkLproto(L, 1, 1);
|
||||
uint32_t flags = 0;
|
||||
SBuf *sb;
|
||||
TValue *o = L->base+1;
|
||||
if (o < L->top) {
|
||||
if (tvisstr(o)) {
|
||||
const char *mode = strVdata(o);
|
||||
char c;
|
||||
while ((c = *mode++)) {
|
||||
if (c == 's') flags |= BCDUMP_F_STRIP;
|
||||
if (c == 'd') flags |= BCDUMP_F_DETERMINISTIC;
|
||||
}
|
||||
} else if (tvistruecond(o)) {
|
||||
flags |= BCDUMP_F_STRIP;
|
||||
}
|
||||
}
|
||||
sb = lj_buf_tmp_(L); /* Assumes lj_bcwrite() doesn't use tmpbuf. */
|
||||
L->top = L->base+1;
|
||||
if (!isluafunc(fn) || lj_bcwrite(L, funcproto(fn), writer_buf, sb, strip))
|
||||
if (!pt || lj_bcwrite(L, pt, writer_buf, sb, flags))
|
||||
lj_err_caller(L, LJ_ERR_STRDUMP);
|
||||
setstrV(L, L->top-1, lj_buf_str(L, sb));
|
||||
lj_gc_check(L);
|
||||
|
|
|
|||
|
|
@ -1052,6 +1052,7 @@ LUA_API int lua_setmetatable(lua_State *L, int idx)
|
|||
/* Flush cache, since traces specialize to basemt. But not during __gc. */
|
||||
if (lj_trace_flushall(L))
|
||||
lj_err_caller(L, LJ_ERR_NOGCMM);
|
||||
o = index2adr(L, idx); /* Stack may have been reallocated. */
|
||||
if (tvisbool(o)) {
|
||||
/* NOBARRIER: basemt is a GC root. */
|
||||
setgcref(basemt_it(g, LJ_TTRUE), obj2gco(mt));
|
||||
|
|
|
|||
|
|
@ -2042,11 +2042,12 @@ static void asm_stack_restore(ASMState *as, SnapShot *snap)
|
|||
SnapEntry *map = &as->T->snapmap[snap->mapofs];
|
||||
SnapEntry *flinks = &as->T->snapmap[snap_nextofs(as->T, snap)-1];
|
||||
MSize n, nent = snap->nent;
|
||||
int32_t bias = 0;
|
||||
/* Store the value of all modified slots to the Lua stack. */
|
||||
for (n = 0; n < nent; n++) {
|
||||
SnapEntry sn = map[n];
|
||||
BCReg s = snap_slot(sn);
|
||||
int32_t ofs = 8*((int32_t)s-1);
|
||||
int32_t ofs = 8*((int32_t)s-1) - bias;
|
||||
IRRef ref = snap_ref(sn);
|
||||
IRIns *ir = IR(ref);
|
||||
if ((sn & SNAP_NORESTORE))
|
||||
|
|
@ -2065,6 +2066,12 @@ static void asm_stack_restore(ASMState *as, SnapShot *snap)
|
|||
emit_lso(as, ARMI_STR, tmp, RID_BASE, ofs+4);
|
||||
#else
|
||||
Reg src = ra_alloc1(as, ref, RSET_FPR);
|
||||
if (LJ_UNLIKELY(ofs < -1020 || ofs > 1020)) {
|
||||
int32_t adj = ofs & 0xffffff00; /* K12-friendly. */
|
||||
bias += adj;
|
||||
ofs -= adj;
|
||||
emit_addptr(as, RID_BASE, -adj);
|
||||
}
|
||||
emit_vlso(as, ARMI_VSTR_D, src, RID_BASE, ofs);
|
||||
#endif
|
||||
} else {
|
||||
|
|
@ -2093,6 +2100,7 @@ static void asm_stack_restore(ASMState *as, SnapShot *snap)
|
|||
}
|
||||
checkmclim(as);
|
||||
}
|
||||
emit_addptr(as, RID_BASE, bias);
|
||||
lj_assertA(map + nent == flinks, "inconsistent frames in snapshot");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -653,11 +653,11 @@ static void asm_conv(ASMState *as, IRIns *ir)
|
|||
rset_exclude(RSET_GPR, dest));
|
||||
emit_fg(as, MIPSI_TRUNC_L_D, tmp, left); /* Delay slot. */
|
||||
#if !LJ_TARGET_MIPSR6
|
||||
emit_branch(as, MIPSI_BC1T, 0, 0, l_end);
|
||||
emit_fgh(as, MIPSI_C_OLT_D, 0, left, tmp);
|
||||
emit_branch(as, MIPSI_BC1T, 0, 0, l_end);
|
||||
emit_fgh(as, MIPSI_C_OLT_D, 0, left, tmp);
|
||||
#else
|
||||
emit_branch(as, MIPSI_BC1NEZ, 0, (left&31), l_end);
|
||||
emit_fgh(as, MIPSI_CMP_LT_D, left, left, tmp);
|
||||
emit_branch(as, MIPSI_BC1NEZ, 0, (tmp&31), l_end);
|
||||
emit_fgh(as, MIPSI_CMP_LT_D, tmp, left, tmp);
|
||||
#endif
|
||||
emit_lsptr(as, MIPSI_LDC1, (tmp & 31),
|
||||
(void *)&as->J->k64[LJ_K64_2P63],
|
||||
|
|
@ -670,11 +670,11 @@ static void asm_conv(ASMState *as, IRIns *ir)
|
|||
rset_exclude(RSET_GPR, dest));
|
||||
emit_fg(as, MIPSI_TRUNC_L_S, tmp, left); /* Delay slot. */
|
||||
#if !LJ_TARGET_MIPSR6
|
||||
emit_branch(as, MIPSI_BC1T, 0, 0, l_end);
|
||||
emit_fgh(as, MIPSI_C_OLT_S, 0, left, tmp);
|
||||
emit_branch(as, MIPSI_BC1T, 0, 0, l_end);
|
||||
emit_fgh(as, MIPSI_C_OLT_S, 0, left, tmp);
|
||||
#else
|
||||
emit_branch(as, MIPSI_BC1NEZ, 0, (left&31), l_end);
|
||||
emit_fgh(as, MIPSI_CMP_LT_S, left, left, tmp);
|
||||
emit_branch(as, MIPSI_BC1NEZ, 0, (tmp&31), l_end);
|
||||
emit_fgh(as, MIPSI_CMP_LT_S, tmp, left, tmp);
|
||||
#endif
|
||||
emit_lsptr(as, MIPSI_LWC1, (tmp & 31),
|
||||
(void *)&as->J->k32[LJ_K32_2P63],
|
||||
|
|
@ -690,8 +690,8 @@ static void asm_conv(ASMState *as, IRIns *ir)
|
|||
MIPSIns mi = irt_is64(ir->t) ?
|
||||
(st == IRT_NUM ? MIPSI_TRUNC_L_D : MIPSI_TRUNC_L_S) :
|
||||
(st == IRT_NUM ? MIPSI_TRUNC_W_D : MIPSI_TRUNC_W_S);
|
||||
emit_tg(as, irt_is64(ir->t) ? MIPSI_DMFC1 : MIPSI_MFC1, dest, left);
|
||||
emit_fg(as, mi, left, left);
|
||||
emit_tg(as, irt_is64(ir->t) ? MIPSI_DMFC1 : MIPSI_MFC1, dest, tmp);
|
||||
emit_fg(as, mi, tmp, left);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@
|
|||
|
||||
#define BCDUMP_F_KNOWN (BCDUMP_F_FR2*2-1)
|
||||
|
||||
#define BCDUMP_F_DETERMINISTIC 0x80000000
|
||||
|
||||
/* Type codes for the GC constants of a prototype. Plus length for strings. */
|
||||
enum {
|
||||
BCDUMP_KGC_CHILD, BCDUMP_KGC_TAB, BCDUMP_KGC_I64, BCDUMP_KGC_U64,
|
||||
|
|
@ -61,7 +63,7 @@ enum {
|
|||
/* -- Bytecode reader/writer ---------------------------------------------- */
|
||||
|
||||
LJ_FUNC int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer,
|
||||
void *data, int strip);
|
||||
void *data, uint32_t flags);
|
||||
LJ_FUNC GCproto *lj_bcread_proto(LexState *ls);
|
||||
LJ_FUNC GCproto *lj_bcread(LexState *ls);
|
||||
|
||||
|
|
|
|||
|
|
@ -281,8 +281,11 @@ static void bcread_knum(LexState *ls, GCproto *pt, MSize sizekn)
|
|||
static void bcread_bytecode(LexState *ls, GCproto *pt, MSize sizebc)
|
||||
{
|
||||
BCIns *bc = proto_bc(pt);
|
||||
bc[0] = BCINS_AD((pt->flags & PROTO_VARARG) ? BC_FUNCV : BC_FUNCF,
|
||||
pt->framesize, 0);
|
||||
BCIns op;
|
||||
if (ls->fr2 != LJ_FR2) op = BC_NOT; /* Mark non-native prototype. */
|
||||
else if ((pt->flags & PROTO_VARARG)) op = BC_FUNCV;
|
||||
else op = BC_FUNCF;
|
||||
bc[0] = BCINS_AD(op, pt->framesize, 0);
|
||||
bcread_block(ls, bc+1, (sizebc-1)*(MSize)sizeof(BCIns));
|
||||
/* Swap bytecode instructions if the endianess differs. */
|
||||
if (bcread_swap(ls)) {
|
||||
|
|
@ -395,7 +398,7 @@ static int bcread_header(LexState *ls)
|
|||
bcread_byte(ls) != BCDUMP_VERSION) return 0;
|
||||
bcread_flags(ls) = flags = bcread_uleb128(ls);
|
||||
if ((flags & ~(BCDUMP_F_KNOWN)) != 0) return 0;
|
||||
if ((flags & BCDUMP_F_FR2) != LJ_FR2*BCDUMP_F_FR2) return 0;
|
||||
if ((flags & BCDUMP_F_FR2) != (uint32_t)ls->fr2*BCDUMP_F_FR2) return 0;
|
||||
if ((flags & BCDUMP_F_FFI)) {
|
||||
#if LJ_HASFFI
|
||||
lua_State *L = ls->L;
|
||||
|
|
|
|||
111
src/lj_bcwrite.c
111
src/lj_bcwrite.c
|
|
@ -27,7 +27,9 @@ typedef struct BCWriteCtx {
|
|||
GCproto *pt; /* Root prototype. */
|
||||
lua_Writer wfunc; /* Writer callback. */
|
||||
void *wdata; /* Writer callback data. */
|
||||
int strip; /* Strip debug info. */
|
||||
TValue **heap; /* Heap used for deterministic sorting. */
|
||||
uint32_t heapsz; /* Size of heap. */
|
||||
uint32_t flags; /* BCDUMP_F_* flags. */
|
||||
int status; /* Status from writer callback. */
|
||||
#ifdef LUA_USE_ASSERT
|
||||
global_State *g;
|
||||
|
|
@ -76,6 +78,75 @@ static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow)
|
|||
ctx->sb.w = p;
|
||||
}
|
||||
|
||||
/* Compare two template table keys. */
|
||||
static LJ_AINLINE int bcwrite_ktabk_lt(TValue *a, TValue *b)
|
||||
{
|
||||
uint32_t at = itype(a), bt = itype(b);
|
||||
if (at != bt) { /* This also handles false and true keys. */
|
||||
return at < bt;
|
||||
} else if (at == LJ_TSTR) {
|
||||
return lj_str_cmp(strV(a), strV(b)) < 0;
|
||||
} else {
|
||||
return a->u64 < b->u64; /* This works for numbers and integers. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert key into a sorted heap. */
|
||||
static void bcwrite_ktabk_heap_insert(TValue **heap, MSize idx, MSize end,
|
||||
TValue *key)
|
||||
{
|
||||
MSize child;
|
||||
while ((child = idx * 2 + 1) < end) {
|
||||
/* Find lower of the two children. */
|
||||
TValue *c0 = heap[child];
|
||||
if (child + 1 < end) {
|
||||
TValue *c1 = heap[child + 1];
|
||||
if (bcwrite_ktabk_lt(c1, c0)) {
|
||||
c0 = c1;
|
||||
child++;
|
||||
}
|
||||
}
|
||||
if (bcwrite_ktabk_lt(key, c0)) break; /* Key lower? Found our position. */
|
||||
heap[idx] = c0; /* Move lower child up. */
|
||||
idx = child; /* Descend. */
|
||||
}
|
||||
heap[idx] = key; /* Insert key here. */
|
||||
}
|
||||
|
||||
/* Resize heap, dropping content. */
|
||||
static void bcwrite_heap_resize(BCWriteCtx *ctx, uint32_t nsz)
|
||||
{
|
||||
lua_State *L = sbufL(&ctx->sb);
|
||||
if (ctx->heapsz) {
|
||||
lj_mem_freevec(G(L), ctx->heap, ctx->heapsz, TValue *);
|
||||
ctx->heapsz = 0;
|
||||
}
|
||||
if (nsz) {
|
||||
ctx->heap = lj_mem_newvec(L, nsz, TValue *);
|
||||
ctx->heapsz = nsz;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write hash part of template table in sorted order. */
|
||||
static void bcwrite_ktab_sorted_hash(BCWriteCtx *ctx, Node *node, MSize nhash)
|
||||
{
|
||||
TValue **heap = ctx->heap;
|
||||
MSize i = nhash;
|
||||
for (;; node--) { /* Build heap. */
|
||||
if (!tvisnil(&node->key)) {
|
||||
bcwrite_ktabk_heap_insert(heap, --i, nhash, &node->key);
|
||||
if (i == 0) break;
|
||||
}
|
||||
}
|
||||
do { /* Drain heap. */
|
||||
TValue *key = heap[0]; /* Output lowest key from top. */
|
||||
bcwrite_ktabk(ctx, key, 0);
|
||||
bcwrite_ktabk(ctx, (TValue *)((char *)key - offsetof(Node, key)), 1);
|
||||
key = heap[--nhash]; /* Remove last key. */
|
||||
bcwrite_ktabk_heap_insert(heap, 0, nhash, key); /* Re-insert. */
|
||||
} while (nhash);
|
||||
}
|
||||
|
||||
/* Write a template table. */
|
||||
static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t)
|
||||
{
|
||||
|
|
@ -92,7 +163,7 @@ static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t)
|
|||
MSize i, hmask = t->hmask;
|
||||
Node *node = noderef(t->node);
|
||||
for (i = 0; i <= hmask; i++)
|
||||
nhash += !tvisnil(&node[i].val);
|
||||
nhash += !tvisnil(&node[i].key);
|
||||
}
|
||||
/* Write number of array slots and hash slots. */
|
||||
p = lj_strfmt_wuleb128(p, narray);
|
||||
|
|
@ -105,14 +176,20 @@ static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t)
|
|||
bcwrite_ktabk(ctx, o, 1);
|
||||
}
|
||||
if (nhash) { /* Write hash entries. */
|
||||
MSize i = nhash;
|
||||
Node *node = noderef(t->node) + t->hmask;
|
||||
for (;; node--)
|
||||
if (!tvisnil(&node->val)) {
|
||||
bcwrite_ktabk(ctx, &node->key, 0);
|
||||
bcwrite_ktabk(ctx, &node->val, 1);
|
||||
if (--i == 0) break;
|
||||
}
|
||||
if ((ctx->flags & BCDUMP_F_DETERMINISTIC) && nhash > 1) {
|
||||
if (ctx->heapsz < nhash)
|
||||
bcwrite_heap_resize(ctx, t->hmask + 1);
|
||||
bcwrite_ktab_sorted_hash(ctx, node, nhash);
|
||||
} else {
|
||||
MSize i = nhash;
|
||||
for (;; node--)
|
||||
if (!tvisnil(&node->key)) {
|
||||
bcwrite_ktabk(ctx, &node->key, 0);
|
||||
bcwrite_ktabk(ctx, &node->val, 1);
|
||||
if (--i == 0) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -269,7 +346,7 @@ static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt)
|
|||
p = lj_strfmt_wuleb128(p, pt->sizekgc);
|
||||
p = lj_strfmt_wuleb128(p, pt->sizekn);
|
||||
p = lj_strfmt_wuleb128(p, pt->sizebc-1);
|
||||
if (!ctx->strip) {
|
||||
if (!(ctx->flags & BCDUMP_F_STRIP)) {
|
||||
if (proto_lineinfo(pt))
|
||||
sizedbg = pt->sizept - (MSize)((char *)proto_lineinfo(pt) - (char *)pt);
|
||||
p = lj_strfmt_wuleb128(p, sizedbg);
|
||||
|
|
@ -317,11 +394,10 @@ static void bcwrite_header(BCWriteCtx *ctx)
|
|||
*p++ = BCDUMP_HEAD2;
|
||||
*p++ = BCDUMP_HEAD3;
|
||||
*p++ = BCDUMP_VERSION;
|
||||
*p++ = (ctx->strip ? BCDUMP_F_STRIP : 0) +
|
||||
*p++ = (ctx->flags & (BCDUMP_F_STRIP | BCDUMP_F_FR2)) +
|
||||
LJ_BE*BCDUMP_F_BE +
|
||||
((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0) +
|
||||
LJ_FR2*BCDUMP_F_FR2;
|
||||
if (!ctx->strip) {
|
||||
((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0);
|
||||
if (!(ctx->flags & BCDUMP_F_STRIP)) {
|
||||
p = lj_strfmt_wuleb128(p, len);
|
||||
p = lj_buf_wmem(p, name, len);
|
||||
}
|
||||
|
|
@ -352,14 +428,16 @@ static TValue *cpwriter(lua_State *L, lua_CFunction dummy, void *ud)
|
|||
|
||||
/* Write bytecode for a prototype. */
|
||||
int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data,
|
||||
int strip)
|
||||
uint32_t flags)
|
||||
{
|
||||
BCWriteCtx ctx;
|
||||
int status;
|
||||
ctx.pt = pt;
|
||||
ctx.wfunc = writer;
|
||||
ctx.wdata = data;
|
||||
ctx.strip = strip;
|
||||
ctx.heapsz = 0;
|
||||
if ((bc_op(proto_bc(pt)[0]) != BC_NOT) == LJ_FR2) flags |= BCDUMP_F_FR2;
|
||||
ctx.flags = flags;
|
||||
ctx.status = 0;
|
||||
#ifdef LUA_USE_ASSERT
|
||||
ctx.g = G(L);
|
||||
|
|
@ -368,6 +446,7 @@ int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data,
|
|||
status = lj_vm_cpcall(L, NULL, &ctx, cpwriter);
|
||||
if (status == 0) status = ctx.status;
|
||||
lj_buf_free(G(sbufL(&ctx.sb)), &ctx.sb);
|
||||
bcwrite_heap_resize(&ctx, 0);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe)
|
|||
if (cf == NULL || (char *)cframe_pc(cf) == (char *)cframe_L(cf))
|
||||
return NO_BCPOS;
|
||||
ins = cframe_pc(cf); /* Only happens during error/hook handling. */
|
||||
if (!ins) return NO_BCPOS;
|
||||
} else {
|
||||
if (frame_islua(nextframe)) {
|
||||
ins = frame_pc(nextframe);
|
||||
|
|
|
|||
23
src/lj_err.c
23
src/lj_err.c
|
|
@ -822,7 +822,14 @@ LJ_NOINLINE void lj_err_mem(lua_State *L)
|
|||
TValue *base = tvref(G(L)->jit_base);
|
||||
if (base) L->base = base;
|
||||
}
|
||||
if (curr_funcisL(L)) L->top = curr_topL(L);
|
||||
if (curr_funcisL(L)) {
|
||||
L->top = curr_topL(L);
|
||||
if (LJ_UNLIKELY(L->top > tvref(L->maxstack))) {
|
||||
/* The current Lua frame violates the stack. Replace it with a dummy. */
|
||||
L->top = L->base;
|
||||
setframe_gc(L->base - 1 - LJ_FR2, obj2gco(L), LJ_TTHREAD);
|
||||
}
|
||||
}
|
||||
setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRMEM));
|
||||
lj_err_throw(L, LUA_ERRMEM);
|
||||
}
|
||||
|
|
@ -883,9 +890,11 @@ LJ_NOINLINE void LJ_FASTCALL lj_err_run(lua_State *L)
|
|||
{
|
||||
ptrdiff_t ef = (LJ_HASJIT && tvref(G(L)->jit_base)) ? 0 : finderrfunc(L);
|
||||
if (ef) {
|
||||
TValue *errfunc = restorestack(L, ef);
|
||||
TValue *top = L->top;
|
||||
TValue *errfunc, *top;
|
||||
lj_state_checkstack(L, LUA_MINSTACK * 2); /* Might raise new error. */
|
||||
lj_trace_abort(G(L));
|
||||
errfunc = restorestack(L, ef);
|
||||
top = L->top;
|
||||
if (!tvisfunc(errfunc) || L->status == LUA_ERRERR) {
|
||||
setstrV(L, top-1, lj_err_str(L, LJ_ERR_ERRERR));
|
||||
lj_err_throw(L, LUA_ERRERR);
|
||||
|
|
@ -900,7 +909,15 @@ LJ_NOINLINE void LJ_FASTCALL lj_err_run(lua_State *L)
|
|||
lj_err_throw(L, LUA_ERRRUN);
|
||||
}
|
||||
|
||||
/* Stack overflow error. */
|
||||
void LJ_FASTCALL lj_err_stkov(lua_State *L)
|
||||
{
|
||||
lj_debug_addloc(L, err2msg(LJ_ERR_STKOV), L->base-1, NULL);
|
||||
lj_err_run(L);
|
||||
}
|
||||
|
||||
#if LJ_HASJIT
|
||||
/* Rethrow error after doing a trace exit. */
|
||||
LJ_NOINLINE void LJ_FASTCALL lj_err_trace(lua_State *L, int errcode)
|
||||
{
|
||||
if (errcode == LUA_ERRRUN)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ LJ_DATA const char *lj_err_allmsg;
|
|||
LJ_FUNC GCstr *lj_err_str(lua_State *L, ErrMsg em);
|
||||
LJ_FUNCA_NORET void LJ_FASTCALL lj_err_throw(lua_State *L, int errcode);
|
||||
LJ_FUNC_NORET void lj_err_mem(lua_State *L);
|
||||
LJ_FUNC_NORET void LJ_FASTCALL lj_err_stkov(lua_State *L);
|
||||
LJ_FUNC_NORET void LJ_FASTCALL lj_err_run(lua_State *L);
|
||||
#if LJ_HASJIT
|
||||
LJ_FUNCA_NORET void LJ_FASTCALL lj_err_trace(lua_State *L, int errcode);
|
||||
|
|
|
|||
|
|
@ -99,6 +99,14 @@ static ptrdiff_t results_wanted(jit_State *J)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static TValue *rec_stop_stitch_cp(lua_State *L, lua_CFunction dummy, void *ud)
|
||||
{
|
||||
jit_State *J = (jit_State *)ud;
|
||||
lj_record_stop(J, LJ_TRLINK_STITCH, 0);
|
||||
UNUSED(L); UNUSED(dummy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Trace stitching: add continuation below frame to start a new trace. */
|
||||
static void recff_stitch(jit_State *J)
|
||||
{
|
||||
|
|
@ -109,10 +117,7 @@ static void recff_stitch(jit_State *J)
|
|||
TValue *nframe = base + 1 + LJ_FR2;
|
||||
const BCIns *pc = frame_pc(base-1);
|
||||
TValue *pframe = frame_prevl(base-1);
|
||||
|
||||
/* Check for this now. Throwing in lj_record_stop messes up the stack. */
|
||||
if (J->cur.nsnap >= (MSize)J->param[JIT_P_maxsnap])
|
||||
lj_trace_err(J, LJ_TRERR_SNAPOV);
|
||||
int errcode;
|
||||
|
||||
/* Move func + args up in Lua stack and insert continuation. */
|
||||
memmove(&base[1], &base[-1-LJ_FR2], sizeof(TValue)*nslot);
|
||||
|
|
@ -137,13 +142,19 @@ static void recff_stitch(jit_State *J)
|
|||
J->baseslot += 2 + LJ_FR2;
|
||||
J->framedepth++;
|
||||
|
||||
lj_record_stop(J, LJ_TRLINK_STITCH, 0);
|
||||
errcode = lj_vm_cpcall(L, NULL, J, rec_stop_stitch_cp);
|
||||
|
||||
/* Undo Lua stack changes. */
|
||||
memmove(&base[-1-LJ_FR2], &base[1], sizeof(TValue)*nslot);
|
||||
setframe_pc(base-1, pc);
|
||||
L->base -= 2 + LJ_FR2;
|
||||
L->top -= 2 + LJ_FR2;
|
||||
|
||||
if (errcode) {
|
||||
if (errcode == LUA_ERRRUN)
|
||||
copyTV(L, L->top-1, L->top + (1 + LJ_FR2));
|
||||
lj_err_throw(L, errcode); /* Propagate errors. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback handler for fast functions that are not recorded (yet). */
|
||||
|
|
@ -1205,6 +1216,12 @@ static void LJ_FASTCALL recff_buffer_method_set(jit_State *J, RecordFFData *rd)
|
|||
if (tref_isstr(tr)) {
|
||||
TRef trp = emitir(IRT(IR_STRREF, IRT_PGC), tr, lj_ir_kint(J, 0));
|
||||
TRef len = emitir(IRTI(IR_FLOAD), tr, IRFL_STR_LEN);
|
||||
IRIns *irp = IR(tref_ref(trp));
|
||||
/* trp must point into the anchored obj, even after folding. */
|
||||
if (irp->o == IR_STRREF)
|
||||
tr = irp->op1;
|
||||
else if (!tref_isk(tr))
|
||||
trp = emitir(IRT(IR_ADD, IRT_PGC), tr, lj_ir_kintpgc(J, sizeof(GCstr)));
|
||||
lj_ir_call(J, IRCALL_lj_bufx_set, trbuf, trp, len, tr);
|
||||
#if LJ_HASFFI
|
||||
} else if (tref_iscdata(tr)) {
|
||||
|
|
@ -1445,6 +1462,15 @@ static void LJ_FASTCALL recff_table_new(jit_State *J, RecordFFData *rd)
|
|||
{
|
||||
TRef tra = lj_opt_narrow_toint(J, J->base[0]);
|
||||
TRef trh = lj_opt_narrow_toint(J, J->base[1]);
|
||||
if (tref_isk(tra) && tref_isk(trh)) {
|
||||
int32_t a = IR(tref_ref(tra))->i;
|
||||
if (a < 0x7fff) {
|
||||
uint32_t hbits = hsize2hbits(IR(tref_ref(trh))->i);
|
||||
a = a > 0 ? a+1 : 0;
|
||||
J->base[0] = emitir(IRTG(IR_TNEW, IRT_TAB), (uint32_t)a, hbits);
|
||||
return;
|
||||
}
|
||||
}
|
||||
J->base[0] = lj_ir_call(J, IRCALL_lj_tab_new_ah, tra, trh);
|
||||
UNUSED(rd);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,6 +108,9 @@ static void gc_mark_start(global_State *g)
|
|||
gc_markobj(g, tabref(mainthread(g)->env));
|
||||
gc_marktv(g, &g->registrytv);
|
||||
gc_mark_gcroot(g);
|
||||
#if LJ_HASFFI
|
||||
if (ctype_ctsG(g)) gc_markobj(g, ctype_ctsG(g)->finalizer);
|
||||
#endif
|
||||
g->gc.state = GCSpropagate;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -637,7 +637,7 @@ static void LJ_FASTCALL gdbjit_debugabbrev(GDBJITctx *ctx)
|
|||
DUV(DW_AT_low_pc); DUV(DW_FORM_addr);
|
||||
DUV(DW_AT_high_pc); DUV(DW_FORM_addr);
|
||||
DUV(DW_AT_stmt_list); DUV(DW_FORM_data4);
|
||||
DB(0); DB(0);
|
||||
DB(0); DB(0); DB(0);
|
||||
|
||||
ctx->p = p;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -385,6 +385,7 @@ typedef struct IRType1 { uint8_t irt; } IRType1;
|
|||
#define irt_isu32(t) (irt_type(t) == IRT_U32)
|
||||
#define irt_isi64(t) (irt_type(t) == IRT_I64)
|
||||
#define irt_isu64(t) (irt_type(t) == IRT_U64)
|
||||
#define irt_isp32(t) (irt_type(t) == IRT_P32)
|
||||
|
||||
#define irt_isfp(t) (irt_isnum(t) || irt_isfloat(t))
|
||||
#define irt_isinteger(t) (irt_typerange((t), IRT_I8, IRT_INT))
|
||||
|
|
|
|||
|
|
@ -411,6 +411,7 @@ int lj_lex_setup(lua_State *L, LexState *ls)
|
|||
ls->linenumber = 1;
|
||||
ls->lastline = 1;
|
||||
ls->endmark = 0;
|
||||
ls->fr2 = LJ_FR2; /* Generate native bytecode by default. */
|
||||
lex_next(ls); /* Read-ahead first char. */
|
||||
if (ls->c == 0xef && ls->p + 2 <= ls->pe && (uint8_t)ls->p[0] == 0xbb &&
|
||||
(uint8_t)ls->p[1] == 0xbf) { /* Skip UTF-8 BOM (if buffered). */
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ typedef struct LexState {
|
|||
MSize sizebcstack; /* Size of bytecode stack. */
|
||||
uint32_t level; /* Syntactical nesting level. */
|
||||
int endmark; /* Trust bytecode end marker, even if not at EOF. */
|
||||
int fr2; /* Generate bytecode for LJ_FR2 mode. */
|
||||
} LexState;
|
||||
|
||||
LJ_FUNC int lj_lex_setup(lua_State *L, LexState *ls);
|
||||
|
|
|
|||
18
src/lj_lib.c
18
src/lj_lib.c
|
|
@ -62,6 +62,7 @@ static const uint8_t *lib_read_lfunc(lua_State *L, const uint8_t *p, GCtab *tab)
|
|||
ls.pe = (const char *)~(uintptr_t)0;
|
||||
ls.c = -1;
|
||||
ls.level = (BCDUMP_F_STRIP|(LJ_BE*BCDUMP_F_BE));
|
||||
ls.fr2 = LJ_FR2;
|
||||
ls.chunkname = name;
|
||||
pt = lj_bcread_proto(&ls);
|
||||
pt->firstline = ~(BCLine)0;
|
||||
|
|
@ -266,6 +267,23 @@ GCfunc *lj_lib_checkfunc(lua_State *L, int narg)
|
|||
return funcV(o);
|
||||
}
|
||||
|
||||
GCproto *lj_lib_checkLproto(lua_State *L, int narg, int nolua)
|
||||
{
|
||||
TValue *o = L->base + narg-1;
|
||||
if (L->top > o) {
|
||||
if (tvisproto(o)) {
|
||||
return protoV(o);
|
||||
} else if (tvisfunc(o)) {
|
||||
if (isluafunc(funcV(o)))
|
||||
return funcproto(funcV(o));
|
||||
else if (nolua)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
lj_err_argt(L, narg, LUA_TFUNCTION);
|
||||
return NULL; /* unreachable */
|
||||
}
|
||||
|
||||
GCtab *lj_lib_checktab(lua_State *L, int narg)
|
||||
{
|
||||
TValue *o = L->base + narg-1;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ LJ_FUNC lua_Number lj_lib_checknum(lua_State *L, int narg);
|
|||
LJ_FUNC int32_t lj_lib_checkint(lua_State *L, int narg);
|
||||
LJ_FUNC int32_t lj_lib_optint(lua_State *L, int narg, int32_t def);
|
||||
LJ_FUNC GCfunc *lj_lib_checkfunc(lua_State *L, int narg);
|
||||
LJ_FUNC GCproto *lj_lib_checkLproto(lua_State *L, int narg, int nolua);
|
||||
LJ_FUNC GCtab *lj_lib_checktab(lua_State *L, int narg);
|
||||
LJ_FUNC GCtab *lj_lib_checktabornil(lua_State *L, int narg);
|
||||
LJ_FUNC int lj_lib_checkopt(lua_State *L, int narg, int def, const char *lst);
|
||||
|
|
|
|||
|
|
@ -34,14 +34,28 @@ static TValue *cpparser(lua_State *L, lua_CFunction dummy, void *ud)
|
|||
UNUSED(dummy);
|
||||
cframe_errfunc(L->cframe) = -1; /* Inherit error function. */
|
||||
bc = lj_lex_setup(L, ls);
|
||||
if (ls->mode && !strchr(ls->mode, bc ? 'b' : 't')) {
|
||||
setstrV(L, L->top++, lj_err_str(L, LJ_ERR_XMODE));
|
||||
lj_err_throw(L, LUA_ERRSYNTAX);
|
||||
if (ls->mode) {
|
||||
int xmode = 1;
|
||||
const char *mode = ls->mode;
|
||||
char c;
|
||||
while ((c = *mode++)) {
|
||||
if (c == (bc ? 'b' : 't')) xmode = 0;
|
||||
if (c == (LJ_FR2 ? 'W' : 'X')) ls->fr2 = !LJ_FR2;
|
||||
}
|
||||
if (xmode) {
|
||||
setstrV(L, L->top++, lj_err_str(L, LJ_ERR_XMODE));
|
||||
lj_err_throw(L, LUA_ERRSYNTAX);
|
||||
}
|
||||
}
|
||||
pt = bc ? lj_bcread(ls) : lj_parse(ls);
|
||||
fn = lj_func_newL_empty(L, pt, tabref(L->env));
|
||||
/* Don't combine above/below into one statement. */
|
||||
setfuncV(L, L->top++, fn);
|
||||
if (ls->fr2 == LJ_FR2) {
|
||||
fn = lj_func_newL_empty(L, pt, tabref(L->env));
|
||||
/* Don't combine above/below into one statement. */
|
||||
setfuncV(L, L->top++, fn);
|
||||
} else {
|
||||
/* Non-native generation returns a dumpable, but non-runnable prototype. */
|
||||
setprotoV(L, L->top++, pt);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -159,9 +173,10 @@ LUALIB_API int luaL_loadstring(lua_State *L, const char *s)
|
|||
LUA_API int lua_dump(lua_State *L, lua_Writer writer, void *data)
|
||||
{
|
||||
cTValue *o = L->top-1;
|
||||
uint32_t flags = LJ_FR2*BCDUMP_F_FR2; /* Default mode for legacy C API. */
|
||||
lj_checkapi(L->top > L->base, "top slot empty");
|
||||
if (tvisfunc(o) && isluafunc(funcV(o)))
|
||||
return lj_bcwrite(L, funcproto(funcV(o)), writer, data, 0);
|
||||
return lj_bcwrite(L, funcproto(funcV(o)), writer, data, flags);
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -217,25 +217,23 @@ static TRef fwd_ahload(jit_State *J, IRRef xref)
|
|||
}
|
||||
ref = store->prev;
|
||||
}
|
||||
if (ir->o == IR_TNEW && !irt_isnil(fins->t))
|
||||
return 0; /* Type instability in loop-carried dependency. */
|
||||
if (irt_ispri(fins->t)) {
|
||||
return TREF_PRI(irt_type(fins->t));
|
||||
} else if (irt_isnum(fins->t) || (LJ_DUALNUM && irt_isint(fins->t)) ||
|
||||
irt_isstr(fins->t)) {
|
||||
/* Simplified here: let loop_unroll() figure out any type instability. */
|
||||
if (ir->o == IR_TNEW) {
|
||||
return TREF_NIL;
|
||||
} else {
|
||||
TValue keyv;
|
||||
cTValue *tv;
|
||||
IRIns *key = IR(xr->op2);
|
||||
if (key->o == IR_KSLOT) key = IR(key->op1);
|
||||
lj_ir_kvalue(J->L, &keyv, key);
|
||||
tv = lj_tab_get(J->L, ir_ktab(IR(ir->op1)), &keyv);
|
||||
if (itype2irt(tv) != irt_type(fins->t))
|
||||
return 0; /* Type instability in loop-carried dependency. */
|
||||
if (irt_isnum(fins->t))
|
||||
if (tvispri(tv))
|
||||
return TREF_PRI(itype2irt(tv));
|
||||
else if (tvisnum(tv))
|
||||
return lj_ir_knum_u64(J, tv->u64);
|
||||
else if (LJ_DUALNUM && irt_isint(fins->t))
|
||||
else if (tvisint(tv))
|
||||
return lj_ir_kint(J, intV(tv));
|
||||
else
|
||||
else if (tvisgcv(tv))
|
||||
return lj_ir_kstr(J, strV(tv));
|
||||
}
|
||||
/* Othwerwise: don't intern as a constant. */
|
||||
|
|
@ -964,6 +962,8 @@ int lj_opt_fwd_wasnonnil(jit_State *J, IROpT loadop, IRRef xref)
|
|||
if (skref == xkref || !irref_isk(skref) || !irref_isk(xkref))
|
||||
return 0; /* A nil store with same const key or var key MAY alias. */
|
||||
/* Different const keys CANNOT alias. */
|
||||
} else if (irt_isp32(IR(skref)->t) != irt_isp32(IR(xkref)->t)) {
|
||||
return 0; /* HREF and HREFK MAY alias. */
|
||||
} /* Different key types CANNOT alias. */
|
||||
} /* Other non-nil stores MAY alias. */
|
||||
ref = store->prev;
|
||||
|
|
|
|||
|
|
@ -667,19 +667,20 @@ static void bcemit_store(FuncState *fs, ExpDesc *var, ExpDesc *e)
|
|||
/* Emit method lookup expression. */
|
||||
static void bcemit_method(FuncState *fs, ExpDesc *e, ExpDesc *key)
|
||||
{
|
||||
BCReg idx, func, obj = expr_toanyreg(fs, e);
|
||||
BCReg idx, func, fr2, obj = expr_toanyreg(fs, e);
|
||||
expr_free(fs, e);
|
||||
func = fs->freereg;
|
||||
bcemit_AD(fs, BC_MOV, func+1+LJ_FR2, obj); /* Copy object to 1st argument. */
|
||||
fr2 = fs->ls->fr2;
|
||||
bcemit_AD(fs, BC_MOV, func+1+fr2, obj); /* Copy object to 1st argument. */
|
||||
lj_assertFS(expr_isstrk(key), "bad usage");
|
||||
idx = const_str(fs, key);
|
||||
if (idx <= BCMAX_C) {
|
||||
bcreg_reserve(fs, 2+LJ_FR2);
|
||||
bcreg_reserve(fs, 2+fr2);
|
||||
bcemit_ABC(fs, BC_TGETS, func, obj, idx);
|
||||
} else {
|
||||
bcreg_reserve(fs, 3+LJ_FR2);
|
||||
bcemit_AD(fs, BC_KSTR, func+2+LJ_FR2, idx);
|
||||
bcemit_ABC(fs, BC_TGETV, func, obj, func+2+LJ_FR2);
|
||||
bcreg_reserve(fs, 3+fr2);
|
||||
bcemit_AD(fs, BC_KSTR, func+2+fr2, idx);
|
||||
bcemit_ABC(fs, BC_TGETV, func, obj, func+2+fr2);
|
||||
fs->freereg--;
|
||||
}
|
||||
e->u.s.info = func;
|
||||
|
|
@ -1326,9 +1327,12 @@ static void fs_fixup_bc(FuncState *fs, GCproto *pt, BCIns *bc, MSize n)
|
|||
{
|
||||
BCInsLine *base = fs->bcbase;
|
||||
MSize i;
|
||||
BCIns op;
|
||||
pt->sizebc = n;
|
||||
bc[0] = BCINS_AD((fs->flags & PROTO_VARARG) ? BC_FUNCV : BC_FUNCF,
|
||||
fs->framesize, 0);
|
||||
if (fs->ls->fr2 != LJ_FR2) op = BC_NOT; /* Mark non-native prototype. */
|
||||
else if ((fs->flags & PROTO_VARARG)) op = BC_FUNCV;
|
||||
else op = BC_FUNCF;
|
||||
bc[0] = BCINS_AD(op, fs->framesize, 0);
|
||||
for (i = 1; i < n; i++)
|
||||
bc[i] = base[i].ins;
|
||||
}
|
||||
|
|
@ -1937,11 +1941,11 @@ static void parse_args(LexState *ls, ExpDesc *e)
|
|||
lj_assertFS(e->k == VNONRELOC, "bad expr type %d", e->k);
|
||||
base = e->u.s.info; /* Base register for call. */
|
||||
if (args.k == VCALL) {
|
||||
ins = BCINS_ABC(BC_CALLM, base, 2, args.u.s.aux - base - 1 - LJ_FR2);
|
||||
ins = BCINS_ABC(BC_CALLM, base, 2, args.u.s.aux - base - 1 - ls->fr2);
|
||||
} else {
|
||||
if (args.k != VVOID)
|
||||
expr_tonextreg(fs, &args);
|
||||
ins = BCINS_ABC(BC_CALL, base, 2, fs->freereg - base - LJ_FR2);
|
||||
ins = BCINS_ABC(BC_CALL, base, 2, fs->freereg - base - ls->fr2);
|
||||
}
|
||||
expr_init(e, VCALL, bcemit_INS(fs, ins));
|
||||
e->u.s.aux = base;
|
||||
|
|
@ -1981,7 +1985,7 @@ static void expr_primary(LexState *ls, ExpDesc *v)
|
|||
parse_args(ls, v);
|
||||
} else if (ls->tok == '(' || ls->tok == TK_string || ls->tok == '{') {
|
||||
expr_tonextreg(fs, v);
|
||||
if (LJ_FR2) bcreg_reserve(fs, 1);
|
||||
if (ls->fr2) bcreg_reserve(fs, 1);
|
||||
parse_args(ls, v);
|
||||
} else {
|
||||
break;
|
||||
|
|
@ -2566,7 +2570,7 @@ static void parse_for_iter(LexState *ls, GCstr *indexname)
|
|||
line = ls->linenumber;
|
||||
assign_adjust(ls, 3, expr_list(ls, &e), &e);
|
||||
/* The iterator needs another 3 [4] slots (func [pc] | state ctl). */
|
||||
bcreg_bump(fs, 3+LJ_FR2);
|
||||
bcreg_bump(fs, 3+ls->fr2);
|
||||
isnext = (nvars <= 5 && predict_next(ls, fs, exprpc));
|
||||
var_add(ls, 3); /* Hidden control variables. */
|
||||
lex_check(ls, TK_do);
|
||||
|
|
|
|||
|
|
@ -903,6 +903,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
|
|||
{
|
||||
TValue *frame = J->L->base - 1;
|
||||
ptrdiff_t i;
|
||||
BCReg baseadj = 0;
|
||||
for (i = 0; i < gotresults; i++)
|
||||
(void)getslot(J, rbase+i); /* Ensure all results have a reference. */
|
||||
while (frame_ispcall(frame)) { /* Immediately resolve pcall() returns. */
|
||||
|
|
@ -911,6 +912,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
|
|||
lj_trace_err(J, LJ_TRERR_NYIRETL);
|
||||
lj_assertJ(J->baseslot > 1+LJ_FR2, "bad baseslot for return");
|
||||
gotresults++;
|
||||
baseadj += cbase;
|
||||
rbase += cbase;
|
||||
J->baseslot -= (BCReg)cbase;
|
||||
J->base -= cbase;
|
||||
|
|
@ -935,6 +937,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
|
|||
if (--J->framedepth < 0) /* NYI: return of vararg func to lower frame. */
|
||||
lj_trace_err(J, LJ_TRERR_NYIRETL);
|
||||
lj_assertJ(J->baseslot > 1+LJ_FR2, "bad baseslot for return");
|
||||
baseadj += cbase;
|
||||
rbase += cbase;
|
||||
J->baseslot -= (BCReg)cbase;
|
||||
J->base -= cbase;
|
||||
|
|
@ -948,7 +951,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
|
|||
if ((pt->flags & PROTO_NOJIT))
|
||||
lj_trace_err(J, LJ_TRERR_CJITOFF);
|
||||
if (J->framedepth == 0 && J->pt && frame == J->L->base - 1) {
|
||||
if (check_downrec_unroll(J, pt)) {
|
||||
if (!J->cur.root && check_downrec_unroll(J, pt)) {
|
||||
J->maxslot = (BCReg)(rbase + gotresults);
|
||||
lj_snap_purge(J);
|
||||
lj_record_stop(J, LJ_TRLINK_DOWNREC, J->cur.traceno); /* Down-rec. */
|
||||
|
|
@ -970,6 +973,8 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
|
|||
lj_trace_err(J, LJ_TRERR_LLEAVE);
|
||||
} else if (J->needsnap) { /* Tailcalled to ff with side-effects. */
|
||||
lj_trace_err(J, LJ_TRERR_NYIRETL); /* No way to insert snapshot here. */
|
||||
} else if (1 + pt->framesize >= LJ_MAX_JSLOTS) {
|
||||
lj_trace_err(J, LJ_TRERR_STACKOV);
|
||||
} else { /* Return to lower frame. Guard for the target we return to. */
|
||||
TRef trpt = lj_ir_kgc(J, obj2gco(pt), IRT_PROTO);
|
||||
TRef trpc = lj_ir_kptr(J, (void *)frame_pc(frame));
|
||||
|
|
@ -1003,7 +1008,8 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
|
|||
BCReg bslot = bc_b(*(frame_contpc(frame)-1));
|
||||
TRef tr = gotresults ? J->base[cbase+rbase] : TREF_NIL;
|
||||
if (bslot != J->maxslot) { /* Concatenate the remainder. */
|
||||
TValue *b = J->L->base, save; /* Simulate lower frame and result. */
|
||||
/* Simulate lower frame and result. */
|
||||
TValue *b = J->L->base - baseadj, save;
|
||||
/* Can't handle MM_concat + CALLT + fast func side-effects. */
|
||||
if (J->postproc != LJ_POST_NONE)
|
||||
lj_trace_err(J, LJ_TRERR_NYIRETL);
|
||||
|
|
@ -1016,7 +1022,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
|
|||
J->L->base = b - cbase;
|
||||
tr = rec_cat(J, bslot, cbase-(2<<LJ_FR2));
|
||||
b = J->L->base + cbase; /* Undo. */
|
||||
J->L->base = b;
|
||||
J->L->base = b + baseadj;
|
||||
copyTV(J->L, b-(2<<LJ_FR2), &save);
|
||||
}
|
||||
if (tr) { /* Store final result. */
|
||||
|
|
|
|||
|
|
@ -453,6 +453,7 @@ static TRef snap_replay_const(jit_State *J, IRIns *ir)
|
|||
case IR_KNUM: case IR_KINT64:
|
||||
return lj_ir_k64(J, (IROp)ir->o, ir_k64(ir)->u64);
|
||||
case IR_KPTR: return lj_ir_kptr(J, ir_kptr(ir)); /* Continuation. */
|
||||
case IR_KNULL: return lj_ir_knull(J, irt_type(ir->t));
|
||||
default: lj_assertJ(0, "bad IR constant op %d", ir->o); return TREF_NIL;
|
||||
}
|
||||
}
|
||||
|
|
@ -557,13 +558,15 @@ void lj_snap_replay(jit_State *J, GCtrace *T)
|
|||
IRRef refp = snap_ref(sn);
|
||||
IRIns *ir = &T->ir[refp];
|
||||
if (regsp_reg(ir->r) == RID_SUNK) {
|
||||
uint8_t m;
|
||||
if (J->slot[snap_slot(sn)] != snap_slot(sn)) continue;
|
||||
pass23 = 1;
|
||||
lj_assertJ(ir->o == IR_TNEW || ir->o == IR_TDUP ||
|
||||
ir->o == IR_CNEW || ir->o == IR_CNEWI,
|
||||
"sunk parent IR %04d has bad op %d", refp - REF_BIAS, ir->o);
|
||||
if (ir->op1 >= T->nk) snap_pref(J, T, map, nent, seen, ir->op1);
|
||||
if (ir->op2 >= T->nk) snap_pref(J, T, map, nent, seen, ir->op2);
|
||||
m = lj_ir_mode[ir->o];
|
||||
if (irm_op1(m) == IRMref) snap_pref(J, T, map, nent, seen, ir->op1);
|
||||
if (irm_op2(m) == IRMref) snap_pref(J, T, map, nent, seen, ir->op2);
|
||||
if (LJ_HASFFI && ir->o == IR_CNEWI) {
|
||||
if (LJ_32 && refp+1 < T->nins && (ir+1)->o == IR_HIOP)
|
||||
snap_pref(J, T, map, nent, seen, (ir+1)->op2);
|
||||
|
|
@ -591,14 +594,16 @@ void lj_snap_replay(jit_State *J, GCtrace *T)
|
|||
IRIns *ir = &T->ir[refp];
|
||||
if (regsp_reg(ir->r) == RID_SUNK) {
|
||||
TRef op1, op2;
|
||||
uint8_t m;
|
||||
if (J->slot[snap_slot(sn)] != snap_slot(sn)) { /* De-dup allocs. */
|
||||
J->slot[snap_slot(sn)] = J->slot[J->slot[snap_slot(sn)]];
|
||||
continue;
|
||||
}
|
||||
op1 = ir->op1;
|
||||
if (op1 >= T->nk) op1 = snap_pref(J, T, map, nent, seen, op1);
|
||||
m = lj_ir_mode[ir->o];
|
||||
if (irm_op1(m) == IRMref) op1 = snap_pref(J, T, map, nent, seen, op1);
|
||||
op2 = ir->op2;
|
||||
if (op2 >= T->nk) op2 = snap_pref(J, T, map, nent, seen, op2);
|
||||
if (irm_op2(m) == IRMref) op2 = snap_pref(J, T, map, nent, seen, op2);
|
||||
if (LJ_HASFFI && ir->o == IR_CNEWI) {
|
||||
if (LJ_32 && refp+1 < T->nins && (ir+1)->o == IR_HIOP) {
|
||||
lj_needsplit(J); /* Emit joining HIOP. */
|
||||
|
|
@ -624,9 +629,25 @@ void lj_snap_replay(jit_State *J, GCtrace *T)
|
|||
if (irr->o == IR_HREFK || irr->o == IR_AREF) {
|
||||
IRIns *irf = &T->ir[irr->op1];
|
||||
tmp = emitir(irf->ot, tmp, irf->op2);
|
||||
} else if (irr->o == IR_NEWREF) {
|
||||
IRRef allocref = tref_ref(tr);
|
||||
IRRef keyref = tref_ref(key);
|
||||
IRRef newref_ref = J->chain[IR_NEWREF];
|
||||
IRIns *newref = &J->cur.ir[newref_ref];
|
||||
lj_assertJ(irref_isk(keyref),
|
||||
"sunk store for parent IR %04d with bad key %04d",
|
||||
refp - REF_BIAS, keyref - REF_BIAS);
|
||||
if (newref_ref > allocref && newref->op2 == keyref) {
|
||||
lj_assertJ(newref->op1 == allocref,
|
||||
"sunk store for parent IR %04d with bad tab %04d",
|
||||
refp - REF_BIAS, allocref - REF_BIAS);
|
||||
tmp = newref_ref;
|
||||
goto skip_newref;
|
||||
}
|
||||
}
|
||||
}
|
||||
tmp = emitir(irr->ot, tmp, key);
|
||||
skip_newref:
|
||||
val = snap_pref(J, T, map, nent, seen, irs->op2);
|
||||
if (val == 0) {
|
||||
IRIns *irc = &T->ir[irs->op2];
|
||||
|
|
@ -882,9 +903,13 @@ static void snap_unsink(jit_State *J, GCtrace *T, ExitState *ex,
|
|||
if (irk->o == IR_FREF) {
|
||||
switch (irk->op2) {
|
||||
case IRFL_TAB_META:
|
||||
snap_restoreval(J, T, ex, snapno, rfilt, irs->op2, &tmp);
|
||||
/* NOBARRIER: The table is new (marked white). */
|
||||
setgcref(t->metatable, obj2gco(tabV(&tmp)));
|
||||
if (T->ir[irs->op2].o == IR_KNULL) {
|
||||
setgcrefnull(t->metatable);
|
||||
} else {
|
||||
snap_restoreval(J, T, ex, snapno, rfilt, irs->op2, &tmp);
|
||||
/* NOBARRIER: The table is new (marked white). */
|
||||
setgcref(t->metatable, obj2gco(tabV(&tmp)));
|
||||
}
|
||||
break;
|
||||
case IRFL_TAB_NOMM:
|
||||
/* Negative metamethod cache invalidated by lj_tab_set() below. */
|
||||
|
|
|
|||
|
|
@ -102,27 +102,49 @@ void lj_state_shrinkstack(lua_State *L, MSize used)
|
|||
/* Try to grow stack. */
|
||||
void LJ_FASTCALL lj_state_growstack(lua_State *L, MSize need)
|
||||
{
|
||||
MSize n;
|
||||
if (L->stacksize >= LJ_STACK_MAXEX) {
|
||||
/* 4. Throw 'error in error handling' when we are _over_ the limit. */
|
||||
if (L->stacksize > LJ_STACK_MAXEX)
|
||||
lj_err_throw(L, LUA_ERRERR); /* Does not invoke an error handler. */
|
||||
/* 1. We are _at_ the limit after the last growth. */
|
||||
if (L->status < LUA_ERRRUN) { /* 2. Throw 'stack overflow'. */
|
||||
L->status = LUA_ERRRUN; /* Prevent ending here again for pushed msg. */
|
||||
lj_err_msg(L, LJ_ERR_STKOV); /* May invoke an error handler. */
|
||||
MSize n = L->stacksize + need;
|
||||
if (LJ_LIKELY(n < LJ_STACK_MAX)) { /* The stack can grow as requested. */
|
||||
if (n < 2 * L->stacksize) { /* Try to double the size. */
|
||||
n = 2 * L->stacksize;
|
||||
if (n > LJ_STACK_MAX)
|
||||
n = LJ_STACK_MAX;
|
||||
}
|
||||
resizestack(L, n);
|
||||
} else { /* Request would overflow. Raise a stack overflow error. */
|
||||
if (LJ_HASJIT) {
|
||||
TValue *base = tvref(G(L)->jit_base);
|
||||
if (base) L->base = base;
|
||||
}
|
||||
if (curr_funcisL(L)) {
|
||||
L->top = curr_topL(L);
|
||||
if (L->top > tvref(L->maxstack)) {
|
||||
/* The current Lua frame violates the stack, so replace it with a
|
||||
** dummy. This can happen when BC_IFUNCF is trying to grow the stack.
|
||||
*/
|
||||
L->top = L->base;
|
||||
setframe_gc(L->base - 1 - LJ_FR2, obj2gco(L), LJ_TTHREAD);
|
||||
}
|
||||
}
|
||||
if (L->stacksize <= LJ_STACK_MAXEX) {
|
||||
/* An error handler might want to inspect the stack overflow error, but
|
||||
** will need some stack space to run in. We give it a stack size beyond
|
||||
** the normal limit in order to do so, then rely on lj_state_relimitstack
|
||||
** calls during unwinding to bring us back to a convential stack size.
|
||||
** The + 1 is space for the error message, and 2 * LUA_MINSTACK is for
|
||||
** the lj_state_checkstack() call in lj_err_run().
|
||||
*/
|
||||
resizestack(L, LJ_STACK_MAX + 1 + 2 * LUA_MINSTACK);
|
||||
lj_err_stkov(L); /* May invoke an error handler. */
|
||||
} else {
|
||||
/* If we're here, then the stack overflow error handler is requesting
|
||||
** to grow the stack even further. We have no choice but to abort the
|
||||
** error handler.
|
||||
*/
|
||||
GCstr *em = lj_err_str(L, LJ_ERR_STKOV); /* Might OOM. */
|
||||
setstrV(L, L->top++, em); /* There is always space to push an error. */
|
||||
lj_err_throw(L, LUA_ERRERR); /* Does not invoke an error handler. */
|
||||
}
|
||||
/* 3. Add space (over the limit) for pushed message and error handler. */
|
||||
}
|
||||
n = L->stacksize + need;
|
||||
if (n > LJ_STACK_MAX) {
|
||||
n += 2*LUA_MINSTACK;
|
||||
} else if (n < 2*L->stacksize) {
|
||||
n = 2*L->stacksize;
|
||||
if (n >= LJ_STACK_MAX)
|
||||
n = LJ_STACK_MAX;
|
||||
}
|
||||
resizestack(L, n);
|
||||
}
|
||||
|
||||
void LJ_FASTCALL lj_state_growstack1(lua_State *L)
|
||||
|
|
|
|||
|
|
@ -454,7 +454,8 @@ static char *lj_strfmt_wfnum(SBuf *sb, SFormat sf, lua_Number n, char *p)
|
|||
prec--;
|
||||
if (!i) {
|
||||
if (ndlo == ndhi) { prec = 0; break; }
|
||||
lj_strfmt_wuint9(tail, nd[++ndlo]);
|
||||
ndlo = (ndlo + 1) & 0x3f;
|
||||
lj_strfmt_wuint9(tail, nd[ndlo]);
|
||||
i = 9;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -936,7 +936,7 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr)
|
|||
} else if (G(L)->gc.state == GCSatomic || G(L)->gc.state == GCSfinalize) {
|
||||
if (!(G(L)->hookmask & HOOK_GC))
|
||||
lj_gc_step(L); /* Exited because of GC: drive GC forward. */
|
||||
} else {
|
||||
} else if ((J->flags & JIT_F_ON)) {
|
||||
trace_hotside(J, pc);
|
||||
}
|
||||
#ifdef LUA_USE_TRACE_LOGS
|
||||
|
|
|
|||
|
|
@ -78,4 +78,5 @@ LUA_API const char *luaJIT_profile_dumpstack(lua_State *L, const char *fmt,
|
|||
/* Enforce (dynamic) linker error for version mismatches. Call from main. */
|
||||
LUA_API void LUAJIT_VERSION_SYM(void);
|
||||
|
||||
#error "DO NOT USE luajit_rolling.h -- only include build-generated luajit.h"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
@rem Add more debug flags here, e.g. DEBUGCFLAGS=/DLUA_USE_APICHECK
|
||||
@set DEBUGCFLAGS=
|
||||
@set LJCOMPILE=cl /nologo /c /O2 /W3 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_STDIO_INLINE=__declspec(dllexport)__inline
|
||||
@set LJDYNBUILD=/MD /DLUA_BUILD_AS_DLL
|
||||
@set LJLINK=link /nologo
|
||||
@set LJMT=mt /nologo
|
||||
@set LJLIB=lib /nologo /nodefaultlib
|
||||
|
|
@ -93,12 +94,13 @@ buildvm -m folddef -o lj_folddef.h lj_opt_fold.c
|
|||
@shift
|
||||
@set BUILDTYPE=debug
|
||||
@set LJCOMPILE=%LJCOMPILE% /Zi %DEBUGCFLAGS%
|
||||
@set LJDYNBUILD=/MDd /DLUA_BUILD_AS_DLL
|
||||
@set LJLINK=%LJLINK% /opt:ref /opt:icf /incremental:no
|
||||
:NODEBUG
|
||||
@set LJLINK=%LJLINK% /%BUILDTYPE%
|
||||
@if "%1"=="amalg" goto :AMALGDLL
|
||||
@if "%1"=="static" goto :STATIC
|
||||
%LJCOMPILE% /MD /DLUA_BUILD_AS_DLL lj_*.c lib_*.c
|
||||
%LJCOMPILE% %LJDYNBUILD% lj_*.c lib_*.c
|
||||
@if errorlevel 1 goto :BAD
|
||||
%LJLINK% /DLL /out:%LJDLLNAME% lj_*.obj lib_*.obj
|
||||
@if errorlevel 1 goto :BAD
|
||||
|
|
@ -110,7 +112,7 @@ buildvm -m folddef -o lj_folddef.h lj_opt_fold.c
|
|||
@if errorlevel 1 goto :BAD
|
||||
@goto :MTDLL
|
||||
:AMALGDLL
|
||||
%LJCOMPILE% /MD /DLUA_BUILD_AS_DLL ljamalg.c
|
||||
%LJCOMPILE% %LJDYNBUILD% ljamalg.c
|
||||
@if errorlevel 1 goto :BAD
|
||||
%LJLINK% /DLL /out:%LJDLLNAME% ljamalg.obj lj_vm.obj
|
||||
@if errorlevel 1 goto :BAD
|
||||
|
|
|
|||
|
|
@ -1720,9 +1720,10 @@ static void build_subroutines(BuildCtx *ctx)
|
|||
|
|
||||
|//-- Base library: iterators -------------------------------------------
|
||||
|
|
||||
|.ffunc next
|
||||
|.ffunc_1 next
|
||||
| cmplwi NARGS8:RC, 8
|
||||
| lwz TAB:CARG1, WORD_LO(BASE)
|
||||
| lwz CARG2, WORD_HI(BASE)
|
||||
| blt ->fff_fallback
|
||||
|.if ENDIAN_LE
|
||||
| add TMP1, BASE, NARGS8:RC
|
||||
|
|
@ -1730,7 +1731,9 @@ static void build_subroutines(BuildCtx *ctx)
|
|||
|.else
|
||||
| stwx TISNIL, BASE, NARGS8:RC // Set missing 2nd arg to nil.
|
||||
|.endif
|
||||
| checktab CARG2
|
||||
| lwz PC, FRAME_PC(BASE)
|
||||
| bne ->fff_fallback
|
||||
| stp BASE, L->base // Add frame since C call can throw.
|
||||
| stp BASE, L->top // Dummy frame length is ok.
|
||||
| la CARG2, 8(BASE)
|
||||
|
|
@ -5703,8 +5706,8 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
|
|||
| crand 4*cr0+eq, 4*cr0+eq, 4*cr7+eq
|
||||
| add TMP3, PC, TMP0
|
||||
| bne cr0, >5
|
||||
| lus TMP1, 0xfffe
|
||||
| ori TMP1, TMP1, 0x7fff
|
||||
| lus TMP1, (LJ_KEYINDEX >> 16)
|
||||
| ori TMP1, TMP1, (LJ_KEYINDEX & 0xffff)
|
||||
| stw ZERO, WORD_LO-8(RA) // Initialize control var.
|
||||
| stw TMP1, WORD_HI-8(RA)
|
||||
| addis PC, TMP3, -(BCBIAS_J*4 >> 16)
|
||||
|
|
|
|||
|
|
@ -264,6 +264,19 @@
|
|||
| lay PC, (-BCBIAS_J*4)(TMPR1, PC)
|
||||
|.endmacro
|
||||
|
|
||||
|// Decrement hashed hotcount and trigger trace recorder if zero.
|
||||
|.macro hotloop, reg
|
||||
| lgr reg, PC
|
||||
| srlg reg, reg, 1
|
||||
| nill reg, HOTCOUNT_PCMASK
|
||||
| afi reg, GG_DISP2HOT
|
||||
| agr reg, DISPATCH
|
||||
| lg TMPR1, (reg)
|
||||
| aghi TMPR1, -HOTCOUNT_LOOP
|
||||
| stg TMPR1, (reg)
|
||||
| jl ->vm_hotloop
|
||||
|.endmacro
|
||||
|
|
||||
|// Set current VM state.
|
||||
|.macro set_vmstate, st
|
||||
| lghi TMPR1, ~LJ_VMST_..st
|
||||
|
|
@ -2030,9 +2043,24 @@ static void build_subroutines(BuildCtx *ctx)
|
|||
| stg r0, 0
|
||||
|
|
||||
|->vm_hotloop: // Hot loop counter underflow.
|
||||
| stg r0, 0
|
||||
| stg r0, 0
|
||||
|
|
||||
|.if JIT
|
||||
| lg LFUNC:RB, -16(BASE)
|
||||
| cleartp LFUNC:RB
|
||||
| lg RB, LFUNC:RB->pc
|
||||
| llgc RD, (PC2PROTO(framesize))(RB)
|
||||
| sllg RD, RD, 3
|
||||
| la RD, 0(RD, BASE)
|
||||
| lg L:RB, SAVE_L
|
||||
| stg BASE, L:RB->base
|
||||
| stg RD, L:RB->top
|
||||
| lgr CARG2, PC
|
||||
| la CARG1, GG_DISP2J(DISPATCH)
|
||||
| stg L:RB, (DISPATCH_J(L))(DISPATCH)
|
||||
| stg PC, SAVE_PC
|
||||
| brasl r14, extern lj_trace_hot // (jit_State *J, const BCIns *pc)
|
||||
| j <3
|
||||
|.endif
|
||||
|
|
||||
|->vm_callhook: // Dispatch target for call hooks.
|
||||
| stg PC, SAVE_PC
|
||||
|.if JIT
|
||||
|
|
@ -2131,7 +2159,8 @@ static void build_subroutines(BuildCtx *ctx)
|
|||
|
|
||||
|->vm_next:
|
||||
|.if JIT
|
||||
| NYI // On big-endian.
|
||||
| stg r0, 0 // NYI On big-endian.
|
||||
| stg r0, 0
|
||||
|.endif
|
||||
|
|
||||
|//-----------------------------------------------------------------------
|
||||
|
|
@ -2140,8 +2169,16 @@ static void build_subroutines(BuildCtx *ctx)
|
|||
|
|
||||
|// Handler for callback functions. Callback slot number in ah/al.
|
||||
|->vm_ffi_callback:
|
||||
| stg r0, 0
|
||||
| stg r0, 0
|
||||
|.if FFI
|
||||
|.type CTSTATE, CTState, PC
|
||||
| saveregs
|
||||
| la DISPATCH, GG_G2DISP(RB)
|
||||
| lg CTSTATE, GL:RB->ctype_state
|
||||
| llgcr RC, RC
|
||||
| stg RC, CTSTATE->cb.slot
|
||||
|
|
||||
| la RC, CFRAME_SIZE(sp)
|
||||
|.endif
|
||||
|
|
||||
|->cont_ffi_callback: // Return from FFI callback.
|
||||
| stg r0, 0
|
||||
|
|
@ -3758,11 +3795,13 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
|
|||
|.define FOR_EXT, 24(RA)
|
||||
|
||||
case BC_FORL:
|
||||
{
|
||||
|.if JIT
|
||||
| hotloop RB
|
||||
|.endif
|
||||
| // Fall through. Assumes BC_IFORL follows and ins_AJ is a no-op.
|
||||
break;
|
||||
}
|
||||
|
||||
case BC_JFORI:
|
||||
case BC_JFORL:
|
||||
|
|
|
|||
Loading…
Reference in a new issue