Add minified Lua interpreter plus Lua BitOp (minilua) to run DynASM.
+
Change DynASM bit operations to use Lua BitOp
+
Translate only vm_*.dasc for detected target architecture.
+
Improve target detection for msvcbuild.bat.
+
Fix build issues on Cygwin and MinGW with optional MSys.
+
Handle cross-compiles with FPU/no-FPU or hard-fp/soft-fp ABI mismatch.
+
Remove some library functions for no-JIT/no-FFI builds.
+
Add uninstall target to top-level Makefile.
+
+
Correctness and completeness:
+
+
Preserve snapshot #0 PC for all traces.
+
Fix argument checks for coroutine.create().
+
Command line prints version and JIT status to stdout, not stderr.
+
Fix userdata __gc separations at Lua state close.
+
Fix TDUP to HLOAD forwarding for LJ_DUALNUM builds.
+
Fix buffer check in bytecode writer.
+
Make os.date() thread-safe.
+
Add missing declarations for MSVC intrinsics.
+
Fix dispatch table modifications for return hooks.
+
Workaround for MSVC conversion bug (double → uint32_t → int32_t).
+
Fix FOLD rule (i-j)-i => 0-j.
+
Never use DWARF unwinder on Windows.
+
Fix shrinking of direct mapped blocks in builtin allocator.
+
Limit recursion depth in string.match() et al.
+
Fix late despecialization of ITERN after loop has been entered.
+
Fix 'f' and 'L' options for debug.getinfo() and lua_getinfo().
+
Fix package.searchpath().
+
OSX: Change dylib names to be consistent with other platforms.
+
Android: Workaround for broken sprintf("%g", -0.0).
+
x86: Remove support for ancient CPUs without CMOV (before Pentium Pro).
+
x86: Fix register allocation for calls returning register pair.
+
x86/x64: Fix fusion of unsigned byte comparisons with swapped operands.
+
ARM: Fix tonumber() argument check.
+
ARM: Fix modulo operator and math.floor()/math.ceil() for inf/nan.
+
ARM: Invoke SPLIT pass for leftover IR_TOBIT.
+
ARM: Fix BASE register coalescing.
+
PPC: Fix interpreter state setup in callbacks.
+
PPC: Fix string.sub() range check.
+
MIPS: Support generation of MIPS/MIPSEL bytecode object files.
+
MIPS: Fix calls to floor()/ceil()/trunc().
+
ARM/PPC: Detect more target architecture variants.
+
ARM/PPC/e500/MIPS: Fix tailcalls from fast functions, esp. tostring().
+
ARM/PPC/MIPS: Fix rematerialization of FP constants.
+
FFI: Don't call FreeLibrary() on our own EXE/DLL.
+
FFI: Resolve metamethods for constructors, too.
+
FFI: Properly disable callbacks on iOS (would require executable memory).
+
FFI: Fix cdecl string parsing during recording.
+
FFI: Show address pointed to for tostring(ref), too.
+
FFI: Fix alignment of C call argument/return structure.
+
FFI: Initialize all fields of standard types.
+
FFI: Fix callback handling when new C types are declared in callback.
+
FFI: Fix recording of constructors for pointers.
+
FFI: Always resolve metamethods for pointers to structs.
+
FFI: Correctly propagate alignment when interning nested types.
+
+
Structural and performance enhancements:
+
+
Add allocation sinking and store sinking optimization.
+
Constify immutable upvalues.
+
Add builtin string to integer or FP number conversion. Improves cross-platform consistency and correctness.
+
Create string hash slots in template tables for non-const values, too. Avoids later table resizes.
+
Eliminate HREFK guard for template table references.
+
Add various new FOLD rules.
+
Don't use stack unwinding for lua_yield() (slow on x64).
+
ARM, PPC, MIPS: Improve XLOAD operand fusion and register hinting.
+
PPC, MIPS: Compile math.sqrt() to sqrt instruction, if available.
+
FFI: Fold KPTR + constant offset in SPLIT pass.
+
FFI: Optimize/inline ffi.copy() and ffi.fill().
+
FFI: Compile and optimize array/struct copies.
+
FFI: Compile ffi.typeof(cdata|ctype), ffi.sizeof(), ffi.alignof(), ffi.offsetof() and ffi.gc().
+
+
+
+
LuaJIT 2.0.0-beta10 — 2012-05-09
+
+
New features:
+
+
The MIPS of LuaJIT is complete. It requires a CPU conforming to the
+MIPS32 R1 architecture with hardware FPU. O32 hard-fp ABI,
+little-endian or big-endian.
+
Auto-detect target arch via cross-compiler. No need for
+TARGET=arch anymore.
+
Make DynASM compatible with Lua 5.2.
+
From Lua 5.2: Try __tostring metamethod on non-string error
+messages..
+
+
Correctness and completeness:
+
+
Fix parsing of hex literals with exponents.
+
Fix bytecode dump for certain number constants.
+
Fix argument type in error message for relative arguments.
+
Fix argument error handling on Lua stacks without a frame.
+
Add missing mcode limit check in assembler backend.
+
Fix compilation on OpenBSD.
+
Avoid recursive GC steps after GC-triggered trace exit.
+
Replace <unwind.h> definitions with our own.
+
Fix OSX build issues. Bump minimum required OSX version to 10.4.
+
Fix discharge order of comparisons in Lua parser.
+
Ensure running __gc of userdata created in __gc
+at state close.
+
Limit number of userdata __gc separations at state close.
+
Fix bytecode JMP slot range when optimizing
+and/or with constant LHS.
+
Fix DSE of USTORE.
+
Make lua_concat() work from C hook with partial frame.
+
Add required PHIs for implicit conversions, e.g. via XREF
+forwarding.
+
Add more comparison variants to Valgrind suppressions file.
+
Disable loading bytecode with an extra header (BOM or #!).
+
Fix PHI stack slot syncing.
+
ARM: Reorder type/value tests to silence Valgrind.
+
ARM: Fix register allocation for ldrd-optimized
+HREFK.
+
ARM: Fix conditional branch fixup for OBAR.
+
ARM: Invoke SPLIT pass for double args in FFI call.
+
ARM: Handle all CALL* ops with double results in
+SPLIT pass.
+
ARM: Fix rejoin of POW in SPLIT pass.
+
ARM: Fix compilation of math.sinh, math.cosh,
+math.tanh.
+
ARM, PPC: Avoid pointless arg clearing in BC_IFUNCF.
+
PPC: Fix resume after yield from hook.
+
PPC: Fix argument checking for rawget().
+
PPC: Fix fusion of floating-point XLOAD/XSTORE.
+
PPC: Fix HREFK code generation for huge tables.
+
PPC: Use builtin D-Cache/I-Cache sync code.
+
+
FFI library:
+
+
Ignore empty statements in ffi.cdef().
+
Ignore number parsing errors while skipping definitions.
+
Don't touch frame in callbacks with tailcalls to fast functions.
+
Fix library unloading on POSIX systems.
+
Finalize cdata before userdata when closing the state.
+
Change ffi.load() library name resolution for Cygwin.
+
Fix resolving of function name redirects on Windows/x86.
+
Fix symbol resolving error messages on Windows.
+
Fix blacklisting of C functions calling callbacks.
+
Fix result type of pointer difference.
+
Use correct PC in FFI metamethod error message.
+
Allow 'typedef _Bool int BOOL;' for the Windows API.
+
Don't record test for bool result of call, if ignored.
+
+
+
+
LuaJIT 2.0.0-beta9 — 2011-12-14
+
+
New features:
+
+
PPC port of LuaJIT is complete. Default is the dual-number port
+(usually faster). Single-number port selectable via src/Makefile
+at build time.
+
Add FFI callback support.
+
Extend -b to generate .c, .h or .obj/.o
+files with embedded bytecode.
+
Allow loading embedded bytecode with require().
+
From Lua 5.2: Change to '\z' escape. Reject undefined escape
+sequences.
+
+
Correctness and completeness:
+
+
Fix OSX 10.7 build. Fix install_name and versioning on OSX.
+
Fix iOS build.
+
Install dis_arm.lua, too.
+
Mark installed shared library as executable.
+
Add debug option to msvcbuild.bat and improve error handling.
+
Fix data-flow analysis for iterators.
+
Fix forced unwinding triggered by external unwinder.
+
Record missing for loop slot loads (return to lower frame).
+
Always use ANSI variants of Windows system functions.
+
Fix GC barrier for multi-result table constructor (TSETM).
+
Fix/add various FOLD rules.
+
Add potential PHI for number conversions due to type instability.
+
Do not eliminate PHIs only referenced from other PHIs.
+
Correctly anchor implicit number to string conversions in Lua/C API.
+
Fix various stack limit checks.
+
x64: Use thread-safe exceptions for external unwinding (GCC platforms).
+
x64: Fix result type of cdata index conversions.
+
x64: Fix math.random() and bit.bswap() code generation.
+
x64: Fix lightuserdata comparisons.
+
x64: Always extend stack-passed arguments to pointer size.
+
ARM: Many fixes to code generation backend.
+
PPC/e500: Fix dispatch for binop metamethods.
+
PPC/e500: Save/restore condition registers when entering/leaving the VM.
+
PPC/e500: Fix write barrier in stores of strings to upvalues.
+
+
FFI library:
+
+
Fix C comment parsing.
+
Fix snapshot optimization for cdata comparisons.
+
Fix recording of const/enum lookups in namespaces.
+
Fix call argument and return handling for I8/U8/I16/U16 types.
+
Fix unfused loads of float fields.
+
Fix ffi.string() recording.
+
Save GetLastError() around ffi.load() and symbol
+resolving, too.
+
Improve ld script detection in ffi.load().
+
Record loads/stores to external variables in namespaces.
+
Compile calls to stdcall, fastcall and vararg functions.
+
Treat function ctypes like pointers in comparisons.
+
Resolve __call metamethod for pointers, too.
+
Record C function calls with bool return values.
+
Record ffi.errno().
+
x86: Fix number to uint32_t conversion rounding.
+
x86: Fix 64 bit arithmetic in assembler backend.
+
x64: Fix struct-by-value calling conventions.
+
ARM: Ensure invocation of SPLIT pass for float conversions.
+
+
Structural and performance enhancements:
+
+
Display trace types with -jv and -jdump.
+
Record isolated calls. But prefer recording loops over calls.
+
Specialize to prototype for non-monomorphic functions. Solves the
+trace-explosion problem for closure-heavy programming styles.
+
Always generate a portable vmdef.lua. Easier for distros.
+
+
+
+
LuaJIT 2.0.0-beta8 — 2011-06-23
+
+
New features:
+
+
Soft-float ARM port of LuaJIT is complete.
+
Add support for bytecode loading/saving and -b command line
+option.
+
From Lua 5.2: __len metamethod for tables
+(disabled by default).
+
+
Correctness and completeness:
+
+
ARM: Misc. fixes for interpreter.
+
x86/x64: Fix bit.* argument checking in interpreter.
+
Catch early out-of-memory in memory allocator initialization.
+
Fix data-flow analysis for paths leading to an upvalue close.
+
Fix check for missing arguments in string.format().
+
Fix Solaris/x86 build (note: not a supported target).
+
Fix recording of loops with instable directions in side traces.
+
x86/x64: Fix fusion of comparisons with u8/u16
+XLOAD.
+
x86/x64: Fix register allocation for variable shifts.
+
+
FFI library:
+
+
Add ffi.errno(). Save errno/GetLastError()
+around allocations etc.
+
Fix __gc for VLA/VLS cdata objects.
+
Fix recording of casts from 32 bit cdata pointers to integers.
+
tonumber(cdata) returns nil for non-numbers.
+
Show address pointed to for tostring(pointer).
+
Print NULL pointers as "cdata<... *>: NULL".
+
Support __tostring metamethod for pointers to structs, too.
+
+
Structural and performance enhancements:
+
+
More tuning for loop unrolling heuristics.
+
Flatten and compress in-memory debug info (saves ~70%).
FFI library: Resolve ld script redirection in ffi.load().
+
From Lua 5.2: package.searchpath(), fp:read("*L"),
+load(string).
+
From Lua 5.2, disabled by default: empty statement,
+table.unpack(), modified coroutine.running().
+
+
Correctness and completeness:
+
+
FFI library: numerous fixes.
+
Fix type mismatches in store-to-load forwarding.
+
Fix error handling within metamethods.
+
Fix table.maxn().
+
Improve accuracy of x^-k on x64.
+
Fix code generation for Intel Atom in x64 mode.
+
Fix narrowing of POW.
+
Fix recording of retried fast functions.
+
Fix code generation for bit.bnot() and multiplies.
+
Fix error location within cpcall frames.
+
Add workaround for old libgcc unwind bug.
+
Fix lua_yield() and getmetatable(lightuserdata) on x64.
+
Misc. fixes for PPC/e500 interpreter.
+
Fix stack slot updates for down-recursion.
+
+
Structural and performance enhancements:
+
+
Add dual-number mode (int/double) for the VM. Enabled for ARM.
+
Improve narrowing of arithmetic operators and for loops.
+
Tune loop unrolling heuristics and increase trace recorder limits.
+
Eliminate dead slots in snapshots using bytecode data-flow analysis.
+
Avoid phantom stores to proxy tables.
+
Optimize lookups in empty proxy tables.
+
Improve bytecode optimization of and/or operators.
+
+
+
+
LuaJIT 2.0.0-beta6 — 2011-02-11
+
+
New features:
+
+
PowerPC/e500v2 port of the LuaJIT interpreter is complete.
+
Various minor features from Lua 5.2: Hex escapes in literals,
+'\*' escape, reversible string.format("%q",s),
+"%g" pattern, table.sort checks callbacks,
+os.exit(status|true|false[,close]).
+
Lua 5.2 __pairs and __ipairs metamethods
+(disabled by default).
+
Initial release of the FFI library.
+
+
Correctness and completeness:
+
+
Fix string.format() for non-finite numbers.
+
Fix memory leak when compiled to use the built-in allocator.
+
x86/x64: Fix unnecessary resize in TSETM bytecode.
+
Fix various GC issues with traces and jit.flush().
+
x64: Fix fusion of indexes for array references.
+
x86/x64: Fix stack overflow handling for coroutine results.
+
Enable low-2GB memory allocation on FreeBSD/x64.
+
Fix collectgarbage("count") result if more than 2GB is in use.
+
Fix parsing of hex floats.
+
x86/x64: Fix loop branch inversion with trailing
+HREF+NE/EQ.
+
Add jit.os string.
+
coroutine.create() permits running C functions, too.
+
Fix OSX build to work with newer ld64 versions.
+
Fix bytecode optimization of and/or operators.
+
+
Structural and performance enhancements:
+
+
Emit specialized bytecode for pairs()/next().
+
Improve bytecode coalescing of nil constants.
+
Compile calls to vararg functions.
+
Compile select().
+
Improve alias analysis, esp. for loads from allocations.
+
Tuning of various compiler heuristics.
+
Refactor and extend IR conversion instructions.
+
x86/x64: Various backend enhancements related to the FFI.
+
Add SPLIT pass to split 64 bit IR instructions for 32 bit CPUs.
+
+
+
+
LuaJIT 2.0.0-beta5 — 2010-08-24
+
+
Correctness and completeness:
+
+
Fix trace exit dispatch to function headers.
+
Fix Windows and OSX builds with LUAJIT_DISABLE_JIT.
+
Reorganize and fix placement of generated machine code on x64.
+
Fix TNEW in x64 interpreter.
+
Do not eliminate PHIs for values only referenced from side exits.
+
OS-independent canonicalization of strings for non-finite numbers.
+
Fix string.char() range check on x64.
+
Fix tostring() resolving within print().
+
Fix error handling for next().
+
Fix passing of constant arguments to external calls on x64.
+
Fix interpreter argument check for two-argument SSE math functions.
+
Fix C frame chain corruption caused by lua_cpcall().
+
Fix return from pcall() within active hook.
+
+
Structural and performance enhancements:
+
+
Replace on-trace GC frame syncing with interpreter exit.
+
Improve hash lookup specialization by not removing dead keys during GC.
+
Turn traces into true GC objects.
+
Avoid starting a GC cycle immediately after library init.
+
Add weak guards to improve dead-code elimination.
+
Speed up string interning.
+
+
+
+
LuaJIT 2.0.0-beta4 — 2010-03-28
+
+
Correctness and completeness:
+
+
Fix precondition for on-trace creation of table keys.
+
Fix {f()} on x64 when table is resized.
+
Fix folding of ordered comparisons with same references.
+
Fix snapshot restores for multi-result bytecodes.
+
Fix potential hang when recording bytecode with nested closures.
+
Fix recording of getmetatable(), tonumber() and bad argument types.
+
Fix SLOAD fusion across returns to lower frames.
+
+
Structural and performance enhancements:
+
+
Add array bounds check elimination. -Oabc is enabled by default.
+
More tuning for x64, e.g. smaller table objects.
+
+
+
+
LuaJIT 2.0.0-beta3 — 2010-03-07
+
+
LuaJIT x64 port:
+
+
Port integrated memory allocator to Linux/x64, Windows/x64 and OSX/x64.
+
Port interpreter and JIT compiler to x64.
+
Port DynASM to x64.
+
Many 32/64 bit cleanups in the VM.
+
Allow building the interpreter with either x87 or SSE2 arithmetics.
+
Add external unwinding and C++ exception interop (default on x64).
+
+
Correctness and completeness:
+
+
Fix constructor bytecode generation for certain conditional values.
+
Fix some cases of ordered string comparisons.
+
Fix lua_tocfunction().
+
Fix cutoff register in JMP bytecode for some conditional expressions.
+
Fix PHI marking algorithm for references from variant slots.
+
Fix package.cpath for non-default PREFIX.
+
Fix DWARF2 frame unwind information for interpreter on OSX.
+
Drive the GC forward on string allocations in the parser.
+
Implement call/return hooks (zero-cost if disabled).
+
Implement yield from C hooks.
+
Disable JIT compiler on older non-SSE2 CPUs instead of aborting.
+
+
Structural and performance enhancements:
+
+
Compile recursive code (tail-, up- and down-recursion).
+
Improve heuristics for bytecode penalties and blacklisting.
+
Split CALL/FUNC recording and clean up fast function call semantics.
+
Major redesign of internal function call handling.
+
Improve FOR loop const specialization and integerness checks.
+
Switch to pre-initialized stacks. Avoid frame-clearing.
+
Colocation of prototypes and related data: bytecode, constants, debug info.
+
Cleanup parser and streamline bytecode generation.
+
Add support for weak IR references to register allocator.
+
Switch to compressed, extensible snapshots.
+
Compile returns to frames below the start frame.
+
Improve alias analysis of upvalues using a disambiguation hash value.
+
Compile floor/ceil/trunc to SSE2 helper calls or SSE4.1 instructions.
+LuaJIT adds some extensions to the standard Lua/C API. The LuaJIT include
+directory must be in the compiler search path (-Ipath)
+to be able to include the required header for C code:
+
+
+#include "luajit.h"
+
+
+Or for C++ code:
+
+
+#include "lua.hpp"
+
+
+
luaJIT_setmode(L, idx, mode)
+— Control VM
+
+This is a C API extension to allow control of the VM from C code. The
+full prototype of LuaJIT_setmode is:
+
+
+LUA_API int luaJIT_setmode(lua_State *L, int idx, int mode);
+
+
+The returned status is either success (1) or failure (0).
+The second argument is either 0 or a stack index (similar to the
+other Lua/C API functions).
+
+
+The third argument specifies the mode, which is 'or'ed with a flag.
+The flag can be LUAJIT_MODE_OFF to turn a feature on,
+LUAJIT_MODE_ON to turn a feature off, or
+LUAJIT_MODE_FLUSH to flush cached code.
+
+
+The following modes are defined:
+
+
+
luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE|flag)
+
+Turn the whole JIT compiler on or off or flush the whole cache of compiled code.
+
+This sets the mode for the function at the stack index idx or
+the parent of the calling function (idx = 0). It either
+enables JIT compilation for a function, disables it and flushes any
+already compiled code or only flushes already compiled code. This
+applies recursively to all sub-functions of the function with
+LUAJIT_MODE_ALLFUNC or only to the sub-functions with
+LUAJIT_MODE_ALLSUBFUNC.
+
+Flushes the specified root trace and all of its side traces from the cache.
+The code for the trace will be retained as long as there are any other
+traces which link to it.
+
+This mode defines a wrapper function for calls to C functions. If
+called with LUAJIT_MODE_ON, the stack index at idx
+must be a lightuserdata object holding a pointer to the wrapper
+function. From now on all C functions are called through the wrapper
+function. If called with LUAJIT_MODE_OFF this mode is turned
+off and all C functions are directly called.
+
+
+The wrapper function can be used for debugging purposes or to catch
+and convert foreign exceptions. But please read the section on
+C++ exception interoperability
+first. Recommended usage can be seen in this C++ code excerpt:
+
+
+#include <exception>
+#include "lua.hpp"
+
+// Catch C++ exceptions and convert them to Lua error messages.
+// Customize as needed for your own exception classes.
+static int wrap_exceptions(lua_State *L, lua_CFunction f)
+{
+ try {
+ return f(L); // Call wrapped function and return result.
+ } catch (const char *s) { // Catch and convert exceptions.
+ lua_pushstring(L, s);
+ } catch (std::exception& e) {
+ lua_pushstring(L, e.what());
+ } catch (...) {
+ lua_pushliteral(L, "caught (...)");
+ }
+ return lua_error(L); // Rethrow as a Lua error.
+}
+
+static int myinit(lua_State *L)
+{
+ ...
+ // Define wrapper function and enable it.
+ lua_pushlightuserdata(L, (void *)wrap_exceptions);
+ luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC|LUAJIT_MODE_ON);
+ lua_pop(L, 1);
+ ...
+}
+
+
+Note that you can only define a single global wrapper function,
+so be careful when using this mechanism from multiple C++ modules.
+Also note that this mechanism is not without overhead.
+
+
+The FFI library allows calling external C functions and
+using C data structures from pure Lua code.
+
+
+
+
+The FFI library largely obviates the need to write tedious manual
+Lua/C bindings in C. No need to learn a separate binding language
+— it parses plain C declarations! These can be
+cut-n-pasted from C header files or reference manuals. It's up to
+the task of binding large libraries without the need for dealing with
+fragile binding generators.
+
+
+
+The FFI library is tightly integrated into LuaJIT (it's not available
+as a separate module). The code generated by the JIT-compiler for
+accesses to C data structures from Lua code is on par with the
+code a C compiler would generate. Calls to C functions can
+be inlined in JIT-compiled code, unlike calls to functions bound via
+the classic Lua/C API.
+
+
+This page gives a short introduction to the usage of the FFI library.
+Please use the FFI sub-topics in the navigation bar to learn more.
+
+
+
Motivating Example: Calling External C Functions
+
+It's really easy to call an external C library function:
+
+② Add a C declaration
+for the function. The part inside the double-brackets (in green) is
+just standard C syntax.
+
+
+③ Call the named
+C function — Yes, it's that simple!
+
+
+Actually, what goes on behind the scenes is far from simple: ③ makes use of the standard
+C library namespace ffi.C. Indexing this namespace with
+a symbol name ("printf") automatically binds it to the
+standard C library. The result is a special kind of object which,
+when called, runs the printf function. The arguments passed
+to this function are automatically converted from Lua objects to the
+corresponding C types.
+
+
+Ok, so maybe the use of printf() wasn't such a spectacular
+example. You could have done that with io.write() and
+string.format(), too. But you get the idea ...
+
+
+So here's something to pop up a message box on Windows:
+
+Compare this with the effort required to bind that function using the
+classic Lua/C API: create an extra C file, add a C function
+that retrieves and checks the argument types passed from Lua and calls
+the actual C function, add a list of module functions and their
+names, add a luaopen_* function and register all module
+functions, compile and link it into a shared library (DLL), move it to
+the proper path, add Lua code that loads the module aaaand ... finally
+call the binding function. Phew!
+
+
+
Motivating Example: Using C Data Structures
+
+The FFI library allows you to create and access C data
+structures. Of course the main use for this is for interfacing with
+C functions. But they can be used stand-alone, too.
+
+
+Lua is built upon high-level data types. They are flexible, extensible
+and dynamic. That's why we all love Lua so much. Alas, this can be
+inefficient for certain tasks, where you'd really want a low-level
+data type. E.g. a large array of a fixed structure needs to be
+implemented with a big table holding lots of tiny tables. This imposes
+both a substantial memory overhead as well as a performance overhead.
+
+
+Here's a sketch of a library that operates on color images plus a
+simple benchmark. First, the plain Lua version:
+
+
+local floor = math.floor
+
+local function image_ramp_green(n)
+ local img = {}
+ local f = 255/(n-1)
+ for i=1,n do
+ img[i] = { red = 0, green = floor((i-1)*f), blue = 0, alpha = 255 }
+ end
+ return img
+end
+
+local function image_to_grey(img, n)
+ for i=1,n do
+ local y = floor(0.3*img[i].red + 0.59*img[i].green + 0.11*img[i].blue)
+ img[i].red = y; img[i].green = y; img[i].blue = y
+ end
+end
+
+local N = 400*400
+local img = image_ramp_green(N)
+for i=1,1000 do
+ image_to_grey(img, N)
+end
+
+
+This creates a table with 160.000 pixels, each of which is a table
+holding four number values in the range of 0-255. First an image with
+a green ramp is created (1D for simplicity), then the image is
+converted to greyscale 1000 times. Yes, that's silly, but I was in
+need of a simple example ...
+
+
+And here's the FFI version. The modified parts have been marked in
+bold:
+
+
+①
+
+
+
+
+
+②
+
+③
+④
+
+
+
+
+
+
+③
+⑤local ffi = require("ffi")
+ffi.cdef[[
+typedef struct { uint8_t red, green, blue, alpha; } rgba_pixel;
+]]
+
+local function image_ramp_green(n)
+ local img = ffi.new("rgba_pixel[?]", n)
+ local f = 255/(n-1)
+ for i=0,n-1 do
+ img[i].green = i*f
+ img[i].alpha = 255
+ end
+ return img
+end
+
+local function image_to_grey(img, n)
+ for i=0,n-1 do
+ local y = 0.3*img[i].red + 0.59*img[i].green + 0.11*img[i].blue
+ img[i].red = y; img[i].green = y; img[i].blue = y
+ end
+end
+
+local N = 400*400
+local img = image_ramp_green(N)
+for i=1,1000 do
+ image_to_grey(img, N)
+end
+
+
+Ok, so that wasn't too difficult:
+
+
+① First, load the FFI
+library and declare the low-level data type. Here we choose a
+struct which holds four byte fields, one for each component
+of a 4x8 bit RGBA pixel.
+
+
+② Creating the data
+structure with ffi.new() is straightforward — the
+'?' is a placeholder for the number of elements of a
+variable-length array.
+
+
+③ C arrays are
+zero-based, so the indexes have to run from 0 to
+n-1. One might want to allocate one more element instead to
+simplify converting legacy code.
+
+
+④ Since ffi.new()
+zero-fills the array by default, we only need to set the green and the
+alpha fields.
+
+
+⑤ The calls to
+math.floor() can be omitted here, because floating-point
+numbers are already truncated towards zero when converting them to an
+integer. This happens implicitly when the number is stored in the
+fields of each pixel.
+
+
+Now let's have a look at the impact of the changes: first, memory
+consumption for the image is down from 22 Megabytes to
+640 Kilobytes (400*400*4 bytes). That's a factor of 35x less! So,
+yes, tables do have a noticeable overhead. BTW: The original program
+would consume 40 Megabytes in plain Lua (on x64).
+
+
+Next, performance: the pure Lua version runs in 9.57 seconds (52.9
+seconds with the Lua interpreter) and the FFI version runs in 0.48
+seconds on my machine (YMMV). That's a factor of 20x faster (110x
+faster than the Lua interpreter).
+
+
+The avid reader may notice that converting the pure Lua version over
+to use array indexes for the colors ([1] instead of
+.red, [2] instead of .green etc.) ought to
+be more compact and faster. This is certainly true (by a factor of
+~1.7x). Switching to a struct-of-arrays would help, too.
+
+
+However the resulting code would be less idiomatic and rather
+error-prone. And it still doesn't get even close to the performance of
+the FFI version of the code. Also, high-level data structures cannot
+be easily passed to other C functions, especially I/O functions,
+without undue conversion penalties.
+
+This page describes the API functions provided by the FFI library in
+detail. It's recommended to read through the
+introduction and the
+FFI tutorial first.
+
+
+
Glossary
+
+
cdecl — An abstract C type declaration (a Lua
+string).
+
ctype — A C type object. This is a special kind of
+cdata returned by ffi.typeof(). It serves as a
+cdataconstructor when called.
+
cdata — A C data object. It holds a value of the
+corresponding ctype.
+
ct — A C type specification which can be used for
+most of the API functions. Either a cdecl, a ctype or a
+cdata serving as a template type.
+
cb — A callback object. This is a C data object
+holding a special function pointer. Calling this function from
+C code runs an associated Lua function.
+
VLA — A variable-length array is declared with a
+? instead of the number of elements, e.g. "int[?]".
+The number of elements (nelem) must be given when it's
+created.
+
VLS — A variable-length struct is a struct C
+type where the last element is a VLA. The same rules for
+declaration and creation apply.
+
+
+
Declaring and Accessing External Symbols
+
+External symbols must be declared first and can then be accessed by
+indexing a C library
+namespace, which automatically binds the symbol to a specific
+library.
+
+
+
ffi.cdef(def)
+
+Adds multiple C declarations for types or external symbols (named
+variables or functions). def must be a Lua string. It's
+recommended to use the syntactic sugar for string arguments as
+follows:
+
+
+ffi.cdef[[
+typedef struct foo { int a, b; } foo_t; // Declare a struct and typedef.
+int dofoo(foo_t *f, int n); /* Declare an external C function. */
+]]
+
+
+The contents of the string (the part in green above) must be a
+sequence of
+C declarations,
+separated by semicolons. The trailing semicolon for a single
+declaration may be omitted.
+
+
+Please note that external symbols are only declared, but they
+are not bound to any specific address, yet. Binding is
+achieved with C library namespaces (see below).
+
+
+C declarations are not passed through a C pre-processor,
+yet. No pre-processor tokens are allowed, except for
+#pragma pack. Replace #define in existing
+C header files with enum, static const
+or typedef and/or pass the files through an external
+C pre-processor (once). Be careful not to include unneeded or
+redundant declarations from unrelated header files.
+
+
+
ffi.C
+
+This is the default C library namespace — note the
+uppercase 'C'. It binds to the default set of symbols or
+libraries on the target system. These are more or less the same as a
+C compiler would offer by default, without specifying extra link
+libraries.
+
+
+On POSIX systems, this binds to symbols in the default or global
+namespace. This includes all exported symbols from the executable and
+any libraries loaded into the global namespace. This includes at least
+libc, libm, libdl (on Linux),
+libgcc (if compiled with GCC), as well as any exported
+symbols from the Lua/C API provided by LuaJIT itself.
+
+
+On Windows systems, this binds to symbols exported from the
+*.exe, the lua51.dll (i.e. the Lua/C API
+provided by LuaJIT itself), the C runtime library LuaJIT was linked
+with (msvcrt*.dll), kernel32.dll,
+user32.dll and gdi32.dll.
+
+
+
clib = ffi.load(name [,global])
+
+This loads the dynamic library given by name and returns
+a new C library namespace which binds to its symbols. On POSIX
+systems, if global is true, the library symbols are
+loaded into the global namespace, too.
+
+
+If name is a path, the library is loaded from this path.
+Otherwise name is canonicalized in a system-dependent way and
+searched in the default search path for dynamic libraries:
+
+
+On POSIX systems, if the name contains no dot, the extension
+.so is appended. Also, the lib prefix is prepended
+if necessary. So ffi.load("z") looks for "libz.so"
+in the default shared library search path.
+
+
+On Windows systems, if the name contains no dot, the extension
+.dll is appended. So ffi.load("ws2_32") looks for
+"ws2_32.dll" in the default DLL search path.
+
+
+
Creating cdata Objects
+
+The following API functions create cdata objects (type()
+returns "cdata"). All created cdata objects are
+garbage collected.
+
+Creates a cdata object for the given ct. VLA/VLS types
+require the nelem argument. The second syntax uses a ctype as
+a constructor and is otherwise fully equivalent.
+
+
+The cdata object is initialized according to the
+rules for initializers,
+using the optional init arguments. Excess initializers cause
+an error.
+
+
+Performance notice: if you want to create many objects of one kind,
+parse the cdecl only once and get its ctype with
+ffi.typeof(). Then use the ctype as a constructor repeatedly.
+
+
+Please note that an anonymous struct declaration implicitly
+creates a new and distinguished ctype every time you use it for
+ffi.new(). This is probably not what you want,
+especially if you create more than one cdata object. Different anonymous
+structs are not considered assignment-compatible by the
+C standard, even though they may have the same fields! Also, they
+are considered different types by the JIT-compiler, which may cause an
+excessive number of traces. It's strongly suggested to either declare
+a named struct or typedef with ffi.cdef()
+or to create a single ctype object for an anonymous struct
+with ffi.typeof().
+
+
+
ctype = ffi.typeof(ct)
+
+Creates a ctype object for the given ct.
+
+
+This function is especially useful to parse a cdecl only once and then
+use the resulting ctype object as a constructor.
+
+
+
cdata = ffi.cast(ct, init)
+
+Creates a scalar cdata object for the given ct. The cdata
+object is initialized with init using the "cast" variant of
+the C type conversion
+rules.
+
+
+This functions is mainly useful to override the pointer compatibility
+checks or to convert pointers to addresses or vice versa.
+
+
+
ctype = ffi.metatype(ct, metatable)
+
+Creates a ctype object for the given ct and associates it with
+a metatable. Only struct/union types, complex numbers
+and vectors are allowed. Other types may be wrapped in a
+struct, if needed.
+
+
+The association with a metatable is permanent and cannot be changed
+afterwards. Neither the contents of the metatable nor the
+contents of an __index table (if any) may be modified
+afterwards. The associated metatable automatically applies to all uses
+of this type, no matter how the objects are created or where they
+originate from. Note that pre-defined operations on types have
+precedence (e.g. declared field names cannot be overriden).
+
+
+All standard Lua metamethods are implemented. These are called directly,
+without shortcuts and on any mix of types. For binary operations, the
+left operand is checked first for a valid ctype metamethod. The
+__gc metamethod only applies to struct/union
+types and performs an implicit ffi.gc()
+call during creation of an instance.
+
+
+
cdata = ffi.gc(cdata, finalizer)
+
+Associates a finalizer with a pointer or aggregate cdata object. The
+cdata object is returned unchanged.
+
+
+This function allows safe integration of unmanaged resources into the
+automatic memory management of the LuaJIT garbage collector. Typical
+usage:
+
+
+local p = ffi.gc(ffi.C.malloc(n), ffi.C.free)
+...
+p = nil -- Last reference to p is gone.
+-- GC will eventually run finalizer: ffi.C.free(p)
+
+
+A cdata finalizer works like the __gc metamethod for userdata
+objects: when the last reference to a cdata object is gone, the
+associated finalizer is called with the cdata object as an argument. The
+finalizer can be a Lua function or a cdata function or cdata function
+pointer. An existing finalizer can be removed by setting a nil
+finalizer, e.g. right before explicitly deleting a resource:
+
+
+ffi.C.free(ffi.gc(p, nil)) -- Manually free the memory.
+
+
+
C Type Information
+
+The following API functions return information about C types.
+They are most useful for inspecting cdata objects.
+
+
+
size = ffi.sizeof(ct [,nelem])
+
+Returns the size of ct in bytes. Returns nil if
+the size is not known (e.g. for "void" or function types).
+Requires nelem for VLA/VLS types, except for cdata objects.
+
+
+
align = ffi.alignof(ct)
+
+Returns the minimum required alignment for ct in bytes.
+
+
+
ofs [,bpos,bsize] = ffi.offsetof(ct, field)
+
+Returns the offset (in bytes) of field relative to the start
+of ct, which must be a struct. Additionally returns
+the position and the field size (in bits) for bit fields.
+
+
+
status = ffi.istype(ct, obj)
+
+Returns true if obj has the C type given by
+ct. Returns false otherwise.
+
+
+C type qualifiers (const etc.) are ignored. Pointers are
+checked with the standard pointer compatibility rules, but without any
+special treatment for void *. If ct specifies a
+struct/union, then a pointer to this type is accepted,
+too. Otherwise the types must match exactly.
+
+
+Note: this function accepts all kinds of Lua objects for the
+obj argument, but always returns false for non-cdata
+objects.
+
+
+
Utility Functions
+
+
err = ffi.errno([newerr])
+
+Returns the error number set by the last C function call which
+indicated an error condition. If the optional newerr argument
+is present, the error number is set to the new value and the previous
+value is returned.
+
+
+This function offers a portable and OS-independent way to get and set the
+error number. Note that only some C functions set the error
+number. And it's only significant if the function actually indicated an
+error condition (e.g. with a return value of -1 or
+NULL). Otherwise, it may or may not contain any previously set
+value.
+
+
+You're advised to call this function only when needed and as close as
+possible after the return of the related C function. The
+errno value is preserved across hooks, memory allocations,
+invocations of the JIT compiler and other internal VM activity. The same
+applies to the value returned by GetLastError() on Windows, but
+you need to declare and call it yourself.
+
+
+
str = ffi.string(ptr [,len])
+
+Creates an interned Lua string from the data pointed to by
+ptr.
+
+
+If the optional argument len is missing, ptr is
+converted to a "char *" and the data is assumed to be
+zero-terminated. The length of the string is computed with
+strlen().
+
+
+Otherwise ptr is converted to a "void *" and
+len gives the length of the data. The data may contain
+embedded zeros and need not be byte-oriented (though this may cause
+endianess issues).
+
+
+This function is mainly useful to convert (temporary)
+"const char *" pointers returned by
+C functions to Lua strings and store them or pass them to other
+functions expecting a Lua string. The Lua string is an (interned) copy
+of the data and bears no relation to the original data area anymore.
+Lua strings are 8 bit clean and may be used to hold arbitrary,
+non-character data.
+
+
+Performance notice: it's faster to pass the length of the string, if
+it's known. E.g. when the length is returned by a C call like
+sprintf().
+
+
+
ffi.copy(dst, src, len)
+ffi.copy(dst, str)
+
+Copies the data pointed to by src to dst.
+dst is converted to a "void *" and src
+is converted to a "const void *".
+
+
+In the first syntax, len gives the number of bytes to copy.
+Caveat: if src is a Lua string, then len must not
+exceed #src+1.
+
+
+In the second syntax, the source of the copy must be a Lua string. All
+bytes of the string plus a zero-terminator are copied to
+dst (i.e. #src+1 bytes).
+
+
+Performance notice: ffi.copy() may be used as a faster
+(inlinable) replacement for the C library functions
+memcpy(), strcpy() and strncpy().
+
+
+
ffi.fill(dst, len [,c])
+
+Fills the data pointed to by dst with len constant
+bytes, given by c. If c is omitted, the data is
+zero-filled.
+
+
+Performance notice: ffi.fill() may be used as a faster
+(inlinable) replacement for the C library function
+memset(dst, c, len). Please note the different
+order of arguments!
+
+
+
Target-specific Information
+
+
status = ffi.abi(param)
+
+Returns true if param (a Lua string) applies for the
+target ABI (Application Binary Interface). Returns false
+otherwise. The following parameters are currently defined:
+
+
+
+
Parameter
+
Description
+
+
+
32bit
32 bit architecture
+
+
64bit
64 bit architecture
+
+
le
Little-endian architecture
+
+
be
Big-endian architecture
+
+
fpu
Target has a hardware FPU
+
+
softfp
softfp calling conventions
+
+
hardfp
hardfp calling conventions
+
+
eabi
EABI variant of the standard ABI
+
+
win
Windows variant of the standard ABI
+
+
gc64
64 bit GC references
+
+
+
ffi.os
+
+Contains the target OS name. Same contents as
+jit.os.
+
+
+
ffi.arch
+
+Contains the target architecture name. Same contents as
+jit.arch.
+
+
+
Methods for Callbacks
+
+The C types for callbacks
+have some extra methods:
+
+
+
cb:free()
+
+Free the resources associated with a callback. The associated Lua
+function is unanchored and may be garbage collected. The callback
+function pointer is no longer valid and must not be called anymore
+(it may be reused by a subsequently created callback).
+
+
+
cb:set(func)
+
+Associate a new Lua function with a callback. The C type of the
+callback and the callback function pointer are unchanged.
+
+
+This method is useful to dynamically switch the receiver of callbacks
+without creating a new callback each time and registering it again (e.g.
+with a GUI library).
+
+
+
Extended Standard Library Functions
+
+The following standard library functions have been extended to work
+with cdata objects:
+
+
+
n = tonumber(cdata)
+
+Converts a number cdata object to a double and returns it as
+a Lua number. This is particularly useful for boxed 64 bit
+integer values. Caveat: this conversion may incur a precision loss.
+
+
+
s = tostring(cdata)
+
+Returns a string representation of the value of 64 bit integers
+("nnnLL" or "nnnULL") or
+complex numbers ("re±imi"). Otherwise
+returns a string representation of the C type of a ctype object
+("ctype<type>") or a cdata object
+("cdata<type>: address"), unless you
+override it with a __tostring metamethod (see
+ffi.metatype()).
+
+Calls the __pairs or __ipairs metamethod of the
+corresponding ctype.
+
+
+
Extensions to the Lua Parser
+
+The parser for Lua source code treats numeric literals with the
+suffixes LL or ULL as signed or unsigned 64 bit
+integers. Case doesn't matter, but uppercase is recommended for
+readability. It handles decimal (42LL), hexadecimal
+(0x2aLL) and binary (0b101010LL) literals.
+
+
+The imaginary part of complex numbers can be specified by suffixing
+number literals with i or I, e.g. 12.5i.
+Caveat: you'll need to use 1i to get an imaginary part with
+the value one, since i itself still refers to a variable
+named i.
+
+This page describes the detailed semantics underlying the FFI library
+and its interaction with both Lua and C code.
+
+
+Given that the FFI library is designed to interface with C code
+and that declarations can be written in plain C syntax, it
+closely follows the C language semantics, wherever possible.
+Some minor concessions are needed for smoother interoperation with Lua
+language semantics.
+
+
+Please don't be overwhelmed by the contents of this page — this
+is a reference and you may need to consult it, if in doubt. It doesn't
+hurt to skim this page, but most of the semantics "just work" as you'd
+expect them to work. It should be straightforward to write
+applications using the LuaJIT FFI for developers with a C or C++
+background.
+
+
+
C Language Support
+
+The FFI library has a built-in C parser with a minimal memory
+footprint. It's used by the ffi.* library
+functions to declare C types or external symbols.
+
+
+It's only purpose is to parse C declarations, as found e.g. in
+C header files. Although it does evaluate constant expressions,
+it's not a C compiler. The body of inline
+C function definitions is simply ignored.
+
+
+Also, this is not a validating C parser. It expects and
+accepts correctly formed C declarations, but it may choose to
+ignore bad declarations or show rather generic error messages. If in
+doubt, please check the input against your favorite C compiler.
+
+
+The C parser complies to the C99 language standard plus
+the following extensions:
+
+
+
+
The '\e' escape in character and string literals.
+
+
The C99/C++ boolean type, declared with the keywords bool
+or _Bool.
+
+
Complex numbers, declared with the keywords complex or
+_Complex.
+
+
Two complex number types: complex (aka
+complex double) and complex float.
+
+
Vector types, declared with the GCC mode or
+vector_size attribute.
+
+
Unnamed ('transparent') struct/union fields
+inside a struct/union.
+
+
Incomplete enum declarations, handled like incomplete
+struct declarations.
+
+
Unnamed enum fields inside a
+struct/union. This is similar to a scoped C++
+enum, except that declared constants are visible in the
+global namespace, too.
+
+
Scoped static const declarations inside a
+struct/union (from C++).
+
+
Zero-length arrays ([0]), empty
+struct/union, variable-length arrays (VLA,
+[?]) and variable-length structs (VLS, with a trailing
+VLA).
+
+
C++ reference types (int &x).
+
+
Alternate GCC keywords with '__', e.g.
+__const__.
+
+
GCC __attribute__ with the following attributes:
+aligned, packed, mode,
+vector_size, cdecl, fastcall,
+stdcall, thiscall.
+
+
The GCC __extension__ keyword and the GCC
+__alignof__ operator.
+
+
GCC __asm__("symname") symbol name redirection for
+function declarations.
+
+
MSVC keywords for fixed-length types: __int8,
+__int16, __int32 and __int64.
+You're encouraged to use these types in preference to
+compiler-specific extensions or target-dependent standard types.
+E.g. char differs in signedness and long differs in
+size, depending on the target architecture and platform ABI.
+
+
+The following C features are not supported:
+
+
+
+
A declaration must always have a type specifier; it doesn't
+default to an int type.
+
+
Old-style empty function declarations (K&R) are not allowed.
+All C functions must have a proper prototype declaration. A
+function declared without parameters (int foo();) is
+treated as a function taking zero arguments, like in C++.
+
+
The long double C type is parsed correctly, but
+there's no support for the related conversions, accesses or arithmetic
+operations.
+
+
Wide character strings and character literals are not
+supported.
+
+
See below for features that are currently
+not implemented.
+
+
+
+
C Type Conversion Rules
+
+
Conversions from C types to Lua objects
+
+These conversion rules apply for read accesses to
+C types: indexing pointers, arrays or
+struct/union types; reading external variables or
+constant values; retrieving return values from C calls:
+
+
+
+
Input
+
Conversion
+
Output
+
+
+
int8_t, int16_t
→sign-extint32_t → double
number
+
+
uint8_t, uint16_t
→zero-extint32_t → double
number
+
+
int32_t, uint32_t
→ double
number
+
+
int64_t, uint64_t
boxed value
64 bit int cdata
+
+
double, float
→ double
number
+
+
bool
0 → false, otherwise true
boolean
+
+
enum
boxed value
enum cdata
+
+
Complex number
boxed value
complex cdata
+
+
Vector
boxed value
vector cdata
+
+
Pointer
boxed value
pointer cdata
+
+
Array
boxed reference
reference cdata
+
+
struct/union
boxed reference
reference cdata
+
+
+Bitfields are treated like their underlying type.
+
+
+Reference types are dereferenced before a conversion can take
+place — the conversion is applied to the C type pointed to
+by the reference.
+
+
+
Conversions from Lua objects to C types
+
+These conversion rules apply for write accesses to
+C types: indexing pointers, arrays or
+struct/union types; initializing cdata objects;
+casts to C types; writing to external variables; passing
+arguments to C calls:
+
+If the result type of this conversion doesn't match the
+C type of the destination, the
+conversion rules between C types
+are applied.
+
+
+Reference types are immutable after initialization ("no re-seating of
+references"). For initialization purposes or when passing values to
+reference parameters, they are treated like pointers. Note that unlike
+in C++, there's no way to implement automatic reference generation of
+variables under the Lua language semantics. If you want to call a
+function with a reference parameter, you need to explicitly pass a
+one-element array.
+
+
+
Conversions between C types
+
+These conversion rules are more or less the same as the standard
+C conversion rules. Some rules only apply to casts, or require
+pointer or type compatibility:
+
+
+
+
Input
+
Conversion
+
Output
+
+
+
Signed integer
→narrow or sign-extend
Integer
+
+
Unsigned integer
→narrow or zero-extend
Integer
+
+
Integer
→round
double, float
+
+
double, float
→truncint32_t →narrow
(u)int8_t, (u)int16_t
+
+
double, float
→trunc
(u)int32_t, (u)int64_t
+
+
double, float
→round
float, double
+
+
Number
n == 0 → 0, otherwise 1
bool
+
+
bool
false → 0, true → 1
Number
+
+
Complex number
convert real part
Number
+
+
Number
convert real part, imag = 0
Complex number
+
+
Complex number
convert real and imag part
Complex number
+
+
Number
convert scalar and replicate
Vector
+
+
Vector
copy (same size)
Vector
+
+
struct/union
take base address (compat)
Pointer
+
+
Array
take base address (compat)
Pointer
+
+
Function
take function address
Function pointer
+
+
Number
convert via uintptr_t (cast)
Pointer
+
+
Pointer
convert address (compat/cast)
Pointer
+
+
Pointer
convert address (cast)
Integer
+
+
Array
convert base address (cast)
Integer
+
+
Array
copy (compat)
Array
+
+
struct/union
copy (identical type)
struct/union
+
+
+Bitfields or enum types are treated like their underlying
+type.
+
+
+Conversions not listed above will raise an error. E.g. it's not
+possible to convert a pointer to a complex number or vice versa.
+
+
+
Conversions for vararg C function arguments
+
+The following default conversion rules apply when passing Lua objects
+to the variable argument part of vararg C functions:
+
+
+
+
Input
+
Conversion
+
Output
+
+
+
number
→
double
+
+
boolean
false → 0, true → 1
bool
+
+
nil
NULL →
(void *)
+
+
userdata
userdata payload →
(void *)
+
+
lightuserdata
lightuserdata address →
(void *)
+
+
string
string data →
const char *
+
+
float cdata
→
double
+
+
Array cdata
take base address
Element pointer
+
+
struct/union cdata
take base address
struct/union pointer
+
+
Function cdata
take function address
Function pointer
+
+
Any other cdata
no conversion
C type
+
+
+To pass a Lua object, other than a cdata object, as a specific type,
+you need to override the conversion rules: create a temporary cdata
+object with a constructor or a cast and initialize it with the value
+to pass:
+
+
+Assuming x is a Lua number, here's how to pass it as an
+integer to a vararg function:
+
+If you don't do this, the default Lua number → double
+conversion rule applies. A vararg C function expecting an integer
+will see a garbled or uninitialized value.
+
+
+
Initializers
+
+Creating a cdata object with
+ffi.new() or the
+equivalent constructor syntax always initializes its contents, too.
+Different rules apply, depending on the number of optional
+initializers and the C types involved:
+
+
+
If no initializers are given, the object is filled with zero bytes.
Valarrays (complex numbers and vectors) are treated like scalars
+when a single initializer is given. Otherwise they are treated like
+regular arrays.
+
+
Aggregate types (arrays and structs) accept either a single cdata
+initializer of the same type (copy constructor), a single
+table initializer, or a flat list of
+initializers.
+
+
The elements of an array are initialized, starting at index zero.
+If a single initializer is given for an array, it's repeated for all
+remaining elements. This doesn't happen if two or more initializers
+are given: all remaining uninitialized elements are filled with zero
+bytes.
+
+
Byte arrays may also be initialized with a Lua string. This copies
+the whole string plus a terminating zero-byte. The copy stops early only
+if the array has a known, fixed size.
+
+
The fields of a struct are initialized in the order of
+their declaration. Uninitialized fields are filled with zero
+bytes.
+
+
Only the first field of a union can be initialized with a
+flat initializer.
+
+
Elements or fields which are aggregates themselves are initialized
+with a single initializer, but this may be a table
+initializer or a compatible aggregate.
+
+
Excess initializers cause an error.
+
+
+
+
Table Initializers
+
+The following rules apply if a Lua table is used to initialize an
+Array or a struct/union:
+
+
+
+
If the table index [0] is non-nil, then the
+table is assumed to be zero-based. Otherwise it's assumed to be
+one-based.
+
+
Array elements, starting at index zero, are initialized one-by-one
+with the consecutive table elements, starting at either index
+[0] or [1]. This process stops at the first
+nil table element.
+
+
If exactly one array element was initialized, it's repeated for
+all the remaining elements. Otherwise all remaining uninitialized
+elements are filled with zero bytes.
+
+
The above logic only applies to arrays with a known fixed size.
+A VLA is only initialized with the element(s) given in the table.
+Depending on the use case, you may need to explicitly add a
+NULL or 0 terminator to a VLA.
+
+
A struct/union can be initialized in the
+order of the declaration of its fields. Each field is initialized with
+consecutive table elements, starting at either index [0]
+or [1]. This process stops at the first nil table
+element.
+
+
Otherwise, if neither index [0] nor [1] is present,
+a struct/union is initialized by looking up each field
+name (as a string key) in the table. Each non-nil value is
+used to initialize the corresponding field.
+
+
Uninitialized fields of a struct are filled with zero
+bytes, except for the trailing VLA of a VLS.
+
+
Initialization of a union stops after one field has been
+initialized. If no field has been initialized, the union is
+filled with zero bytes.
+
+
Elements or fields which are aggregates themselves are initialized
+with a single initializer, but this may be a nested table
+initializer (or a compatible aggregate).
+
+
Excess initializers for an array cause an error. Excess
+initializers for a struct/union are ignored.
+Unrelated table entries are ignored, too.
+
+
+
+Example:
+
+
+local ffi = require("ffi")
+
+ffi.cdef[[
+struct foo { int a, b; };
+union bar { int i; double d; };
+struct nested { int x; struct foo y; };
+]]
+
+ffi.new("int[3]", {}) --> 0, 0, 0
+ffi.new("int[3]", {1}) --> 1, 1, 1
+ffi.new("int[3]", {1,2}) --> 1, 2, 0
+ffi.new("int[3]", {1,2,3}) --> 1, 2, 3
+ffi.new("int[3]", {[0]=1}) --> 1, 1, 1
+ffi.new("int[3]", {[0]=1,2}) --> 1, 2, 0
+ffi.new("int[3]", {[0]=1,2,3}) --> 1, 2, 3
+ffi.new("int[3]", {[0]=1,2,3,4}) --> error: too many initializers
+
+ffi.new("struct foo", {}) --> a = 0, b = 0
+ffi.new("struct foo", {1}) --> a = 1, b = 0
+ffi.new("struct foo", {1,2}) --> a = 1, b = 2
+ffi.new("struct foo", {[0]=1,2}) --> a = 1, b = 2
+ffi.new("struct foo", {b=2}) --> a = 0, b = 2
+ffi.new("struct foo", {a=1,b=2,c=3}) --> a = 1, b = 2 'c' is ignored
+
+ffi.new("union bar", {}) --> i = 0, d = 0.0
+ffi.new("union bar", {1}) --> i = 1, d = ?
+ffi.new("union bar", {[0]=1,2}) --> i = 1, d = ? '2' is ignored
+ffi.new("union bar", {d=2}) --> i = ?, d = 2.0
+
+ffi.new("struct nested", {1,{2,3}}) --> x = 1, y.a = 2, y.b = 3
+ffi.new("struct nested", {x=1,y={2,3}}) --> x = 1, y.a = 2, y.b = 3
+
+
+
Operations on cdata Objects
+
+All of the standard Lua operators can be applied to cdata objects or a
+mix of a cdata object and another Lua object. The following list shows
+the pre-defined operations.
+
+
+Reference types are dereferenced before performing each of
+the operations below — the operation is applied to the
+C type pointed to by the reference.
+
+
+The pre-defined operations are always tried first before deferring to a
+metamethod or index table (if any) for the corresponding ctype (except
+for __new). An error is raised if the metamethod lookup or
+index table lookup fails.
+
+
+
Indexing a cdata object
+
+
+
Indexing a pointer/array: a cdata pointer/array can be
+indexed by a cdata number or a Lua number. The element address is
+computed as the base address plus the number value multiplied by the
+element size in bytes. A read access loads the element value and
+converts it to a Lua object. A write
+access converts a Lua object to the element
+type and stores the converted value to the element. An error is
+raised if the element size is undefined or a write access to a
+constant element is attempted.
+
+
Dereferencing a struct/union field: a
+cdata struct/union or a pointer to a
+struct/union can be dereferenced by a string key,
+giving the field name. The field address is computed as the base
+address plus the relative offset of the field. A read access loads the
+field value and converts it to a Lua
+object. A write access converts a Lua
+object to the field type and stores the converted value to the
+field. An error is raised if a write access to a constant
+struct/union or a constant field is attempted.
+Scoped enum constants or static constants are treated like a constant
+field.
+
+
Indexing a complex number: a complex number can be indexed
+either by a cdata number or a Lua number with the values 0 or 1, or by
+the strings "re" or "im". A read access loads the
+real part ([0], .re) or the imaginary part
+([1], .im) part of a complex number and
+converts it to a Lua number. The
+sub-parts of a complex number are immutable — assigning to an
+index of a complex number raises an error. Accessing out-of-bound
+indexes returns unspecified results, but is guaranteed not to trigger
+memory access violations.
+
+
Indexing a vector: a vector is treated like an array for
+indexing purposes, except the vector elements are immutable —
+assigning to an index of a vector raises an error.
+
+
+
+A ctype object can be indexed with a string key, too. The only
+pre-defined operation is reading scoped constants of
+struct/union types. All other accesses defer
+to the corresponding metamethods or index tables (if any).
+
+
+Note: since there's (deliberately) no address-of operator, a cdata
+object holding a value type is effectively immutable after
+initialization. The JIT compiler benefits from this fact when applying
+certain optimizations.
+
+
+As a consequence, the elements of complex numbers and
+vectors are immutable. But the elements of an aggregate holding these
+types may be modified of course. I.e. you cannot assign to
+foo.c.im, but you can assign a (newly created) complex number
+to foo.c.
+
+
+The JIT compiler implements strict aliasing rules: accesses to different
+types do not alias, except for differences in signedness (this
+applies even to char pointers, unlike C99). Type punning
+through unions is explicitly detected and allowed.
+
+
+
Calling a cdata object
+
+
+
Constructor: a ctype object can be called and used as a
+constructor. This is equivalent
+to ffi.new(ct, ...), unless a __new metamethod is
+defined. The __new metamethod is called with the ctype object
+plus any other arguments passed to the contructor. Note that you have to
+use ffi.new inside of it, since calling ct(...) would
+cause infinite recursion.
+
+
C function call: a cdata function or cdata function
+pointer can be called. The passed arguments are
+converted to the C types of the
+parameters given by the function declaration. Arguments passed to the
+variable argument part of vararg C function use
+special conversion rules. This
+C function is called and the return value (if any) is
+converted to a Lua object.
+On Windows/x86 systems, __stdcall functions are automatically
+detected and a function declared as __cdecl (the default) is
+silently fixed up after the first call.
+
+
+
+
Arithmetic on cdata objects
+
+
+
Pointer arithmetic: a cdata pointer/array and a cdata
+number or a Lua number can be added or subtracted. The number must be
+on the right hand side for a subtraction. The result is a pointer of
+the same type with an address plus or minus the number value
+multiplied by the element size in bytes. An error is raised if the
+element size is undefined.
+
+
Pointer difference: two compatible cdata pointers/arrays
+can be subtracted. The result is the difference between their
+addresses, divided by the element size in bytes. An error is raised if
+the element size is undefined or zero.
+
+
64 bit integer arithmetic: the standard arithmetic
+operators (+ - * / % ^ and unary
+minus) can be applied to two cdata numbers, or a cdata number and a
+Lua number. If one of them is an uint64_t, the other side is
+converted to an uint64_t and an unsigned arithmetic operation
+is performed. Otherwise both sides are converted to an
+int64_t and a signed arithmetic operation is performed. The
+result is a boxed 64 bit cdata object.
+
+If one of the operands is an enum and the other operand is a
+string, the string is converted to the value of a matching enum
+constant before the above conversion.
+
+These rules ensure that 64 bit integers are "sticky". Any
+expression involving at least one 64 bit integer operand results
+in another one. The undefined cases for the division, modulo and power
+operators return 2LL ^ 63 or
+2ULL ^ 63.
+
+You'll have to explicitly convert a 64 bit integer to a Lua
+number (e.g. for regular floating-point calculations) with
+tonumber(). But note this may incur a precision loss.
+
+
64 bit bitwise operations: the rules for 64 bit
+arithmetic operators apply analogously.
+
+Unlike the other bit.* operations, bit.tobit()
+converts a cdata number via int64_t to int32_t and
+returns a Lua number.
+
+For bit.band(), bit.bor() and bit.bxor(), the
+conversion to int64_t or uint64_t applies to
+all arguments, if any argument is a cdata number.
+
+For all other operations, only the first argument is used to determine
+the output type. This implies that a cdata number as a shift count for
+shifts and rotates is accepted, but that alone does not cause
+a cdata number output.
+
+
+
+
Comparisons of cdata objects
+
+
+
Pointer comparison: two compatible cdata pointers/arrays
+can be compared. The result is the same as an unsigned comparison of
+their addresses. nil is treated like a NULL pointer,
+which is compatible with any other pointer type.
+
+
64 bit integer comparison: two cdata numbers, or a
+cdata number and a Lua number can be compared with each other. If one
+of them is an uint64_t, the other side is converted to an
+uint64_t and an unsigned comparison is performed. Otherwise
+both sides are converted to an int64_t and a signed
+comparison is performed.
+
+If one of the operands is an enum and the other operand is a
+string, the string is converted to the value of a matching enum
+constant before the above conversion.
+
+
Comparisons for equality/inequality never raise an error.
+Even incompatible pointers can be compared for equality by address. Any
+other incompatible comparison (also with non-cdata objects) treats the
+two sides as unequal.
+
+
+
+
cdata objects as table keys
+
+Lua tables may be indexed by cdata objects, but this doesn't provide
+any useful semantics — cdata objects are unsuitable as table
+keys!
+
+
+A cdata object is treated like any other garbage-collected object and
+is hashed and compared by its address for table indexing. Since
+there's no interning for cdata value types, the same value may be
+boxed in different cdata objects with different addresses. Thus
+t[1LL+1LL] and t[2LL] usually do not point to
+the same hash slot and they certainly do not point to the same
+hash slot as t[2].
+
+
+It would seriously drive up implementation complexity and slow down
+the common case, if one were to add extra handling for by-value
+hashing and comparisons to Lua tables. Given the ubiquity of their use
+inside the VM, this is not acceptable.
+
+
+There are three viable alternatives, if you really need to use cdata
+objects as keys:
+
+
+
+
If you can get by with the precision of Lua numbers
+(52 bits), then use tonumber() on a cdata number or
+combine multiple fields of a cdata aggregate to a Lua number. Then use
+the resulting Lua number as a key when indexing tables.
+One obvious benefit: t[tonumber(2LL)]does point to
+the same slot as t[2].
+
+
Otherwise use either tostring() on 64 bit integers
+or complex numbers or combine multiple fields of a cdata aggregate to
+a Lua string (e.g. with
+ffi.string()). Then
+use the resulting Lua string as a key when indexing tables.
+
+
Create your own specialized hash table implementation using the
+C types provided by the FFI library, just like you would in
+C code. Ultimately this may give much better performance than the
+other alternatives or what a generic by-value hash table could
+possibly provide.
+
+
+
+
Parameterized Types
+
+To facilitate some abstractions, the two functions
+ffi.typeof and
+ffi.cdef support
+parameterized types in C declarations. Note: none of the other API
+functions taking a cdecl allow this.
+
+
+Any place you can write a typedef name, an
+identifier or a number in a declaration, you can write
+$ (the dollar sign) instead. These placeholders are replaced in
+order of appearance with the arguments following the cdecl string:
+
+
+-- Declare a struct with a parameterized field type and name:
+ffi.cdef([[
+typedef struct { $ $; } foo_t;
+]], type1, name1)
+
+-- Anonymous struct with dynamic names:
+local bar_t = ffi.typeof("struct { int $, $; }", name1, name2)
+-- Derived pointer type:
+local bar_ptr_t = ffi.typeof("$ *", bar_t)
+
+-- Parameterized dimensions work even where a VLA won't work:
+local matrix_t = ffi.typeof("uint8_t[$][$]", width, height)
+
+
+Caveat: this is not simple text substitution! A passed ctype or
+cdata object is treated like the underlying type, a passed string is
+considered an identifier and a number is considered a number. You must
+not mix this up: e.g. passing "int" as a string doesn't work in
+place of a type, you'd need to use ffi.typeof("int") instead.
+
+
+The main use for parameterized types are libraries implementing abstract
+data types
+(» example),
+similar to what can be achieved with C++ template metaprogramming.
+Another use case are derived types of anonymous structs, which avoids
+pollution of the global struct namespace.
+
+
+Please note that parameterized types are a nice tool and indispensable
+for certain use cases. But you'll want to use them sparingly in regular
+code, e.g. when all types are actually fixed.
+
+
+
Garbage Collection of cdata Objects
+
+All explicitly (ffi.new(), ffi.cast() etc.) or
+implicitly (accessors) created cdata objects are garbage collected.
+You need to ensure to retain valid references to cdata objects
+somewhere on a Lua stack, an upvalue or in a Lua table while they are
+still in use. Once the last reference to a cdata object is gone, the
+garbage collector will automatically free the memory used by it (at
+the end of the next GC cycle).
+
+
+Please note that pointers themselves are cdata objects, however they
+are not followed by the garbage collector. So e.g. if you
+assign a cdata array to a pointer, you must keep the cdata object
+holding the array alive as long as the pointer is still in use:
+
+
+ffi.cdef[[
+typedef struct { int *a; } foo_t;
+]]
+
+local s = ffi.new("foo_t", ffi.new("int[10]")) -- WRONG!
+
+local a = ffi.new("int[10]") -- OK
+local s = ffi.new("foo_t", a)
+-- Now do something with 's', but keep 'a' alive until you're done.
+
+
+Similar rules apply for Lua strings which are implicitly converted to
+"const char *": the string object itself must be
+referenced somewhere or it'll be garbage collected eventually. The
+pointer will then point to stale data, which may have already been
+overwritten. Note that string literals are automatically kept
+alive as long as the function containing it (actually its prototype)
+is not garbage collected.
+
+
+Objects which are passed as an argument to an external C function
+are kept alive until the call returns. So it's generally safe to
+create temporary cdata objects in argument lists. This is a common
+idiom for passing specific C types to
+vararg functions.
+
+
+Memory areas returned by C functions (e.g. from malloc())
+must be manually managed, of course (or use
+ffi.gc()). Pointers to
+cdata objects are indistinguishable from pointers returned by C
+functions (which is one of the reasons why the GC cannot follow them).
+
+
+
Callbacks
+
+The LuaJIT FFI automatically generates special callback functions
+whenever a Lua function is converted to a C function pointer. This
+associates the generated callback function pointer with the C type
+of the function pointer and the Lua function object (closure).
+
+
+This can happen implicitly due to the usual conversions, e.g. when
+passing a Lua function to a function pointer argument. Or you can use
+ffi.cast() to explicitly cast a Lua function to a
+C function pointer.
+
+
+Currently only certain C function types can be used as callback
+functions. Neither C vararg functions nor functions with
+pass-by-value aggregate argument or result types are supported. There
+are no restrictions for the kind of Lua functions that can be called
+from the callback — no checks for the proper number of arguments
+are made. The return value of the Lua function will be converted to the
+result type and an error will be thrown for invalid conversions.
+
+
+It's allowed to throw errors across a callback invocation, but it's not
+advisable in general. Do this only if you know the C function, that
+called the callback, copes with the forced stack unwinding and doesn't
+leak resources.
+
+
+One thing that's not allowed, is to let an FFI call into a C function
+get JIT-compiled, which in turn calls a callback, calling into Lua again.
+Usually this attempt is caught by the interpreter first and the
+C function is blacklisted for compilation.
+
+
+However, this heuristic may fail under specific circumstances: e.g. a
+message polling function might not run Lua callbacks right away and the call
+gets JIT-compiled. If it later happens to call back into Lua (e.g. a rarely
+invoked error callback), you'll get a VM PANIC with the message
+"bad callback". Then you'll need to manually turn off
+JIT-compilation with
+jit.off() for the
+surrounding Lua function that invokes such a message polling function (or
+similar).
+
+
+
Callback resource handling
+
+Callbacks take up resources — you can only have a limited number
+of them at the same time (500 - 1000, depending on the
+architecture). The associated Lua functions are anchored to prevent
+garbage collection, too.
+
+
+Callbacks due to implicit conversions are permanent! There is no
+way to guess their lifetime, since the C side might store the
+function pointer for later use (typical for GUI toolkits). The associated
+resources cannot be reclaimed until termination:
+
+
+ffi.cdef[[
+typedef int (__stdcall *WNDENUMPROC)(void *hwnd, intptr_t l);
+int EnumWindows(WNDENUMPROC func, intptr_t l);
+]]
+
+-- Implicit conversion to a callback via function pointer argument.
+local count = 0
+ffi.C.EnumWindows(function(hwnd, l)
+ count = count + 1
+ return true
+end, 0)
+-- The callback is permanent and its resources cannot be reclaimed!
+-- Ok, so this may not be a problem, if you do this only once.
+
+
+Note: this example shows that you must properly declare
+__stdcall callbacks on Windows/x86 systems. The calling
+convention cannot be automatically detected, unlike for
+__stdcall calls to Windows functions.
+
+
+For some use cases it's necessary to free up the resources or to
+dynamically redirect callbacks. Use an explicit cast to a
+C function pointer and keep the resulting cdata object. Then use
+the cb:free()
+or cb:set() methods
+on the cdata object:
+
+
+-- Explicitly convert to a callback via cast.
+local count = 0
+local cb = ffi.cast("WNDENUMPROC", function(hwnd, l)
+ count = count + 1
+ return true
+end)
+
+-- Pass it to a C function.
+ffi.C.EnumWindows(cb, 0)
+-- EnumWindows doesn't need the callback after it returns, so free it.
+
+cb:free()
+-- The callback function pointer is no longer valid and its resources
+-- will be reclaimed. The created Lua closure will be garbage collected.
+
+
+
Callback performance
+
+Callbacks are slow! First, the C to Lua transition itself
+has an unavoidable cost, similar to a lua_call() or
+lua_pcall(). Argument and result marshalling add to that cost.
+And finally, neither the C compiler nor LuaJIT can inline or
+optimize across the language barrier and hoist repeated computations out
+of a callback function.
+
+
+Do not use callbacks for performance-sensitive work: e.g. consider a
+numerical integration routine which takes a user-defined function to
+integrate over. It's a bad idea to call a user-defined Lua function from
+C code millions of times. The callback overhead will be absolutely
+detrimental for performance.
+
+
+It's considerably faster to write the numerical integration routine
+itself in Lua — the JIT compiler will be able to inline the
+user-defined function and optimize it together with its calling context,
+with very competitive performance.
+
+
+As a general guideline: use callbacks only when you must, because
+of existing C APIs. E.g. callback performance is irrelevant for a
+GUI application, which waits for user input most of the time, anyway.
+
+
+For new designs avoid push-style APIs: a C function repeatedly
+calling a callback for each result. Instead use pull-style APIs:
+call a C function repeatedly to get a new result. Calls from Lua
+to C via the FFI are much faster than the other way round. Most well-designed
+libraries already use pull-style APIs (read/write, get/put).
+
+
+
C Library Namespaces
+
+A C library namespace is a special kind of object which allows
+access to the symbols contained in shared libraries or the default
+symbol namespace. The default
+ffi.C namespace is
+automatically created when the FFI library is loaded. C library
+namespaces for specific shared libraries may be created with the
+ffi.load() API
+function.
+
+
+Indexing a C library namespace object with a symbol name (a Lua
+string) automatically binds it to the library. First the symbol type
+is resolved — it must have been declared with
+ffi.cdef. Then the
+symbol address is resolved by searching for the symbol name in the
+associated shared libraries or the default symbol namespace. Finally,
+the resulting binding between the symbol name, the symbol type and its
+address is cached. Missing symbol declarations or nonexistent symbol
+names cause an error.
+
+
+This is what happens on a read access for the different kinds of
+symbols:
+
+
+
+
External functions: a cdata object with the type of the function
+and its address is returned.
+
+
External variables: the symbol address is dereferenced and the
+loaded value is converted to a Lua object
+and returned.
+
+
Constant values (static const or enum
+constants): the constant is converted to a
+Lua object and returned.
+
+
+
+This is what happens on a write access:
+
+
+
+
External variables: the value to be written is
+converted to the C type of the
+variable and then stored at the symbol address.
+
+
Writing to constant variables or to any other symbol type causes
+an error, like any other attempted write to a constant location.
+
+
+
+C library namespaces themselves are garbage collected objects. If
+the last reference to the namespace object is gone, the garbage
+collector will eventually release the shared library reference and
+remove all memory associated with the namespace. Since this may
+trigger the removal of the shared library from the memory of the
+running process, it's generally not safe to use function
+cdata objects obtained from a library if the namespace object may be
+unreferenced.
+
+
+Performance notice: the JIT compiler specializes to the identity of
+namespace objects and to the strings used to index it. This
+effectively turns function cdata objects into constants. It's not
+useful and actually counter-productive to explicitly cache these
+function objects, e.g. local strlen = ffi.C.strlen. OTOH it
+is useful to cache the namespace itself, e.g. local C =
+ffi.C.
+
+
+
No Hand-holding!
+
+The FFI library has been designed as a low-level library. The
+goal is to interface with C code and C data types with a
+minimum of overhead. This means you can do anything you can do
+from C: access all memory, overwrite anything in memory, call
+machine code at any memory address and so on.
+
+
+The FFI library provides no memory safety, unlike regular Lua
+code. It will happily allow you to dereference a NULL
+pointer, to access arrays out of bounds or to misdeclare
+C functions. If you make a mistake, your application might crash,
+just like equivalent C code would.
+
+
+This behavior is inevitable, since the goal is to provide full
+interoperability with C code. Adding extra safety measures, like
+bounds checks, would be futile. There's no way to detect
+misdeclarations of C functions, since shared libraries only
+provide symbol names, but no type information. Likewise there's no way
+to infer the valid range of indexes for a returned pointer.
+
+
+Again: the FFI library is a low-level library. This implies it needs
+to be used with care, but it's flexibility and performance often
+outweigh this concern. If you're a C or C++ developer, it'll be easy
+to apply your existing knowledge. OTOH writing code for the FFI
+library is not for the faint of heart and probably shouldn't be the
+first exercise for someone with little experience in Lua, C or C++.
+
+
+As a corollary of the above, the FFI library is not safe for use by
+untrusted Lua code. If you're sandboxing untrusted Lua code, you
+definitely don't want to give this code access to the FFI library or
+to any cdata object (except 64 bit integers or complex
+numbers). Any properly engineered Lua sandbox needs to provide safety
+wrappers for many of the standard Lua library functions —
+similar wrappers need to be written for high-level operations on FFI
+data types, too.
+
+
+
Current Status
+
+The initial release of the FFI library has some limitations and is
+missing some features. Most of these will be fixed in future releases.
+
C declarations are not passed through a C pre-processor,
+yet.
+
The C parser is able to evaluate most constant expressions
+commonly found in C header files. However it doesn't handle the
+full range of C expression semantics and may fail for some
+obscure constructs.
+
static const declarations only work for integer types
+up to 32 bits. Neither declaring string constants nor
+floating-point constants is supported.
+
Packed struct bitfields that cross container boundaries
+are not implemented.
+
Native vector types may be defined with the GCC mode or
+vector_size attribute. But no operations other than loading,
+storing and initializing them are supported, yet.
+
The volatile type qualifier is currently ignored by
+compiled code.
+
ffi.cdef silently
+ignores most re-declarations. Note: avoid re-declarations which do not
+conform to C99. The implementation will eventually be changed to
+perform strict checks.
+
+
+The JIT compiler already handles a large subset of all FFI operations.
+It automatically falls back to the interpreter for unimplemented
+operations (you can check for this with the
+-jv command line option).
+The following operations are currently not compiled and may exhibit
+suboptimal performance, especially when used in inner loops:
+
+
+
Vector operations.
+
Table initializers.
+
Initialization of nested struct/union types.
+
Non-default initialization of VLA/VLS or large C types
+(> 128 bytes or > 16 array elements.
+
Bitfield initializations.
+
Pointer differences for element sizes that are not a power of
+two.
+
Calls to C functions with aggregates passed or returned by
+value.
+
Calls to ctype metamethods which are not plain functions.
+
ctype __newindex tables and non-string lookups in ctype
+__index tables.
+
tostring() for cdata types.
+
Calls to ffi.cdef(), ffi.load() and
+ffi.metatype().
+This page is intended to give you an overview of the features of the FFI
+library by presenting a few use cases and guidelines.
+
+
+This page makes no attempt to explain all of the FFI library, though.
+You'll want to have a look at the ffi.* API
+function reference and the FFI
+semantics to learn more.
+
+
+
Loading the FFI Library
+
+The FFI library is built into LuaJIT by default, but it's not loaded
+and initialized by default. The suggested way to use the FFI library
+is to add the following to the start of every Lua file that needs one
+of its functions:
+
+
+local ffi = require("ffi")
+
+
+Please note this doesn't define an ffi variable in the table
+of globals — you really need to use the local variable. The
+require function ensures the library is only loaded once.
+
+
+Note: If you want to experiment with the FFI from the interactive prompt
+of the command line executable, omit the local, as it doesn't
+preserve local variables across lines.
+
+
+
Accessing Standard System Functions
+
+The following code explains how to access standard system functions.
+We slowly print two lines of dots by sleeping for 10 milliseconds
+after each dot:
+
+
+
+①
+
+
+
+
+
+②
+③
+④
+
+
+
+⑤
+
+
+
+
+
+⑥local ffi = require("ffi")
+ffi.cdef[[
+void Sleep(int ms);
+int poll(struct pollfd *fds, unsigned long nfds, int timeout);
+]]
+
+local sleep
+if ffi.os == "Windows" then
+ function sleep(s)
+ ffi.C.Sleep(s*1000)
+ end
+else
+ function sleep(s)
+ ffi.C.poll(nil, 0, s*1000)
+ end
+end
+
+for i=1,160 do
+ io.write("."); io.flush()
+ sleep(0.01)
+end
+io.write("\n")
+
+
+Here's the step-by-step explanation:
+
+
+① This defines the
+C library functions we're going to use. The part inside the
+double-brackets (in green) is just standard C syntax. You can
+usually get this info from the C header files or the
+documentation provided by each C library or C compiler.
+
+
+② The difficulty we're
+facing here, is that there are different standards to choose from.
+Windows has a simple Sleep() function. On other systems there
+are a variety of functions available to achieve sub-second sleeps, but
+with no clear consensus. Thankfully poll() can be used for
+this task, too, and it's present on most non-Windows systems. The
+check for ffi.os makes sure we use the Windows-specific
+function only on Windows systems.
+
+
+③ Here we're wrapping the
+call to the C function in a Lua function. This isn't strictly
+necessary, but it's helpful to deal with system-specific issues only
+in one part of the code. The way we're wrapping it ensures the check
+for the OS is only done during initialization and not for every call.
+
+
+④ A more subtle point is
+that we defined our sleep() function (for the sake of this
+example) as taking the number of seconds, but accepting fractional
+seconds. Multiplying this by 1000 gets us milliseconds, but that still
+leaves it a Lua number, which is a floating-point value. Alas, the
+Sleep() function only accepts an integer value. Luckily for
+us, the FFI library automatically performs the conversion when calling
+the function (truncating the FP value towards zero, like in C).
+
+
+Some readers will notice that Sleep() is part of
+KERNEL32.DLL and is also a stdcall function. So how
+can this possibly work? The FFI library provides the ffi.C
+default C library namespace, which allows calling functions from
+the default set of libraries, like a C compiler would. Also, the
+FFI library automatically detects stdcall functions, so you
+don't need to declare them as such.
+
+
+⑤ The poll()
+function takes a couple more arguments we're not going to use. You can
+simply use nil to pass a NULL pointer and 0
+for the nfds parameter. Please note that the
+number 0does not convert to a pointer value,
+unlike in C++. You really have to pass pointers to pointer arguments
+and numbers to number arguments.
+
+
+The page on FFI semantics has all
+of the gory details about
+conversions between Lua
+objects and C types. For the most part you don't have to deal
+with this, as it's performed automatically and it's carefully designed
+to bridge the semantic differences between Lua and C.
+
+
+⑥ Now that we have defined
+our own sleep() function, we can just call it from plain Lua
+code. That wasn't so bad, huh? Turning these boring animated dots into
+a fascinating best-selling game is left as an exercise for the reader.
+:-)
+
+
+
Accessing the zlib Compression Library
+
+The following code shows how to access the zlib compression library from Lua code.
+We'll define two convenience wrapper functions that take a string and
+compress or uncompress it to another string:
+
+
+
+①
+
+
+
+
+
+
+②
+
+
+③
+
+④
+
+
+⑤
+
+
+⑥
+
+
+
+
+
+
+
+⑦local ffi = require("ffi")
+ffi.cdef[[
+unsigned long compressBound(unsigned long sourceLen);
+int compress2(uint8_t *dest, unsigned long *destLen,
+ const uint8_t *source, unsigned long sourceLen, int level);
+int uncompress(uint8_t *dest, unsigned long *destLen,
+ const uint8_t *source, unsigned long sourceLen);
+]]
+local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z")
+
+local function compress(txt)
+ local n = zlib.compressBound(#txt)
+ local buf = ffi.new("uint8_t[?]", n)
+ local buflen = ffi.new("unsigned long[1]", n)
+ local res = zlib.compress2(buf, buflen, txt, #txt, 9)
+ assert(res == 0)
+ return ffi.string(buf, buflen[0])
+end
+
+local function uncompress(comp, n)
+ local buf = ffi.new("uint8_t[?]", n)
+ local buflen = ffi.new("unsigned long[1]", n)
+ local res = zlib.uncompress(buf, buflen, comp, #comp)
+ assert(res == 0)
+ return ffi.string(buf, buflen[0])
+end
+
+-- Simple test code.
+local txt = string.rep("abcd", 1000)
+print("Uncompressed size: ", #txt)
+local c = compress(txt)
+print("Compressed size: ", #c)
+local txt2 = uncompress(c, #txt)
+assert(txt2 == txt)
+
+
+Here's the step-by-step explanation:
+
+
+① This defines some of the
+C functions provided by zlib. For the sake of this example, some
+type indirections have been reduced and it uses the pre-defined
+fixed-size integer types, while still adhering to the zlib API/ABI.
+
+
+② This loads the zlib shared
+library. On POSIX systems it's named libz.so and usually
+comes pre-installed. Since ffi.load() automatically adds any
+missing standard prefixes/suffixes, we can simply load the
+"z" library. On Windows it's named zlib1.dll and
+you'll have to download it first from the
+» zlib site. The check for
+ffi.os makes sure we pass the right name to
+ffi.load().
+
+
+③ First, the maximum size of
+the compression buffer is obtained by calling the
+zlib.compressBound function with the length of the
+uncompressed string. The next line allocates a byte buffer of this
+size. The [?] in the type specification indicates a
+variable-length array (VLA). The actual number of elements of this
+array is given as the 2nd argument to ffi.new().
+
+
+④ This may look strange at
+first, but have a look at the declaration of the compress2
+function from zlib: the destination length is defined as a pointer!
+This is because you pass in the maximum buffer size and get back the
+actual length that was used.
+
+
+In C you'd pass in the address of a local variable
+(&buflen). But since there's no address-of operator in
+Lua, we'll just pass in a one-element array. Conveniently it can be
+initialized with the maximum buffer size in one step. Calling the
+actual zlib.compress2 function is then straightforward.
+
+
+⑤ We want to return the
+compressed data as a Lua string, so we'll use ffi.string().
+It needs a pointer to the start of the data and the actual length. The
+length has been returned in the buflen array, so we'll just
+get it from there.
+
+
+Note that since the function returns now, the buf and
+buflen variables will eventually be garbage collected. This
+is fine, because ffi.string() has copied the contents to a
+newly created (interned) Lua string. If you plan to call this function
+lots of times, consider reusing the buffers and/or handing back the
+results in buffers instead of strings. This will reduce the overhead
+for garbage collection and string interning.
+
+
+⑥ The uncompress
+functions does the exact opposite of the compress function.
+The compressed data doesn't include the size of the original string,
+so this needs to be passed in. Otherwise no surprises here.
+
+
+⑦ The code, that makes use
+of the functions we just defined, is just plain Lua code. It doesn't
+need to know anything about the LuaJIT FFI — the convenience
+wrapper functions completely hide it.
+
+
+One major advantage of the LuaJIT FFI is that you are now able to
+write those wrappers in Lua. And at a fraction of the time it
+would cost you to create an extra C module using the Lua/C API.
+Many of the simpler C functions can probably be used directly
+from your Lua code, without any wrappers.
+
+
+Side note: the zlib API uses the long type for passing
+lengths and sizes around. But all those zlib functions actually only
+deal with 32 bit values. This is an unfortunate choice for a
+public API, but may be explained by zlib's history — we'll just
+have to deal with it.
+
+
+First, you should know that a long is a 64 bit type e.g.
+on POSIX/x64 systems, but a 32 bit type on Windows/x64 and on
+32 bit systems. Thus a long result can be either a plain
+Lua number or a boxed 64 bit integer cdata object, depending on
+the target system.
+
+
+Ok, so the ffi.* functions generally accept cdata objects
+wherever you'd want to use a number. That's why we get a away with
+passing n to ffi.string() above. But other Lua
+library functions or modules don't know how to deal with this. So for
+maximum portability one needs to use tonumber() on returned
+long results before passing them on. Otherwise the
+application might work on some systems, but would fail in a POSIX/x64
+environment.
+
+
+
Defining Metamethods for a C Type
+
+The following code explains how to define metamethods for a C type.
+We define a simple point type and add some operations to it:
+
+① This defines the C type for a
+two-dimensional point object.
+
+
+② We have to declare the variable
+holding the point constructor first, because it's used inside of a
+metamethod.
+
+
+③ Let's define an __add
+metamethod which adds the coordinates of two points and creates a new
+point object. For simplicity, this function assumes that both arguments
+are points. But it could be any mix of objects, if at least one operand
+is of the required type (e.g. adding a point plus a number or vice
+versa). Our __len metamethod returns the distance of a point to
+the origin.
+
+
+④ If we run out of operators, we can
+define named methods, too. Here the __index table defines an
+area function. For custom indexing needs, one might want to
+define __index and __newindexfunctions instead.
+
+
+⑤ This associates the metamethods with
+our C type. This only needs to be done once. For convenience, a
+constructor is returned by
+ffi.metatype().
+We're not required to use it, though. The original C type can still
+be used e.g. to create an array of points. The metamethods automatically
+apply to any and all uses of this type.
+
+
+Please note that the association with a metatable is permanent and
+the metatable must not be modified afterwards! Ditto for the
+__index table.
+
+
+⑥ Here are some simple usage examples
+for the point type and their expected results. The pre-defined
+operations (such as a.x) can be freely mixed with the newly
+defined metamethods. Note that area is a method and must be
+called with the Lua syntax for methods: a:area(), not
+a.area().
+
+
+The C type metamethod mechanism is most useful when used in
+conjunction with C libraries that are written in an object-oriented
+style. Creators return a pointer to a new instance and methods take an
+instance pointer as the first argument. Sometimes you can just point
+__index to the library namespace and __gc to the
+destructor and you're done. But often enough you'll want to add
+convenience wrappers, e.g. to return actual Lua strings or when
+returning multiple values.
+
+
+Some C libraries only declare instance pointers as an opaque
+void * type. In this case you can use a fake type for all
+declarations, e.g. a pointer to a named (incomplete) struct will do:
+typedef struct foo_type *foo_handle. The C side doesn't
+know what you declare with the LuaJIT FFI, but as long as the underlying
+types are compatible, everything still works.
+
+
+
Translating C Idioms
+
+Here's a list of common C idioms and their translation to the
+LuaJIT FFI:
+
+
+
+
Idiom
+
C code
+
Lua code
+
+
+
Pointer dereference int *p;
x = *p; *p = y;
x = p[0] p[0] = y
+
+
Pointer indexing int i, *p;
x = p[i]; p[i+1] = y;
x = p[i] p[i+1] = y
+
+
Array indexing int i, a[];
x = a[i]; a[i+1] = y;
x = a[i] a[i+1] = y
+
+
struct/union dereference struct foo s;
x = s.field; s.field = y;
x = s.field s.field = y
+
+
struct/union pointer deref. struct foo *sp;
x = sp->field; sp->field = y;
x = s.field s.field = y
+
+
Pointer arithmetic int i, *p;
x = p + i; y = p - i;
x = p + i y = p - i
+
+
Pointer difference int *p1, *p2;
x = p1 - p2;
x = p1 - p2
+
+
Array element pointer int i, a[];
x = &a[i];
x = a+i
+
+
Cast pointer to address int *p;
x = (intptr_t)p;
x = tonumber( ffi.cast("intptr_t", p))
+
+
Functions with outargs void foo(int *inoutlen);
int len = x; foo(&len); y = len;
local len = ffi.new("int[1]", x) foo(len) y = len[0]
+This replaces several hash-table lookups with a (faster) direct use of
+a local or an upvalue. This is less important with LuaJIT, since the
+JIT compiler optimizes hash-table lookups a lot and is even able to
+hoist most of them out of the inner loops. It can't eliminate
+all of them, though, and it saves some typing for often-used
+functions. So there's still a place for this, even with LuaJIT.
+
+
+The situation is a bit different with C function calls via the
+FFI library. The JIT compiler has special logic to eliminate all
+of the lookup overhead for functions resolved from a
+C library namespace!
+Thus it's not helpful and actually counter-productive to cache
+individual C functions like this:
+
+
+local funca, funcb = ffi.C.funca, ffi.C.funcb -- Not helpful!
+local function foo(x, n)
+ for i=1,n do funcb(funca(x, i), 1) end
+end
+
+
+This turns them into indirect calls and generates bigger and slower
+machine code. Instead you'll want to cache the namespace itself and
+rely on the JIT compiler to eliminate the lookups:
+
+
+local C = ffi.C -- Instead use this!
+local function foo(x, n)
+ for i=1,n do C.funcb(C.funca(x, i), 1) end
+end
+
+
+This generates both shorter and faster code. So don't cache
+C functions, but do cache namespaces! Most often the
+namespace is already in a local variable at an outer scope, e.g. from
+local lib = ffi.load(...). Note that copying
+it to a local variable in the function scope is unnecessary.
+
+The functions in this built-in module control the behavior of the JIT
+compiler engine. Note that JIT-compilation is fully automatic —
+you probably won't need to use any of the following functions unless
+you have special needs.
+
+
+
jit.on()
+jit.off()
+
+Turns the whole JIT compiler on (default) or off.
+
+
+These functions are typically used with the command line options
+-j on or -j off.
+
+jit.on enables JIT compilation for a Lua function (this is
+the default).
+
+
+jit.off disables JIT compilation for a Lua function and
+flushes any already compiled code from the code cache.
+
+
+jit.flush flushes the code, but doesn't affect the
+enable/disable status.
+
+
+The current function, i.e. the Lua function calling this library
+function, can also be specified by passing true as the first
+argument.
+
+
+If the second argument is true, JIT compilation is also
+enabled, disabled or flushed recursively for all sub-functions of a
+function. With false only the sub-functions are affected.
+
+
+The jit.on and jit.off functions only set a flag
+which is checked when the function is about to be compiled. They do
+not trigger immediate compilation.
+
+
+Typical usage is jit.off(true, true) in the main chunk
+of a module to turn off JIT compilation for the whole module for
+debugging purposes.
+
+
+
jit.flush(tr)
+
+Flushes the root trace, specified by its number, and all of its side
+traces from the cache. The code for the trace will be retained as long
+as there are any other traces which link to it.
+
+
+
status, ... = jit.status()
+
+Returns the current status of the JIT compiler. The first result is
+either true or false if the JIT compiler is turned
+on or off. The remaining results are strings for CPU-specific features
+and enabled optimizations.
+
+
+
jit.version
+
+Contains the LuaJIT version string.
+
+
+
jit.version_num
+
+Contains the version number of the LuaJIT core. Version xx.yy.zz
+is represented by the decimal number xxyyzz.
+
+
+
jit.os
+
+Contains the target OS name:
+"Windows", "Linux", "OSX", "BSD", "POSIX" or "Other".
+
+
+
jit.arch
+
+Contains the target architecture name:
+"x86", "x64", "arm", "arm64", "ppc", "mips" or "mips64".
+
+
+
jit.opt.* — JIT compiler optimization control
+
+This sub-module provides the backend for the -O command line
+option.
+
+
+You can also use it programmatically, e.g.:
+
+
+jit.opt.start(2) -- same as -O2
+jit.opt.start("-dce")
+jit.opt.start("hotloop=10", "hotexit=2")
+
+
+Unlike in LuaJIT 1.x, the module is built-in and
+optimization is turned on by default!
+It's no longer necessary to run require("jit.opt").start(),
+which was one of the ways to enable optimization.
+
+
+
jit.util.* — JIT compiler introspection
+
+This sub-module holds functions to introspect the bytecode, generated
+traces, the IR and the generated machine code. The functionality
+provided by this module is still in flux and therefore undocumented.
+
+
+The debug modules -jbc, -jv and -jdump make
+extensive use of these functions. Please check out their source code,
+if you want to know more.
+
+LuaJIT has an integrated statistical profiler with very low overhead. It
+allows sampling the currently executing stack and other parameters in
+regular intervals.
+
+
+The integrated profiler can be accessed from three levels:
+
+The bundled high-level profiler offers basic profiling functionality. It
+generates simple textual summaries or source code annotations. It can be
+accessed with the -jp command line option
+or from Lua code by loading the underlying jit.p module.
+
+
+To cut to the chase — run this to get a CPU usage profile by
+function name:
+
+
+luajit -jp myapp.lua
+
+
+It's not a stated goal of the bundled profiler to add every
+possible option or to cater for special profiling needs. The low-level
+profiler APIs are documented below. They may be used by third-party
+authors to implement advanced functionality, e.g. IDE integration or
+graphical profilers.
+
+
+Note: Sampling works for both interpreted and JIT-compiled code. The
+results for JIT-compiled code may sometimes be surprising. LuaJIT
+heavily optimizes and inlines Lua code — there's no simple
+one-to-one correspondence between source code lines and the sampled
+machine code.
+
+
+
-jp=[options[,output]]
+
+The -jp command line option starts the high-level profiler.
+When the application run by the command line terminates, the profiler
+stops and writes the results to stdout or to the specified
+output file.
+
+
+The options argument specifies how the profiling is to be
+performed:
+
+
+
f — Stack dump: function name, otherwise module:line.
+This is the default mode.
r — Show raw sample counts. Default: show percentages.
+
a — Annotate excerpts from source code files.
+
A — Annotate complete source code files.
+
G — Produce raw output suitable for graphical tools.
+
m<number> — Minimum sample percentage to be shown.
+Default: 3%.
+
i<number> — Sampling interval in milliseconds.
+Default: 10ms.
+Note: The actual sampling precision is OS-dependent.
+
+
+The default output for -jp is a list of the most CPU consuming
+spots in the application. Increasing the stack dump depth with (say)
+-jp=2 may help to point out the main callers or callees of
+hotspots. But sample aggregation is still flat per unique stack dump.
+
+
+To get a two-level view (split view) of callers/callees, use
+-jp=s or -jp=-s. The percentages shown for the second
+level are relative to the first level.
+
+
+To see how much time is spent in each line relative to a function, use
+-jp=fl.
+
+
+To see how much time is spent in different VM states or
+zones, use -jp=v or -jp=z.
+
+
+Combinations of v/z with f/F/l produce two-level
+views, e.g. -jp=vf or -jp=fv. This shows the time
+spent in a VM state or zone vs. hotspots. This can be used to answer
+questions like "Which time consuming functions are only interpreted?" or
+"What's the garbage collector overhead for a specific function?".
+
+
+Multiple options can be combined — but not all combinations make
+sense, see above. E.g. -jp=3si4m1 samples three stack levels
+deep in 4ms intervals and shows a split view of the CPU consuming
+functions and their callers with a 1% threshold.
+
+
+Source code annotations produced by -jp=a or -jp=A are
+always flat and at the line level. Obviously, the source code files need
+to be readable by the profiler script.
+
+
+The high-level profiler can also be started and stopped from Lua code with:
+
+Zones can be used to provide information about different parts of an
+application to the high-level profiler. E.g. a game could make use of an
+"AI" zone, a "PHYS" zone, etc. Zones are hierarchical,
+organized as a stack.
+
+
+The jit.zone module needs to be loaded explicitly:
+
+
+local zone = require("jit.zone")
+
+
+
zone("name") pushes a named zone to the zone stack.
+
zone() pops the current zone from the zone stack and
+returns its name.
+
zone:get() returns the current zone name or nil.
+
zone:flush() flushes the zone stack.
+
+
+To show the time spent in each zone use -jp=z. To show the time
+spent relative to hotspots use e.g. -jp=zf or -jp=fz.
+
+
+
Low-level Lua API
+
+The jit.profile module gives access to the low-level API of the
+profiler from Lua code. This module needs to be loaded explicitly:
+
+local profile = require("jit.profile")
+
+
+This module can be used to implement your own higher-level profiler.
+A typical profiling run starts the profiler, captures stack dumps in
+the profiler callback, adds them to a hash table to aggregate the number
+of samples, stops the profiler and then analyzes all of the captured
+stack dumps. Other parameters can be sampled in the profiler callback,
+too. But it's important not to spend too much time in the callback,
+since this may skew the statistics.
+
+
+
profile.start(mode, cb)
+— Start profiler
+
+This function starts the profiler. The mode argument is a
+string holding options:
+
+
+
f — Profile with precision down to the function level.
+
l — Profile with precision down to the line level.
+
i<number> — Sampling interval in milliseconds (default
+10ms).
+Note: The actual sampling precision is OS-dependent.
+
+
+
+The cb argument is a callback function which is called with
+three arguments: (thread, samples, vmstate). The callback is
+called on a separate coroutine, the thread argument is the
+state that holds the stack to sample for profiling. Note: do
+not modify the stack of that state or call functions on it.
+
+
+samples gives the number of accumulated samples since the last
+callback (usually 1).
+
+
+vmstate holds the VM state at the time the profiling timer
+triggered. This may or may not correspond to the state of the VM when
+the profiling callback is called. The state is either 'N'
+native (compiled) code, 'I' interpreted code, 'C'
+C code, 'G' the garbage collector, or 'J' the JIT
+compiler.
+
+This function allows taking stack dumps in an efficient manner. It
+returns a string with a stack dump for the thread (coroutine),
+formatted according to the fmt argument:
+
+
+
p — Preserve the full path for module names. Otherwise
+only the file name is used.
+
f — Dump the function name if it can be derived. Otherwise
+use module:line.
+
F — Ditto, but dump module:name.
+
l — Dump module:line.
+
Z — Zap the following characters for the last dumped
+frame.
+
All other characters are added verbatim to the output string.
+
+
+The depth argument gives the number of frames to dump, starting
+at the topmost frame of the thread. A negative number dumps the frames in
+inverse order.
+
+
+The first example prints a list of the current module names and line
+numbers of up to 10 frames in separate lines. The second example prints
+semicolon-separated function names for all frames (up to 100) in inverse
+order:
+
+This function starts the profiler. See
+above for a description of the mode argument.
+
+
+The cb argument is a callback function with the following
+declaration:
+
+
+typedef void (*luaJIT_profile_callback)(void *data, lua_State *L,
+ int samples, int vmstate);
+
+
+data is available for use by the callback. L is the
+state that holds the stack to sample for profiling. Note: do
+not modify this stack or call functions on this stack —
+use a separate coroutine for this purpose. See
+above for a description of samples and vmstate.
+
+
+
luaJIT_profile_stop(L)
+— Stop profiler
+
+This function stops the profiler.
+
+
+
p = luaJIT_profile_dumpstack(L, fmt, depth, len)
+— Dump stack
+
+This function allows taking stack dumps in an efficient manner.
+See above for a description of fmt
+and depth.
+
+
+This function returns a const char * pointing to a
+private string buffer of the profiler. The int *len
+argument returns the length of the output string. The buffer is
+overwritten on the next call and deallocated when the profiler stops.
+You either need to consume the content immediately or copy it for later
+use.
+
+LuaJIT is also fully ABI-compatible to Lua 5.1 at the linker/dynamic
+loader level. This means you can compile a C module against the
+standard Lua headers and load the same shared library from either Lua
+or LuaJIT.
+
+
+LuaJIT extends the standard Lua VM with new functionality and adds
+several extension modules. Please note this page is only about
+functional enhancements and not about performance enhancements,
+such as the optimized VM, the faster interpreter or the JIT compiler.
+
+
+
Extensions Modules
+
+LuaJIT comes with several built-in extension modules:
+
+
+
bit.* — Bitwise operations
+
+LuaJIT supports all bitwise operations as defined by
+» Lua BitOp:
+
+This module is a LuaJIT built-in — you don't need to download or
+install Lua BitOp. The Lua BitOp site has full documentation for all
+» Lua BitOp API functions.
+The FFI adds support for
+64 bit bitwise operations,
+using the same API functions.
+
+
+Please make sure to require the module before using any of
+its functions:
+
+
+local bit = require("bit")
+
+
+An already installed Lua BitOp module is ignored by LuaJIT.
+This way you can use bit operations from both Lua and LuaJIT on a
+shared installation.
+
+
+
ffi.* — FFI library
+
+The FFI library allows calling external
+C functions and the use of C data structures from pure Lua
+code.
+
+Unlike the standard implementation in Lua 5.1, xpcall()
+passes any arguments after the error function to the function
+which is called in a protected context.
+
+
+
loadfile() etc. handle UTF-8 source code
+
+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.
+
+
+
tostring() etc. canonicalize NaN and ±Inf
+
+All number-to-string conversions consistently convert non-finite numbers
+to the same strings on all platforms. NaN results in "nan",
+positive infinity results in "inf" and negative infinity results
+in "-inf".
+
+
+
tonumber() etc. use builtin string to number conversion
+
+All string-to-number conversions consistently convert integer and
+floating-point inputs in decimal, hexadecimal and binary on all platforms.
+strtod() is not used anymore, which avoids numerous
+problems with poor C library implementations. The builtin conversion
+function provides full precision according to the IEEE-754 standard, it
+works independently of the current locale and it supports hex floating-point
+numbers (e.g. 0x1.5p-3).
+
+An extra argument has been added to string.dump(). If set to
+true, 'stripped' bytecode without debug information is
+generated. This speeds up later bytecode loading and reduces memory
+usage. See also the
+-b command line option.
+
+
+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.
+
+
+Note: LJ_GC64 mode requires a different frame layout, which implies
+a different, incompatible bytecode format for ports that use this mode (e.g.
+ARM64 or MIPS64) or when explicitly enabled for x64. This may be rectified
+in the future.
+
+
+
table.new(narray, nhash) allocates a pre-sized table
+
+An extra library function table.new() can be made available via
+require("table.new"). This creates a pre-sized table, just like
+the C API equivalent lua_createtable(). This is useful for big
+tables if the final table size is known and automatic table resizing is
+too expensive.
+
+
+
table.clear(tab) clears a table
+
+An extra library function table.clear() can be made available
+via require("table.clear"). This clears all keys and values
+from a table, but preserves the allocated array/hash sizes. This is
+useful when a table, which is linked from multiple places, needs to be
+cleared and/or when recycling a table for use by the same context. This
+avoids managing backlinks, saves an allocation and the overhead of
+incremental array/hash part growth.
+
+
+Please note this function is meant for very specific situations. In most
+cases it's better to replace the (usually single) link with a new table
+and let the GC do its work.
+
+
+
Enhanced PRNG for math.random()
+
+LuaJIT uses a Tausworthe PRNG with period 2^223 to implement
+math.random() and math.randomseed(). The quality of
+the PRNG results is much superior compared to the standard Lua
+implementation which uses the platform-specific ANSI rand().
+
+
+The PRNG generates the same sequences from the same seeds on all
+platforms and makes use of all bits in the seed argument.
+math.random() without arguments generates 52 pseudo-random bits
+for every call. The result is uniformly distributed between 0.0 and 1.0.
+It's correctly scaled up and rounded for math.random(n [,m]) to
+preserve uniformity.
+
+
+
io.* functions handle 64 bit file offsets
+
+The file I/O functions in the standard io.* library handle
+64 bit file offsets. In particular this means it's possible
+to open files larger than 2 Gigabytes and to reposition or obtain
+the current file position for offsets beyond 2 GB
+(fp:seek() method).
+
+
+
debug.* functions identify metamethods
+
+debug.getinfo() and lua_getinfo() also return information
+about invoked metamethods. The namewhat field is set to
+"metamethod" and the name field has the name of
+the corresponding metamethod (e.g. "__index").
+
+
+
Fully Resumable VM
+
+The LuaJIT VM is fully resumable. This means you can yield from a
+coroutine even across contexts, where this would not possible with
+the standard Lua 5.1 VM: e.g. you can yield across pcall()
+and xpcall(), across iterators and across metamethods.
+
+
+
Extensions from Lua 5.2
+
+LuaJIT supports some language and library extensions from Lua 5.2.
+Features that are unlikely to break existing code are unconditionally
+enabled:
+
+
+
goto and ::labels::.
+
Hex escapes '\x3F' and '\*' escape in strings.
+
load(string|reader [, chunkname [,mode [,env]]]).
+
loadstring() is an alias for load().
+
loadfile(filename [,mode [,env]]).
+
math.log(x [,base]).
+
string.rep(s, n [,sep]).
+
string.format(): %q reversible.
+%s checks __tostring.
+%a and "%A added.
+
String matching pattern %g added.
+
io.read("*L").
+
io.lines() and file:lines() process
+io.read() options.
+
os.exit(status|true|false [,close]).
+
package.searchpath(name, path [, sep [, rep]]).
+
package.loadlib(name, "*").
+
debug.getinfo() returns nparams and isvararg
+for option "u".
+
debug.getlocal() accepts function instead of level.
+
debug.getlocal() and debug.setlocal() accept negative
+indexes for varargs.
+
debug.getupvalue() and debug.setupvalue() handle
+C functions.
+Other features are only enabled, if LuaJIT is built with
+-DLUAJIT_ENABLE_LUA52COMPAT:
+
+
+
goto is a keyword and not a valid variable name anymore.
+
break can be placed anywhere. Empty statements (;;)
+are allowed.
+
__lt, __le are invoked for mixed types.
+
__len for tables. rawlen() library function.
+
pairs() and ipairs() check for __pairs and
+__ipairs.
+
coroutine.running() returns two results.
+
table.pack() and table.unpack()
+(same as unpack()).
+
io.write() and file:write() return file handle
+instead of true.
+
os.execute() and pipe:close() return detailed
+exit status.
+
debug.setmetatable() returns object.
+
debug.getuservalue() and debug.setuservalue().
+
Remove math.mod(), string.gfind().
+
package.searchers.
+
module() returns the module table.
+
+
+Note: this provides only partial compatibility with Lua 5.2 at the
+language and Lua library level. LuaJIT is API+ABI-compatible with
+Lua 5.1, which prevents implementing features that would otherwise
+break the Lua/C API and ABI (e.g. _ENV).
+
+
+
Extensions from Lua 5.3
+
+LuaJIT supports some extensions from Lua 5.3:
+
+
Unicode escape '\u{XX...}' embeds the UTF-8 encoding in string literals.
+
The argument table arg can be read (and modified) by LUA_INIT and -e chunks.
+
io.read() and file:read() accept formats with or without a leading *.
+
table.move(a1, f, e, t [,a2]).
+
coroutine.isyieldable().
+
Lua/C API extensions:
+lua_isyieldable()
+
+
+
+
C++ Exception Interoperability
+
+LuaJIT has built-in support for interoperating with C++ exceptions.
+The available range of features depends on the target platform and
+the toolchain used to compile LuaJIT:
+
+
+
+
Platform
+
Compiler
+
Interoperability
+
+
+
POSIX/x64, DWARF2 unwinding
+
GCC 4.3+, Clang
+
Full
+
+
+
ARM -DLUAJIT_UNWIND_EXTERNAL
+
GCC, Clang
+
Full
+
+
+
Other platforms, DWARF2 unwinding
+
GCC, Clang
+
Limited
+
+
+
Windows/x64
+
MSVC or WinSDK
+
Full
+
+
+
Windows/x86
+
Any
+
Full
+
+
+
Other platforms
+
Other compilers
+
No
+
+
+
+Full interoperability means:
+
+
+
C++ exceptions can be caught on the Lua side with pcall(),
+lua_pcall() etc.
+
C++ exceptions will be converted to the generic Lua error
+"C++ exception", unless you use the
+C call wrapper feature.
+
It's safe to throw C++ exceptions across non-protected Lua frames
+on the C stack. The contents of the C++ exception object
+pass through unmodified.
+
Lua errors can be caught on the C++ side with catch(...).
+The corresponding Lua error message can be retrieved from the Lua stack.
+
Throwing Lua errors across C++ frames is safe. C++ destructors
+will be called.
+
+
+Limited interoperability means:
+
+
+
C++ exceptions can be caught on the Lua side with pcall(),
+lua_pcall() etc.
+
C++ exceptions will be converted to the generic Lua error
+"C++ exception", unless you use the
+C call wrapper feature.
+
C++ exceptions will be caught by non-protected Lua frames and
+are rethrown as a generic Lua error. The C++ exception object will
+be destroyed.
+
Lua errors cannot be caught on the C++ side.
+
Throwing Lua errors across C++ frames will not call
+C++ destructors.
+
+
+
+No interoperability means:
+
+
+
It's not safe to throw C++ exceptions across Lua frames.
+
C++ exceptions cannot be caught on the Lua side.
+
Lua errors cannot be caught on the C++ side.
+
Throwing Lua errors across C++ frames will not call
+C++ destructors.
Q: Why do I get this error: "attempt to index global 'arg' (a nil value)"?
+Q: My vararg functions fail after switching to LuaJIT!
+
LuaJIT is compatible to the Lua 5.1 language standard. It doesn't
+support the implicit arg parameter for old-style vararg
+functions from Lua 5.0. Please convert your code to the
+» Lua 5.1
+vararg syntax.
+
+
+
+
Q: Why do I get this error: "bad FPU precision"?
+
Q: I get weird behavior after initializing Direct3D.
+
Q: Some FPU operations crash after I load a Delphi DLL.
+
+
+
+DirectX/Direct3D (up to version 9) sets the x87 FPU to single-precision
+mode by default. This violates the Windows ABI and interferes with the
+operation of many programs — LuaJIT is affected, too. Please make
+sure you always use the D3DCREATE_FPU_PRESERVE flag when
+initializing Direct3D.
+
+Direct3D version 10 or higher do not show this behavior anymore.
+Consider testing your application with older versions, too.
+
+Similarly, the Borland/Delphi runtime modifies the FPU control word and
+enables FP exceptions. Of course this violates the Windows ABI, too.
+Please check the Delphi docs for the Set8087CW method.
+
+
+
+
+
Q: Sometimes Ctrl-C fails to stop my Lua program. Why?
+
The interrupt signal handler sets a Lua debug hook. But this is
+currently ignored by compiled code (this will eventually be fixed). If
+your program is running in a tight loop and never falls back to the
+interpreter, the debug hook never runs and can't throw the
+"interrupted!" error. In the meantime you have to press Ctrl-C
+twice to get stop your program. That's similar to when it's stuck
+running inside a C function under the Lua interpreter.
+
+
+
+
Q: Why doesn't my favorite power-patch for Lua apply against LuaJIT?
+
Because it's a completely redesigned VM and has very little code
+in common with Lua anymore. Also, if the patch introduces changes to
+the Lua semantics, these would need to be reflected everywhere in the
+VM, from the interpreter up to all stages of the compiler. Please
+use only standard Lua language constructs. For many common needs you
+can use source transformations or use wrapper or proxy functions.
+The compiler will happily optimize away such indirections.
+
+
+
+
Q: Lua runs everywhere. Why doesn't LuaJIT support my CPU?
+
Because it's a compiler — it needs to generate native
+machine code. This means the code generator must be ported to each
+architecture. And the fast interpreter is written in assembler and
+must be ported, too. This is quite an undertaking.
+The install documentation shows the supported
+architectures. Other architectures will follow based on sufficient user
+demand and/or sponsoring.
+
+
+
+
Q: When will feature X be added? When will the next version be released?
+
When it's ready.
+C'mon, it's open source — I'm doing it on my own time and you're
+getting it for free. You can either contribute a patch or sponsor
+the development of certain features, if they are important to you.
+
+LuaJIT is only distributed as a source package. This page explains
+how to build and install LuaJIT with different operating systems
+and C compilers.
+
+
+For the impatient (on POSIX systems):
+
+
+make && sudo make install
+
+
+LuaJIT currently builds out-of-the box on most systems.
+Here's the compatibility matrix for the supported combinations of
+operating systems, CPUs and compilers:
+
+The standard configuration should work fine for most installations.
+Usually there is no need to tweak the settings. The following files
+hold all user-configurable settings:
+
+
+
src/luaconf.h sets some configuration variables.
+
Makefile has settings for installing LuaJIT (POSIX
+only).
+
src/Makefile has settings for compiling LuaJIT
+under POSIX, MinGW or Cygwin.
+
src/msvcbuild.bat has settings for compiling LuaJIT with
+MSVC or WinSDK.
+
+
+Please read the instructions given in these files, before changing
+any settings.
+
+
+LuaJIT on x64 currently uses 32 bit GC objects by default.
+LJ_GC64 mode may be explicitly enabled:
+add XCFLAGS=-DLUAJIT_ENABLE_GC64 to the make command or run
+msvcbuild gc64 for MSVC/WinSDK. Please check the note
+about the bytecode format
+differences, too.
+
+
+
POSIX Systems (Linux, OSX, *BSD etc.)
+
Prerequisites
+
+Depending on your distribution, you may need to install a package for
+GCC, the development headers and/or a complete SDK. E.g. on a current
+Debian/Ubuntu, install libc6-dev with the package manager.
+
+
+Download the current source package of LuaJIT (pick the .tar.gz),
+if you haven't already done so. Move it to a directory of your choice,
+open a terminal window and change to this directory. Now unpack the archive
+and change to the newly created directory:
+
+
+tar zxf LuaJIT-2.0.5.tar.gz
+cd LuaJIT-2.0.5
+
Building LuaJIT
+
+The supplied Makefiles try to auto-detect the settings needed for your
+operating system and your compiler. They need to be run with GNU Make,
+which is probably the default on your system, anyway. Simply run:
+
+
+make
+
+
+This always builds a native binary, depending on the host OS
+you're running this command on. Check the section on
+cross-compilation for more options.
+
+
+By default, modules are only searched under the prefix /usr/local.
+You can add an extra prefix to the search paths by appending the
+PREFIX option, e.g.:
+
+
+make PREFIX=/home/myself/lj2
+
+
+Note for OSX: if the MACOSX_DEPLOYMENT_TARGET environment
+variable is not set, then it's forced to 10.4.
+
+
Installing LuaJIT
+
+The top-level Makefile installs LuaJIT by default under
+/usr/local, i.e. the executable ends up in
+/usr/local/bin and so on. You need root privileges
+to write to this path. So, assuming sudo is installed on your system,
+run the following command and enter your sudo password:
+
+
+sudo make install
+
+
+Otherwise specify the directory prefix as an absolute path, e.g.:
+
+
+make install PREFIX=/home/myself/lj2
+
+
+Obviously the prefixes given during build and installation need to be the same.
+
+
+
Windows Systems
+
Prerequisites
+
+Either install one of the open source SDKs
+(» MinGW or
+» Cygwin), which come with a modified
+GCC plus the required development headers.
+
+
+Or install Microsoft's Visual C++ (MSVC). The freely downloadable
+» Express Edition
+works just fine, but only contains an x86 compiler.
+
+
+The freely downloadable
+» Windows SDK
+only comes with command line tools, but this is all you need to build LuaJIT.
+It contains x86 and x64 compilers.
+
+
+Next, download the source package and unpack it using an archive manager
+(e.g. the Windows Explorer) to a directory of your choice.
+
+
Building with MSVC
+
+Open a "Visual Studio .NET Command Prompt", cd to the
+directory where you've unpacked the sources and run these commands:
+
+
+cd src
+msvcbuild
+
+
+Then follow the installation instructions below.
+
+
Building with the Windows SDK
+
+Open a "Windows SDK Command Shell" and select the x86 compiler:
+
+
+setenv /release /x86
+
+
+Or select the x64 compiler:
+
+
+setenv /release /x64
+
+
+Then cd to the directory where you've unpacked the sources
+and run these commands:
+
+
+cd src
+msvcbuild
+
+
+Then follow the installation instructions below.
+
+
Building with MinGW or Cygwin
+
+Open a command prompt window and make sure the MinGW or Cygwin programs
+are in your path. Then cd to the directory where
+you've unpacked the sources and run this command for MinGW:
+
+
+mingw32-make
+
+
+Or this command for Cygwin:
+
+
+make
+
+
+Then follow the installation instructions below.
+
+
Installing LuaJIT
+
+Copy luajit.exe and lua51.dll (built in the src
+directory) to a newly created directory (any location is ok).
+Add lua and lua\jit directories below it and copy
+all Lua files from the src\jit directory of the distribution
+to the latter directory.
+
+
+There are no hardcoded
+absolute path names — all modules are loaded relative to the
+directory where luajit.exe is installed
+(see src/luaconf.h).
+
+
+
Cross-compiling LuaJIT
+
+First, let's clear up some terminology:
+
+
+
Host: This is your development system, usually based on a x64 or x86 CPU.
+
Target: This is the target system you want LuaJIT to run on, e.g. Android/ARM.
+
Toolchain: This comprises a C compiler, linker, assembler and a matching C library.
+
Host (or system) toolchain: This is the toolchain used to build native binaries for your host system.
+
Cross-compile toolchain: This is the toolchain used to build binaries for the target system. They can only be run on the target system.
+
+
+The GNU Makefile-based build system allows cross-compiling on any host
+for any supported target:
+
+
+
Yes, you need a toolchain for both your host and your target!
+
Both host and target architectures must have the same pointer size.
+
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. libc6-dev-i386 on Debian/Ubuntu) and build a 32 bit host part (HOST_CC="gcc -m32").
+
64 bit targets always require compilation on a 64 bit host.
+
+
+You need to specify TARGET_SYS whenever the host OS and the
+target OS differ, or you'll get assembler or linker errors:
+
+
+
E.g. if you're compiling on a Windows or OSX host for embedded Linux or Android, you need to add TARGET_SYS=Linux to the examples below.
+
For a minimal target OS, you may need to disable the built-in allocator in src/Makefile and use TARGET_SYS=Other.
+
Don't forget to specify the same TARGET_SYS for the install step, too.
+
+
+Here are some examples where host and target have the same CPU:
+
+
+# Cross-compile to a 32 bit binary on a multilib x64 OS
+make CC="gcc -m32"
+
+# Cross-compile on Debian/Ubuntu for Windows (mingw32 package)
+make HOST_CC="gcc -m32" CROSS=i586-mingw32msvc- TARGET_SYS=Windows
+
+
+The CROSS prefix allows specifying a standard GNU cross-compile
+toolchain (Binutils, GCC and a matching libc). The prefix may vary
+depending on the --target the toolchain was built for (note the
+CROSS prefix has a trailing "-"). The examples below
+use the canonical toolchain triplets for Linux.
+
+
+Since there's often no easy way to detect CPU features at runtime, it's
+important to compile with the proper CPU or architecture settings:
+
+
+
The best way to get consistent results is to specify the correct settings when building the toolchain yourself.
+
For a pre-built, generic toolchain add -mcpu=... or -march=... and other necessary flags to TARGET_CFLAGS.
+
For ARM it's important to have the correct -mfloat-abi=... setting, too. Otherwise LuaJIT may not run at the full performance of your target CPU.
+
For MIPS it's important to select a supported ABI (o32 on MIPS32, n64 on MIPS64) and consistently compile your project either with hard-float or soft-float compiler settings.
+
+
+Here are some examples for targets with a different CPU than the host:
+
+
+# ARM soft-float
+make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabi- \
+ TARGET_CFLAGS="-mfloat-abi=soft"
+
+# ARM soft-float ABI with VFP (example for Cortex-A9)
+make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabi- \
+ TARGET_CFLAGS="-mcpu=cortex-a9 -mfloat-abi=softfp"
+
+# ARM hard-float ABI with VFP (armhf, most modern toolchains)
+make HOST_CC="gcc -m32" CROSS=arm-linux-gnueabihf-
+
+# ARM64
+make CROSS=aarch64-linux-
+
+# PPC
+make HOST_CC="gcc -m32" CROSS=powerpc-linux-gnu-
+
+# MIPS32 big-endian
+make HOST_CC="gcc -m32" CROSS=mips-linux-
+# MIPS32 little-endian
+make HOST_CC="gcc -m32" CROSS=mipsel-linux-
+
+# MIPS64 big-endian
+make CROSS=mips-linux- TARGET_CFLAGS="-mips64r2 -mabi=64"
+# MIPS64 little-endian
+make CROSS=mipsel-linux- TARGET_CFLAGS="-mips64r2 -mabi=64"
+
+
+You can cross-compile for Android using the Android NDK.
+The environment variables need to match the install locations and the
+desired target platform. E.g. Android 4.0 corresponds to ABI level 14.
+For details check the folder docs in the NDK directory.
+
+
+Only a few common variations for the different CPUs, ABIs and platforms
+are listed. Please use your own judgement for which combination you want
+to build/deploy or which lowest common denominator you want to pick:
+
+You can cross-compile for iOS 3.0+ (iPhone/iPad) using the » iOS SDK:
+
+
+Note: the JIT compiler is disabled for iOS, because regular iOS Apps
+are not allowed to generate code at runtime. You'll only get the performance
+of the LuaJIT interpreter on iOS. This is still faster than plain Lua, but
+much slower than the JIT compiler. Please complain to Apple, not me.
+Or use Android. :-p
+
+Building LuaJIT for consoles requires both a supported host compiler
+(x86 or x64) and a cross-compiler (to PPC or ARM) from the official
+console SDK.
+
+
+Due to restrictions on consoles, the JIT compiler is disabled and only
+the fast interpreter is built. This is still faster than plain Lua,
+but much slower than the JIT compiler. The FFI is disabled, too, since
+it's not very useful in such an environment.
+
+
+The following commands build a static library libluajit.a,
+which can be linked against your game, just like the Lua library.
+
+
+To cross-compile for PS3 from a Linux host (requires
+32 bit GCC, i.e. multilib Linux/x64) or a Windows host (requires
+32 bit MinGW), run this command:
+
+
+make HOST_CC="gcc -m32" CROSS=ppu-lv2-
+
+
+To cross-compile for PS4 from a Windows host,
+open a "Visual Studio .NET Command Prompt" (64 bit host compiler),
+cd to the directory where you've unpacked the sources and
+run the following commands:
+
+
+cd src
+ps4build
+
+
+To cross-compile for PS Vita from a Windows host,
+open a "Visual Studio .NET Command Prompt" (32 bit host compiler),
+cd to the directory where you've unpacked the sources and
+run the following commands:
+
+
+cd src
+psvitabuild
+
+
+To cross-compile for Xbox 360 from a Windows host,
+open a "Visual Studio .NET Command Prompt" (32 bit host compiler),
+cd to the directory where you've unpacked the sources and run
+the following commands:
+
+
+cd src
+xedkbuild
+
+
+To cross-compile for Xbox One from a Windows host,
+open a "Visual Studio .NET Command Prompt" (64 bit host compiler),
+cd to the directory where you've unpacked the sources and run
+the following commands:
+
+
+cd src
+xb1build
+
+
+
Embedding LuaJIT
+
+LuaJIT is API-compatible with Lua 5.1. If you've already embedded Lua
+into your application, you probably don't need to do anything to switch
+to LuaJIT, except link with a different library:
+
+
+
It's strongly suggested to build LuaJIT separately using the supplied
+build system. Please do not attempt to integrate the individual
+source files into your build tree. You'll most likely get the internal build
+dependencies wrong or mess up the compiler flags. Treat LuaJIT like any
+other external library and link your application with either the dynamic
+or static library, depending on your needs.
+
If you want to load C modules compiled for plain Lua
+with require(), you need to make sure the public symbols
+(e.g. lua_pushnumber) are exported, too:
+
On POSIX systems you can either link to the shared library
+or link the static library into your application. In the latter case
+you'll need to export all public symbols from your main executable
+(e.g. -Wl,-E on Linux) and add the external dependencies
+(e.g. -lm -ldl on Linux).
+
Since Windows symbols are bound to a specific DLL name, you need to
+link to the lua51.dll created by the LuaJIT build (do not rename
+the DLL). You may link LuaJIT statically on Windows only if you don't
+intend to load Lua/C modules at runtime.
+
+
+
+If you're building a 64 bit application on OSX which links directly or
+indirectly against LuaJIT which is not built for LJ_GC64 mode,
+you need to link your main executable with these flags:
+
+-pagezero_size 10000 -image_base 100000000
+
+
+
+
Additional hints for initializing LuaJIT using the C API functions:
+
+
Here's a
+» simple example
+for embedding Lua or LuaJIT into your application.
+
Make sure you use luaL_newstate. Avoid using
+lua_newstate, since this uses the (slower) default memory
+allocator from your system (no support for this on x64).
+
Make sure you use luaL_openlibs and not the old Lua 5.0 style
+of calling luaopen_base etc. directly.
+
To change or extend the list of standard libraries to load, copy
+src/lib_init.c to your project and modify it accordingly.
+Make sure the jit library is loaded or the JIT compiler
+will not be activated.
+
The bit.* module for bitwise operations
+is already built-in. There's no need to statically link
+» Lua BitOp to your application.
+
+
+
Hints for Distribution Maintainers
+
+The LuaJIT build system has extra provisions for the needs of most
+POSIX-based distributions. If you're a package maintainer for
+a distribution, please make use of these features and
+avoid patching, subverting, autotoolizing or messing up the build system
+in unspeakable ways.
+
+
+There should be absolutely no need to patch luaconf.h or any
+of the Makefiles. And please do not hand-pick files for your packages —
+simply use whatever make install creates. There's a reason
+for all of the files and directories it creates.
+
+
+The build system uses GNU make and auto-detects most settings based on
+the host you're building it on. This should work fine for native builds,
+even when sandboxed. You may need to pass some of the following flags to
+both the make and the make install command lines
+for a regular distribution build:
+
+
+
PREFIX overrides the installation path and should usually
+be set to /usr. Setting this also changes the module paths and
+the paths needed to locate the shared library.
+
DESTDIR is an absolute path which allows you to install
+to a shadow tree instead of the root tree of the build system.
+
MULTILIB sets the architecture-specific library path component
+for multilib systems. The default is lib.
+
Have a look at the top-level Makefile and src/Makefile
+for additional variables to tweak. The following variables may be
+overridden, but it's not recommended, except for special needs
+like cross-builds:
+BUILDMODE, CC, HOST_CC, STATIC_CC, DYNAMIC_CC, CFLAGS, HOST_CFLAGS,
+TARGET_CFLAGS, LDFLAGS, HOST_LDFLAGS, TARGET_LDFLAGS, TARGET_SHLDFLAGS,
+TARGET_FLAGS, LIBS, HOST_LIBS, TARGET_LIBS, CROSS, HOST_SYS, TARGET_SYS
+
+
+
+The build system has a special target for an amalgamated build, i.e.
+make amalg. This compiles the LuaJIT core as one huge C file
+and allows GCC to generate faster and shorter code. Alas, this requires
+lots of memory during the build. This may be a problem for some users,
+that's why it's not enabled by default. But it shouldn't be a problem for
+most build farms. It's recommended that binary distributions use this
+target for their LuaJIT builds.
+
+Finally, if you encounter any difficulties, please
+contact me first, instead of releasing a broken
+package onto unsuspecting users. Because they'll usually gonna complain
+to me (the upstream) and not you (the package maintainer), anyway.
+
+LuaJIT is a Just-In-Time Compiler (JIT) for the
+» Lua programming language.
+Lua is a powerful, dynamic and light-weight programming language.
+It may be embedded or used as a general-purpose, stand-alone language.
+
+LuaJIT has been successfully used as a scripting middleware in
+games, appliances, network and graphics apps, numerical simulations,
+trading platforms and many other specialty applications. It scales from
+embedded devices, smartphones, desktops up to server farms. It combines
+high flexibility with » high performance
+and an unmatched low memory footprint.
+
+
+LuaJIT has been in continuous development since 2005. It's widely
+considered to be one of the fastest dynamic language
+implementations. It has outperformed other dynamic languages on many
+cross-language benchmarks since its first release — often by a
+substantial margin.
+
+
+For LuaJIT 2.0, the whole VM has been rewritten from the ground up
+and relentlessly optimized for performance. It combines a high-speed
+interpreter, written in assembler, with a state-of-the-art JIT
+compiler.
+
+
+An innovative trace compiler is integrated with advanced,
+SSA-based optimizations and highly tuned code generation backends.
+A substantial reduction of the overhead associated with dynamic languages
+allows it to break into the performance range traditionally reserved for
+offline, static language compilers.
+
+
+
More ...
+
+Please select a sub-topic in the navigation bar to learn more about LuaJIT.
+
+LuaJIT has only a single stand-alone executable, called luajit on
+POSIX systems or luajit.exe on Windows. It can be used to run simple
+Lua statements or whole Lua applications from the command line. It has an
+interactive mode, too.
+
+
+
Command Line Options
+
+The luajit stand-alone executable is just a slightly modified
+version of the regular lua stand-alone executable.
+It supports the same basic options, too. luajit -h
+prints a short list of the available options. Please have a look at the
+» Lua manual
+for details.
+
+
+LuaJIT has some additional options:
+
+
+
-b[options] input output
+
+This option saves or lists bytecode. The following additional options
+are accepted:
+
+
+
-l — Only list bytecode.
+
-s — Strip debug info (this is the default).
+
-g — Keep debug info.
+
-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).
+
-o os — Override OS for object files (default: native).
+
-e chunk — Use chunk string as input.
+
- (a single minus sign) — Use stdin as input and/or stdout as output.
+
+
+The output file type is auto-detected from the extension of the output
+file name:
+
+
+
c — C source file, exported bytecode data.
+
h — C header file, static bytecode data.
+
obj or o — Object file, exported bytecode data
+(OS- and architecture-specific).
+
raw or any other extension — Raw bytecode file (portable).
+
+
+Notes:
+
+
+
See also string.dump()
+for information on bytecode portability and compatibility.
+
A file in raw bytecode format is auto-detected and can be loaded like
+any Lua source file. E.g. directly from the command line or with
+loadfile(), dofile() etc.
+
To statically embed the bytecode of a module in your application,
+generate an object file and just link it with your application.
+
On most ELF-based systems (e.g. Linux) you need to explicitly export the
+global symbols when linking your application, e.g. with: -Wl,-E
+
require() tries to load embedded bytecode data from exported
+symbols (in *.exe or lua51.dll on Windows) and from
+shared libraries in package.cpath.
+
+
+Typical usage examples:
+
+
+luajit -b test.lua test.out # Save bytecode to test.out
+luajit -bg test.lua test.out # Keep debug info
+luajit -be "print('hello world')" test.out # Save cmdline script
+
+luajit -bl test.lua # List to stdout
+luajit -bl test.lua test.txt # List to test.txt
+luajit -ble "print('hello world')" # List cmdline script
+
+luajit -b test.lua test.obj # Generate object file
+# Link test.obj with your application and load it with require("test")
+
+
+
-j cmd[=arg[,arg...]]
+
+This option performs a LuaJIT control command or activates one of the
+loadable extension modules. The command is first looked up in the
+jit.* library. If no matching function is found, a module
+named jit.<cmd> is loaded and the start()
+function of the module is called with the specified arguments (if
+any). The space between -j and cmd is optional.
+
+
+Here are the available LuaJIT control commands:
+
+
+
-jon — Turns the JIT compiler on (default).
+
-joff — Turns the JIT compiler off (only use the interpreter).
+
-jflush — Flushes the whole cache of compiled code.
+
-jv — Shows verbose information about the progress of the JIT compiler.
+
-jdump — Dumps the code and structures used in various compiler stages.
+The -jv and -jdump commands are extension modules
+written in Lua. They are mainly used for debugging the JIT compiler
+itself. For a description of their options and output format, please
+read the comment block at the start of their source.
+They can be found in the lib directory of the source
+distribution or installed under the jit directory. By default
+this is /usr/local/share/luajit-2.0.5/jit on POSIX
+systems.
+
+
+
-O[level]
+-O[+]flag-O-flag
+-Oparam=value
+
+This options allows fine-tuned control of the optimizations used by
+the JIT compiler. This is mainly intended for debugging LuaJIT itself.
+Please note that the JIT compiler is extremely fast (we are talking
+about the microsecond to millisecond range). Disabling optimizations
+doesn't have any visible impact on its overhead, but usually generates
+code that runs slower.
+
+
+The first form sets an optimization level — this enables a
+specific mix of optimization flags. -O0 turns off all
+optimizations and higher numbers enable more optimizations. Omitting
+the level (i.e. just -O) sets the default optimization level,
+which is -O3 in the current version.
+
+
+The second form adds or removes individual optimization flags.
+The third form sets a parameter for the VM or the JIT compiler
+to a specific value.
+
+
+You can either use this option multiple times (like -Ocse
+-O-dce -Ohotloop=10) or separate several settings with a comma
+(like -O+cse,-dce,hotloop=10). The settings are applied from
+left to right and later settings override earlier ones. You can freely
+mix the three forms, but note that setting an optimization level
+overrides all earlier flags.
+
+
+Here are the available flags and at what optimization levels they
+are enabled:
+
+
+
+
Flag
+
-O1
+
-O2
+
-O3
+
+
+
+
fold
•
•
•
Constant Folding, Simplifications and Reassociation
+
+
cse
•
•
•
Common-Subexpression Elimination
+
+
dce
•
•
•
Dead-Code Elimination
+
+
narrow
•
•
Narrowing of numbers to integers
+
+
loop
•
•
Loop Optimizations (code hoisting)
+
+
fwd
•
Load Forwarding (L2L) and Store Forwarding (S2L)
+
+
dse
•
Dead-Store Elimination
+
+
abc
•
Array Bounds Check Elimination
+
+
sink
•
Allocation/Store Sinking
+
+
fuse
•
Fusion of operands into instructions
+
+
+Here are the parameters and their default settings:
+
+
+
+
Parameter
+
Default
+
+
+
+
maxtrace
1000
Max. number of traces in the cache
+
+
maxrecord
4000
Max. number of recorded IR instructions
+
+
maxirconst
500
Max. number of IR constants of a trace
+
+
maxside
100
Max. number of side traces of a root trace
+
+
maxsnap
500
Max. number of snapshots for a trace
+
+
hotloop
56
Number of iterations to detect a hot loop or hot call
+
+
hotexit
10
Number of taken exits to start a side trace
+
+
tryside
4
Number of attempts to compile a side trace
+
+
instunroll
4
Max. unroll factor for instable loops
+
+
loopunroll
15
Max. unroll factor for loop ops in side traces
+
+
callunroll
3
Max. unroll factor for pseudo-recursive calls
+
+
recunroll
2
Min. unroll factor for true recursion
+
+
sizemcode
32
Size of each machine code area in KBytes (Windows: 64K)
+
+
maxmcode
512
Max. total size of all machine code areas in KBytes
+LuaJIT 2.0 is the current
+stable branch. This branch is in
+feature-freeze — new features will only be added to LuaJIT 2.1.
+
+
+
Current Status
+
+LuaJIT ought to run all Lua 5.1-compatible source code just fine.
+It's considered a serious bug if the VM crashes or produces unexpected
+results — please report this.
+
+
+Known incompatibilities and issues in LuaJIT 2.0:
+
+
+
+There are some differences in implementation-defined behavior.
+These either have a good reason, are arbitrary design choices
+or are due to quirks in the VM. The latter cases may get fixed if a
+demonstrable need is shown.
+
+
+The Lua debug API is missing a couple of features (return
+hooks for non-Lua functions) and shows slightly different behavior
+in LuaJIT (no per-coroutine hooks, no tail call counting).
+
+
+Currently some out-of-memory errors from on-trace code are not
+handled correctly. The error may fall through an on-trace
+pcall or it may be passed on to the function set with
+lua_atpanic on x64. This issue will be fixed with the new
+garbage collector.
+
+
+LuaJIT on 64 bit systems provides a limited range of 47 bits for the
+legacy lightuserdata data type.
+This is only relevant on x64 systems which use the negative part of the
+virtual address space in user mode, e.g. Solaris/x64, and on ARM64 systems
+configured with a 48 bit or 52 bit VA.
+Avoid using lightuserdata to hold pointers that may point outside
+of that range, e.g. variables on the stack. In general, avoid this data
+type for new code and replace it with (much more performant) FFI bindings.
+FFI cdata pointers can address the full 64 bit range.
+
+
+
diff --git a/src/host/luajit-2.1.0-beta3/dynasm/dasm_arm.h b/src/host/luajit-2.1.0-beta3/dynasm/dasm_arm.h
new file mode 100644
index 00000000..a43f7c66
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/dynasm/dasm_arm.h
@@ -0,0 +1,456 @@
+/*
+** DynASM ARM encoding engine.
+** Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+** Released under the MIT license. See dynasm.lua for full copyright notice.
+*/
+
+#include
+#include
+#include
+#include
+
+#define DASM_ARCH "arm"
+
+#ifndef DASM_EXTERN
+#define DASM_EXTERN(a,b,c,d) 0
+#endif
+
+/* Action definitions. */
+enum {
+ DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
+ /* The following actions need a buffer position. */
+ DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
+ /* The following actions also have an argument. */
+ DASM_REL_PC, DASM_LABEL_PC,
+ DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, DASM_IMMV8,
+ DASM__MAX
+};
+
+/* Maximum number of section buffer positions for a single dasm_put() call. */
+#define DASM_MAXSECPOS 25
+
+/* DynASM encoder status codes. Action list offset or number are or'ed in. */
+#define DASM_S_OK 0x00000000
+#define DASM_S_NOMEM 0x01000000
+#define DASM_S_PHASE 0x02000000
+#define DASM_S_MATCH_SEC 0x03000000
+#define DASM_S_RANGE_I 0x11000000
+#define DASM_S_RANGE_SEC 0x12000000
+#define DASM_S_RANGE_LG 0x13000000
+#define DASM_S_RANGE_PC 0x14000000
+#define DASM_S_RANGE_REL 0x15000000
+#define DASM_S_UNDEF_LG 0x21000000
+#define DASM_S_UNDEF_PC 0x22000000
+
+/* Macros to convert positions (8 bit section + 24 bit index). */
+#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
+#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
+#define DASM_SEC2POS(sec) ((sec)<<24)
+#define DASM_POS2SEC(pos) ((pos)>>24)
+#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
+
+/* Action list type. */
+typedef const unsigned int *dasm_ActList;
+
+/* Per-section structure. */
+typedef struct dasm_Section {
+ int *rbuf; /* Biased buffer pointer (negative section bias). */
+ int *buf; /* True buffer pointer. */
+ size_t bsize; /* Buffer size in bytes. */
+ int pos; /* Biased buffer position. */
+ int epos; /* End of biased buffer position - max single put. */
+ int ofs; /* Byte offset into section. */
+} dasm_Section;
+
+/* Core structure holding the DynASM encoding state. */
+struct dasm_State {
+ size_t psize; /* Allocated size of this structure. */
+ dasm_ActList actionlist; /* Current actionlist pointer. */
+ int *lglabels; /* Local/global chain/pos ptrs. */
+ size_t lgsize;
+ int *pclabels; /* PC label chains/pos ptrs. */
+ size_t pcsize;
+ void **globals; /* Array of globals (bias -10). */
+ dasm_Section *section; /* Pointer to active section. */
+ size_t codesize; /* Total size of all code sections. */
+ int maxsection; /* 0 <= sectionidx < maxsection. */
+ int status; /* Status code. */
+ dasm_Section sections[1]; /* All sections. Alloc-extended. */
+};
+
+/* The size of the core structure depends on the max. number of sections. */
+#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
+
+
+/* Initialize DynASM state. */
+void dasm_init(Dst_DECL, int maxsection)
+{
+ dasm_State *D;
+ size_t psz = 0;
+ int i;
+ Dst_REF = NULL;
+ DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
+ D = Dst_REF;
+ D->psize = psz;
+ D->lglabels = NULL;
+ D->lgsize = 0;
+ D->pclabels = NULL;
+ D->pcsize = 0;
+ D->globals = NULL;
+ D->maxsection = maxsection;
+ for (i = 0; i < maxsection; i++) {
+ D->sections[i].buf = NULL; /* Need this for pass3. */
+ D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
+ D->sections[i].bsize = 0;
+ D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
+ }
+}
+
+/* Free DynASM state. */
+void dasm_free(Dst_DECL)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ for (i = 0; i < D->maxsection; i++)
+ if (D->sections[i].buf)
+ DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
+ if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
+ if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
+ DASM_M_FREE(Dst, D, D->psize);
+}
+
+/* Setup global label array. Must be called before dasm_setup(). */
+void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
+{
+ dasm_State *D = Dst_REF;
+ D->globals = gl - 10; /* Negative bias to compensate for locals. */
+ DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
+}
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+void dasm_growpc(Dst_DECL, unsigned int maxpc)
+{
+ dasm_State *D = Dst_REF;
+ size_t osz = D->pcsize;
+ DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
+ memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
+}
+
+/* Setup encoder. */
+void dasm_setup(Dst_DECL, const void *actionlist)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ D->actionlist = (dasm_ActList)actionlist;
+ D->status = DASM_S_OK;
+ D->section = &D->sections[0];
+ memset((void *)D->lglabels, 0, D->lgsize);
+ if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
+ for (i = 0; i < D->maxsection; i++) {
+ D->sections[i].pos = DASM_SEC2POS(i);
+ D->sections[i].ofs = 0;
+ }
+}
+
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) { \
+ D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
+#define CKPL(kind, st) \
+ do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
+ D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
+#else
+#define CK(x, st) ((void)0)
+#define CKPL(kind, st) ((void)0)
+#endif
+
+static int dasm_imm12(unsigned int n)
+{
+ int i;
+ for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30))
+ if (n <= 255) return (int)(n + (i << 8));
+ return -1;
+}
+
+/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
+void dasm_put(Dst_DECL, int start, ...)
+{
+ va_list ap;
+ dasm_State *D = Dst_REF;
+ dasm_ActList p = D->actionlist + start;
+ dasm_Section *sec = D->section;
+ int pos = sec->pos, ofs = sec->ofs;
+ int *b;
+
+ if (pos >= sec->epos) {
+ DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
+ sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
+ sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
+ sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
+ }
+
+ b = sec->rbuf;
+ b[pos++] = start;
+
+ va_start(ap, start);
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ if (action >= DASM__MAX) {
+ ofs += 4;
+ } else {
+ int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
+ switch (action) {
+ case DASM_STOP: goto stop;
+ case DASM_SECTION:
+ n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
+ D->section = &D->sections[n]; goto stop;
+ case DASM_ESC: p++; ofs += 4; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
+ case DASM_REL_LG:
+ n = (ins & 2047) - 10; pl = D->lglabels + n;
+ /* Bkwd rel or global. */
+ if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
+ pl += 10; n = *pl;
+ if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
+ goto linkrel;
+ case DASM_REL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putrel:
+ n = *pl;
+ if (n < 0) { /* Label exists. Get label pos and store it. */
+ b[pos] = -n;
+ } else {
+ linkrel:
+ b[pos] = n; /* Else link to rel chain, anchored at label. */
+ *pl = pos;
+ }
+ pos++;
+ break;
+ case DASM_LABEL_LG:
+ pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
+ case DASM_LABEL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putlabel:
+ n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
+ }
+ *pl = -pos; /* Label exists now. */
+ b[pos++] = ofs; /* Store pass1 offset estimate. */
+ break;
+ case DASM_IMM:
+ case DASM_IMM16:
+#ifdef DASM_CHECKS
+ CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
+ if ((ins & 0x8000))
+ CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
+ else
+ CK((n>>((ins>>5)&31)) == 0, RANGE_I);
+#endif
+ b[pos++] = n;
+ break;
+ case DASM_IMMV8:
+ CK((n & 3) == 0, RANGE_I);
+ n >>= 2;
+ case DASM_IMML8:
+ case DASM_IMML12:
+ CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) :
+ (((-n)>>((ins>>5)&31)) == 0), RANGE_I);
+ b[pos++] = n;
+ break;
+ case DASM_IMM12:
+ CK(dasm_imm12((unsigned int)n) != -1, RANGE_I);
+ b[pos++] = n;
+ break;
+ }
+ }
+ }
+stop:
+ va_end(ap);
+ sec->pos = pos;
+ sec->ofs = ofs;
+}
+#undef CK
+
+/* Pass 2: Link sections, shrink aligns, fix label offsets. */
+int dasm_link(Dst_DECL, size_t *szp)
+{
+ dasm_State *D = Dst_REF;
+ int secnum;
+ int ofs = 0;
+
+#ifdef DASM_CHECKS
+ *szp = 0;
+ if (D->status != DASM_S_OK) return D->status;
+ {
+ int pc;
+ for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
+ if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
+ }
+#endif
+
+ { /* Handle globals not defined in this translation unit. */
+ int idx;
+ for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
+ int n = D->lglabels[idx];
+ /* Undefined label: Collapse rel chain and replace with marker (< 0). */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
+ }
+ }
+
+ /* Combine all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->rbuf;
+ int pos = DASM_SEC2POS(secnum);
+ int lastpos = sec->pos;
+
+ while (pos != lastpos) {
+ dasm_ActList p = D->actionlist + b[pos++];
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: p++; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
+ case DASM_REL_LG: case DASM_REL_PC: pos++; break;
+ case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
+ case DASM_IMM: case DASM_IMM12: case DASM_IMM16:
+ case DASM_IMML8: case DASM_IMML12: case DASM_IMMV8: pos++; break;
+ }
+ }
+ stop: (void)0;
+ }
+ ofs += sec->ofs; /* Next section starts right after current section. */
+ }
+
+ D->codesize = ofs; /* Total size of all code sections */
+ *szp = ofs;
+ return DASM_S_OK;
+}
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
+#else
+#define CK(x, st) ((void)0)
+#endif
+
+/* Pass 3: Encode sections. */
+int dasm_encode(Dst_DECL, void *buffer)
+{
+ dasm_State *D = Dst_REF;
+ char *base = (char *)buffer;
+ unsigned int *cp = (unsigned int *)buffer;
+ int secnum;
+
+ /* Encode all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->buf;
+ int *endb = sec->rbuf + sec->pos;
+
+ while (b != endb) {
+ dasm_ActList p = D->actionlist + *b++;
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: *cp++ = *p++; break;
+ case DASM_REL_EXT:
+ n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048));
+ goto patchrel;
+ case DASM_ALIGN:
+ ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000;
+ break;
+ case DASM_REL_LG:
+ CK(n >= 0, UNDEF_LG);
+ case DASM_REL_PC:
+ CK(n >= 0, UNDEF_PC);
+ n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4;
+ patchrel:
+ if ((ins & 0x800) == 0) {
+ CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL);
+ cp[-1] |= ((n >> 2) & 0x00ffffff);
+ } else if ((ins & 0x1000)) {
+ CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL);
+ goto patchimml8;
+ } else if ((ins & 0x2000) == 0) {
+ CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL);
+ goto patchimml;
+ } else {
+ CK((n & 3) == 0 && -1020 <= n && n <= 1020, RANGE_REL);
+ n >>= 2;
+ goto patchimml;
+ }
+ break;
+ case DASM_LABEL_LG:
+ ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
+ break;
+ case DASM_LABEL_PC: break;
+ case DASM_IMM:
+ cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31);
+ break;
+ case DASM_IMM12:
+ cp[-1] |= dasm_imm12((unsigned int)n);
+ break;
+ case DASM_IMM16:
+ cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff);
+ break;
+ case DASM_IMML8: patchimml8:
+ cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) :
+ ((-n & 0x0f) | ((-n & 0xf0) << 4));
+ break;
+ case DASM_IMML12: case DASM_IMMV8: patchimml:
+ cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n);
+ break;
+ default: *cp++ = ins; break;
+ }
+ }
+ stop: (void)0;
+ }
+ }
+
+ if (base + D->codesize != (char *)cp) /* Check for phase errors. */
+ return DASM_S_PHASE;
+ return DASM_S_OK;
+}
+#undef CK
+
+/* Get PC label offset. */
+int dasm_getpclabel(Dst_DECL, unsigned int pc)
+{
+ dasm_State *D = Dst_REF;
+ if (pc*sizeof(int) < D->pcsize) {
+ int pos = D->pclabels[pc];
+ if (pos < 0) return *DASM_POS2PTR(D, -pos);
+ if (pos > 0) return -1; /* Undefined. */
+ }
+ return -2; /* Unused or out of range. */
+}
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+int dasm_checkstep(Dst_DECL, int secmatch)
+{
+ dasm_State *D = Dst_REF;
+ if (D->status == DASM_S_OK) {
+ int i;
+ for (i = 1; i <= 9; i++) {
+ if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
+ D->lglabels[i] = 0;
+ }
+ }
+ if (D->status == DASM_S_OK && secmatch >= 0 &&
+ D->section != &D->sections[secmatch])
+ D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
+ return D->status;
+}
+#endif
+
diff --git a/src/host/luajit-2.1.0-beta3/dynasm/dasm_arm.lua b/src/host/luajit-2.1.0-beta3/dynasm/dasm_arm.lua
new file mode 100644
index 00000000..32f595af
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/dynasm/dasm_arm.lua
@@ -0,0 +1,1125 @@
+------------------------------------------------------------------------------
+-- DynASM ARM module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+
+-- Module information:
+local _info = {
+ arch = "arm",
+ description = "DynASM ARM module",
+ version = "1.4.0",
+ vernum = 10400,
+ release = "2015-10-18",
+ author = "Mike Pall",
+ license = "MIT",
+}
+
+-- Exported glue functions for the arch-specific module.
+local _M = { _info = _info }
+
+-- Cache library functions.
+local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
+local assert, setmetatable, rawget = assert, setmetatable, rawget
+local _s = string
+local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
+local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub
+local concat, sort, insert = table.concat, table.sort, table.insert
+local bit = bit or require("bit")
+local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift
+local ror, tohex = bit.ror, bit.tohex
+
+-- Inherited tables and callbacks.
+local g_opt, g_arch
+local wline, werror, wfatal, wwarn
+
+-- Action name list.
+-- CHECK: Keep this in sync with the C code!
+local action_names = {
+ "STOP", "SECTION", "ESC", "REL_EXT",
+ "ALIGN", "REL_LG", "LABEL_LG",
+ "REL_PC", "LABEL_PC", "IMM", "IMM12", "IMM16", "IMML8", "IMML12", "IMMV8",
+}
+
+-- Maximum number of section buffer positions for dasm_put().
+-- CHECK: Keep this in sync with the C code!
+local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
+
+-- Action name -> action number.
+local map_action = {}
+for n,name in ipairs(action_names) do
+ map_action[name] = n-1
+end
+
+-- Action list buffer.
+local actlist = {}
+
+-- Argument list for next dasm_put(). Start with offset 0 into action list.
+local actargs = { 0 }
+
+-- Current number of section buffer positions for dasm_put().
+local secpos = 1
+
+------------------------------------------------------------------------------
+
+-- Dump action names and numbers.
+local function dumpactions(out)
+ out:write("DynASM encoding engine action codes:\n")
+ for n,name in ipairs(action_names) do
+ local num = map_action[name]
+ out:write(format(" %-10s %02X %d\n", name, num, num))
+ end
+ out:write("\n")
+end
+
+-- Write action list buffer as a huge static C array.
+local function writeactions(out, name)
+ local nn = #actlist
+ if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
+ out:write("static const unsigned int ", name, "[", nn, "] = {\n")
+ for i = 1,nn-1 do
+ assert(out:write("0x", tohex(actlist[i]), ",\n"))
+ end
+ assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
+end
+
+------------------------------------------------------------------------------
+
+-- Add word to action list.
+local function wputxw(n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ actlist[#actlist+1] = n
+end
+
+-- Add action to list with optional arg. Advance buffer pos, too.
+local function waction(action, val, a, num)
+ local w = assert(map_action[action], "bad action name `"..action.."'")
+ wputxw(w * 0x10000 + (val or 0))
+ if a then actargs[#actargs+1] = a end
+ if a or num then secpos = secpos + (num or 1) end
+end
+
+-- Flush action list (intervening C code or buffer pos overflow).
+local function wflush(term)
+ if #actlist == actargs[1] then return end -- Nothing to flush.
+ if not term then waction("STOP") end -- Terminate action list.
+ wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
+ actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
+ secpos = 1 -- The actionlist offset occupies a buffer position, too.
+end
+
+-- Put escaped word.
+local function wputw(n)
+ if n <= 0x000fffff then waction("ESC") end
+ wputxw(n)
+end
+
+-- Reserve position for word.
+local function wpos()
+ local pos = #actlist+1
+ actlist[pos] = ""
+ return pos
+end
+
+-- Store word to reserved position.
+local function wputpos(pos, n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ if n <= 0x000fffff then
+ insert(actlist, pos+1, n)
+ n = map_action.ESC * 0x10000
+ end
+ actlist[pos] = n
+end
+
+------------------------------------------------------------------------------
+
+-- Global label name -> global label number. With auto assignment on 1st use.
+local next_global = 20
+local map_global = setmetatable({}, { __index = function(t, name)
+ if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
+ local n = next_global
+ if n > 2047 then werror("too many global labels") end
+ next_global = n + 1
+ t[name] = n
+ return n
+end})
+
+-- Dump global labels.
+local function dumpglobals(out, lvl)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("Global labels:\n")
+ for i=20,next_global-1 do
+ out:write(format(" %s\n", t[i]))
+ end
+ out:write("\n")
+end
+
+-- Write global label enum.
+local function writeglobals(out, prefix)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("enum {\n")
+ for i=20,next_global-1 do
+ out:write(" ", prefix, t[i], ",\n")
+ end
+ out:write(" ", prefix, "_MAX\n};\n")
+end
+
+-- Write global label names.
+local function writeglobalnames(out, name)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=20,next_global-1 do
+ out:write(" \"", t[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Extern label name -> extern label number. With auto assignment on 1st use.
+local next_extern = 0
+local map_extern_ = {}
+local map_extern = setmetatable({}, { __index = function(t, name)
+ -- No restrictions on the name for now.
+ local n = next_extern
+ if n > 2047 then werror("too many extern labels") end
+ next_extern = n + 1
+ t[name] = n
+ map_extern_[n] = name
+ return n
+end})
+
+-- Dump extern labels.
+local function dumpexterns(out, lvl)
+ out:write("Extern labels:\n")
+ for i=0,next_extern-1 do
+ out:write(format(" %s\n", map_extern_[i]))
+ end
+ out:write("\n")
+end
+
+-- Write extern label names.
+local function writeexternnames(out, name)
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=0,next_extern-1 do
+ out:write(" \"", map_extern_[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Arch-specific maps.
+
+-- Ext. register name -> int. name.
+local map_archdef = { sp = "r13", lr = "r14", pc = "r15", }
+
+-- Int. register name -> ext. name.
+local map_reg_rev = { r13 = "sp", r14 = "lr", r15 = "pc", }
+
+local map_type = {} -- Type name -> { ctype, reg }
+local ctypenum = 0 -- Type number (for Dt... macros).
+
+-- Reverse defines for registers.
+function _M.revdef(s)
+ return map_reg_rev[s] or s
+end
+
+local map_shift = { lsl = 0, lsr = 1, asr = 2, ror = 3, }
+
+local map_cond = {
+ eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7,
+ hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14,
+ hs = 2, lo = 3,
+}
+
+------------------------------------------------------------------------------
+
+-- Template strings for ARM instructions.
+local map_op = {
+ -- Basic data processing instructions.
+ and_3 = "e0000000DNPs",
+ eor_3 = "e0200000DNPs",
+ sub_3 = "e0400000DNPs",
+ rsb_3 = "e0600000DNPs",
+ add_3 = "e0800000DNPs",
+ adc_3 = "e0a00000DNPs",
+ sbc_3 = "e0c00000DNPs",
+ rsc_3 = "e0e00000DNPs",
+ tst_2 = "e1100000NP",
+ teq_2 = "e1300000NP",
+ cmp_2 = "e1500000NP",
+ cmn_2 = "e1700000NP",
+ orr_3 = "e1800000DNPs",
+ mov_2 = "e1a00000DPs",
+ bic_3 = "e1c00000DNPs",
+ mvn_2 = "e1e00000DPs",
+
+ and_4 = "e0000000DNMps",
+ eor_4 = "e0200000DNMps",
+ sub_4 = "e0400000DNMps",
+ rsb_4 = "e0600000DNMps",
+ add_4 = "e0800000DNMps",
+ adc_4 = "e0a00000DNMps",
+ sbc_4 = "e0c00000DNMps",
+ rsc_4 = "e0e00000DNMps",
+ tst_3 = "e1100000NMp",
+ teq_3 = "e1300000NMp",
+ cmp_3 = "e1500000NMp",
+ cmn_3 = "e1700000NMp",
+ orr_4 = "e1800000DNMps",
+ mov_3 = "e1a00000DMps",
+ bic_4 = "e1c00000DNMps",
+ mvn_3 = "e1e00000DMps",
+
+ lsl_3 = "e1a00000DMws",
+ lsr_3 = "e1a00020DMws",
+ asr_3 = "e1a00040DMws",
+ ror_3 = "e1a00060DMws",
+ rrx_2 = "e1a00060DMs",
+
+ -- Multiply and multiply-accumulate.
+ mul_3 = "e0000090NMSs",
+ mla_4 = "e0200090NMSDs",
+ umaal_4 = "e0400090DNMSs", -- v6
+ mls_4 = "e0600090DNMSs", -- v6T2
+ umull_4 = "e0800090DNMSs",
+ umlal_4 = "e0a00090DNMSs",
+ smull_4 = "e0c00090DNMSs",
+ smlal_4 = "e0e00090DNMSs",
+
+ -- Halfword multiply and multiply-accumulate.
+ smlabb_4 = "e1000080NMSD", -- v5TE
+ smlatb_4 = "e10000a0NMSD", -- v5TE
+ smlabt_4 = "e10000c0NMSD", -- v5TE
+ smlatt_4 = "e10000e0NMSD", -- v5TE
+ smlawb_4 = "e1200080NMSD", -- v5TE
+ smulwb_3 = "e12000a0NMS", -- v5TE
+ smlawt_4 = "e12000c0NMSD", -- v5TE
+ smulwt_3 = "e12000e0NMS", -- v5TE
+ smlalbb_4 = "e1400080NMSD", -- v5TE
+ smlaltb_4 = "e14000a0NMSD", -- v5TE
+ smlalbt_4 = "e14000c0NMSD", -- v5TE
+ smlaltt_4 = "e14000e0NMSD", -- v5TE
+ smulbb_3 = "e1600080NMS", -- v5TE
+ smultb_3 = "e16000a0NMS", -- v5TE
+ smulbt_3 = "e16000c0NMS", -- v5TE
+ smultt_3 = "e16000e0NMS", -- v5TE
+
+ -- Miscellaneous data processing instructions.
+ clz_2 = "e16f0f10DM", -- v5T
+ rev_2 = "e6bf0f30DM", -- v6
+ rev16_2 = "e6bf0fb0DM", -- v6
+ revsh_2 = "e6ff0fb0DM", -- v6
+ sel_3 = "e6800fb0DNM", -- v6
+ usad8_3 = "e780f010NMS", -- v6
+ usada8_4 = "e7800010NMSD", -- v6
+ rbit_2 = "e6ff0f30DM", -- v6T2
+ movw_2 = "e3000000DW", -- v6T2
+ movt_2 = "e3400000DW", -- v6T2
+ -- Note: the X encodes width-1, not width.
+ sbfx_4 = "e7a00050DMvX", -- v6T2
+ ubfx_4 = "e7e00050DMvX", -- v6T2
+ -- Note: the X encodes the msb field, not the width.
+ bfc_3 = "e7c0001fDvX", -- v6T2
+ bfi_4 = "e7c00010DMvX", -- v6T2
+
+ -- Packing and unpacking instructions.
+ pkhbt_3 = "e6800010DNM", pkhbt_4 = "e6800010DNMv", -- v6
+ pkhtb_3 = "e6800050DNM", pkhtb_4 = "e6800050DNMv", -- v6
+ sxtab_3 = "e6a00070DNM", sxtab_4 = "e6a00070DNMv", -- v6
+ sxtab16_3 = "e6800070DNM", sxtab16_4 = "e6800070DNMv", -- v6
+ sxtah_3 = "e6b00070DNM", sxtah_4 = "e6b00070DNMv", -- v6
+ sxtb_2 = "e6af0070DM", sxtb_3 = "e6af0070DMv", -- v6
+ sxtb16_2 = "e68f0070DM", sxtb16_3 = "e68f0070DMv", -- v6
+ sxth_2 = "e6bf0070DM", sxth_3 = "e6bf0070DMv", -- v6
+ uxtab_3 = "e6e00070DNM", uxtab_4 = "e6e00070DNMv", -- v6
+ uxtab16_3 = "e6c00070DNM", uxtab16_4 = "e6c00070DNMv", -- v6
+ uxtah_3 = "e6f00070DNM", uxtah_4 = "e6f00070DNMv", -- v6
+ uxtb_2 = "e6ef0070DM", uxtb_3 = "e6ef0070DMv", -- v6
+ uxtb16_2 = "e6cf0070DM", uxtb16_3 = "e6cf0070DMv", -- v6
+ uxth_2 = "e6ff0070DM", uxth_3 = "e6ff0070DMv", -- v6
+
+ -- Saturating instructions.
+ qadd_3 = "e1000050DMN", -- v5TE
+ qsub_3 = "e1200050DMN", -- v5TE
+ qdadd_3 = "e1400050DMN", -- v5TE
+ qdsub_3 = "e1600050DMN", -- v5TE
+ -- Note: the X for ssat* encodes sat_imm-1, not sat_imm.
+ ssat_3 = "e6a00010DXM", ssat_4 = "e6a00010DXMp", -- v6
+ usat_3 = "e6e00010DXM", usat_4 = "e6e00010DXMp", -- v6
+ ssat16_3 = "e6a00f30DXM", -- v6
+ usat16_3 = "e6e00f30DXM", -- v6
+
+ -- Parallel addition and subtraction.
+ sadd16_3 = "e6100f10DNM", -- v6
+ sasx_3 = "e6100f30DNM", -- v6
+ ssax_3 = "e6100f50DNM", -- v6
+ ssub16_3 = "e6100f70DNM", -- v6
+ sadd8_3 = "e6100f90DNM", -- v6
+ ssub8_3 = "e6100ff0DNM", -- v6
+ qadd16_3 = "e6200f10DNM", -- v6
+ qasx_3 = "e6200f30DNM", -- v6
+ qsax_3 = "e6200f50DNM", -- v6
+ qsub16_3 = "e6200f70DNM", -- v6
+ qadd8_3 = "e6200f90DNM", -- v6
+ qsub8_3 = "e6200ff0DNM", -- v6
+ shadd16_3 = "e6300f10DNM", -- v6
+ shasx_3 = "e6300f30DNM", -- v6
+ shsax_3 = "e6300f50DNM", -- v6
+ shsub16_3 = "e6300f70DNM", -- v6
+ shadd8_3 = "e6300f90DNM", -- v6
+ shsub8_3 = "e6300ff0DNM", -- v6
+ uadd16_3 = "e6500f10DNM", -- v6
+ uasx_3 = "e6500f30DNM", -- v6
+ usax_3 = "e6500f50DNM", -- v6
+ usub16_3 = "e6500f70DNM", -- v6
+ uadd8_3 = "e6500f90DNM", -- v6
+ usub8_3 = "e6500ff0DNM", -- v6
+ uqadd16_3 = "e6600f10DNM", -- v6
+ uqasx_3 = "e6600f30DNM", -- v6
+ uqsax_3 = "e6600f50DNM", -- v6
+ uqsub16_3 = "e6600f70DNM", -- v6
+ uqadd8_3 = "e6600f90DNM", -- v6
+ uqsub8_3 = "e6600ff0DNM", -- v6
+ uhadd16_3 = "e6700f10DNM", -- v6
+ uhasx_3 = "e6700f30DNM", -- v6
+ uhsax_3 = "e6700f50DNM", -- v6
+ uhsub16_3 = "e6700f70DNM", -- v6
+ uhadd8_3 = "e6700f90DNM", -- v6
+ uhsub8_3 = "e6700ff0DNM", -- v6
+
+ -- Load/store instructions.
+ str_2 = "e4000000DL", str_3 = "e4000000DL", str_4 = "e4000000DL",
+ strb_2 = "e4400000DL", strb_3 = "e4400000DL", strb_4 = "e4400000DL",
+ ldr_2 = "e4100000DL", ldr_3 = "e4100000DL", ldr_4 = "e4100000DL",
+ ldrb_2 = "e4500000DL", ldrb_3 = "e4500000DL", ldrb_4 = "e4500000DL",
+ strh_2 = "e00000b0DL", strh_3 = "e00000b0DL",
+ ldrh_2 = "e01000b0DL", ldrh_3 = "e01000b0DL",
+ ldrd_2 = "e00000d0DL", ldrd_3 = "e00000d0DL", -- v5TE
+ ldrsb_2 = "e01000d0DL", ldrsb_3 = "e01000d0DL",
+ strd_2 = "e00000f0DL", strd_3 = "e00000f0DL", -- v5TE
+ ldrsh_2 = "e01000f0DL", ldrsh_3 = "e01000f0DL",
+
+ ldm_2 = "e8900000oR", ldmia_2 = "e8900000oR", ldmfd_2 = "e8900000oR",
+ ldmda_2 = "e8100000oR", ldmfa_2 = "e8100000oR",
+ ldmdb_2 = "e9100000oR", ldmea_2 = "e9100000oR",
+ ldmib_2 = "e9900000oR", ldmed_2 = "e9900000oR",
+ stm_2 = "e8800000oR", stmia_2 = "e8800000oR", stmfd_2 = "e8800000oR",
+ stmda_2 = "e8000000oR", stmfa_2 = "e8000000oR",
+ stmdb_2 = "e9000000oR", stmea_2 = "e9000000oR",
+ stmib_2 = "e9800000oR", stmed_2 = "e9800000oR",
+ pop_1 = "e8bd0000R", push_1 = "e92d0000R",
+
+ -- Branch instructions.
+ b_1 = "ea000000B",
+ bl_1 = "eb000000B",
+ blx_1 = "e12fff30C",
+ bx_1 = "e12fff10M",
+
+ -- Miscellaneous instructions.
+ nop_0 = "e1a00000",
+ mrs_1 = "e10f0000D",
+ bkpt_1 = "e1200070K", -- v5T
+ svc_1 = "ef000000T", swi_1 = "ef000000T",
+ ud_0 = "e7f001f0",
+
+ -- VFP instructions.
+ ["vadd.f32_3"] = "ee300a00dnm",
+ ["vadd.f64_3"] = "ee300b00Gdnm",
+ ["vsub.f32_3"] = "ee300a40dnm",
+ ["vsub.f64_3"] = "ee300b40Gdnm",
+ ["vmul.f32_3"] = "ee200a00dnm",
+ ["vmul.f64_3"] = "ee200b00Gdnm",
+ ["vnmul.f32_3"] = "ee200a40dnm",
+ ["vnmul.f64_3"] = "ee200b40Gdnm",
+ ["vmla.f32_3"] = "ee000a00dnm",
+ ["vmla.f64_3"] = "ee000b00Gdnm",
+ ["vmls.f32_3"] = "ee000a40dnm",
+ ["vmls.f64_3"] = "ee000b40Gdnm",
+ ["vnmla.f32_3"] = "ee100a40dnm",
+ ["vnmla.f64_3"] = "ee100b40Gdnm",
+ ["vnmls.f32_3"] = "ee100a00dnm",
+ ["vnmls.f64_3"] = "ee100b00Gdnm",
+ ["vdiv.f32_3"] = "ee800a00dnm",
+ ["vdiv.f64_3"] = "ee800b00Gdnm",
+
+ ["vabs.f32_2"] = "eeb00ac0dm",
+ ["vabs.f64_2"] = "eeb00bc0Gdm",
+ ["vneg.f32_2"] = "eeb10a40dm",
+ ["vneg.f64_2"] = "eeb10b40Gdm",
+ ["vsqrt.f32_2"] = "eeb10ac0dm",
+ ["vsqrt.f64_2"] = "eeb10bc0Gdm",
+ ["vcmp.f32_2"] = "eeb40a40dm",
+ ["vcmp.f64_2"] = "eeb40b40Gdm",
+ ["vcmpe.f32_2"] = "eeb40ac0dm",
+ ["vcmpe.f64_2"] = "eeb40bc0Gdm",
+ ["vcmpz.f32_1"] = "eeb50a40d",
+ ["vcmpz.f64_1"] = "eeb50b40Gd",
+ ["vcmpze.f32_1"] = "eeb50ac0d",
+ ["vcmpze.f64_1"] = "eeb50bc0Gd",
+
+ vldr_2 = "ed100a00dl|ed100b00Gdl",
+ vstr_2 = "ed000a00dl|ed000b00Gdl",
+ vldm_2 = "ec900a00or",
+ vldmia_2 = "ec900a00or",
+ vldmdb_2 = "ed100a00or",
+ vpop_1 = "ecbd0a00r",
+ vstm_2 = "ec800a00or",
+ vstmia_2 = "ec800a00or",
+ vstmdb_2 = "ed000a00or",
+ vpush_1 = "ed2d0a00r",
+
+ ["vmov.f32_2"] = "eeb00a40dm|eeb00a00dY", -- #imm is VFPv3 only
+ ["vmov.f64_2"] = "eeb00b40Gdm|eeb00b00GdY", -- #imm is VFPv3 only
+ vmov_2 = "ee100a10Dn|ee000a10nD",
+ vmov_3 = "ec500a10DNm|ec400a10mDN|ec500b10GDNm|ec400b10GmDN",
+
+ vmrs_0 = "eef1fa10",
+ vmrs_1 = "eef10a10D",
+ vmsr_1 = "eee10a10D",
+
+ ["vcvt.s32.f32_2"] = "eebd0ac0dm",
+ ["vcvt.s32.f64_2"] = "eebd0bc0dGm",
+ ["vcvt.u32.f32_2"] = "eebc0ac0dm",
+ ["vcvt.u32.f64_2"] = "eebc0bc0dGm",
+ ["vcvtr.s32.f32_2"] = "eebd0a40dm",
+ ["vcvtr.s32.f64_2"] = "eebd0b40dGm",
+ ["vcvtr.u32.f32_2"] = "eebc0a40dm",
+ ["vcvtr.u32.f64_2"] = "eebc0b40dGm",
+ ["vcvt.f32.s32_2"] = "eeb80ac0dm",
+ ["vcvt.f64.s32_2"] = "eeb80bc0GdFm",
+ ["vcvt.f32.u32_2"] = "eeb80a40dm",
+ ["vcvt.f64.u32_2"] = "eeb80b40GdFm",
+ ["vcvt.f32.f64_2"] = "eeb70bc0dGm",
+ ["vcvt.f64.f32_2"] = "eeb70ac0GdFm",
+
+ -- VFPv4 only:
+ ["vfma.f32_3"] = "eea00a00dnm",
+ ["vfma.f64_3"] = "eea00b00Gdnm",
+ ["vfms.f32_3"] = "eea00a40dnm",
+ ["vfms.f64_3"] = "eea00b40Gdnm",
+ ["vfnma.f32_3"] = "ee900a40dnm",
+ ["vfnma.f64_3"] = "ee900b40Gdnm",
+ ["vfnms.f32_3"] = "ee900a00dnm",
+ ["vfnms.f64_3"] = "ee900b00Gdnm",
+
+ -- NYI: Advanced SIMD instructions.
+
+ -- NYI: I have no need for these instructions right now:
+ -- swp, swpb, strex, ldrex, strexd, ldrexd, strexb, ldrexb, strexh, ldrexh
+ -- msr, nopv6, yield, wfe, wfi, sev, dbg, bxj, smc, srs, rfe
+ -- cps, setend, pli, pld, pldw, clrex, dsb, dmb, isb
+ -- stc, ldc, mcr, mcr2, mrc, mrc2, mcrr, mcrr2, mrrc, mrrc2, cdp, cdp2
+}
+
+-- Add mnemonics for "s" variants.
+do
+ local t = {}
+ for k,v in pairs(map_op) do
+ if sub(v, -1) == "s" then
+ local v2 = sub(v, 1, 2)..char(byte(v, 3)+1)..sub(v, 4, -2)
+ t[sub(k, 1, -3).."s"..sub(k, -2)] = v2
+ end
+ end
+ for k,v in pairs(t) do
+ map_op[k] = v
+ end
+end
+
+------------------------------------------------------------------------------
+
+local function parse_gpr(expr)
+ local tname, ovreg = match(expr, "^([%w_]+):(r1?[0-9])$")
+ local tp = map_type[tname or expr]
+ if tp then
+ local reg = ovreg or tp.reg
+ if not reg then
+ werror("type `"..(tname or expr).."' needs a register override")
+ end
+ expr = reg
+ end
+ local r = match(expr, "^r(1?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 15 then return r, tp end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_gpr_pm(expr)
+ local pm, expr2 = match(expr, "^([+-]?)(.*)$")
+ return parse_gpr(expr2), (pm == "-")
+end
+
+local function parse_vr(expr, tp)
+ local t, r = match(expr, "^([sd])([0-9]+)$")
+ if t == tp then
+ r = tonumber(r)
+ if r <= 31 then
+ if t == "s" then return shr(r, 1), band(r, 1) end
+ return band(r, 15), shr(r, 4)
+ end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_reglist(reglist)
+ reglist = match(reglist, "^{%s*([^}]*)}$")
+ if not reglist then werror("register list expected") end
+ local rr = 0
+ for p in gmatch(reglist..",", "%s*([^,]*),") do
+ local rbit = shl(1, parse_gpr(gsub(p, "%s+$", "")))
+ if band(rr, rbit) ~= 0 then
+ werror("duplicate register `"..p.."'")
+ end
+ rr = rr + rbit
+ end
+ return rr
+end
+
+local function parse_vrlist(reglist)
+ local ta, ra, tb, rb = match(reglist,
+ "^{%s*([sd])([0-9]+)%s*%-%s*([sd])([0-9]+)%s*}$")
+ ra, rb = tonumber(ra), tonumber(rb)
+ if ta and ta == tb and ra and rb and ra <= 31 and rb <= 31 and ra <= rb then
+ local nr = rb+1 - ra
+ if ta == "s" then
+ return shl(shr(ra,1),12)+shl(band(ra,1),22) + nr
+ else
+ return shl(band(ra,15),12)+shl(shr(ra,4),22) + nr*2 + 0x100
+ end
+ end
+ werror("register list expected")
+end
+
+local function parse_imm(imm, bits, shift, scale, signed)
+ imm = match(imm, "^#(.*)$")
+ if not imm then werror("expected immediate operand") end
+ local n = tonumber(imm)
+ if n then
+ local m = sar(n, scale)
+ if shl(m, scale) == n then
+ if signed then
+ local s = sar(m, bits-1)
+ if s == 0 then return shl(m, shift)
+ elseif s == -1 then return shl(m + shl(1, bits), shift) end
+ else
+ if sar(m, bits) == 0 then return shl(m, shift) end
+ end
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm)
+ return 0
+ end
+end
+
+local function parse_imm12(imm)
+ local n = tonumber(imm)
+ if n then
+ local m = band(n)
+ for i=0,-15,-1 do
+ if shr(m, 8) == 0 then return m + shl(band(i, 15), 8) end
+ m = ror(m, 2)
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMM12", 0, imm)
+ return 0
+ end
+end
+
+local function parse_imm16(imm)
+ imm = match(imm, "^#(.*)$")
+ if not imm then werror("expected immediate operand") end
+ local n = tonumber(imm)
+ if n then
+ if shr(n, 16) == 0 then return band(n, 0x0fff) + shl(band(n, 0xf000), 4) end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMM16", 32*16, imm)
+ return 0
+ end
+end
+
+local function parse_imm_load(imm, ext)
+ local n = tonumber(imm)
+ if n then
+ if ext then
+ if n >= -255 and n <= 255 then
+ local up = 0x00800000
+ if n < 0 then n = -n; up = 0 end
+ return shl(band(n, 0xf0), 4) + band(n, 0x0f) + up
+ end
+ else
+ if n >= -4095 and n <= 4095 then
+ if n >= 0 then return n+0x00800000 end
+ return -n
+ end
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction(ext and "IMML8" or "IMML12", 32768 + shl(ext and 8 or 12, 5), imm)
+ return 0
+ end
+end
+
+local function parse_shift(shift, gprok)
+ if shift == "rrx" then
+ return 3 * 32
+ else
+ local s, s2 = match(shift, "^(%S+)%s*(.*)$")
+ s = map_shift[s]
+ if not s then werror("expected shift operand") end
+ if sub(s2, 1, 1) == "#" then
+ return parse_imm(s2, 5, 7, 0, false) + shl(s, 5)
+ else
+ if not gprok then werror("expected immediate shift operand") end
+ return shl(parse_gpr(s2), 8) + shl(s, 5) + 16
+ end
+ end
+end
+
+local function parse_label(label, def)
+ local prefix = sub(label, 1, 2)
+ -- =>label (pc label reference)
+ if prefix == "=>" then
+ return "PC", 0, sub(label, 3)
+ end
+ -- ->name (global label reference)
+ if prefix == "->" then
+ return "LG", map_global[sub(label, 3)]
+ end
+ if def then
+ -- [1-9] (local label definition)
+ if match(label, "^[1-9]$") then
+ return "LG", 10+tonumber(label)
+ end
+ else
+ -- [<>][1-9] (local label reference)
+ local dir, lnum = match(label, "^([<>])([1-9])$")
+ if dir then -- Fwd: 1-9, Bkwd: 11-19.
+ return "LG", lnum + (dir == ">" and 0 or 10)
+ end
+ -- extern label (extern label reference)
+ local extname = match(label, "^extern%s+(%S+)$")
+ if extname then
+ return "EXT", map_extern[extname]
+ end
+ end
+ werror("bad label `"..label.."'")
+end
+
+local function parse_load(params, nparams, n, op)
+ local oplo = band(op, 255)
+ local ext, ldrd = (oplo ~= 0), (oplo == 208)
+ local d
+ if (ldrd or oplo == 240) then
+ d = band(shr(op, 12), 15)
+ if band(d, 1) ~= 0 then werror("odd destination register") end
+ end
+ local pn = params[n]
+ local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$")
+ local p2 = params[n+1]
+ if not p1 then
+ if not p2 then
+ if match(pn, "^[<>=%-]") or match(pn, "^extern%s+") then
+ local mode, n, s = parse_label(pn, false)
+ waction("REL_"..mode, n + (ext and 0x1800 or 0x0800), s, 1)
+ return op + 15 * 65536 + 0x01000000 + (ext and 0x00400000 or 0)
+ end
+ local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$")
+ if reg and tailr ~= "" then
+ local d, tp = parse_gpr(reg)
+ if tp then
+ waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12),
+ format(tp.ctypefmt, tailr))
+ return op + shl(d, 16) + 0x01000000 + (ext and 0x00400000 or 0)
+ end
+ end
+ end
+ werror("expected address operand")
+ end
+ if wb == "!" then op = op + 0x00200000 end
+ if p2 then
+ if wb == "!" then werror("bad use of '!'") end
+ local p3 = params[n+2]
+ op = op + shl(parse_gpr(p1), 16)
+ local imm = match(p2, "^#(.*)$")
+ if imm then
+ local m = parse_imm_load(imm, ext)
+ if p3 then werror("too many parameters") end
+ op = op + m + (ext and 0x00400000 or 0)
+ else
+ local m, neg = parse_gpr_pm(p2)
+ if ldrd and (m == d or m-1 == d) then werror("register conflict") end
+ op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000)
+ if p3 then op = op + parse_shift(p3) end
+ end
+ else
+ local p1a, p2 = match(p1, "^([^,%s]*)%s*(.*)$")
+ op = op + shl(parse_gpr(p1a), 16) + 0x01000000
+ if p2 ~= "" then
+ local imm = match(p2, "^,%s*#(.*)$")
+ if imm then
+ local m = parse_imm_load(imm, ext)
+ op = op + m + (ext and 0x00400000 or 0)
+ else
+ local p2a, p3 = match(p2, "^,%s*([^,%s]*)%s*,?%s*(.*)$")
+ local m, neg = parse_gpr_pm(p2a)
+ if ldrd and (m == d or m-1 == d) then werror("register conflict") end
+ op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000)
+ if p3 ~= "" then
+ if ext then werror("too many parameters") end
+ op = op + parse_shift(p3)
+ end
+ end
+ else
+ if wb == "!" then werror("bad use of '!'") end
+ op = op + (ext and 0x00c00000 or 0x00800000)
+ end
+ end
+ return op
+end
+
+local function parse_vload(q)
+ local reg, imm = match(q, "^%[%s*([^,%s]*)%s*(.*)%]$")
+ if reg then
+ local d = shl(parse_gpr(reg), 16)
+ if imm == "" then return d end
+ imm = match(imm, "^,%s*#(.*)$")
+ if imm then
+ local n = tonumber(imm)
+ if n then
+ if n >= -1020 and n <= 1020 and n%4 == 0 then
+ return d + (n >= 0 and n/4+0x00800000 or -n/4)
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMMV8", 32768 + 32*8, imm)
+ return d
+ end
+ end
+ else
+ if match(q, "^[<>=%-]") or match(q, "^extern%s+") then
+ local mode, n, s = parse_label(q, false)
+ waction("REL_"..mode, n + 0x2800, s, 1)
+ return 15 * 65536
+ end
+ local reg, tailr = match(q, "^([%w_:]+)%s*(.*)$")
+ if reg and tailr ~= "" then
+ local d, tp = parse_gpr(reg)
+ if tp then
+ waction("IMMV8", 32768 + 32*8, format(tp.ctypefmt, tailr))
+ return shl(d, 16)
+ end
+ end
+ end
+ werror("expected address operand")
+end
+
+------------------------------------------------------------------------------
+
+-- Handle opcodes defined with template strings.
+local function parse_template(params, template, nparams, pos)
+ local op = tonumber(sub(template, 1, 8), 16)
+ local n = 1
+ local vr = "s"
+
+ -- Process each character.
+ for p in gmatch(sub(template, 9), ".") do
+ local q = params[n]
+ if p == "D" then
+ op = op + shl(parse_gpr(q), 12); n = n + 1
+ elseif p == "N" then
+ op = op + shl(parse_gpr(q), 16); n = n + 1
+ elseif p == "S" then
+ op = op + shl(parse_gpr(q), 8); n = n + 1
+ elseif p == "M" then
+ op = op + parse_gpr(q); n = n + 1
+ elseif p == "d" then
+ local r,h = parse_vr(q, vr); op = op+shl(r,12)+shl(h,22); n = n + 1
+ elseif p == "n" then
+ local r,h = parse_vr(q, vr); op = op+shl(r,16)+shl(h,7); n = n + 1
+ elseif p == "m" then
+ local r,h = parse_vr(q, vr); op = op+r+shl(h,5); n = n + 1
+ elseif p == "P" then
+ local imm = match(q, "^#(.*)$")
+ if imm then
+ op = op + parse_imm12(imm) + 0x02000000
+ else
+ op = op + parse_gpr(q)
+ end
+ n = n + 1
+ elseif p == "p" then
+ op = op + parse_shift(q, true); n = n + 1
+ elseif p == "L" then
+ op = parse_load(params, nparams, n, op)
+ elseif p == "l" then
+ op = op + parse_vload(q)
+ elseif p == "B" then
+ local mode, n, s = parse_label(q, false)
+ waction("REL_"..mode, n, s, 1)
+ elseif p == "C" then -- blx gpr vs. blx label.
+ if match(q, "^([%w_]+):(r1?[0-9])$") or match(q, "^r(1?[0-9])$") then
+ op = op + parse_gpr(q)
+ else
+ if op < 0xe0000000 then werror("unconditional instruction") end
+ local mode, n, s = parse_label(q, false)
+ waction("REL_"..mode, n, s, 1)
+ op = 0xfa000000
+ end
+ elseif p == "F" then
+ vr = "s"
+ elseif p == "G" then
+ vr = "d"
+ elseif p == "o" then
+ local r, wb = match(q, "^([^!]*)(!?)$")
+ op = op + shl(parse_gpr(r), 16) + (wb == "!" and 0x00200000 or 0)
+ n = n + 1
+ elseif p == "R" then
+ op = op + parse_reglist(q); n = n + 1
+ elseif p == "r" then
+ op = op + parse_vrlist(q); n = n + 1
+ elseif p == "W" then
+ op = op + parse_imm16(q); n = n + 1
+ elseif p == "v" then
+ op = op + parse_imm(q, 5, 7, 0, false); n = n + 1
+ elseif p == "w" then
+ local imm = match(q, "^#(.*)$")
+ if imm then
+ op = op + parse_imm(q, 5, 7, 0, false); n = n + 1
+ else
+ op = op + shl(parse_gpr(q), 8) + 16
+ end
+ elseif p == "X" then
+ op = op + parse_imm(q, 5, 16, 0, false); n = n + 1
+ elseif p == "Y" then
+ local imm = tonumber(match(q, "^#(.*)$")); n = n + 1
+ if not imm or shr(imm, 8) ~= 0 then
+ werror("bad immediate operand")
+ end
+ op = op + shl(band(imm, 0xf0), 12) + band(imm, 0x0f)
+ elseif p == "K" then
+ local imm = tonumber(match(q, "^#(.*)$")); n = n + 1
+ if not imm or shr(imm, 16) ~= 0 then
+ werror("bad immediate operand")
+ end
+ op = op + shl(band(imm, 0xfff0), 4) + band(imm, 0x000f)
+ elseif p == "T" then
+ op = op + parse_imm(q, 24, 0, 0, false); n = n + 1
+ elseif p == "s" then
+ -- Ignored.
+ else
+ assert(false)
+ end
+ end
+ wputpos(pos, op)
+end
+
+map_op[".template__"] = function(params, template, nparams)
+ if not params then return template:gsub("%x%x%x%x%x%x%x%x", "") end
+
+ -- Limit number of section buffer positions used by a single dasm_put().
+ -- A single opcode needs a maximum of 3 positions.
+ if secpos+3 > maxsecpos then wflush() end
+ local pos = wpos()
+ local lpos, apos, spos = #actlist, #actargs, secpos
+
+ local ok, err
+ for t in gmatch(template, "[^|]+") do
+ ok, err = pcall(parse_template, params, t, nparams, pos)
+ if ok then return end
+ secpos = spos
+ actlist[lpos+1] = nil
+ actlist[lpos+2] = nil
+ actlist[lpos+3] = nil
+ actargs[apos+1] = nil
+ actargs[apos+2] = nil
+ actargs[apos+3] = nil
+ end
+ error(err, 0)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode to mark the position where the action list is to be emitted.
+map_op[".actionlist_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeactions(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the global enum is to be emitted.
+map_op[".globals_1"] = function(params)
+ if not params then return "prefix" end
+ local prefix = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobals(out, prefix) end)
+end
+
+-- Pseudo-opcode to mark the position where the global names are to be emitted.
+map_op[".globalnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobalnames(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the extern names are to be emitted.
+map_op[".externnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeexternnames(out, name) end)
+end
+
+------------------------------------------------------------------------------
+
+-- Label pseudo-opcode (converted from trailing colon form).
+map_op[".label_1"] = function(params)
+ if not params then return "[1-9] | ->global | =>pcexpr" end
+ if secpos+1 > maxsecpos then wflush() end
+ local mode, n, s = parse_label(params[1], true)
+ if mode == "EXT" then werror("bad label definition") end
+ waction("LABEL_"..mode, n, s, 1)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcodes for data storage.
+map_op[".long_*"] = function(params)
+ if not params then return "imm..." end
+ for _,p in ipairs(params) do
+ local n = tonumber(p)
+ if not n then werror("bad immediate `"..p.."'") end
+ if n < 0 then n = n + 2^32 end
+ wputw(n)
+ if secpos+2 > maxsecpos then wflush() end
+ end
+end
+
+-- Alignment pseudo-opcode.
+map_op[".align_1"] = function(params)
+ if not params then return "numpow2" end
+ if secpos+1 > maxsecpos then wflush() end
+ local align = tonumber(params[1])
+ if align then
+ local x = align
+ -- Must be a power of 2 in the range (2 ... 256).
+ for i=1,8 do
+ x = x / 2
+ if x == 1 then
+ waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
+ return
+ end
+ end
+ end
+ werror("bad alignment")
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode for (primitive) type definitions (map to C types).
+map_op[".type_3"] = function(params, nparams)
+ if not params then
+ return nparams == 2 and "name, ctype" or "name, ctype, reg"
+ end
+ local name, ctype, reg = params[1], params[2], params[3]
+ if not match(name, "^[%a_][%w_]*$") then
+ werror("bad type name `"..name.."'")
+ end
+ local tp = map_type[name]
+ if tp then
+ werror("duplicate type `"..name.."'")
+ end
+ -- Add #type to defines. A bit unclean to put it in map_archdef.
+ map_archdef["#"..name] = "sizeof("..ctype..")"
+ -- Add new type and emit shortcut define.
+ local num = ctypenum + 1
+ map_type[name] = {
+ ctype = ctype,
+ ctypefmt = format("Dt%X(%%s)", num),
+ reg = reg,
+ }
+ wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
+ ctypenum = num
+end
+map_op[".type_2"] = map_op[".type_3"]
+
+-- Dump type definitions.
+local function dumptypes(out, lvl)
+ local t = {}
+ for name in pairs(map_type) do t[#t+1] = name end
+ sort(t)
+ out:write("Type definitions:\n")
+ for _,name in ipairs(t) do
+ local tp = map_type[name]
+ local reg = tp.reg or ""
+ out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
+ end
+ out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Set the current section.
+function _M.section(num)
+ waction("SECTION", num)
+ wflush(true) -- SECTION is a terminal action.
+end
+
+------------------------------------------------------------------------------
+
+-- Dump architecture description.
+function _M.dumparch(out)
+ out:write(format("DynASM %s version %s, released %s\n\n",
+ _info.arch, _info.version, _info.release))
+ dumpactions(out)
+end
+
+-- Dump all user defined elements.
+function _M.dumpdef(out, lvl)
+ dumptypes(out, lvl)
+ dumpglobals(out, lvl)
+ dumpexterns(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Pass callbacks from/to the DynASM core.
+function _M.passcb(wl, we, wf, ww)
+ wline, werror, wfatal, wwarn = wl, we, wf, ww
+ return wflush
+end
+
+-- Setup the arch-specific module.
+function _M.setup(arch, opt)
+ g_arch, g_opt = arch, opt
+end
+
+-- Merge the core maps and the arch-specific maps.
+function _M.mergemaps(map_coreop, map_def)
+ setmetatable(map_op, { __index = function(t, k)
+ local v = map_coreop[k]
+ if v then return v end
+ local k1, cc, k2 = match(k, "^(.-)(..)([._].*)$")
+ local cv = map_cond[cc]
+ if cv then
+ local v = rawget(t, k1..k2)
+ if type(v) == "string" then
+ local scv = format("%x", cv)
+ return gsub(scv..sub(v, 2), "|e", "|"..scv)
+ end
+ end
+ end })
+ setmetatable(map_def, { __index = map_archdef })
+ return map_op, map_def
+end
+
+return _M
+
+------------------------------------------------------------------------------
+
diff --git a/src/host/luajit-2.1.0-beta3/dynasm/dasm_arm64.h b/src/host/luajit-2.1.0-beta3/dynasm/dasm_arm64.h
new file mode 100644
index 00000000..47e1e074
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/dynasm/dasm_arm64.h
@@ -0,0 +1,518 @@
+/*
+** DynASM ARM64 encoding engine.
+** Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+** Released under the MIT license. See dynasm.lua for full copyright notice.
+*/
+
+#include
+#include
+#include
+#include
+
+#define DASM_ARCH "arm64"
+
+#ifndef DASM_EXTERN
+#define DASM_EXTERN(a,b,c,d) 0
+#endif
+
+/* Action definitions. */
+enum {
+ DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
+ /* The following actions need a buffer position. */
+ DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
+ /* The following actions also have an argument. */
+ DASM_REL_PC, DASM_LABEL_PC,
+ DASM_IMM, DASM_IMM6, DASM_IMM12, DASM_IMM13W, DASM_IMM13X, DASM_IMML,
+ DASM__MAX
+};
+
+/* Maximum number of section buffer positions for a single dasm_put() call. */
+#define DASM_MAXSECPOS 25
+
+/* DynASM encoder status codes. Action list offset or number are or'ed in. */
+#define DASM_S_OK 0x00000000
+#define DASM_S_NOMEM 0x01000000
+#define DASM_S_PHASE 0x02000000
+#define DASM_S_MATCH_SEC 0x03000000
+#define DASM_S_RANGE_I 0x11000000
+#define DASM_S_RANGE_SEC 0x12000000
+#define DASM_S_RANGE_LG 0x13000000
+#define DASM_S_RANGE_PC 0x14000000
+#define DASM_S_RANGE_REL 0x15000000
+#define DASM_S_UNDEF_LG 0x21000000
+#define DASM_S_UNDEF_PC 0x22000000
+
+/* Macros to convert positions (8 bit section + 24 bit index). */
+#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
+#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
+#define DASM_SEC2POS(sec) ((sec)<<24)
+#define DASM_POS2SEC(pos) ((pos)>>24)
+#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
+
+/* Action list type. */
+typedef const unsigned int *dasm_ActList;
+
+/* Per-section structure. */
+typedef struct dasm_Section {
+ int *rbuf; /* Biased buffer pointer (negative section bias). */
+ int *buf; /* True buffer pointer. */
+ size_t bsize; /* Buffer size in bytes. */
+ int pos; /* Biased buffer position. */
+ int epos; /* End of biased buffer position - max single put. */
+ int ofs; /* Byte offset into section. */
+} dasm_Section;
+
+/* Core structure holding the DynASM encoding state. */
+struct dasm_State {
+ size_t psize; /* Allocated size of this structure. */
+ dasm_ActList actionlist; /* Current actionlist pointer. */
+ int *lglabels; /* Local/global chain/pos ptrs. */
+ size_t lgsize;
+ int *pclabels; /* PC label chains/pos ptrs. */
+ size_t pcsize;
+ void **globals; /* Array of globals (bias -10). */
+ dasm_Section *section; /* Pointer to active section. */
+ size_t codesize; /* Total size of all code sections. */
+ int maxsection; /* 0 <= sectionidx < maxsection. */
+ int status; /* Status code. */
+ dasm_Section sections[1]; /* All sections. Alloc-extended. */
+};
+
+/* The size of the core structure depends on the max. number of sections. */
+#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
+
+
+/* Initialize DynASM state. */
+void dasm_init(Dst_DECL, int maxsection)
+{
+ dasm_State *D;
+ size_t psz = 0;
+ int i;
+ Dst_REF = NULL;
+ DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
+ D = Dst_REF;
+ D->psize = psz;
+ D->lglabels = NULL;
+ D->lgsize = 0;
+ D->pclabels = NULL;
+ D->pcsize = 0;
+ D->globals = NULL;
+ D->maxsection = maxsection;
+ for (i = 0; i < maxsection; i++) {
+ D->sections[i].buf = NULL; /* Need this for pass3. */
+ D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
+ D->sections[i].bsize = 0;
+ D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
+ }
+}
+
+/* Free DynASM state. */
+void dasm_free(Dst_DECL)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ for (i = 0; i < D->maxsection; i++)
+ if (D->sections[i].buf)
+ DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
+ if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
+ if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
+ DASM_M_FREE(Dst, D, D->psize);
+}
+
+/* Setup global label array. Must be called before dasm_setup(). */
+void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
+{
+ dasm_State *D = Dst_REF;
+ D->globals = gl - 10; /* Negative bias to compensate for locals. */
+ DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
+}
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+void dasm_growpc(Dst_DECL, unsigned int maxpc)
+{
+ dasm_State *D = Dst_REF;
+ size_t osz = D->pcsize;
+ DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
+ memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
+}
+
+/* Setup encoder. */
+void dasm_setup(Dst_DECL, const void *actionlist)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ D->actionlist = (dasm_ActList)actionlist;
+ D->status = DASM_S_OK;
+ D->section = &D->sections[0];
+ memset((void *)D->lglabels, 0, D->lgsize);
+ if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
+ for (i = 0; i < D->maxsection; i++) {
+ D->sections[i].pos = DASM_SEC2POS(i);
+ D->sections[i].ofs = 0;
+ }
+}
+
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) { \
+ D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
+#define CKPL(kind, st) \
+ do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
+ D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
+#else
+#define CK(x, st) ((void)0)
+#define CKPL(kind, st) ((void)0)
+#endif
+
+static int dasm_imm12(unsigned int n)
+{
+ if ((n >> 12) == 0)
+ return n;
+ else if ((n & 0xff000fff) == 0)
+ return (n >> 12) | 0x1000;
+ else
+ return -1;
+}
+
+static int dasm_ffs(unsigned long long x)
+{
+ int n = -1;
+ while (x) { x >>= 1; n++; }
+ return n;
+}
+
+static int dasm_imm13(int lo, int hi)
+{
+ int inv = 0, w = 64, s = 0xfff, xa, xb;
+ unsigned long long n = (((unsigned long long)hi) << 32) | (unsigned int)lo;
+ unsigned long long m = 1ULL, a, b, c;
+ if (n & 1) { n = ~n; inv = 1; }
+ a = n & -n; b = (n+a)&-(n+a); c = (n+a-b)&-(n+a-b);
+ xa = dasm_ffs(a); xb = dasm_ffs(b);
+ if (c) {
+ w = dasm_ffs(c) - xa;
+ if (w == 32) m = 0x0000000100000001UL;
+ else if (w == 16) m = 0x0001000100010001UL;
+ else if (w == 8) m = 0x0101010101010101UL;
+ else if (w == 4) m = 0x1111111111111111UL;
+ else if (w == 2) m = 0x5555555555555555UL;
+ else return -1;
+ s = (-2*w & 0x3f) - 1;
+ } else if (!a) {
+ return -1;
+ } else if (xb == -1) {
+ xb = 64;
+ }
+ if ((b-a) * m != n) return -1;
+ if (inv) {
+ return ((w - xb) << 6) | (s+w+xa-xb);
+ } else {
+ return ((w - xa) << 6) | (s+xb-xa);
+ }
+ return -1;
+}
+
+/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
+void dasm_put(Dst_DECL, int start, ...)
+{
+ va_list ap;
+ dasm_State *D = Dst_REF;
+ dasm_ActList p = D->actionlist + start;
+ dasm_Section *sec = D->section;
+ int pos = sec->pos, ofs = sec->ofs;
+ int *b;
+
+ if (pos >= sec->epos) {
+ DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
+ sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
+ sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
+ sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
+ }
+
+ b = sec->rbuf;
+ b[pos++] = start;
+
+ va_start(ap, start);
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ if (action >= DASM__MAX) {
+ ofs += 4;
+ } else {
+ int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
+ switch (action) {
+ case DASM_STOP: goto stop;
+ case DASM_SECTION:
+ n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
+ D->section = &D->sections[n]; goto stop;
+ case DASM_ESC: p++; ofs += 4; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
+ case DASM_REL_LG:
+ n = (ins & 2047) - 10; pl = D->lglabels + n;
+ /* Bkwd rel or global. */
+ if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
+ pl += 10; n = *pl;
+ if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
+ goto linkrel;
+ case DASM_REL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putrel:
+ n = *pl;
+ if (n < 0) { /* Label exists. Get label pos and store it. */
+ b[pos] = -n;
+ } else {
+ linkrel:
+ b[pos] = n; /* Else link to rel chain, anchored at label. */
+ *pl = pos;
+ }
+ pos++;
+ break;
+ case DASM_LABEL_LG:
+ pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
+ case DASM_LABEL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putlabel:
+ n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
+ }
+ *pl = -pos; /* Label exists now. */
+ b[pos++] = ofs; /* Store pass1 offset estimate. */
+ break;
+ case DASM_IMM:
+ CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
+ n >>= ((ins>>10)&31);
+#ifdef DASM_CHECKS
+ if ((ins & 0x8000))
+ CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
+ else
+ CK((n>>((ins>>5)&31)) == 0, RANGE_I);
+#endif
+ b[pos++] = n;
+ break;
+ case DASM_IMM6:
+ CK((n >> 6) == 0, RANGE_I);
+ b[pos++] = n;
+ break;
+ case DASM_IMM12:
+ CK(dasm_imm12((unsigned int)n) != -1, RANGE_I);
+ b[pos++] = n;
+ break;
+ case DASM_IMM13W:
+ CK(dasm_imm13(n, n) != -1, RANGE_I);
+ b[pos++] = n;
+ break;
+ case DASM_IMM13X: {
+ int m = va_arg(ap, int);
+ CK(dasm_imm13(n, m) != -1, RANGE_I);
+ b[pos++] = n;
+ b[pos++] = m;
+ break;
+ }
+ case DASM_IMML: {
+#ifdef DASM_CHECKS
+ int scale = (p[-2] >> 30);
+ CK((!(n & ((1<>scale) < 4096) ||
+ (unsigned int)(n+256) < 512, RANGE_I);
+#endif
+ b[pos++] = n;
+ break;
+ }
+ }
+ }
+ }
+stop:
+ va_end(ap);
+ sec->pos = pos;
+ sec->ofs = ofs;
+}
+#undef CK
+
+/* Pass 2: Link sections, shrink aligns, fix label offsets. */
+int dasm_link(Dst_DECL, size_t *szp)
+{
+ dasm_State *D = Dst_REF;
+ int secnum;
+ int ofs = 0;
+
+#ifdef DASM_CHECKS
+ *szp = 0;
+ if (D->status != DASM_S_OK) return D->status;
+ {
+ int pc;
+ for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
+ if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
+ }
+#endif
+
+ { /* Handle globals not defined in this translation unit. */
+ int idx;
+ for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
+ int n = D->lglabels[idx];
+ /* Undefined label: Collapse rel chain and replace with marker (< 0). */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
+ }
+ }
+
+ /* Combine all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->rbuf;
+ int pos = DASM_SEC2POS(secnum);
+ int lastpos = sec->pos;
+
+ while (pos != lastpos) {
+ dasm_ActList p = D->actionlist + b[pos++];
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: p++; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
+ case DASM_REL_LG: case DASM_REL_PC: pos++; break;
+ case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
+ case DASM_IMM: case DASM_IMM6: case DASM_IMM12: case DASM_IMM13W:
+ case DASM_IMML: pos++; break;
+ case DASM_IMM13X: pos += 2; break;
+ }
+ }
+ stop: (void)0;
+ }
+ ofs += sec->ofs; /* Next section starts right after current section. */
+ }
+
+ D->codesize = ofs; /* Total size of all code sections */
+ *szp = ofs;
+ return DASM_S_OK;
+}
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
+#else
+#define CK(x, st) ((void)0)
+#endif
+
+/* Pass 3: Encode sections. */
+int dasm_encode(Dst_DECL, void *buffer)
+{
+ dasm_State *D = Dst_REF;
+ char *base = (char *)buffer;
+ unsigned int *cp = (unsigned int *)buffer;
+ int secnum;
+
+ /* Encode all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->buf;
+ int *endb = sec->rbuf + sec->pos;
+
+ while (b != endb) {
+ dasm_ActList p = D->actionlist + *b++;
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: *cp++ = *p++; break;
+ case DASM_REL_EXT:
+ n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048));
+ goto patchrel;
+ case DASM_ALIGN:
+ ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000;
+ break;
+ case DASM_REL_LG:
+ CK(n >= 0, UNDEF_LG);
+ case DASM_REL_PC:
+ CK(n >= 0, UNDEF_PC);
+ n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) + 4;
+ patchrel:
+ if (!(ins & 0xf800)) { /* B, BL */
+ CK((n & 3) == 0 && ((n+0x08000000) >> 28) == 0, RANGE_REL);
+ cp[-1] |= ((n >> 2) & 0x03ffffff);
+ } else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */
+ CK((n & 3) == 0 && ((n+0x00100000) >> 21) == 0, RANGE_REL);
+ cp[-1] |= ((n << 3) & 0x00ffffe0);
+ } else if ((ins & 0x3000) == 0x2000) { /* ADR */
+ CK(((n+0x00100000) >> 21) == 0, RANGE_REL);
+ cp[-1] |= ((n << 3) & 0x00ffffe0) | ((n & 3) << 29);
+ } else if ((ins & 0x3000) == 0x3000) { /* ADRP */
+ cp[-1] |= ((n >> 9) & 0x00ffffe0) | (((n >> 12) & 3) << 29);
+ } else if ((ins & 0x1000)) { /* TBZ, TBNZ */
+ CK((n & 3) == 0 && ((n+0x00008000) >> 16) == 0, RANGE_REL);
+ cp[-1] |= ((n << 3) & 0x0007ffe0);
+ }
+ break;
+ case DASM_LABEL_LG:
+ ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
+ break;
+ case DASM_LABEL_PC: break;
+ case DASM_IMM:
+ cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
+ break;
+ case DASM_IMM6:
+ cp[-1] |= ((n&31) << 19) | ((n&32) << 26);
+ break;
+ case DASM_IMM12:
+ cp[-1] |= (dasm_imm12((unsigned int)n) << 10);
+ break;
+ case DASM_IMM13W:
+ cp[-1] |= (dasm_imm13(n, n) << 10);
+ break;
+ case DASM_IMM13X:
+ cp[-1] |= (dasm_imm13(n, *b++) << 10);
+ break;
+ case DASM_IMML: {
+ int scale = (p[-2] >> 30);
+ cp[-1] |= (!(n & ((1<>scale) < 4096) ?
+ ((n << (10-scale)) | 0x01000000) : ((n & 511) << 12);
+ break;
+ }
+ default: *cp++ = ins; break;
+ }
+ }
+ stop: (void)0;
+ }
+ }
+
+ if (base + D->codesize != (char *)cp) /* Check for phase errors. */
+ return DASM_S_PHASE;
+ return DASM_S_OK;
+}
+#undef CK
+
+/* Get PC label offset. */
+int dasm_getpclabel(Dst_DECL, unsigned int pc)
+{
+ dasm_State *D = Dst_REF;
+ if (pc*sizeof(int) < D->pcsize) {
+ int pos = D->pclabels[pc];
+ if (pos < 0) return *DASM_POS2PTR(D, -pos);
+ if (pos > 0) return -1; /* Undefined. */
+ }
+ return -2; /* Unused or out of range. */
+}
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+int dasm_checkstep(Dst_DECL, int secmatch)
+{
+ dasm_State *D = Dst_REF;
+ if (D->status == DASM_S_OK) {
+ int i;
+ for (i = 1; i <= 9; i++) {
+ if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
+ D->lglabels[i] = 0;
+ }
+ }
+ if (D->status == DASM_S_OK && secmatch >= 0 &&
+ D->section != &D->sections[secmatch])
+ D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
+ return D->status;
+}
+#endif
+
diff --git a/src/host/luajit-2.1.0-beta3/dynasm/dasm_arm64.lua b/src/host/luajit-2.1.0-beta3/dynasm/dasm_arm64.lua
new file mode 100644
index 00000000..8a5f735d
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/dynasm/dasm_arm64.lua
@@ -0,0 +1,1166 @@
+------------------------------------------------------------------------------
+-- DynASM ARM64 module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+
+-- Module information:
+local _info = {
+ arch = "arm",
+ description = "DynASM ARM64 module",
+ version = "1.4.0",
+ vernum = 10400,
+ release = "2015-10-18",
+ author = "Mike Pall",
+ license = "MIT",
+}
+
+-- Exported glue functions for the arch-specific module.
+local _M = { _info = _info }
+
+-- Cache library functions.
+local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
+local assert, setmetatable, rawget = assert, setmetatable, rawget
+local _s = string
+local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
+local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub
+local concat, sort, insert = table.concat, table.sort, table.insert
+local bit = bit or require("bit")
+local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift
+local ror, tohex = bit.ror, bit.tohex
+
+-- Inherited tables and callbacks.
+local g_opt, g_arch
+local wline, werror, wfatal, wwarn
+
+-- Action name list.
+-- CHECK: Keep this in sync with the C code!
+local action_names = {
+ "STOP", "SECTION", "ESC", "REL_EXT",
+ "ALIGN", "REL_LG", "LABEL_LG",
+ "REL_PC", "LABEL_PC", "IMM", "IMM6", "IMM12", "IMM13W", "IMM13X", "IMML",
+}
+
+-- Maximum number of section buffer positions for dasm_put().
+-- CHECK: Keep this in sync with the C code!
+local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
+
+-- Action name -> action number.
+local map_action = {}
+for n,name in ipairs(action_names) do
+ map_action[name] = n-1
+end
+
+-- Action list buffer.
+local actlist = {}
+
+-- Argument list for next dasm_put(). Start with offset 0 into action list.
+local actargs = { 0 }
+
+-- Current number of section buffer positions for dasm_put().
+local secpos = 1
+
+------------------------------------------------------------------------------
+
+-- Dump action names and numbers.
+local function dumpactions(out)
+ out:write("DynASM encoding engine action codes:\n")
+ for n,name in ipairs(action_names) do
+ local num = map_action[name]
+ out:write(format(" %-10s %02X %d\n", name, num, num))
+ end
+ out:write("\n")
+end
+
+-- Write action list buffer as a huge static C array.
+local function writeactions(out, name)
+ local nn = #actlist
+ if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
+ out:write("static const unsigned int ", name, "[", nn, "] = {\n")
+ for i = 1,nn-1 do
+ assert(out:write("0x", tohex(actlist[i]), ",\n"))
+ end
+ assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
+end
+
+------------------------------------------------------------------------------
+
+-- Add word to action list.
+local function wputxw(n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ actlist[#actlist+1] = n
+end
+
+-- Add action to list with optional arg. Advance buffer pos, too.
+local function waction(action, val, a, num)
+ local w = assert(map_action[action], "bad action name `"..action.."'")
+ wputxw(w * 0x10000 + (val or 0))
+ if a then actargs[#actargs+1] = a end
+ if a or num then secpos = secpos + (num or 1) end
+end
+
+-- Flush action list (intervening C code or buffer pos overflow).
+local function wflush(term)
+ if #actlist == actargs[1] then return end -- Nothing to flush.
+ if not term then waction("STOP") end -- Terminate action list.
+ wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
+ actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
+ secpos = 1 -- The actionlist offset occupies a buffer position, too.
+end
+
+-- Put escaped word.
+local function wputw(n)
+ if n <= 0x000fffff then waction("ESC") end
+ wputxw(n)
+end
+
+-- Reserve position for word.
+local function wpos()
+ local pos = #actlist+1
+ actlist[pos] = ""
+ return pos
+end
+
+-- Store word to reserved position.
+local function wputpos(pos, n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ if n <= 0x000fffff then
+ insert(actlist, pos+1, n)
+ n = map_action.ESC * 0x10000
+ end
+ actlist[pos] = n
+end
+
+------------------------------------------------------------------------------
+
+-- Global label name -> global label number. With auto assignment on 1st use.
+local next_global = 20
+local map_global = setmetatable({}, { __index = function(t, name)
+ if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
+ local n = next_global
+ if n > 2047 then werror("too many global labels") end
+ next_global = n + 1
+ t[name] = n
+ return n
+end})
+
+-- Dump global labels.
+local function dumpglobals(out, lvl)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("Global labels:\n")
+ for i=20,next_global-1 do
+ out:write(format(" %s\n", t[i]))
+ end
+ out:write("\n")
+end
+
+-- Write global label enum.
+local function writeglobals(out, prefix)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("enum {\n")
+ for i=20,next_global-1 do
+ out:write(" ", prefix, t[i], ",\n")
+ end
+ out:write(" ", prefix, "_MAX\n};\n")
+end
+
+-- Write global label names.
+local function writeglobalnames(out, name)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=20,next_global-1 do
+ out:write(" \"", t[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Extern label name -> extern label number. With auto assignment on 1st use.
+local next_extern = 0
+local map_extern_ = {}
+local map_extern = setmetatable({}, { __index = function(t, name)
+ -- No restrictions on the name for now.
+ local n = next_extern
+ if n > 2047 then werror("too many extern labels") end
+ next_extern = n + 1
+ t[name] = n
+ map_extern_[n] = name
+ return n
+end})
+
+-- Dump extern labels.
+local function dumpexterns(out, lvl)
+ out:write("Extern labels:\n")
+ for i=0,next_extern-1 do
+ out:write(format(" %s\n", map_extern_[i]))
+ end
+ out:write("\n")
+end
+
+-- Write extern label names.
+local function writeexternnames(out, name)
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=0,next_extern-1 do
+ out:write(" \"", map_extern_[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Arch-specific maps.
+
+-- Ext. register name -> int. name.
+local map_archdef = { xzr = "@x31", wzr = "@w31", lr = "x30", }
+
+-- Int. register name -> ext. name.
+local map_reg_rev = { ["@x31"] = "xzr", ["@w31"] = "wzr", x30 = "lr", }
+
+local map_type = {} -- Type name -> { ctype, reg }
+local ctypenum = 0 -- Type number (for Dt... macros).
+
+-- Reverse defines for registers.
+function _M.revdef(s)
+ return map_reg_rev[s] or s
+end
+
+local map_shift = { lsl = 0, lsr = 1, asr = 2, }
+
+local map_extend = {
+ uxtb = 0, uxth = 1, uxtw = 2, uxtx = 3,
+ sxtb = 4, sxth = 5, sxtw = 6, sxtx = 7,
+}
+
+local map_cond = {
+ eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7,
+ hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14,
+ hs = 2, lo = 3,
+}
+
+------------------------------------------------------------------------------
+
+local parse_reg_type
+
+local function parse_reg(expr)
+ if not expr then werror("expected register name") end
+ local tname, ovreg = match(expr, "^([%w_]+):(@?%l%d+)$")
+ local tp = map_type[tname or expr]
+ if tp then
+ local reg = ovreg or tp.reg
+ if not reg then
+ werror("type `"..(tname or expr).."' needs a register override")
+ end
+ expr = reg
+ end
+ local ok31, rt, r = match(expr, "^(@?)([xwqdshb])([123]?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 30 or (r == 31 and ok31 ~= "" or (rt ~= "w" and rt ~= "x")) then
+ if not parse_reg_type then
+ parse_reg_type = rt
+ elseif parse_reg_type ~= rt then
+ werror("register size mismatch")
+ end
+ return r, tp
+ end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_reg_base(expr)
+ if expr == "sp" then return 0x3e0 end
+ local base, tp = parse_reg(expr)
+ if parse_reg_type ~= "x" then werror("bad register type") end
+ parse_reg_type = false
+ return shl(base, 5), tp
+end
+
+local parse_ctx = {}
+
+local loadenv = setfenv and function(s)
+ local code = loadstring(s, "")
+ if code then setfenv(code, parse_ctx) end
+ return code
+end or function(s)
+ return load(s, "", nil, parse_ctx)
+end
+
+-- Try to parse simple arithmetic, too, since some basic ops are aliases.
+local function parse_number(n)
+ local x = tonumber(n)
+ if x then return x end
+ local code = loadenv("return "..n)
+ if code then
+ local ok, y = pcall(code)
+ if ok then return y end
+ end
+ return nil
+end
+
+local function parse_imm(imm, bits, shift, scale, signed)
+ imm = match(imm, "^#(.*)$")
+ if not imm then werror("expected immediate operand") end
+ local n = parse_number(imm)
+ if n then
+ local m = sar(n, scale)
+ if shl(m, scale) == n then
+ if signed then
+ local s = sar(m, bits-1)
+ if s == 0 then return shl(m, shift)
+ elseif s == -1 then return shl(m + shl(1, bits), shift) end
+ else
+ if sar(m, bits) == 0 then return shl(m, shift) end
+ end
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm)
+ return 0
+ end
+end
+
+local function parse_imm12(imm)
+ imm = match(imm, "^#(.*)$")
+ if not imm then werror("expected immediate operand") end
+ local n = parse_number(imm)
+ if n then
+ if shr(n, 12) == 0 then
+ return shl(n, 10)
+ elseif band(n, 0xff000fff) == 0 then
+ return shr(n, 2) + 0x00400000
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMM12", 0, imm)
+ return 0
+ end
+end
+
+local function parse_imm13(imm)
+ imm = match(imm, "^#(.*)$")
+ if not imm then werror("expected immediate operand") end
+ local n = parse_number(imm)
+ local r64 = parse_reg_type == "x"
+ if n and n % 1 == 0 and n >= 0 and n <= 0xffffffff then
+ local inv = false
+ if band(n, 1) == 1 then n = bit.bnot(n); inv = true end
+ local t = {}
+ for i=1,32 do t[i] = band(n, 1); n = shr(n, 1) end
+ local b = table.concat(t)
+ b = b..(r64 and (inv and "1" or "0"):rep(32) or b)
+ local p0, p1, p0a, p1a = b:match("^(0+)(1+)(0*)(1*)")
+ if p0 then
+ local w = p1a == "" and (r64 and 64 or 32) or #p1+#p0a
+ if band(w, w-1) == 0 and b == b:sub(1, w):rep(64/w) then
+ local s = band(-2*w, 0x3f) - 1
+ if w == 64 then s = s + 0x1000 end
+ if inv then
+ return shl(w-#p1-#p0, 16) + shl(s+w-#p1, 10)
+ else
+ return shl(w-#p0, 16) + shl(s+#p1, 10)
+ end
+ end
+ end
+ werror("out of range immediate `"..imm.."'")
+ elseif r64 then
+ waction("IMM13X", 0, format("(unsigned int)(%s)", imm))
+ actargs[#actargs+1] = format("(unsigned int)((unsigned long long)(%s)>>32)", imm)
+ return 0
+ else
+ waction("IMM13W", 0, imm)
+ return 0
+ end
+end
+
+local function parse_imm6(imm)
+ imm = match(imm, "^#(.*)$")
+ if not imm then werror("expected immediate operand") end
+ local n = parse_number(imm)
+ if n then
+ if n >= 0 and n <= 63 then
+ return shl(band(n, 0x1f), 19) + (n >= 32 and 0x80000000 or 0)
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMM6", 0, imm)
+ return 0
+ end
+end
+
+local function parse_imm_load(imm, scale)
+ local n = parse_number(imm)
+ if n then
+ local m = sar(n, scale)
+ if shl(m, scale) == n and m >= 0 and m < 0x1000 then
+ return shl(m, 10) + 0x01000000 -- Scaled, unsigned 12 bit offset.
+ elseif n >= -256 and n < 256 then
+ return shl(band(n, 511), 12) -- Unscaled, signed 9 bit offset.
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMML", 0, imm)
+ return 0
+ end
+end
+
+local function parse_fpimm(imm)
+ imm = match(imm, "^#(.*)$")
+ if not imm then werror("expected immediate operand") end
+ local n = parse_number(imm)
+ if n then
+ local m, e = math.frexp(n)
+ local s, e2 = 0, band(e-2, 7)
+ if m < 0 then m = -m; s = 0x00100000 end
+ m = m*32-16
+ if m % 1 == 0 and m >= 0 and m <= 15 and sar(shl(e2, 29), 29)+2 == e then
+ return s + shl(e2, 17) + shl(m, 13)
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ werror("NYI fpimm action")
+ end
+end
+
+local function parse_shift(expr)
+ local s, s2 = match(expr, "^(%S+)%s*(.*)$")
+ s = map_shift[s]
+ if not s then werror("expected shift operand") end
+ return parse_imm(s2, 6, 10, 0, false) + shl(s, 22)
+end
+
+local function parse_lslx16(expr)
+ local n = match(expr, "^lsl%s*#(%d+)$")
+ n = tonumber(n)
+ if not n then werror("expected shift operand") end
+ if band(n, parse_reg_type == "x" and 0xffffffcf or 0xffffffef) ~= 0 then
+ werror("bad shift amount")
+ end
+ return shl(n, 17)
+end
+
+local function parse_extend(expr)
+ local s, s2 = match(expr, "^(%S+)%s*(.*)$")
+ if s == "lsl" then
+ s = parse_reg_type == "x" and 3 or 2
+ else
+ s = map_extend[s]
+ end
+ if not s then werror("expected extend operand") end
+ return (s2 == "" and 0 or parse_imm(s2, 3, 10, 0, false)) + shl(s, 13)
+end
+
+local function parse_cond(expr, inv)
+ local c = map_cond[expr]
+ if not c then werror("expected condition operand") end
+ return shl(bit.bxor(c, inv), 12)
+end
+
+local function parse_load(params, nparams, n, op)
+ if params[n+2] then werror("too many operands") end
+ local pn, p2 = params[n], params[n+1]
+ local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$")
+ if not p1 then
+ if not p2 then
+ local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$")
+ if reg and tailr ~= "" then
+ local base, tp = parse_reg_base(reg)
+ if tp then
+ waction("IMML", 0, format(tp.ctypefmt, tailr))
+ return op + base
+ end
+ end
+ end
+ werror("expected address operand")
+ end
+ local scale = shr(op, 30)
+ if p2 then
+ if wb == "!" then werror("bad use of '!'") end
+ op = op + parse_reg_base(p1) + parse_imm(p2, 9, 12, 0, true) + 0x400
+ elseif wb == "!" then
+ local p1a, p2a = match(p1, "^([^,%s]*)%s*,%s*(.*)$")
+ if not p1a then werror("bad use of '!'") end
+ op = op + parse_reg_base(p1a) + parse_imm(p2a, 9, 12, 0, true) + 0xc00
+ else
+ local p1a, p2a = match(p1, "^([^,%s]*)%s*(.*)$")
+ op = op + parse_reg_base(p1a)
+ if p2a ~= "" then
+ local imm = match(p2a, "^,%s*#(.*)$")
+ if imm then
+ op = op + parse_imm_load(imm, scale)
+ else
+ local p2b, p3b, p3s = match(p2a, "^,%s*([^,%s]*)%s*,?%s*(%S*)%s*(.*)$")
+ op = op + shl(parse_reg(p2b), 16) + 0x00200800
+ if parse_reg_type ~= "x" and parse_reg_type ~= "w" then
+ werror("bad index register type")
+ end
+ if p3b == "" then
+ if parse_reg_type ~= "x" then werror("bad index register type") end
+ op = op + 0x6000
+ else
+ if p3s == "" or p3s == "#0" then
+ elseif p3s == "#"..scale then
+ op = op + 0x1000
+ else
+ werror("bad scale")
+ end
+ if parse_reg_type == "x" then
+ if p3b == "lsl" and p3s ~= "" then op = op + 0x6000
+ elseif p3b == "sxtx" then op = op + 0xe000
+ else
+ werror("bad extend/shift specifier")
+ end
+ else
+ if p3b == "uxtw" then op = op + 0x4000
+ elseif p3b == "sxtw" then op = op + 0xc000
+ else
+ werror("bad extend/shift specifier")
+ end
+ end
+ end
+ end
+ else
+ if wb == "!" then werror("bad use of '!'") end
+ op = op + 0x01000000
+ end
+ end
+ return op
+end
+
+local function parse_load_pair(params, nparams, n, op)
+ if params[n+2] then werror("too many operands") end
+ local pn, p2 = params[n], params[n+1]
+ local scale = shr(op, 30) == 0 and 2 or 3
+ local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$")
+ if not p1 then
+ if not p2 then
+ local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$")
+ if reg and tailr ~= "" then
+ local base, tp = parse_reg_base(reg)
+ if tp then
+ waction("IMM", 32768+7*32+15+scale*1024, format(tp.ctypefmt, tailr))
+ return op + base + 0x01000000
+ end
+ end
+ end
+ werror("expected address operand")
+ end
+ if p2 then
+ if wb == "!" then werror("bad use of '!'") end
+ op = op + 0x00800000
+ else
+ local p1a, p2a = match(p1, "^([^,%s]*)%s*,%s*(.*)$")
+ if p1a then p1, p2 = p1a, p2a else p2 = "#0" end
+ op = op + (wb == "!" and 0x01800000 or 0x01000000)
+ end
+ return op + parse_reg_base(p1) + parse_imm(p2, 7, 15, scale, true)
+end
+
+local function parse_label(label, def)
+ local prefix = sub(label, 1, 2)
+ -- =>label (pc label reference)
+ if prefix == "=>" then
+ return "PC", 0, sub(label, 3)
+ end
+ -- ->name (global label reference)
+ if prefix == "->" then
+ return "LG", map_global[sub(label, 3)]
+ end
+ if def then
+ -- [1-9] (local label definition)
+ if match(label, "^[1-9]$") then
+ return "LG", 10+tonumber(label)
+ end
+ else
+ -- [<>][1-9] (local label reference)
+ local dir, lnum = match(label, "^([<>])([1-9])$")
+ if dir then -- Fwd: 1-9, Bkwd: 11-19.
+ return "LG", lnum + (dir == ">" and 0 or 10)
+ end
+ -- extern label (extern label reference)
+ local extname = match(label, "^extern%s+(%S+)$")
+ if extname then
+ return "EXT", map_extern[extname]
+ end
+ end
+ werror("bad label `"..label.."'")
+end
+
+local function branch_type(op)
+ if band(op, 0x7c000000) == 0x14000000 then return 0 -- B, BL
+ elseif shr(op, 24) == 0x54 or band(op, 0x7e000000) == 0x34000000 or
+ band(op, 0x3b000000) == 0x18000000 then
+ return 0x800 -- B.cond, CBZ, CBNZ, LDR* literal
+ elseif band(op, 0x7e000000) == 0x36000000 then return 0x1000 -- TBZ, TBNZ
+ elseif band(op, 0x9f000000) == 0x10000000 then return 0x2000 -- ADR
+ elseif band(op, 0x9f000000) == band(0x90000000) then return 0x3000 -- ADRP
+ else
+ assert(false, "unknown branch type")
+ end
+end
+
+------------------------------------------------------------------------------
+
+local map_op, op_template
+
+local function op_alias(opname, f)
+ return function(params, nparams)
+ if not params then return "-> "..opname:sub(1, -3) end
+ f(params, nparams)
+ op_template(params, map_op[opname], nparams)
+ end
+end
+
+local function alias_bfx(p)
+ p[4] = "#("..p[3]:sub(2)..")+("..p[4]:sub(2)..")-1"
+end
+
+local function alias_bfiz(p)
+ parse_reg(p[1])
+ if parse_reg_type == "w" then
+ p[3] = "#-("..p[3]:sub(2)..")%32"
+ p[4] = "#("..p[4]:sub(2)..")-1"
+ else
+ p[3] = "#-("..p[3]:sub(2)..")%64"
+ p[4] = "#("..p[4]:sub(2)..")-1"
+ end
+end
+
+local alias_lslimm = op_alias("ubfm_4", function(p)
+ parse_reg(p[1])
+ local sh = p[3]:sub(2)
+ if parse_reg_type == "w" then
+ p[3] = "#-("..sh..")%32"
+ p[4] = "#31-("..sh..")"
+ else
+ p[3] = "#-("..sh..")%64"
+ p[4] = "#63-("..sh..")"
+ end
+end)
+
+-- Template strings for ARM instructions.
+map_op = {
+ -- Basic data processing instructions.
+ add_3 = "0b000000DNMg|11000000pDpNIg|8b206000pDpNMx",
+ add_4 = "0b000000DNMSg|0b200000DNMXg|8b200000pDpNMXx|8b200000pDpNxMwX",
+ adds_3 = "2b000000DNMg|31000000DpNIg|ab206000DpNMx",
+ adds_4 = "2b000000DNMSg|2b200000DNMXg|ab200000DpNMXx|ab200000DpNxMwX",
+ cmn_2 = "2b00001fNMg|3100001fpNIg|ab20601fpNMx",
+ cmn_3 = "2b00001fNMSg|2b20001fNMXg|ab20001fpNMXx|ab20001fpNxMwX",
+
+ sub_3 = "4b000000DNMg|51000000pDpNIg|cb206000pDpNMx",
+ sub_4 = "4b000000DNMSg|4b200000DNMXg|cb200000pDpNMXx|cb200000pDpNxMwX",
+ subs_3 = "6b000000DNMg|71000000DpNIg|eb206000DpNMx",
+ subs_4 = "6b000000DNMSg|6b200000DNMXg|eb200000DpNMXx|eb200000DpNxMwX",
+ cmp_2 = "6b00001fNMg|7100001fpNIg|eb20601fpNMx",
+ cmp_3 = "6b00001fNMSg|6b20001fNMXg|eb20001fpNMXx|eb20001fpNxMwX",
+
+ neg_2 = "4b0003e0DMg",
+ neg_3 = "4b0003e0DMSg",
+ negs_2 = "6b0003e0DMg",
+ negs_3 = "6b0003e0DMSg",
+
+ adc_3 = "1a000000DNMg",
+ adcs_3 = "3a000000DNMg",
+ sbc_3 = "5a000000DNMg",
+ sbcs_3 = "7a000000DNMg",
+ ngc_2 = "5a0003e0DMg",
+ ngcs_2 = "7a0003e0DMg",
+
+ and_3 = "0a000000DNMg|12000000pDNig",
+ and_4 = "0a000000DNMSg",
+ orr_3 = "2a000000DNMg|32000000pDNig",
+ orr_4 = "2a000000DNMSg",
+ eor_3 = "4a000000DNMg|52000000pDNig",
+ eor_4 = "4a000000DNMSg",
+ ands_3 = "6a000000DNMg|72000000DNig",
+ ands_4 = "6a000000DNMSg",
+ tst_2 = "6a00001fNMg|7200001fNig",
+ tst_3 = "6a00001fNMSg",
+
+ bic_3 = "0a200000DNMg",
+ bic_4 = "0a200000DNMSg",
+ orn_3 = "2a200000DNMg",
+ orn_4 = "2a200000DNMSg",
+ eon_3 = "4a200000DNMg",
+ eon_4 = "4a200000DNMSg",
+ bics_3 = "6a200000DNMg",
+ bics_4 = "6a200000DNMSg",
+
+ movn_2 = "12800000DWg",
+ movn_3 = "12800000DWRg",
+ movz_2 = "52800000DWg",
+ movz_3 = "52800000DWRg",
+ movk_2 = "72800000DWg",
+ movk_3 = "72800000DWRg",
+
+ -- TODO: this doesn't cover all valid immediates for mov reg, #imm.
+ mov_2 = "2a0003e0DMg|52800000DW|320003e0pDig|11000000pDpNg",
+ mov_3 = "2a0003e0DMSg",
+ mvn_2 = "2a2003e0DMg",
+ mvn_3 = "2a2003e0DMSg",
+
+ adr_2 = "10000000DBx",
+ adrp_2 = "90000000DBx",
+
+ csel_4 = "1a800000DNMCg",
+ csinc_4 = "1a800400DNMCg",
+ csinv_4 = "5a800000DNMCg",
+ csneg_4 = "5a800400DNMCg",
+ cset_2 = "1a9f07e0Dcg",
+ csetm_2 = "5a9f03e0Dcg",
+ cinc_3 = "1a800400DNmcg",
+ cinv_3 = "5a800000DNmcg",
+ cneg_3 = "5a800400DNmcg",
+
+ ccmn_4 = "3a400000NMVCg|3a400800N5VCg",
+ ccmp_4 = "7a400000NMVCg|7a400800N5VCg",
+
+ madd_4 = "1b000000DNMAg",
+ msub_4 = "1b008000DNMAg",
+ mul_3 = "1b007c00DNMg",
+ mneg_3 = "1b00fc00DNMg",
+
+ smaddl_4 = "9b200000DxNMwAx",
+ smsubl_4 = "9b208000DxNMwAx",
+ smull_3 = "9b207c00DxNMw",
+ smnegl_3 = "9b20fc00DxNMw",
+ smulh_3 = "9b407c00DNMx",
+ umaddl_4 = "9ba00000DxNMwAx",
+ umsubl_4 = "9ba08000DxNMwAx",
+ umull_3 = "9ba07c00DxNMw",
+ umnegl_3 = "9ba0fc00DxNMw",
+ umulh_3 = "9bc07c00DNMx",
+
+ udiv_3 = "1ac00800DNMg",
+ sdiv_3 = "1ac00c00DNMg",
+
+ -- Bit operations.
+ sbfm_4 = "13000000DN12w|93400000DN12x",
+ bfm_4 = "33000000DN12w|b3400000DN12x",
+ ubfm_4 = "53000000DN12w|d3400000DN12x",
+ extr_4 = "13800000DNM2w|93c00000DNM2x",
+
+ sxtb_2 = "13001c00DNw|93401c00DNx",
+ sxth_2 = "13003c00DNw|93403c00DNx",
+ sxtw_2 = "93407c00DxNw",
+ uxtb_2 = "53001c00DNw",
+ uxth_2 = "53003c00DNw",
+
+ sbfx_4 = op_alias("sbfm_4", alias_bfx),
+ bfxil_4 = op_alias("bfm_4", alias_bfx),
+ ubfx_4 = op_alias("ubfm_4", alias_bfx),
+ sbfiz_4 = op_alias("sbfm_4", alias_bfiz),
+ bfi_4 = op_alias("bfm_4", alias_bfiz),
+ ubfiz_4 = op_alias("ubfm_4", alias_bfiz),
+
+ lsl_3 = function(params, nparams)
+ if params and params[3]:byte() == 35 then
+ return alias_lslimm(params, nparams)
+ else
+ return op_template(params, "1ac02000DNMg", nparams)
+ end
+ end,
+ lsr_3 = "1ac02400DNMg|53007c00DN1w|d340fc00DN1x",
+ asr_3 = "1ac02800DNMg|13007c00DN1w|9340fc00DN1x",
+ ror_3 = "1ac02c00DNMg|13800000DNm2w|93c00000DNm2x",
+
+ clz_2 = "5ac01000DNg",
+ cls_2 = "5ac01400DNg",
+ rbit_2 = "5ac00000DNg",
+ rev_2 = "5ac00800DNw|dac00c00DNx",
+ rev16_2 = "5ac00400DNg",
+ rev32_2 = "dac00800DNx",
+
+ -- Loads and stores.
+ ["strb_*"] = "38000000DwL",
+ ["ldrb_*"] = "38400000DwL",
+ ["ldrsb_*"] = "38c00000DwL|38800000DxL",
+ ["strh_*"] = "78000000DwL",
+ ["ldrh_*"] = "78400000DwL",
+ ["ldrsh_*"] = "78c00000DwL|78800000DxL",
+ ["str_*"] = "b8000000DwL|f8000000DxL|bc000000DsL|fc000000DdL",
+ ["ldr_*"] = "18000000DwB|58000000DxB|1c000000DsB|5c000000DdB|b8400000DwL|f8400000DxL|bc400000DsL|fc400000DdL",
+ ["ldrsw_*"] = "98000000DxB|b8800000DxL",
+ -- NOTE: ldur etc. are handled by ldr et al.
+
+ ["stp_*"] = "28000000DAwP|a8000000DAxP|2c000000DAsP|6c000000DAdP",
+ ["ldp_*"] = "28400000DAwP|a8400000DAxP|2c400000DAsP|6c400000DAdP",
+ ["ldpsw_*"] = "68400000DAxP",
+
+ -- Branches.
+ b_1 = "14000000B",
+ bl_1 = "94000000B",
+ blr_1 = "d63f0000Nx",
+ br_1 = "d61f0000Nx",
+ ret_0 = "d65f03c0",
+ ret_1 = "d65f0000Nx",
+ -- b.cond is added below.
+ cbz_2 = "34000000DBg",
+ cbnz_2 = "35000000DBg",
+ tbz_3 = "36000000DTBw|36000000DTBx",
+ tbnz_3 = "37000000DTBw|37000000DTBx",
+
+ -- Miscellaneous instructions.
+ -- TODO: hlt, hvc, smc, svc, eret, dcps[123], drps, mrs, msr
+ -- TODO: sys, sysl, ic, dc, at, tlbi
+ -- TODO: hint, yield, wfe, wfi, sev, sevl
+ -- TODO: clrex, dsb, dmb, isb
+ nop_0 = "d503201f",
+ brk_0 = "d4200000",
+ brk_1 = "d4200000W",
+
+ -- Floating point instructions.
+ fmov_2 = "1e204000DNf|1e260000DwNs|1e270000DsNw|9e660000DxNd|9e670000DdNx|1e201000DFf",
+ fabs_2 = "1e20c000DNf",
+ fneg_2 = "1e214000DNf",
+ fsqrt_2 = "1e21c000DNf",
+
+ fcvt_2 = "1e22c000DdNs|1e624000DsNd",
+
+ -- TODO: half-precision and fixed-point conversions.
+ fcvtas_2 = "1e240000DwNs|9e240000DxNs|1e640000DwNd|9e640000DxNd",
+ fcvtau_2 = "1e250000DwNs|9e250000DxNs|1e650000DwNd|9e650000DxNd",
+ fcvtms_2 = "1e300000DwNs|9e300000DxNs|1e700000DwNd|9e700000DxNd",
+ fcvtmu_2 = "1e310000DwNs|9e310000DxNs|1e710000DwNd|9e710000DxNd",
+ fcvtns_2 = "1e200000DwNs|9e200000DxNs|1e600000DwNd|9e600000DxNd",
+ fcvtnu_2 = "1e210000DwNs|9e210000DxNs|1e610000DwNd|9e610000DxNd",
+ fcvtps_2 = "1e280000DwNs|9e280000DxNs|1e680000DwNd|9e680000DxNd",
+ fcvtpu_2 = "1e290000DwNs|9e290000DxNs|1e690000DwNd|9e690000DxNd",
+ fcvtzs_2 = "1e380000DwNs|9e380000DxNs|1e780000DwNd|9e780000DxNd",
+ fcvtzu_2 = "1e390000DwNs|9e390000DxNs|1e790000DwNd|9e790000DxNd",
+
+ scvtf_2 = "1e220000DsNw|9e220000DsNx|1e620000DdNw|9e620000DdNx",
+ ucvtf_2 = "1e230000DsNw|9e230000DsNx|1e630000DdNw|9e630000DdNx",
+
+ frintn_2 = "1e244000DNf",
+ frintp_2 = "1e24c000DNf",
+ frintm_2 = "1e254000DNf",
+ frintz_2 = "1e25c000DNf",
+ frinta_2 = "1e264000DNf",
+ frintx_2 = "1e274000DNf",
+ frinti_2 = "1e27c000DNf",
+
+ fadd_3 = "1e202800DNMf",
+ fsub_3 = "1e203800DNMf",
+ fmul_3 = "1e200800DNMf",
+ fnmul_3 = "1e208800DNMf",
+ fdiv_3 = "1e201800DNMf",
+
+ fmadd_4 = "1f000000DNMAf",
+ fmsub_4 = "1f008000DNMAf",
+ fnmadd_4 = "1f200000DNMAf",
+ fnmsub_4 = "1f208000DNMAf",
+
+ fmax_3 = "1e204800DNMf",
+ fmaxnm_3 = "1e206800DNMf",
+ fmin_3 = "1e205800DNMf",
+ fminnm_3 = "1e207800DNMf",
+
+ fcmp_2 = "1e202000NMf|1e202008NZf",
+ fcmpe_2 = "1e202010NMf|1e202018NZf",
+
+ fccmp_4 = "1e200400NMVCf",
+ fccmpe_4 = "1e200410NMVCf",
+
+ fcsel_4 = "1e200c00DNMCf",
+
+ -- TODO: crc32*, aes*, sha*, pmull
+ -- TODO: SIMD instructions.
+}
+
+for cond,c in pairs(map_cond) do
+ map_op["b"..cond.."_1"] = tohex(0x54000000+c).."B"
+end
+
+------------------------------------------------------------------------------
+
+-- Handle opcodes defined with template strings.
+local function parse_template(params, template, nparams, pos)
+ local op = tonumber(sub(template, 1, 8), 16)
+ local n = 1
+ local rtt = {}
+
+ parse_reg_type = false
+
+ -- Process each character.
+ for p in gmatch(sub(template, 9), ".") do
+ local q = params[n]
+ if p == "D" then
+ op = op + parse_reg(q); n = n + 1
+ elseif p == "N" then
+ op = op + shl(parse_reg(q), 5); n = n + 1
+ elseif p == "M" then
+ op = op + shl(parse_reg(q), 16); n = n + 1
+ elseif p == "A" then
+ op = op + shl(parse_reg(q), 10); n = n + 1
+ elseif p == "m" then
+ op = op + shl(parse_reg(params[n-1]), 16)
+
+ elseif p == "p" then
+ if q == "sp" then params[n] = "@x31" end
+ elseif p == "g" then
+ if parse_reg_type == "x" then
+ op = op + 0x80000000
+ elseif parse_reg_type ~= "w" then
+ werror("bad register type")
+ end
+ parse_reg_type = false
+ elseif p == "f" then
+ if parse_reg_type == "d" then
+ op = op + 0x00400000
+ elseif parse_reg_type ~= "s" then
+ werror("bad register type")
+ end
+ parse_reg_type = false
+ elseif p == "x" or p == "w" or p == "d" or p == "s" then
+ if parse_reg_type ~= p then
+ werror("register size mismatch")
+ end
+ parse_reg_type = false
+
+ elseif p == "L" then
+ op = parse_load(params, nparams, n, op)
+ elseif p == "P" then
+ op = parse_load_pair(params, nparams, n, op)
+
+ elseif p == "B" then
+ local mode, v, s = parse_label(q, false); n = n + 1
+ local m = branch_type(op)
+ waction("REL_"..mode, v+m, s, 1)
+
+ elseif p == "I" then
+ op = op + parse_imm12(q); n = n + 1
+ elseif p == "i" then
+ op = op + parse_imm13(q); n = n + 1
+ elseif p == "W" then
+ op = op + parse_imm(q, 16, 5, 0, false); n = n + 1
+ elseif p == "T" then
+ op = op + parse_imm6(q); n = n + 1
+ elseif p == "1" then
+ op = op + parse_imm(q, 6, 16, 0, false); n = n + 1
+ elseif p == "2" then
+ op = op + parse_imm(q, 6, 10, 0, false); n = n + 1
+ elseif p == "5" then
+ op = op + parse_imm(q, 5, 16, 0, false); n = n + 1
+ elseif p == "V" then
+ op = op + parse_imm(q, 4, 0, 0, false); n = n + 1
+ elseif p == "F" then
+ op = op + parse_fpimm(q); n = n + 1
+ elseif p == "Z" then
+ if q ~= "#0" and q ~= "#0.0" then werror("expected zero immediate") end
+ n = n + 1
+
+ elseif p == "S" then
+ op = op + parse_shift(q); n = n + 1
+ elseif p == "X" then
+ op = op + parse_extend(q); n = n + 1
+ elseif p == "R" then
+ op = op + parse_lslx16(q); n = n + 1
+ elseif p == "C" then
+ op = op + parse_cond(q, 0); n = n + 1
+ elseif p == "c" then
+ op = op + parse_cond(q, 1); n = n + 1
+
+ else
+ assert(false)
+ end
+ end
+ wputpos(pos, op)
+end
+
+function op_template(params, template, nparams)
+ if not params then return template:gsub("%x%x%x%x%x%x%x%x", "") end
+
+ -- Limit number of section buffer positions used by a single dasm_put().
+ -- A single opcode needs a maximum of 3 positions.
+ if secpos+3 > maxsecpos then wflush() end
+ local pos = wpos()
+ local lpos, apos, spos = #actlist, #actargs, secpos
+
+ local ok, err
+ for t in gmatch(template, "[^|]+") do
+ ok, err = pcall(parse_template, params, t, nparams, pos)
+ if ok then return end
+ secpos = spos
+ actlist[lpos+1] = nil
+ actlist[lpos+2] = nil
+ actlist[lpos+3] = nil
+ actargs[apos+1] = nil
+ actargs[apos+2] = nil
+ actargs[apos+3] = nil
+ end
+ error(err, 0)
+end
+
+map_op[".template__"] = op_template
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode to mark the position where the action list is to be emitted.
+map_op[".actionlist_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeactions(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the global enum is to be emitted.
+map_op[".globals_1"] = function(params)
+ if not params then return "prefix" end
+ local prefix = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobals(out, prefix) end)
+end
+
+-- Pseudo-opcode to mark the position where the global names are to be emitted.
+map_op[".globalnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobalnames(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the extern names are to be emitted.
+map_op[".externnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeexternnames(out, name) end)
+end
+
+------------------------------------------------------------------------------
+
+-- Label pseudo-opcode (converted from trailing colon form).
+map_op[".label_1"] = function(params)
+ if not params then return "[1-9] | ->global | =>pcexpr" end
+ if secpos+1 > maxsecpos then wflush() end
+ local mode, n, s = parse_label(params[1], true)
+ if mode == "EXT" then werror("bad label definition") end
+ waction("LABEL_"..mode, n, s, 1)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcodes for data storage.
+map_op[".long_*"] = function(params)
+ if not params then return "imm..." end
+ for _,p in ipairs(params) do
+ local n = tonumber(p)
+ if not n then werror("bad immediate `"..p.."'") end
+ if n < 0 then n = n + 2^32 end
+ wputw(n)
+ if secpos+2 > maxsecpos then wflush() end
+ end
+end
+
+-- Alignment pseudo-opcode.
+map_op[".align_1"] = function(params)
+ if not params then return "numpow2" end
+ if secpos+1 > maxsecpos then wflush() end
+ local align = tonumber(params[1])
+ if align then
+ local x = align
+ -- Must be a power of 2 in the range (2 ... 256).
+ for i=1,8 do
+ x = x / 2
+ if x == 1 then
+ waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
+ return
+ end
+ end
+ end
+ werror("bad alignment")
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode for (primitive) type definitions (map to C types).
+map_op[".type_3"] = function(params, nparams)
+ if not params then
+ return nparams == 2 and "name, ctype" or "name, ctype, reg"
+ end
+ local name, ctype, reg = params[1], params[2], params[3]
+ if not match(name, "^[%a_][%w_]*$") then
+ werror("bad type name `"..name.."'")
+ end
+ local tp = map_type[name]
+ if tp then
+ werror("duplicate type `"..name.."'")
+ end
+ -- Add #type to defines. A bit unclean to put it in map_archdef.
+ map_archdef["#"..name] = "sizeof("..ctype..")"
+ -- Add new type and emit shortcut define.
+ local num = ctypenum + 1
+ map_type[name] = {
+ ctype = ctype,
+ ctypefmt = format("Dt%X(%%s)", num),
+ reg = reg,
+ }
+ wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
+ ctypenum = num
+end
+map_op[".type_2"] = map_op[".type_3"]
+
+-- Dump type definitions.
+local function dumptypes(out, lvl)
+ local t = {}
+ for name in pairs(map_type) do t[#t+1] = name end
+ sort(t)
+ out:write("Type definitions:\n")
+ for _,name in ipairs(t) do
+ local tp = map_type[name]
+ local reg = tp.reg or ""
+ out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
+ end
+ out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Set the current section.
+function _M.section(num)
+ waction("SECTION", num)
+ wflush(true) -- SECTION is a terminal action.
+end
+
+------------------------------------------------------------------------------
+
+-- Dump architecture description.
+function _M.dumparch(out)
+ out:write(format("DynASM %s version %s, released %s\n\n",
+ _info.arch, _info.version, _info.release))
+ dumpactions(out)
+end
+
+-- Dump all user defined elements.
+function _M.dumpdef(out, lvl)
+ dumptypes(out, lvl)
+ dumpglobals(out, lvl)
+ dumpexterns(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Pass callbacks from/to the DynASM core.
+function _M.passcb(wl, we, wf, ww)
+ wline, werror, wfatal, wwarn = wl, we, wf, ww
+ return wflush
+end
+
+-- Setup the arch-specific module.
+function _M.setup(arch, opt)
+ g_arch, g_opt = arch, opt
+end
+
+-- Merge the core maps and the arch-specific maps.
+function _M.mergemaps(map_coreop, map_def)
+ setmetatable(map_op, { __index = map_coreop })
+ setmetatable(map_def, { __index = map_archdef })
+ return map_op, map_def
+end
+
+return _M
+
+------------------------------------------------------------------------------
+
diff --git a/src/host/luajit-2.1.0-beta3/dynasm/dasm_mips.h b/src/host/luajit-2.1.0-beta3/dynasm/dasm_mips.h
new file mode 100644
index 00000000..4b49fd8c
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/dynasm/dasm_mips.h
@@ -0,0 +1,419 @@
+/*
+** DynASM MIPS encoding engine.
+** Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+** Released under the MIT license. See dynasm.lua for full copyright notice.
+*/
+
+#include
+#include
+#include
+#include
+
+#define DASM_ARCH "mips"
+
+#ifndef DASM_EXTERN
+#define DASM_EXTERN(a,b,c,d) 0
+#endif
+
+/* Action definitions. */
+enum {
+ DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
+ /* The following actions need a buffer position. */
+ DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
+ /* The following actions also have an argument. */
+ DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMS,
+ DASM__MAX
+};
+
+/* Maximum number of section buffer positions for a single dasm_put() call. */
+#define DASM_MAXSECPOS 25
+
+/* DynASM encoder status codes. Action list offset or number are or'ed in. */
+#define DASM_S_OK 0x00000000
+#define DASM_S_NOMEM 0x01000000
+#define DASM_S_PHASE 0x02000000
+#define DASM_S_MATCH_SEC 0x03000000
+#define DASM_S_RANGE_I 0x11000000
+#define DASM_S_RANGE_SEC 0x12000000
+#define DASM_S_RANGE_LG 0x13000000
+#define DASM_S_RANGE_PC 0x14000000
+#define DASM_S_RANGE_REL 0x15000000
+#define DASM_S_UNDEF_LG 0x21000000
+#define DASM_S_UNDEF_PC 0x22000000
+
+/* Macros to convert positions (8 bit section + 24 bit index). */
+#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
+#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
+#define DASM_SEC2POS(sec) ((sec)<<24)
+#define DASM_POS2SEC(pos) ((pos)>>24)
+#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
+
+/* Action list type. */
+typedef const unsigned int *dasm_ActList;
+
+/* Per-section structure. */
+typedef struct dasm_Section {
+ int *rbuf; /* Biased buffer pointer (negative section bias). */
+ int *buf; /* True buffer pointer. */
+ size_t bsize; /* Buffer size in bytes. */
+ int pos; /* Biased buffer position. */
+ int epos; /* End of biased buffer position - max single put. */
+ int ofs; /* Byte offset into section. */
+} dasm_Section;
+
+/* Core structure holding the DynASM encoding state. */
+struct dasm_State {
+ size_t psize; /* Allocated size of this structure. */
+ dasm_ActList actionlist; /* Current actionlist pointer. */
+ int *lglabels; /* Local/global chain/pos ptrs. */
+ size_t lgsize;
+ int *pclabels; /* PC label chains/pos ptrs. */
+ size_t pcsize;
+ void **globals; /* Array of globals (bias -10). */
+ dasm_Section *section; /* Pointer to active section. */
+ size_t codesize; /* Total size of all code sections. */
+ int maxsection; /* 0 <= sectionidx < maxsection. */
+ int status; /* Status code. */
+ dasm_Section sections[1]; /* All sections. Alloc-extended. */
+};
+
+/* The size of the core structure depends on the max. number of sections. */
+#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
+
+
+/* Initialize DynASM state. */
+void dasm_init(Dst_DECL, int maxsection)
+{
+ dasm_State *D;
+ size_t psz = 0;
+ int i;
+ Dst_REF = NULL;
+ DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
+ D = Dst_REF;
+ D->psize = psz;
+ D->lglabels = NULL;
+ D->lgsize = 0;
+ D->pclabels = NULL;
+ D->pcsize = 0;
+ D->globals = NULL;
+ D->maxsection = maxsection;
+ for (i = 0; i < maxsection; i++) {
+ D->sections[i].buf = NULL; /* Need this for pass3. */
+ D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
+ D->sections[i].bsize = 0;
+ D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
+ }
+}
+
+/* Free DynASM state. */
+void dasm_free(Dst_DECL)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ for (i = 0; i < D->maxsection; i++)
+ if (D->sections[i].buf)
+ DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
+ if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
+ if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
+ DASM_M_FREE(Dst, D, D->psize);
+}
+
+/* Setup global label array. Must be called before dasm_setup(). */
+void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
+{
+ dasm_State *D = Dst_REF;
+ D->globals = gl - 10; /* Negative bias to compensate for locals. */
+ DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
+}
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+void dasm_growpc(Dst_DECL, unsigned int maxpc)
+{
+ dasm_State *D = Dst_REF;
+ size_t osz = D->pcsize;
+ DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
+ memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
+}
+
+/* Setup encoder. */
+void dasm_setup(Dst_DECL, const void *actionlist)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ D->actionlist = (dasm_ActList)actionlist;
+ D->status = DASM_S_OK;
+ D->section = &D->sections[0];
+ memset((void *)D->lglabels, 0, D->lgsize);
+ if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
+ for (i = 0; i < D->maxsection; i++) {
+ D->sections[i].pos = DASM_SEC2POS(i);
+ D->sections[i].ofs = 0;
+ }
+}
+
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) { \
+ D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
+#define CKPL(kind, st) \
+ do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
+ D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
+#else
+#define CK(x, st) ((void)0)
+#define CKPL(kind, st) ((void)0)
+#endif
+
+/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
+void dasm_put(Dst_DECL, int start, ...)
+{
+ va_list ap;
+ dasm_State *D = Dst_REF;
+ dasm_ActList p = D->actionlist + start;
+ dasm_Section *sec = D->section;
+ int pos = sec->pos, ofs = sec->ofs;
+ int *b;
+
+ if (pos >= sec->epos) {
+ DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
+ sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
+ sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
+ sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
+ }
+
+ b = sec->rbuf;
+ b[pos++] = start;
+
+ va_start(ap, start);
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16) - 0xff00;
+ if (action >= DASM__MAX) {
+ ofs += 4;
+ } else {
+ int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
+ switch (action) {
+ case DASM_STOP: goto stop;
+ case DASM_SECTION:
+ n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
+ D->section = &D->sections[n]; goto stop;
+ case DASM_ESC: p++; ofs += 4; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
+ case DASM_REL_LG:
+ n = (ins & 2047) - 10; pl = D->lglabels + n;
+ /* Bkwd rel or global. */
+ if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
+ pl += 10; n = *pl;
+ if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
+ goto linkrel;
+ case DASM_REL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putrel:
+ n = *pl;
+ if (n < 0) { /* Label exists. Get label pos and store it. */
+ b[pos] = -n;
+ } else {
+ linkrel:
+ b[pos] = n; /* Else link to rel chain, anchored at label. */
+ *pl = pos;
+ }
+ pos++;
+ break;
+ case DASM_LABEL_LG:
+ pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
+ case DASM_LABEL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putlabel:
+ n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
+ }
+ *pl = -pos; /* Label exists now. */
+ b[pos++] = ofs; /* Store pass1 offset estimate. */
+ break;
+ case DASM_IMM: case DASM_IMMS:
+#ifdef DASM_CHECKS
+ CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
+#endif
+ n >>= ((ins>>10)&31);
+#ifdef DASM_CHECKS
+ if (ins & 0x8000)
+ CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
+ else
+ CK((n>>((ins>>5)&31)) == 0, RANGE_I);
+#endif
+ b[pos++] = n;
+ break;
+ }
+ }
+ }
+stop:
+ va_end(ap);
+ sec->pos = pos;
+ sec->ofs = ofs;
+}
+#undef CK
+
+/* Pass 2: Link sections, shrink aligns, fix label offsets. */
+int dasm_link(Dst_DECL, size_t *szp)
+{
+ dasm_State *D = Dst_REF;
+ int secnum;
+ int ofs = 0;
+
+#ifdef DASM_CHECKS
+ *szp = 0;
+ if (D->status != DASM_S_OK) return D->status;
+ {
+ int pc;
+ for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
+ if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
+ }
+#endif
+
+ { /* Handle globals not defined in this translation unit. */
+ int idx;
+ for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
+ int n = D->lglabels[idx];
+ /* Undefined label: Collapse rel chain and replace with marker (< 0). */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
+ }
+ }
+
+ /* Combine all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->rbuf;
+ int pos = DASM_SEC2POS(secnum);
+ int lastpos = sec->pos;
+
+ while (pos != lastpos) {
+ dasm_ActList p = D->actionlist + b[pos++];
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16) - 0xff00;
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: p++; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
+ case DASM_REL_LG: case DASM_REL_PC: pos++; break;
+ case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
+ case DASM_IMM: case DASM_IMMS: pos++; break;
+ }
+ }
+ stop: (void)0;
+ }
+ ofs += sec->ofs; /* Next section starts right after current section. */
+ }
+
+ D->codesize = ofs; /* Total size of all code sections */
+ *szp = ofs;
+ return DASM_S_OK;
+}
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
+#else
+#define CK(x, st) ((void)0)
+#endif
+
+/* Pass 3: Encode sections. */
+int dasm_encode(Dst_DECL, void *buffer)
+{
+ dasm_State *D = Dst_REF;
+ char *base = (char *)buffer;
+ unsigned int *cp = (unsigned int *)buffer;
+ int secnum;
+
+ /* Encode all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->buf;
+ int *endb = sec->rbuf + sec->pos;
+
+ while (b != endb) {
+ dasm_ActList p = D->actionlist + *b++;
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16) - 0xff00;
+ int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: *cp++ = *p++; break;
+ case DASM_REL_EXT:
+ n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1);
+ goto patchrel;
+ case DASM_ALIGN:
+ ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000;
+ break;
+ case DASM_REL_LG:
+ CK(n >= 0, UNDEF_LG);
+ case DASM_REL_PC:
+ CK(n >= 0, UNDEF_PC);
+ n = *DASM_POS2PTR(D, n);
+ if (ins & 2048)
+ n = n - (int)((char *)cp - base);
+ else
+ n = (n + (int)(size_t)base) & 0x0fffffff;
+ patchrel:
+ CK((n & 3) == 0 &&
+ ((n + ((ins & 2048) ? 0x00020000 : 0)) >>
+ ((ins & 2048) ? 18 : 28)) == 0, RANGE_REL);
+ cp[-1] |= ((n>>2) & ((ins & 2048) ? 0x0000ffff: 0x03ffffff));
+ break;
+ case DASM_LABEL_LG:
+ ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
+ break;
+ case DASM_LABEL_PC: break;
+ case DASM_IMMS:
+ cp[-1] |= ((n>>3) & 4); n &= 0x1f;
+ /* fallthrough */
+ case DASM_IMM:
+ cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
+ break;
+ default: *cp++ = ins; break;
+ }
+ }
+ stop: (void)0;
+ }
+ }
+
+ if (base + D->codesize != (char *)cp) /* Check for phase errors. */
+ return DASM_S_PHASE;
+ return DASM_S_OK;
+}
+#undef CK
+
+/* Get PC label offset. */
+int dasm_getpclabel(Dst_DECL, unsigned int pc)
+{
+ dasm_State *D = Dst_REF;
+ if (pc*sizeof(int) < D->pcsize) {
+ int pos = D->pclabels[pc];
+ if (pos < 0) return *DASM_POS2PTR(D, -pos);
+ if (pos > 0) return -1; /* Undefined. */
+ }
+ return -2; /* Unused or out of range. */
+}
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+int dasm_checkstep(Dst_DECL, int secmatch)
+{
+ dasm_State *D = Dst_REF;
+ if (D->status == DASM_S_OK) {
+ int i;
+ for (i = 1; i <= 9; i++) {
+ if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
+ D->lglabels[i] = 0;
+ }
+ }
+ if (D->status == DASM_S_OK && secmatch >= 0 &&
+ D->section != &D->sections[secmatch])
+ D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
+ return D->status;
+}
+#endif
+
diff --git a/src/host/luajit-2.1.0-beta3/dynasm/dasm_mips.lua b/src/host/luajit-2.1.0-beta3/dynasm/dasm_mips.lua
new file mode 100644
index 00000000..78a4e34a
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/dynasm/dasm_mips.lua
@@ -0,0 +1,1008 @@
+------------------------------------------------------------------------------
+-- DynASM MIPS32/MIPS64 module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+
+local mips64 = mips64
+
+-- Module information:
+local _info = {
+ arch = mips64 and "mips64" or "mips",
+ description = "DynASM MIPS32/MIPS64 module",
+ version = "1.4.0",
+ vernum = 10400,
+ release = "2016-05-24",
+ author = "Mike Pall",
+ license = "MIT",
+}
+
+-- Exported glue functions for the arch-specific module.
+local _M = { _info = _info }
+
+-- Cache library functions.
+local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
+local assert, setmetatable = assert, setmetatable
+local _s = string
+local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
+local match, gmatch = _s.match, _s.gmatch
+local concat, sort = table.concat, table.sort
+local bit = bit or require("bit")
+local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift
+local tohex = bit.tohex
+
+-- Inherited tables and callbacks.
+local g_opt, g_arch
+local wline, werror, wfatal, wwarn
+
+-- Action name list.
+-- CHECK: Keep this in sync with the C code!
+local action_names = {
+ "STOP", "SECTION", "ESC", "REL_EXT",
+ "ALIGN", "REL_LG", "LABEL_LG",
+ "REL_PC", "LABEL_PC", "IMM", "IMMS",
+}
+
+-- Maximum number of section buffer positions for dasm_put().
+-- CHECK: Keep this in sync with the C code!
+local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
+
+-- Action name -> action number.
+local map_action = {}
+for n,name in ipairs(action_names) do
+ map_action[name] = n-1
+end
+
+-- Action list buffer.
+local actlist = {}
+
+-- Argument list for next dasm_put(). Start with offset 0 into action list.
+local actargs = { 0 }
+
+-- Current number of section buffer positions for dasm_put().
+local secpos = 1
+
+------------------------------------------------------------------------------
+
+-- Dump action names and numbers.
+local function dumpactions(out)
+ out:write("DynASM encoding engine action codes:\n")
+ for n,name in ipairs(action_names) do
+ local num = map_action[name]
+ out:write(format(" %-10s %02X %d\n", name, num, num))
+ end
+ out:write("\n")
+end
+
+-- Write action list buffer as a huge static C array.
+local function writeactions(out, name)
+ local nn = #actlist
+ if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
+ out:write("static const unsigned int ", name, "[", nn, "] = {\n")
+ for i = 1,nn-1 do
+ assert(out:write("0x", tohex(actlist[i]), ",\n"))
+ end
+ assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
+end
+
+------------------------------------------------------------------------------
+
+-- Add word to action list.
+local function wputxw(n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ actlist[#actlist+1] = n
+end
+
+-- Add action to list with optional arg. Advance buffer pos, too.
+local function waction(action, val, a, num)
+ local w = assert(map_action[action], "bad action name `"..action.."'")
+ wputxw(0xff000000 + w * 0x10000 + (val or 0))
+ if a then actargs[#actargs+1] = a end
+ if a or num then secpos = secpos + (num or 1) end
+end
+
+-- Flush action list (intervening C code or buffer pos overflow).
+local function wflush(term)
+ if #actlist == actargs[1] then return end -- Nothing to flush.
+ if not term then waction("STOP") end -- Terminate action list.
+ wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
+ actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
+ secpos = 1 -- The actionlist offset occupies a buffer position, too.
+end
+
+-- Put escaped word.
+local function wputw(n)
+ if n >= 0xff000000 then waction("ESC") end
+ wputxw(n)
+end
+
+-- Reserve position for word.
+local function wpos()
+ local pos = #actlist+1
+ actlist[pos] = ""
+ return pos
+end
+
+-- Store word to reserved position.
+local function wputpos(pos, n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ actlist[pos] = n
+end
+
+------------------------------------------------------------------------------
+
+-- Global label name -> global label number. With auto assignment on 1st use.
+local next_global = 20
+local map_global = setmetatable({}, { __index = function(t, name)
+ if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
+ local n = next_global
+ if n > 2047 then werror("too many global labels") end
+ next_global = n + 1
+ t[name] = n
+ return n
+end})
+
+-- Dump global labels.
+local function dumpglobals(out, lvl)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("Global labels:\n")
+ for i=20,next_global-1 do
+ out:write(format(" %s\n", t[i]))
+ end
+ out:write("\n")
+end
+
+-- Write global label enum.
+local function writeglobals(out, prefix)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("enum {\n")
+ for i=20,next_global-1 do
+ out:write(" ", prefix, t[i], ",\n")
+ end
+ out:write(" ", prefix, "_MAX\n};\n")
+end
+
+-- Write global label names.
+local function writeglobalnames(out, name)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=20,next_global-1 do
+ out:write(" \"", t[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Extern label name -> extern label number. With auto assignment on 1st use.
+local next_extern = 0
+local map_extern_ = {}
+local map_extern = setmetatable({}, { __index = function(t, name)
+ -- No restrictions on the name for now.
+ local n = next_extern
+ if n > 2047 then werror("too many extern labels") end
+ next_extern = n + 1
+ t[name] = n
+ map_extern_[n] = name
+ return n
+end})
+
+-- Dump extern labels.
+local function dumpexterns(out, lvl)
+ out:write("Extern labels:\n")
+ for i=0,next_extern-1 do
+ out:write(format(" %s\n", map_extern_[i]))
+ end
+ out:write("\n")
+end
+
+-- Write extern label names.
+local function writeexternnames(out, name)
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=0,next_extern-1 do
+ out:write(" \"", map_extern_[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Arch-specific maps.
+local map_archdef = { sp="r29", ra="r31" } -- Ext. register name -> int. name.
+
+local map_type = {} -- Type name -> { ctype, reg }
+local ctypenum = 0 -- Type number (for Dt... macros).
+
+-- Reverse defines for registers.
+function _M.revdef(s)
+ if s == "r29" then return "sp"
+ elseif s == "r31" then return "ra" end
+ return s
+end
+
+------------------------------------------------------------------------------
+
+-- Template strings for MIPS instructions.
+local map_op = {
+ -- First-level opcodes.
+ j_1 = "08000000J",
+ jal_1 = "0c000000J",
+ b_1 = "10000000B",
+ beqz_2 = "10000000SB",
+ beq_3 = "10000000STB",
+ bnez_2 = "14000000SB",
+ bne_3 = "14000000STB",
+ blez_2 = "18000000SB",
+ bgtz_2 = "1c000000SB",
+ addi_3 = "20000000TSI",
+ li_2 = "24000000TI",
+ addiu_3 = "24000000TSI",
+ slti_3 = "28000000TSI",
+ sltiu_3 = "2c000000TSI",
+ andi_3 = "30000000TSU",
+ lu_2 = "34000000TU",
+ ori_3 = "34000000TSU",
+ xori_3 = "38000000TSU",
+ lui_2 = "3c000000TU",
+ beqzl_2 = "50000000SB",
+ beql_3 = "50000000STB",
+ bnezl_2 = "54000000SB",
+ bnel_3 = "54000000STB",
+ blezl_2 = "58000000SB",
+ bgtzl_2 = "5c000000SB",
+ daddi_3 = mips64 and "60000000TSI",
+ daddiu_3 = mips64 and "64000000TSI",
+ ldl_2 = mips64 and "68000000TO",
+ ldr_2 = mips64 and "6c000000TO",
+ lb_2 = "80000000TO",
+ lh_2 = "84000000TO",
+ lwl_2 = "88000000TO",
+ lw_2 = "8c000000TO",
+ lbu_2 = "90000000TO",
+ lhu_2 = "94000000TO",
+ lwr_2 = "98000000TO",
+ lwu_2 = mips64 and "9c000000TO",
+ sb_2 = "a0000000TO",
+ sh_2 = "a4000000TO",
+ swl_2 = "a8000000TO",
+ sw_2 = "ac000000TO",
+ sdl_2 = mips64 and "b0000000TO",
+ sdr_2 = mips64 and "b1000000TO",
+ swr_2 = "b8000000TO",
+ cache_2 = "bc000000NO",
+ ll_2 = "c0000000TO",
+ lwc1_2 = "c4000000HO",
+ pref_2 = "cc000000NO",
+ ldc1_2 = "d4000000HO",
+ ld_2 = mips64 and "dc000000TO",
+ sc_2 = "e0000000TO",
+ swc1_2 = "e4000000HO",
+ scd_2 = mips64 and "f0000000TO",
+ sdc1_2 = "f4000000HO",
+ sd_2 = mips64 and "fc000000TO",
+
+ -- Opcode SPECIAL.
+ nop_0 = "00000000",
+ sll_3 = "00000000DTA",
+ sextw_2 = "00000000DT",
+ movf_2 = "00000001DS",
+ movf_3 = "00000001DSC",
+ movt_2 = "00010001DS",
+ movt_3 = "00010001DSC",
+ srl_3 = "00000002DTA",
+ rotr_3 = "00200002DTA",
+ sra_3 = "00000003DTA",
+ sllv_3 = "00000004DTS",
+ srlv_3 = "00000006DTS",
+ rotrv_3 = "00000046DTS",
+ drotrv_3 = mips64 and "00000056DTS",
+ srav_3 = "00000007DTS",
+ jr_1 = "00000008S",
+ jalr_1 = "0000f809S",
+ jalr_2 = "00000009DS",
+ movz_3 = "0000000aDST",
+ movn_3 = "0000000bDST",
+ syscall_0 = "0000000c",
+ syscall_1 = "0000000cY",
+ break_0 = "0000000d",
+ break_1 = "0000000dY",
+ sync_0 = "0000000f",
+ mfhi_1 = "00000010D",
+ mthi_1 = "00000011S",
+ mflo_1 = "00000012D",
+ mtlo_1 = "00000013S",
+ dsllv_3 = mips64 and "00000014DTS",
+ dsrlv_3 = mips64 and "00000016DTS",
+ dsrav_3 = mips64 and "00000017DTS",
+ mult_2 = "00000018ST",
+ multu_2 = "00000019ST",
+ div_2 = "0000001aST",
+ divu_2 = "0000001bST",
+ dmult_2 = mips64 and "0000001cST",
+ dmultu_2 = mips64 and "0000001dST",
+ ddiv_2 = mips64 and "0000001eST",
+ ddivu_2 = mips64 and "0000001fST",
+ add_3 = "00000020DST",
+ move_2 = mips64 and "00000025DS" or "00000021DS",
+ addu_3 = "00000021DST",
+ sub_3 = "00000022DST",
+ negu_2 = mips64 and "0000002fDT" or "00000023DT",
+ subu_3 = "00000023DST",
+ and_3 = "00000024DST",
+ or_3 = "00000025DST",
+ xor_3 = "00000026DST",
+ not_2 = "00000027DS",
+ nor_3 = "00000027DST",
+ slt_3 = "0000002aDST",
+ sltu_3 = "0000002bDST",
+ dadd_3 = mips64 and "0000002cDST",
+ daddu_3 = mips64 and "0000002dDST",
+ dsub_3 = mips64 and "0000002eDST",
+ dsubu_3 = mips64 and "0000002fDST",
+ tge_2 = "00000030ST",
+ tge_3 = "00000030STZ",
+ tgeu_2 = "00000031ST",
+ tgeu_3 = "00000031STZ",
+ tlt_2 = "00000032ST",
+ tlt_3 = "00000032STZ",
+ tltu_2 = "00000033ST",
+ tltu_3 = "00000033STZ",
+ teq_2 = "00000034ST",
+ teq_3 = "00000034STZ",
+ tne_2 = "00000036ST",
+ tne_3 = "00000036STZ",
+ dsll_3 = mips64 and "00000038DTa",
+ dsrl_3 = mips64 and "0000003aDTa",
+ drotr_3 = mips64 and "0020003aDTa",
+ dsra_3 = mips64 and "0000003bDTa",
+ dsll32_3 = mips64 and "0000003cDTA",
+ dsrl32_3 = mips64 and "0000003eDTA",
+ drotr32_3 = mips64 and "0020003eDTA",
+ dsra32_3 = mips64 and "0000003fDTA",
+
+ -- Opcode REGIMM.
+ bltz_2 = "04000000SB",
+ bgez_2 = "04010000SB",
+ bltzl_2 = "04020000SB",
+ bgezl_2 = "04030000SB",
+ tgei_2 = "04080000SI",
+ tgeiu_2 = "04090000SI",
+ tlti_2 = "040a0000SI",
+ tltiu_2 = "040b0000SI",
+ teqi_2 = "040c0000SI",
+ tnei_2 = "040e0000SI",
+ bltzal_2 = "04100000SB",
+ bal_1 = "04110000B",
+ bgezal_2 = "04110000SB",
+ bltzall_2 = "04120000SB",
+ bgezall_2 = "04130000SB",
+ synci_1 = "041f0000O",
+
+ -- Opcode SPECIAL2.
+ madd_2 = "70000000ST",
+ maddu_2 = "70000001ST",
+ mul_3 = "70000002DST",
+ msub_2 = "70000004ST",
+ msubu_2 = "70000005ST",
+ clz_2 = "70000020DS=",
+ clo_2 = "70000021DS=",
+ dclz_2 = mips64 and "70000024DS=",
+ dclo_2 = mips64 and "70000025DS=",
+ sdbbp_0 = "7000003f",
+ sdbbp_1 = "7000003fY",
+
+ -- Opcode SPECIAL3.
+ ext_4 = "7c000000TSAM", -- Note: last arg is msbd = size-1
+ dextm_4 = mips64 and "7c000001TSAM", -- Args: pos | size-1-32
+ dextu_4 = mips64 and "7c000002TSAM", -- Args: pos-32 | size-1
+ dext_4 = mips64 and "7c000003TSAM", -- Args: pos | size-1
+ zextw_2 = mips64 and "7c00f803TS",
+ ins_4 = "7c000004TSAM", -- Note: last arg is msb = pos+size-1
+ dinsm_4 = mips64 and "7c000005TSAM", -- Args: pos | pos+size-33
+ dinsu_4 = mips64 and "7c000006TSAM", -- Args: pos-32 | pos+size-33
+ dins_4 = mips64 and "7c000007TSAM", -- Args: pos | pos+size-1
+ wsbh_2 = "7c0000a0DT",
+ dsbh_2 = mips64 and "7c0000a4DT",
+ dshd_2 = mips64 and "7c000164DT",
+ seb_2 = "7c000420DT",
+ seh_2 = "7c000620DT",
+ rdhwr_2 = "7c00003bTD",
+
+ -- Opcode COP0.
+ mfc0_2 = "40000000TD",
+ mfc0_3 = "40000000TDW",
+ dmfc0_2 = mips64 and "40200000TD",
+ dmfc0_3 = mips64 and "40200000TDW",
+ mtc0_2 = "40800000TD",
+ mtc0_3 = "40800000TDW",
+ dmtc0_2 = mips64 and "40a00000TD",
+ dmtc0_3 = mips64 and "40a00000TDW",
+ rdpgpr_2 = "41400000DT",
+ di_0 = "41606000",
+ di_1 = "41606000T",
+ ei_0 = "41606020",
+ ei_1 = "41606020T",
+ wrpgpr_2 = "41c00000DT",
+ tlbr_0 = "42000001",
+ tlbwi_0 = "42000002",
+ tlbwr_0 = "42000006",
+ tlbp_0 = "42000008",
+ eret_0 = "42000018",
+ deret_0 = "4200001f",
+ wait_0 = "42000020",
+
+ -- Opcode COP1.
+ mfc1_2 = "44000000TG",
+ dmfc1_2 = mips64 and "44200000TG",
+ cfc1_2 = "44400000TG",
+ mfhc1_2 = "44600000TG",
+ mtc1_2 = "44800000TG",
+ dmtc1_2 = mips64 and "44a00000TG",
+ ctc1_2 = "44c00000TG",
+ mthc1_2 = "44e00000TG",
+
+ bc1f_1 = "45000000B",
+ bc1f_2 = "45000000CB",
+ bc1t_1 = "45010000B",
+ bc1t_2 = "45010000CB",
+ bc1fl_1 = "45020000B",
+ bc1fl_2 = "45020000CB",
+ bc1tl_1 = "45030000B",
+ bc1tl_2 = "45030000CB",
+
+ ["add.s_3"] = "46000000FGH",
+ ["sub.s_3"] = "46000001FGH",
+ ["mul.s_3"] = "46000002FGH",
+ ["div.s_3"] = "46000003FGH",
+ ["sqrt.s_2"] = "46000004FG",
+ ["abs.s_2"] = "46000005FG",
+ ["mov.s_2"] = "46000006FG",
+ ["neg.s_2"] = "46000007FG",
+ ["round.l.s_2"] = "46000008FG",
+ ["trunc.l.s_2"] = "46000009FG",
+ ["ceil.l.s_2"] = "4600000aFG",
+ ["floor.l.s_2"] = "4600000bFG",
+ ["round.w.s_2"] = "4600000cFG",
+ ["trunc.w.s_2"] = "4600000dFG",
+ ["ceil.w.s_2"] = "4600000eFG",
+ ["floor.w.s_2"] = "4600000fFG",
+ ["movf.s_2"] = "46000011FG",
+ ["movf.s_3"] = "46000011FGC",
+ ["movt.s_2"] = "46010011FG",
+ ["movt.s_3"] = "46010011FGC",
+ ["movz.s_3"] = "46000012FGT",
+ ["movn.s_3"] = "46000013FGT",
+ ["recip.s_2"] = "46000015FG",
+ ["rsqrt.s_2"] = "46000016FG",
+ ["cvt.d.s_2"] = "46000021FG",
+ ["cvt.w.s_2"] = "46000024FG",
+ ["cvt.l.s_2"] = "46000025FG",
+ ["cvt.ps.s_3"] = "46000026FGH",
+ ["c.f.s_2"] = "46000030GH",
+ ["c.f.s_3"] = "46000030VGH",
+ ["c.un.s_2"] = "46000031GH",
+ ["c.un.s_3"] = "46000031VGH",
+ ["c.eq.s_2"] = "46000032GH",
+ ["c.eq.s_3"] = "46000032VGH",
+ ["c.ueq.s_2"] = "46000033GH",
+ ["c.ueq.s_3"] = "46000033VGH",
+ ["c.olt.s_2"] = "46000034GH",
+ ["c.olt.s_3"] = "46000034VGH",
+ ["c.ult.s_2"] = "46000035GH",
+ ["c.ult.s_3"] = "46000035VGH",
+ ["c.ole.s_2"] = "46000036GH",
+ ["c.ole.s_3"] = "46000036VGH",
+ ["c.ule.s_2"] = "46000037GH",
+ ["c.ule.s_3"] = "46000037VGH",
+ ["c.sf.s_2"] = "46000038GH",
+ ["c.sf.s_3"] = "46000038VGH",
+ ["c.ngle.s_2"] = "46000039GH",
+ ["c.ngle.s_3"] = "46000039VGH",
+ ["c.seq.s_2"] = "4600003aGH",
+ ["c.seq.s_3"] = "4600003aVGH",
+ ["c.ngl.s_2"] = "4600003bGH",
+ ["c.ngl.s_3"] = "4600003bVGH",
+ ["c.lt.s_2"] = "4600003cGH",
+ ["c.lt.s_3"] = "4600003cVGH",
+ ["c.nge.s_2"] = "4600003dGH",
+ ["c.nge.s_3"] = "4600003dVGH",
+ ["c.le.s_2"] = "4600003eGH",
+ ["c.le.s_3"] = "4600003eVGH",
+ ["c.ngt.s_2"] = "4600003fGH",
+ ["c.ngt.s_3"] = "4600003fVGH",
+
+ ["add.d_3"] = "46200000FGH",
+ ["sub.d_3"] = "46200001FGH",
+ ["mul.d_3"] = "46200002FGH",
+ ["div.d_3"] = "46200003FGH",
+ ["sqrt.d_2"] = "46200004FG",
+ ["abs.d_2"] = "46200005FG",
+ ["mov.d_2"] = "46200006FG",
+ ["neg.d_2"] = "46200007FG",
+ ["round.l.d_2"] = "46200008FG",
+ ["trunc.l.d_2"] = "46200009FG",
+ ["ceil.l.d_2"] = "4620000aFG",
+ ["floor.l.d_2"] = "4620000bFG",
+ ["round.w.d_2"] = "4620000cFG",
+ ["trunc.w.d_2"] = "4620000dFG",
+ ["ceil.w.d_2"] = "4620000eFG",
+ ["floor.w.d_2"] = "4620000fFG",
+ ["movf.d_2"] = "46200011FG",
+ ["movf.d_3"] = "46200011FGC",
+ ["movt.d_2"] = "46210011FG",
+ ["movt.d_3"] = "46210011FGC",
+ ["movz.d_3"] = "46200012FGT",
+ ["movn.d_3"] = "46200013FGT",
+ ["recip.d_2"] = "46200015FG",
+ ["rsqrt.d_2"] = "46200016FG",
+ ["cvt.s.d_2"] = "46200020FG",
+ ["cvt.w.d_2"] = "46200024FG",
+ ["cvt.l.d_2"] = "46200025FG",
+ ["c.f.d_2"] = "46200030GH",
+ ["c.f.d_3"] = "46200030VGH",
+ ["c.un.d_2"] = "46200031GH",
+ ["c.un.d_3"] = "46200031VGH",
+ ["c.eq.d_2"] = "46200032GH",
+ ["c.eq.d_3"] = "46200032VGH",
+ ["c.ueq.d_2"] = "46200033GH",
+ ["c.ueq.d_3"] = "46200033VGH",
+ ["c.olt.d_2"] = "46200034GH",
+ ["c.olt.d_3"] = "46200034VGH",
+ ["c.ult.d_2"] = "46200035GH",
+ ["c.ult.d_3"] = "46200035VGH",
+ ["c.ole.d_2"] = "46200036GH",
+ ["c.ole.d_3"] = "46200036VGH",
+ ["c.ule.d_2"] = "46200037GH",
+ ["c.ule.d_3"] = "46200037VGH",
+ ["c.sf.d_2"] = "46200038GH",
+ ["c.sf.d_3"] = "46200038VGH",
+ ["c.ngle.d_2"] = "46200039GH",
+ ["c.ngle.d_3"] = "46200039VGH",
+ ["c.seq.d_2"] = "4620003aGH",
+ ["c.seq.d_3"] = "4620003aVGH",
+ ["c.ngl.d_2"] = "4620003bGH",
+ ["c.ngl.d_3"] = "4620003bVGH",
+ ["c.lt.d_2"] = "4620003cGH",
+ ["c.lt.d_3"] = "4620003cVGH",
+ ["c.nge.d_2"] = "4620003dGH",
+ ["c.nge.d_3"] = "4620003dVGH",
+ ["c.le.d_2"] = "4620003eGH",
+ ["c.le.d_3"] = "4620003eVGH",
+ ["c.ngt.d_2"] = "4620003fGH",
+ ["c.ngt.d_3"] = "4620003fVGH",
+
+ ["add.ps_3"] = "46c00000FGH",
+ ["sub.ps_3"] = "46c00001FGH",
+ ["mul.ps_3"] = "46c00002FGH",
+ ["abs.ps_2"] = "46c00005FG",
+ ["mov.ps_2"] = "46c00006FG",
+ ["neg.ps_2"] = "46c00007FG",
+ ["movf.ps_2"] = "46c00011FG",
+ ["movf.ps_3"] = "46c00011FGC",
+ ["movt.ps_2"] = "46c10011FG",
+ ["movt.ps_3"] = "46c10011FGC",
+ ["movz.ps_3"] = "46c00012FGT",
+ ["movn.ps_3"] = "46c00013FGT",
+ ["cvt.s.pu_2"] = "46c00020FG",
+ ["cvt.s.pl_2"] = "46c00028FG",
+ ["pll.ps_3"] = "46c0002cFGH",
+ ["plu.ps_3"] = "46c0002dFGH",
+ ["pul.ps_3"] = "46c0002eFGH",
+ ["puu.ps_3"] = "46c0002fFGH",
+ ["c.f.ps_2"] = "46c00030GH",
+ ["c.f.ps_3"] = "46c00030VGH",
+ ["c.un.ps_2"] = "46c00031GH",
+ ["c.un.ps_3"] = "46c00031VGH",
+ ["c.eq.ps_2"] = "46c00032GH",
+ ["c.eq.ps_3"] = "46c00032VGH",
+ ["c.ueq.ps_2"] = "46c00033GH",
+ ["c.ueq.ps_3"] = "46c00033VGH",
+ ["c.olt.ps_2"] = "46c00034GH",
+ ["c.olt.ps_3"] = "46c00034VGH",
+ ["c.ult.ps_2"] = "46c00035GH",
+ ["c.ult.ps_3"] = "46c00035VGH",
+ ["c.ole.ps_2"] = "46c00036GH",
+ ["c.ole.ps_3"] = "46c00036VGH",
+ ["c.ule.ps_2"] = "46c00037GH",
+ ["c.ule.ps_3"] = "46c00037VGH",
+ ["c.sf.ps_2"] = "46c00038GH",
+ ["c.sf.ps_3"] = "46c00038VGH",
+ ["c.ngle.ps_2"] = "46c00039GH",
+ ["c.ngle.ps_3"] = "46c00039VGH",
+ ["c.seq.ps_2"] = "46c0003aGH",
+ ["c.seq.ps_3"] = "46c0003aVGH",
+ ["c.ngl.ps_2"] = "46c0003bGH",
+ ["c.ngl.ps_3"] = "46c0003bVGH",
+ ["c.lt.ps_2"] = "46c0003cGH",
+ ["c.lt.ps_3"] = "46c0003cVGH",
+ ["c.nge.ps_2"] = "46c0003dGH",
+ ["c.nge.ps_3"] = "46c0003dVGH",
+ ["c.le.ps_2"] = "46c0003eGH",
+ ["c.le.ps_3"] = "46c0003eVGH",
+ ["c.ngt.ps_2"] = "46c0003fGH",
+ ["c.ngt.ps_3"] = "46c0003fVGH",
+
+ ["cvt.s.w_2"] = "46800020FG",
+ ["cvt.d.w_2"] = "46800021FG",
+
+ ["cvt.s.l_2"] = "46a00020FG",
+ ["cvt.d.l_2"] = "46a00021FG",
+
+ -- Opcode COP1X.
+ lwxc1_2 = "4c000000FX",
+ ldxc1_2 = "4c000001FX",
+ luxc1_2 = "4c000005FX",
+ swxc1_2 = "4c000008FX",
+ sdxc1_2 = "4c000009FX",
+ suxc1_2 = "4c00000dFX",
+ prefx_2 = "4c00000fMX",
+ ["alnv.ps_4"] = "4c00001eFGHS",
+ ["madd.s_4"] = "4c000020FRGH",
+ ["madd.d_4"] = "4c000021FRGH",
+ ["madd.ps_4"] = "4c000026FRGH",
+ ["msub.s_4"] = "4c000028FRGH",
+ ["msub.d_4"] = "4c000029FRGH",
+ ["msub.ps_4"] = "4c00002eFRGH",
+ ["nmadd.s_4"] = "4c000030FRGH",
+ ["nmadd.d_4"] = "4c000031FRGH",
+ ["nmadd.ps_4"] = "4c000036FRGH",
+ ["nmsub.s_4"] = "4c000038FRGH",
+ ["nmsub.d_4"] = "4c000039FRGH",
+ ["nmsub.ps_4"] = "4c00003eFRGH",
+}
+
+------------------------------------------------------------------------------
+
+local function parse_gpr(expr)
+ local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$")
+ local tp = map_type[tname or expr]
+ if tp then
+ local reg = ovreg or tp.reg
+ if not reg then
+ werror("type `"..(tname or expr).."' needs a register override")
+ end
+ expr = reg
+ end
+ local r = match(expr, "^r([1-3]?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 31 then return r, tp end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_fpr(expr)
+ local r = match(expr, "^f([1-3]?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 31 then return r end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_imm(imm, bits, shift, scale, signed, action)
+ local n = tonumber(imm)
+ if n then
+ local m = sar(n, scale)
+ if shl(m, scale) == n then
+ if signed then
+ local s = sar(m, bits-1)
+ if s == 0 then return shl(m, shift)
+ elseif s == -1 then return shl(m + shl(1, bits), shift) end
+ else
+ if sar(m, bits) == 0 then return shl(m, shift) end
+ end
+ end
+ werror("out of range immediate `"..imm.."'")
+ elseif match(imm, "^[rf]([1-3]?[0-9])$") or
+ match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then
+ werror("expected immediate operand, got register")
+ else
+ waction(action or "IMM",
+ (signed and 32768 or 0)+shl(scale, 10)+shl(bits, 5)+shift, imm)
+ return 0
+ end
+end
+
+local function parse_disp(disp)
+ local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$")
+ if imm then
+ local r = shl(parse_gpr(reg), 21)
+ local extname = match(imm, "^extern%s+(%S+)$")
+ if extname then
+ waction("REL_EXT", map_extern[extname], nil, 1)
+ return r
+ else
+ return r + parse_imm(imm, 16, 0, 0, true)
+ end
+ end
+ local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$")
+ if reg and tailr ~= "" then
+ local r, tp = parse_gpr(reg)
+ if tp then
+ waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr))
+ return shl(r, 21)
+ end
+ end
+ werror("bad displacement `"..disp.."'")
+end
+
+local function parse_index(idx)
+ local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$")
+ if rt then
+ rt = parse_gpr(rt)
+ rs = parse_gpr(rs)
+ return shl(rt, 16) + shl(rs, 21)
+ end
+ werror("bad index `"..idx.."'")
+end
+
+local function parse_label(label, def)
+ local prefix = sub(label, 1, 2)
+ -- =>label (pc label reference)
+ if prefix == "=>" then
+ return "PC", 0, sub(label, 3)
+ end
+ -- ->name (global label reference)
+ if prefix == "->" then
+ return "LG", map_global[sub(label, 3)]
+ end
+ if def then
+ -- [1-9] (local label definition)
+ if match(label, "^[1-9]$") then
+ return "LG", 10+tonumber(label)
+ end
+ else
+ -- [<>][1-9] (local label reference)
+ local dir, lnum = match(label, "^([<>])([1-9])$")
+ if dir then -- Fwd: 1-9, Bkwd: 11-19.
+ return "LG", lnum + (dir == ">" and 0 or 10)
+ end
+ -- extern label (extern label reference)
+ local extname = match(label, "^extern%s+(%S+)$")
+ if extname then
+ return "EXT", map_extern[extname]
+ end
+ end
+ werror("bad label `"..label.."'")
+end
+
+------------------------------------------------------------------------------
+
+-- Handle opcodes defined with template strings.
+map_op[".template__"] = function(params, template, nparams)
+ if not params then return sub(template, 9) end
+ local op = tonumber(sub(template, 1, 8), 16)
+ local n = 1
+
+ -- Limit number of section buffer positions used by a single dasm_put().
+ -- A single opcode needs a maximum of 2 positions (ins/ext).
+ if secpos+2 > maxsecpos then wflush() end
+ local pos = wpos()
+
+ -- Process each character.
+ for p in gmatch(sub(template, 9), ".") do
+ if p == "D" then
+ op = op + shl(parse_gpr(params[n]), 11); n = n + 1
+ elseif p == "T" then
+ op = op + shl(parse_gpr(params[n]), 16); n = n + 1
+ elseif p == "S" then
+ op = op + shl(parse_gpr(params[n]), 21); n = n + 1
+ elseif p == "F" then
+ op = op + shl(parse_fpr(params[n]), 6); n = n + 1
+ elseif p == "G" then
+ op = op + shl(parse_fpr(params[n]), 11); n = n + 1
+ elseif p == "H" then
+ op = op + shl(parse_fpr(params[n]), 16); n = n + 1
+ elseif p == "R" then
+ op = op + shl(parse_fpr(params[n]), 21); n = n + 1
+ elseif p == "I" then
+ op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1
+ elseif p == "U" then
+ op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1
+ elseif p == "O" then
+ op = op + parse_disp(params[n]); n = n + 1
+ elseif p == "X" then
+ op = op + parse_index(params[n]); n = n + 1
+ elseif p == "B" or p == "J" then
+ local mode, n, s = parse_label(params[n], false)
+ if p == "B" then n = n + 2048 end
+ waction("REL_"..mode, n, s, 1)
+ n = n + 1
+ elseif p == "A" then
+ op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1
+ elseif p == "a" then
+ local m = parse_imm(params[n], 6, 6, 0, false, "IMMS"); n = n + 1
+ op = op + band(m, 0x7c0) + band(shr(m, 9), 4)
+ elseif p == "M" then
+ op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1
+ elseif p == "N" then
+ op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1
+ elseif p == "C" then
+ op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1
+ elseif p == "V" then
+ op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1
+ elseif p == "W" then
+ op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1
+ elseif p == "Y" then
+ op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1
+ elseif p == "Z" then
+ op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1
+ elseif p == "=" then
+ op = op + shl(band(op, 0xf800), 5) -- Copy D to T for clz, clo.
+ else
+ assert(false)
+ end
+ end
+ wputpos(pos, op)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode to mark the position where the action list is to be emitted.
+map_op[".actionlist_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeactions(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the global enum is to be emitted.
+map_op[".globals_1"] = function(params)
+ if not params then return "prefix" end
+ local prefix = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobals(out, prefix) end)
+end
+
+-- Pseudo-opcode to mark the position where the global names are to be emitted.
+map_op[".globalnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobalnames(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the extern names are to be emitted.
+map_op[".externnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeexternnames(out, name) end)
+end
+
+------------------------------------------------------------------------------
+
+-- Label pseudo-opcode (converted from trailing colon form).
+map_op[".label_1"] = function(params)
+ if not params then return "[1-9] | ->global | =>pcexpr" end
+ if secpos+1 > maxsecpos then wflush() end
+ local mode, n, s = parse_label(params[1], true)
+ if mode == "EXT" then werror("bad label definition") end
+ waction("LABEL_"..mode, n, s, 1)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcodes for data storage.
+map_op[".long_*"] = function(params)
+ if not params then return "imm..." end
+ for _,p in ipairs(params) do
+ local n = tonumber(p)
+ if not n then werror("bad immediate `"..p.."'") end
+ if n < 0 then n = n + 2^32 end
+ wputw(n)
+ if secpos+2 > maxsecpos then wflush() end
+ end
+end
+
+-- Alignment pseudo-opcode.
+map_op[".align_1"] = function(params)
+ if not params then return "numpow2" end
+ if secpos+1 > maxsecpos then wflush() end
+ local align = tonumber(params[1])
+ if align then
+ local x = align
+ -- Must be a power of 2 in the range (2 ... 256).
+ for i=1,8 do
+ x = x / 2
+ if x == 1 then
+ waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
+ return
+ end
+ end
+ end
+ werror("bad alignment")
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode for (primitive) type definitions (map to C types).
+map_op[".type_3"] = function(params, nparams)
+ if not params then
+ return nparams == 2 and "name, ctype" or "name, ctype, reg"
+ end
+ local name, ctype, reg = params[1], params[2], params[3]
+ if not match(name, "^[%a_][%w_]*$") then
+ werror("bad type name `"..name.."'")
+ end
+ local tp = map_type[name]
+ if tp then
+ werror("duplicate type `"..name.."'")
+ end
+ -- Add #type to defines. A bit unclean to put it in map_archdef.
+ map_archdef["#"..name] = "sizeof("..ctype..")"
+ -- Add new type and emit shortcut define.
+ local num = ctypenum + 1
+ map_type[name] = {
+ ctype = ctype,
+ ctypefmt = format("Dt%X(%%s)", num),
+ reg = reg,
+ }
+ wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
+ ctypenum = num
+end
+map_op[".type_2"] = map_op[".type_3"]
+
+-- Dump type definitions.
+local function dumptypes(out, lvl)
+ local t = {}
+ for name in pairs(map_type) do t[#t+1] = name end
+ sort(t)
+ out:write("Type definitions:\n")
+ for _,name in ipairs(t) do
+ local tp = map_type[name]
+ local reg = tp.reg or ""
+ out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
+ end
+ out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Set the current section.
+function _M.section(num)
+ waction("SECTION", num)
+ wflush(true) -- SECTION is a terminal action.
+end
+
+------------------------------------------------------------------------------
+
+-- Dump architecture description.
+function _M.dumparch(out)
+ out:write(format("DynASM %s version %s, released %s\n\n",
+ _info.arch, _info.version, _info.release))
+ dumpactions(out)
+end
+
+-- Dump all user defined elements.
+function _M.dumpdef(out, lvl)
+ dumptypes(out, lvl)
+ dumpglobals(out, lvl)
+ dumpexterns(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Pass callbacks from/to the DynASM core.
+function _M.passcb(wl, we, wf, ww)
+ wline, werror, wfatal, wwarn = wl, we, wf, ww
+ return wflush
+end
+
+-- Setup the arch-specific module.
+function _M.setup(arch, opt)
+ g_arch, g_opt = arch, opt
+end
+
+-- Merge the core maps and the arch-specific maps.
+function _M.mergemaps(map_coreop, map_def)
+ setmetatable(map_op, { __index = map_coreop })
+ setmetatable(map_def, { __index = map_archdef })
+ return map_op, map_def
+end
+
+return _M
+
+------------------------------------------------------------------------------
+
diff --git a/src/host/luajit-2.1.0-beta3/dynasm/dasm_mips64.lua b/src/host/luajit-2.1.0-beta3/dynasm/dasm_mips64.lua
new file mode 100644
index 00000000..5636b23a
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/dynasm/dasm_mips64.lua
@@ -0,0 +1,12 @@
+------------------------------------------------------------------------------
+-- DynASM MIPS64 module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+-- This module just sets 64 bit mode for the combined MIPS/MIPS64 module.
+-- All the interesting stuff is there.
+------------------------------------------------------------------------------
+
+mips64 = true -- Using a global is an ugly, but effective solution.
+return require("dasm_mips")
diff --git a/src/host/luajit-2.1.0-beta3/dynasm/dasm_ppc.h b/src/host/luajit-2.1.0-beta3/dynasm/dasm_ppc.h
new file mode 100644
index 00000000..3a7ee9b0
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/dynasm/dasm_ppc.h
@@ -0,0 +1,419 @@
+/*
+** DynASM PPC/PPC64 encoding engine.
+** Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+** Released under the MIT license. See dynasm.lua for full copyright notice.
+*/
+
+#include
+#include
+#include
+#include
+
+#define DASM_ARCH "ppc"
+
+#ifndef DASM_EXTERN
+#define DASM_EXTERN(a,b,c,d) 0
+#endif
+
+/* Action definitions. */
+enum {
+ DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
+ /* The following actions need a buffer position. */
+ DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
+ /* The following actions also have an argument. */
+ DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMSH,
+ DASM__MAX
+};
+
+/* Maximum number of section buffer positions for a single dasm_put() call. */
+#define DASM_MAXSECPOS 25
+
+/* DynASM encoder status codes. Action list offset or number are or'ed in. */
+#define DASM_S_OK 0x00000000
+#define DASM_S_NOMEM 0x01000000
+#define DASM_S_PHASE 0x02000000
+#define DASM_S_MATCH_SEC 0x03000000
+#define DASM_S_RANGE_I 0x11000000
+#define DASM_S_RANGE_SEC 0x12000000
+#define DASM_S_RANGE_LG 0x13000000
+#define DASM_S_RANGE_PC 0x14000000
+#define DASM_S_RANGE_REL 0x15000000
+#define DASM_S_UNDEF_LG 0x21000000
+#define DASM_S_UNDEF_PC 0x22000000
+
+/* Macros to convert positions (8 bit section + 24 bit index). */
+#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
+#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
+#define DASM_SEC2POS(sec) ((sec)<<24)
+#define DASM_POS2SEC(pos) ((pos)>>24)
+#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
+
+/* Action list type. */
+typedef const unsigned int *dasm_ActList;
+
+/* Per-section structure. */
+typedef struct dasm_Section {
+ int *rbuf; /* Biased buffer pointer (negative section bias). */
+ int *buf; /* True buffer pointer. */
+ size_t bsize; /* Buffer size in bytes. */
+ int pos; /* Biased buffer position. */
+ int epos; /* End of biased buffer position - max single put. */
+ int ofs; /* Byte offset into section. */
+} dasm_Section;
+
+/* Core structure holding the DynASM encoding state. */
+struct dasm_State {
+ size_t psize; /* Allocated size of this structure. */
+ dasm_ActList actionlist; /* Current actionlist pointer. */
+ int *lglabels; /* Local/global chain/pos ptrs. */
+ size_t lgsize;
+ int *pclabels; /* PC label chains/pos ptrs. */
+ size_t pcsize;
+ void **globals; /* Array of globals (bias -10). */
+ dasm_Section *section; /* Pointer to active section. */
+ size_t codesize; /* Total size of all code sections. */
+ int maxsection; /* 0 <= sectionidx < maxsection. */
+ int status; /* Status code. */
+ dasm_Section sections[1]; /* All sections. Alloc-extended. */
+};
+
+/* The size of the core structure depends on the max. number of sections. */
+#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
+
+
+/* Initialize DynASM state. */
+void dasm_init(Dst_DECL, int maxsection)
+{
+ dasm_State *D;
+ size_t psz = 0;
+ int i;
+ Dst_REF = NULL;
+ DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
+ D = Dst_REF;
+ D->psize = psz;
+ D->lglabels = NULL;
+ D->lgsize = 0;
+ D->pclabels = NULL;
+ D->pcsize = 0;
+ D->globals = NULL;
+ D->maxsection = maxsection;
+ for (i = 0; i < maxsection; i++) {
+ D->sections[i].buf = NULL; /* Need this for pass3. */
+ D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
+ D->sections[i].bsize = 0;
+ D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
+ }
+}
+
+/* Free DynASM state. */
+void dasm_free(Dst_DECL)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ for (i = 0; i < D->maxsection; i++)
+ if (D->sections[i].buf)
+ DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
+ if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
+ if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
+ DASM_M_FREE(Dst, D, D->psize);
+}
+
+/* Setup global label array. Must be called before dasm_setup(). */
+void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
+{
+ dasm_State *D = Dst_REF;
+ D->globals = gl - 10; /* Negative bias to compensate for locals. */
+ DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
+}
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+void dasm_growpc(Dst_DECL, unsigned int maxpc)
+{
+ dasm_State *D = Dst_REF;
+ size_t osz = D->pcsize;
+ DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
+ memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
+}
+
+/* Setup encoder. */
+void dasm_setup(Dst_DECL, const void *actionlist)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ D->actionlist = (dasm_ActList)actionlist;
+ D->status = DASM_S_OK;
+ D->section = &D->sections[0];
+ memset((void *)D->lglabels, 0, D->lgsize);
+ if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
+ for (i = 0; i < D->maxsection; i++) {
+ D->sections[i].pos = DASM_SEC2POS(i);
+ D->sections[i].ofs = 0;
+ }
+}
+
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) { \
+ D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
+#define CKPL(kind, st) \
+ do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
+ D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
+#else
+#define CK(x, st) ((void)0)
+#define CKPL(kind, st) ((void)0)
+#endif
+
+/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
+void dasm_put(Dst_DECL, int start, ...)
+{
+ va_list ap;
+ dasm_State *D = Dst_REF;
+ dasm_ActList p = D->actionlist + start;
+ dasm_Section *sec = D->section;
+ int pos = sec->pos, ofs = sec->ofs;
+ int *b;
+
+ if (pos >= sec->epos) {
+ DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
+ sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
+ sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
+ sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
+ }
+
+ b = sec->rbuf;
+ b[pos++] = start;
+
+ va_start(ap, start);
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ if (action >= DASM__MAX) {
+ ofs += 4;
+ } else {
+ int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
+ switch (action) {
+ case DASM_STOP: goto stop;
+ case DASM_SECTION:
+ n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
+ D->section = &D->sections[n]; goto stop;
+ case DASM_ESC: p++; ofs += 4; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
+ case DASM_REL_LG:
+ n = (ins & 2047) - 10; pl = D->lglabels + n;
+ /* Bkwd rel or global. */
+ if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
+ pl += 10; n = *pl;
+ if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
+ goto linkrel;
+ case DASM_REL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putrel:
+ n = *pl;
+ if (n < 0) { /* Label exists. Get label pos and store it. */
+ b[pos] = -n;
+ } else {
+ linkrel:
+ b[pos] = n; /* Else link to rel chain, anchored at label. */
+ *pl = pos;
+ }
+ pos++;
+ break;
+ case DASM_LABEL_LG:
+ pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
+ case DASM_LABEL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putlabel:
+ n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
+ }
+ *pl = -pos; /* Label exists now. */
+ b[pos++] = ofs; /* Store pass1 offset estimate. */
+ break;
+ case DASM_IMM:
+#ifdef DASM_CHECKS
+ CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
+#endif
+ n >>= ((ins>>10)&31);
+#ifdef DASM_CHECKS
+ if (ins & 0x8000)
+ CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
+ else
+ CK((n>>((ins>>5)&31)) == 0, RANGE_I);
+#endif
+ b[pos++] = n;
+ break;
+ case DASM_IMMSH:
+ CK((n >> 6) == 0, RANGE_I);
+ b[pos++] = n;
+ break;
+ }
+ }
+ }
+stop:
+ va_end(ap);
+ sec->pos = pos;
+ sec->ofs = ofs;
+}
+#undef CK
+
+/* Pass 2: Link sections, shrink aligns, fix label offsets. */
+int dasm_link(Dst_DECL, size_t *szp)
+{
+ dasm_State *D = Dst_REF;
+ int secnum;
+ int ofs = 0;
+
+#ifdef DASM_CHECKS
+ *szp = 0;
+ if (D->status != DASM_S_OK) return D->status;
+ {
+ int pc;
+ for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
+ if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
+ }
+#endif
+
+ { /* Handle globals not defined in this translation unit. */
+ int idx;
+ for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
+ int n = D->lglabels[idx];
+ /* Undefined label: Collapse rel chain and replace with marker (< 0). */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
+ }
+ }
+
+ /* Combine all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->rbuf;
+ int pos = DASM_SEC2POS(secnum);
+ int lastpos = sec->pos;
+
+ while (pos != lastpos) {
+ dasm_ActList p = D->actionlist + b[pos++];
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: p++; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
+ case DASM_REL_LG: case DASM_REL_PC: pos++; break;
+ case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
+ case DASM_IMM: case DASM_IMMSH: pos++; break;
+ }
+ }
+ stop: (void)0;
+ }
+ ofs += sec->ofs; /* Next section starts right after current section. */
+ }
+
+ D->codesize = ofs; /* Total size of all code sections */
+ *szp = ofs;
+ return DASM_S_OK;
+}
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
+#else
+#define CK(x, st) ((void)0)
+#endif
+
+/* Pass 3: Encode sections. */
+int dasm_encode(Dst_DECL, void *buffer)
+{
+ dasm_State *D = Dst_REF;
+ char *base = (char *)buffer;
+ unsigned int *cp = (unsigned int *)buffer;
+ int secnum;
+
+ /* Encode all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->buf;
+ int *endb = sec->rbuf + sec->pos;
+
+ while (b != endb) {
+ dasm_ActList p = D->actionlist + *b++;
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: *cp++ = *p++; break;
+ case DASM_REL_EXT:
+ n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1) - 4;
+ goto patchrel;
+ case DASM_ALIGN:
+ ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000;
+ break;
+ case DASM_REL_LG:
+ CK(n >= 0, UNDEF_LG);
+ case DASM_REL_PC:
+ CK(n >= 0, UNDEF_PC);
+ n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base);
+ patchrel:
+ CK((n & 3) == 0 &&
+ (((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >>
+ ((ins & 2048) ? 16 : 26)) == 0, RANGE_REL);
+ cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc));
+ break;
+ case DASM_LABEL_LG:
+ ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
+ break;
+ case DASM_LABEL_PC: break;
+ case DASM_IMM:
+ cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
+ break;
+ case DASM_IMMSH:
+ cp[-1] |= (ins & 1) ? ((n&31)<<11)|((n&32)>>4) : ((n&31)<<6)|(n&32);
+ break;
+ default: *cp++ = ins; break;
+ }
+ }
+ stop: (void)0;
+ }
+ }
+
+ if (base + D->codesize != (char *)cp) /* Check for phase errors. */
+ return DASM_S_PHASE;
+ return DASM_S_OK;
+}
+#undef CK
+
+/* Get PC label offset. */
+int dasm_getpclabel(Dst_DECL, unsigned int pc)
+{
+ dasm_State *D = Dst_REF;
+ if (pc*sizeof(int) < D->pcsize) {
+ int pos = D->pclabels[pc];
+ if (pos < 0) return *DASM_POS2PTR(D, -pos);
+ if (pos > 0) return -1; /* Undefined. */
+ }
+ return -2; /* Unused or out of range. */
+}
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+int dasm_checkstep(Dst_DECL, int secmatch)
+{
+ dasm_State *D = Dst_REF;
+ if (D->status == DASM_S_OK) {
+ int i;
+ for (i = 1; i <= 9; i++) {
+ if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
+ D->lglabels[i] = 0;
+ }
+ }
+ if (D->status == DASM_S_OK && secmatch >= 0 &&
+ D->section != &D->sections[secmatch])
+ D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
+ return D->status;
+}
+#endif
+
diff --git a/src/host/luajit-2.1.0-beta3/dynasm/dasm_ppc.lua b/src/host/luajit-2.1.0-beta3/dynasm/dasm_ppc.lua
new file mode 100644
index 00000000..f73974dd
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/dynasm/dasm_ppc.lua
@@ -0,0 +1,1919 @@
+------------------------------------------------------------------------------
+-- DynASM PPC/PPC64 module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+--
+-- Support for various extensions contributed by Caio Souza Oliveira.
+------------------------------------------------------------------------------
+
+-- Module information:
+local _info = {
+ arch = "ppc",
+ description = "DynASM PPC module",
+ version = "1.4.0",
+ vernum = 10400,
+ release = "2015-10-18",
+ author = "Mike Pall",
+ license = "MIT",
+}
+
+-- Exported glue functions for the arch-specific module.
+local _M = { _info = _info }
+
+-- Cache library functions.
+local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
+local assert, setmetatable = assert, setmetatable
+local _s = string
+local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
+local match, gmatch = _s.match, _s.gmatch
+local concat, sort = table.concat, table.sort
+local bit = bit or require("bit")
+local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift
+local tohex = bit.tohex
+
+-- Inherited tables and callbacks.
+local g_opt, g_arch
+local wline, werror, wfatal, wwarn
+
+-- Action name list.
+-- CHECK: Keep this in sync with the C code!
+local action_names = {
+ "STOP", "SECTION", "ESC", "REL_EXT",
+ "ALIGN", "REL_LG", "LABEL_LG",
+ "REL_PC", "LABEL_PC", "IMM", "IMMSH"
+}
+
+-- Maximum number of section buffer positions for dasm_put().
+-- CHECK: Keep this in sync with the C code!
+local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
+
+-- Action name -> action number.
+local map_action = {}
+for n,name in ipairs(action_names) do
+ map_action[name] = n-1
+end
+
+-- Action list buffer.
+local actlist = {}
+
+-- Argument list for next dasm_put(). Start with offset 0 into action list.
+local actargs = { 0 }
+
+-- Current number of section buffer positions for dasm_put().
+local secpos = 1
+
+------------------------------------------------------------------------------
+
+-- Dump action names and numbers.
+local function dumpactions(out)
+ out:write("DynASM encoding engine action codes:\n")
+ for n,name in ipairs(action_names) do
+ local num = map_action[name]
+ out:write(format(" %-10s %02X %d\n", name, num, num))
+ end
+ out:write("\n")
+end
+
+-- Write action list buffer as a huge static C array.
+local function writeactions(out, name)
+ local nn = #actlist
+ if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
+ out:write("static const unsigned int ", name, "[", nn, "] = {\n")
+ for i = 1,nn-1 do
+ assert(out:write("0x", tohex(actlist[i]), ",\n"))
+ end
+ assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
+end
+
+------------------------------------------------------------------------------
+
+-- Add word to action list.
+local function wputxw(n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ actlist[#actlist+1] = n
+end
+
+-- Add action to list with optional arg. Advance buffer pos, too.
+local function waction(action, val, a, num)
+ local w = assert(map_action[action], "bad action name `"..action.."'")
+ wputxw(w * 0x10000 + (val or 0))
+ if a then actargs[#actargs+1] = a end
+ if a or num then secpos = secpos + (num or 1) end
+end
+
+-- Flush action list (intervening C code or buffer pos overflow).
+local function wflush(term)
+ if #actlist == actargs[1] then return end -- Nothing to flush.
+ if not term then waction("STOP") end -- Terminate action list.
+ wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
+ actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
+ secpos = 1 -- The actionlist offset occupies a buffer position, too.
+end
+
+-- Put escaped word.
+local function wputw(n)
+ if n <= 0xffffff then waction("ESC") end
+ wputxw(n)
+end
+
+-- Reserve position for word.
+local function wpos()
+ local pos = #actlist+1
+ actlist[pos] = ""
+ return pos
+end
+
+-- Store word to reserved position.
+local function wputpos(pos, n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ actlist[pos] = n
+end
+
+------------------------------------------------------------------------------
+
+-- Global label name -> global label number. With auto assignment on 1st use.
+local next_global = 20
+local map_global = setmetatable({}, { __index = function(t, name)
+ if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
+ local n = next_global
+ if n > 2047 then werror("too many global labels") end
+ next_global = n + 1
+ t[name] = n
+ return n
+end})
+
+-- Dump global labels.
+local function dumpglobals(out, lvl)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("Global labels:\n")
+ for i=20,next_global-1 do
+ out:write(format(" %s\n", t[i]))
+ end
+ out:write("\n")
+end
+
+-- Write global label enum.
+local function writeglobals(out, prefix)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("enum {\n")
+ for i=20,next_global-1 do
+ out:write(" ", prefix, t[i], ",\n")
+ end
+ out:write(" ", prefix, "_MAX\n};\n")
+end
+
+-- Write global label names.
+local function writeglobalnames(out, name)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=20,next_global-1 do
+ out:write(" \"", t[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Extern label name -> extern label number. With auto assignment on 1st use.
+local next_extern = 0
+local map_extern_ = {}
+local map_extern = setmetatable({}, { __index = function(t, name)
+ -- No restrictions on the name for now.
+ local n = next_extern
+ if n > 2047 then werror("too many extern labels") end
+ next_extern = n + 1
+ t[name] = n
+ map_extern_[n] = name
+ return n
+end})
+
+-- Dump extern labels.
+local function dumpexterns(out, lvl)
+ out:write("Extern labels:\n")
+ for i=0,next_extern-1 do
+ out:write(format(" %s\n", map_extern_[i]))
+ end
+ out:write("\n")
+end
+
+-- Write extern label names.
+local function writeexternnames(out, name)
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=0,next_extern-1 do
+ out:write(" \"", map_extern_[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Arch-specific maps.
+local map_archdef = { sp = "r1" } -- Ext. register name -> int. name.
+
+local map_type = {} -- Type name -> { ctype, reg }
+local ctypenum = 0 -- Type number (for Dt... macros).
+
+-- Reverse defines for registers.
+function _M.revdef(s)
+ if s == "r1" then return "sp" end
+ return s
+end
+
+local map_cond = {
+ lt = 0, gt = 1, eq = 2, so = 3,
+ ge = 4, le = 5, ne = 6, ns = 7,
+}
+
+------------------------------------------------------------------------------
+
+local map_op, op_template
+
+local function op_alias(opname, f)
+ return function(params, nparams)
+ if not params then return "-> "..opname:sub(1, -3) end
+ f(params, nparams)
+ op_template(params, map_op[opname], nparams)
+ end
+end
+
+-- Template strings for PPC instructions.
+map_op = {
+ tdi_3 = "08000000ARI",
+ twi_3 = "0c000000ARI",
+ mulli_3 = "1c000000RRI",
+ subfic_3 = "20000000RRI",
+ cmplwi_3 = "28000000XRU",
+ cmplwi_2 = "28000000-RU",
+ cmpldi_3 = "28200000XRU",
+ cmpldi_2 = "28200000-RU",
+ cmpwi_3 = "2c000000XRI",
+ cmpwi_2 = "2c000000-RI",
+ cmpdi_3 = "2c200000XRI",
+ cmpdi_2 = "2c200000-RI",
+ addic_3 = "30000000RRI",
+ ["addic._3"] = "34000000RRI",
+ addi_3 = "38000000RR0I",
+ li_2 = "38000000RI",
+ la_2 = "38000000RD",
+ addis_3 = "3c000000RR0I",
+ lis_2 = "3c000000RI",
+ lus_2 = "3c000000RU",
+ bc_3 = "40000000AAK",
+ bcl_3 = "40000001AAK",
+ bdnz_1 = "42000000K",
+ bdz_1 = "42400000K",
+ sc_0 = "44000000",
+ b_1 = "48000000J",
+ bl_1 = "48000001J",
+ rlwimi_5 = "50000000RR~AAA.",
+ rlwinm_5 = "54000000RR~AAA.",
+ rlwnm_5 = "5c000000RR~RAA.",
+ ori_3 = "60000000RR~U",
+ nop_0 = "60000000",
+ oris_3 = "64000000RR~U",
+ xori_3 = "68000000RR~U",
+ xoris_3 = "6c000000RR~U",
+ ["andi._3"] = "70000000RR~U",
+ ["andis._3"] = "74000000RR~U",
+ lwz_2 = "80000000RD",
+ lwzu_2 = "84000000RD",
+ lbz_2 = "88000000RD",
+ lbzu_2 = "8c000000RD",
+ stw_2 = "90000000RD",
+ stwu_2 = "94000000RD",
+ stb_2 = "98000000RD",
+ stbu_2 = "9c000000RD",
+ lhz_2 = "a0000000RD",
+ lhzu_2 = "a4000000RD",
+ lha_2 = "a8000000RD",
+ lhau_2 = "ac000000RD",
+ sth_2 = "b0000000RD",
+ sthu_2 = "b4000000RD",
+ lmw_2 = "b8000000RD",
+ stmw_2 = "bc000000RD",
+ lfs_2 = "c0000000FD",
+ lfsu_2 = "c4000000FD",
+ lfd_2 = "c8000000FD",
+ lfdu_2 = "cc000000FD",
+ stfs_2 = "d0000000FD",
+ stfsu_2 = "d4000000FD",
+ stfd_2 = "d8000000FD",
+ stfdu_2 = "dc000000FD",
+ ld_2 = "e8000000RD", -- NYI: displacement must be divisible by 4.
+ ldu_2 = "e8000001RD",
+ lwa_2 = "e8000002RD",
+ std_2 = "f8000000RD",
+ stdu_2 = "f8000001RD",
+
+ subi_3 = op_alias("addi_3", function(p) p[3] = "-("..p[3]..")" end),
+ subis_3 = op_alias("addis_3", function(p) p[3] = "-("..p[3]..")" end),
+ subic_3 = op_alias("addic_3", function(p) p[3] = "-("..p[3]..")" end),
+ ["subic._3"] = op_alias("addic._3", function(p) p[3] = "-("..p[3]..")" end),
+
+ rotlwi_3 = op_alias("rlwinm_5", function(p)
+ p[4] = "0"; p[5] = "31"
+ end),
+ rotrwi_3 = op_alias("rlwinm_5", function(p)
+ p[3] = "32-("..p[3]..")"; p[4] = "0"; p[5] = "31"
+ end),
+ rotlw_3 = op_alias("rlwnm_5", function(p)
+ p[4] = "0"; p[5] = "31"
+ end),
+ slwi_3 = op_alias("rlwinm_5", function(p)
+ p[5] = "31-("..p[3]..")"; p[4] = "0"
+ end),
+ srwi_3 = op_alias("rlwinm_5", function(p)
+ p[4] = p[3]; p[3] = "32-("..p[3]..")"; p[5] = "31"
+ end),
+ clrlwi_3 = op_alias("rlwinm_5", function(p)
+ p[4] = p[3]; p[3] = "0"; p[5] = "31"
+ end),
+ clrrwi_3 = op_alias("rlwinm_5", function(p)
+ p[5] = "31-("..p[3]..")"; p[3] = "0"; p[4] = "0"
+ end),
+
+ -- Primary opcode 4:
+ mulhhwu_3 = "10000010RRR.",
+ machhwu_3 = "10000018RRR.",
+ mulhhw_3 = "10000050RRR.",
+ nmachhw_3 = "1000005cRRR.",
+ machhwsu_3 = "10000098RRR.",
+ machhws_3 = "100000d8RRR.",
+ nmachhws_3 = "100000dcRRR.",
+ mulchwu_3 = "10000110RRR.",
+ macchwu_3 = "10000118RRR.",
+ mulchw_3 = "10000150RRR.",
+ macchw_3 = "10000158RRR.",
+ nmacchw_3 = "1000015cRRR.",
+ macchwsu_3 = "10000198RRR.",
+ macchws_3 = "100001d8RRR.",
+ nmacchws_3 = "100001dcRRR.",
+ mullhw_3 = "10000350RRR.",
+ maclhw_3 = "10000358RRR.",
+ nmaclhw_3 = "1000035cRRR.",
+ maclhwsu_3 = "10000398RRR.",
+ maclhws_3 = "100003d8RRR.",
+ nmaclhws_3 = "100003dcRRR.",
+ machhwuo_3 = "10000418RRR.",
+ nmachhwo_3 = "1000045cRRR.",
+ machhwsuo_3 = "10000498RRR.",
+ machhwso_3 = "100004d8RRR.",
+ nmachhwso_3 = "100004dcRRR.",
+ macchwuo_3 = "10000518RRR.",
+ macchwo_3 = "10000558RRR.",
+ nmacchwo_3 = "1000055cRRR.",
+ macchwsuo_3 = "10000598RRR.",
+ macchwso_3 = "100005d8RRR.",
+ nmacchwso_3 = "100005dcRRR.",
+ maclhwo_3 = "10000758RRR.",
+ nmaclhwo_3 = "1000075cRRR.",
+ maclhwsuo_3 = "10000798RRR.",
+ maclhwso_3 = "100007d8RRR.",
+ nmaclhwso_3 = "100007dcRRR.",
+
+ vaddubm_3 = "10000000VVV",
+ vmaxub_3 = "10000002VVV",
+ vrlb_3 = "10000004VVV",
+ vcmpequb_3 = "10000006VVV",
+ vmuloub_3 = "10000008VVV",
+ vaddfp_3 = "1000000aVVV",
+ vmrghb_3 = "1000000cVVV",
+ vpkuhum_3 = "1000000eVVV",
+ vmhaddshs_4 = "10000020VVVV",
+ vmhraddshs_4 = "10000021VVVV",
+ vmladduhm_4 = "10000022VVVV",
+ vmsumubm_4 = "10000024VVVV",
+ vmsummbm_4 = "10000025VVVV",
+ vmsumuhm_4 = "10000026VVVV",
+ vmsumuhs_4 = "10000027VVVV",
+ vmsumshm_4 = "10000028VVVV",
+ vmsumshs_4 = "10000029VVVV",
+ vsel_4 = "1000002aVVVV",
+ vperm_4 = "1000002bVVVV",
+ vsldoi_4 = "1000002cVVVP",
+ vpermxor_4 = "1000002dVVVV",
+ vmaddfp_4 = "1000002eVVVV~",
+ vnmsubfp_4 = "1000002fVVVV~",
+ vaddeuqm_4 = "1000003cVVVV",
+ vaddecuq_4 = "1000003dVVVV",
+ vsubeuqm_4 = "1000003eVVVV",
+ vsubecuq_4 = "1000003fVVVV",
+ vadduhm_3 = "10000040VVV",
+ vmaxuh_3 = "10000042VVV",
+ vrlh_3 = "10000044VVV",
+ vcmpequh_3 = "10000046VVV",
+ vmulouh_3 = "10000048VVV",
+ vsubfp_3 = "1000004aVVV",
+ vmrghh_3 = "1000004cVVV",
+ vpkuwum_3 = "1000004eVVV",
+ vadduwm_3 = "10000080VVV",
+ vmaxuw_3 = "10000082VVV",
+ vrlw_3 = "10000084VVV",
+ vcmpequw_3 = "10000086VVV",
+ vmulouw_3 = "10000088VVV",
+ vmuluwm_3 = "10000089VVV",
+ vmrghw_3 = "1000008cVVV",
+ vpkuhus_3 = "1000008eVVV",
+ vaddudm_3 = "100000c0VVV",
+ vmaxud_3 = "100000c2VVV",
+ vrld_3 = "100000c4VVV",
+ vcmpeqfp_3 = "100000c6VVV",
+ vcmpequd_3 = "100000c7VVV",
+ vpkuwus_3 = "100000ceVVV",
+ vadduqm_3 = "10000100VVV",
+ vmaxsb_3 = "10000102VVV",
+ vslb_3 = "10000104VVV",
+ vmulosb_3 = "10000108VVV",
+ vrefp_2 = "1000010aV-V",
+ vmrglb_3 = "1000010cVVV",
+ vpkshus_3 = "1000010eVVV",
+ vaddcuq_3 = "10000140VVV",
+ vmaxsh_3 = "10000142VVV",
+ vslh_3 = "10000144VVV",
+ vmulosh_3 = "10000148VVV",
+ vrsqrtefp_2 = "1000014aV-V",
+ vmrglh_3 = "1000014cVVV",
+ vpkswus_3 = "1000014eVVV",
+ vaddcuw_3 = "10000180VVV",
+ vmaxsw_3 = "10000182VVV",
+ vslw_3 = "10000184VVV",
+ vmulosw_3 = "10000188VVV",
+ vexptefp_2 = "1000018aV-V",
+ vmrglw_3 = "1000018cVVV",
+ vpkshss_3 = "1000018eVVV",
+ vmaxsd_3 = "100001c2VVV",
+ vsl_3 = "100001c4VVV",
+ vcmpgefp_3 = "100001c6VVV",
+ vlogefp_2 = "100001caV-V",
+ vpkswss_3 = "100001ceVVV",
+ vadduhs_3 = "10000240VVV",
+ vminuh_3 = "10000242VVV",
+ vsrh_3 = "10000244VVV",
+ vcmpgtuh_3 = "10000246VVV",
+ vmuleuh_3 = "10000248VVV",
+ vrfiz_2 = "1000024aV-V",
+ vsplth_3 = "1000024cVV3",
+ vupkhsh_2 = "1000024eV-V",
+ vminuw_3 = "10000282VVV",
+ vminud_3 = "100002c2VVV",
+ vcmpgtud_3 = "100002c7VVV",
+ vrfim_2 = "100002caV-V",
+ vcmpgtsb_3 = "10000306VVV",
+ vcfux_3 = "1000030aVVA~",
+ vaddshs_3 = "10000340VVV",
+ vminsh_3 = "10000342VVV",
+ vsrah_3 = "10000344VVV",
+ vcmpgtsh_3 = "10000346VVV",
+ vmulesh_3 = "10000348VVV",
+ vcfsx_3 = "1000034aVVA~",
+ vspltish_2 = "1000034cVS",
+ vupkhpx_2 = "1000034eV-V",
+ vaddsws_3 = "10000380VVV",
+ vminsw_3 = "10000382VVV",
+ vsraw_3 = "10000384VVV",
+ vcmpgtsw_3 = "10000386VVV",
+ vmulesw_3 = "10000388VVV",
+ vctuxs_3 = "1000038aVVA~",
+ vspltisw_2 = "1000038cVS",
+ vminsd_3 = "100003c2VVV",
+ vsrad_3 = "100003c4VVV",
+ vcmpbfp_3 = "100003c6VVV",
+ vcmpgtsd_3 = "100003c7VVV",
+ vctsxs_3 = "100003caVVA~",
+ vupklpx_2 = "100003ceV-V",
+ vsububm_3 = "10000400VVV",
+ ["bcdadd._4"] = "10000401VVVy.",
+ vavgub_3 = "10000402VVV",
+ vand_3 = "10000404VVV",
+ ["vcmpequb._3"] = "10000406VVV",
+ vmaxfp_3 = "1000040aVVV",
+ vsubuhm_3 = "10000440VVV",
+ ["bcdsub._4"] = "10000441VVVy.",
+ vavguh_3 = "10000442VVV",
+ vandc_3 = "10000444VVV",
+ ["vcmpequh._3"] = "10000446VVV",
+ vminfp_3 = "1000044aVVV",
+ vpkudum_3 = "1000044eVVV",
+ vsubuwm_3 = "10000480VVV",
+ vavguw_3 = "10000482VVV",
+ vor_3 = "10000484VVV",
+ ["vcmpequw._3"] = "10000486VVV",
+ vpmsumw_3 = "10000488VVV",
+ ["vcmpeqfp._3"] = "100004c6VVV",
+ ["vcmpequd._3"] = "100004c7VVV",
+ vpkudus_3 = "100004ceVVV",
+ vavgsb_3 = "10000502VVV",
+ vavgsh_3 = "10000542VVV",
+ vorc_3 = "10000544VVV",
+ vbpermq_3 = "1000054cVVV",
+ vpksdus_3 = "1000054eVVV",
+ vavgsw_3 = "10000582VVV",
+ vsld_3 = "100005c4VVV",
+ ["vcmpgefp._3"] = "100005c6VVV",
+ vpksdss_3 = "100005ceVVV",
+ vsububs_3 = "10000600VVV",
+ mfvscr_1 = "10000604V--",
+ vsum4ubs_3 = "10000608VVV",
+ vsubuhs_3 = "10000640VVV",
+ mtvscr_1 = "10000644--V",
+ ["vcmpgtuh._3"] = "10000646VVV",
+ vsum4shs_3 = "10000648VVV",
+ vupkhsw_2 = "1000064eV-V",
+ vsubuws_3 = "10000680VVV",
+ vshasigmaw_4 = "10000682VVYp",
+ veqv_3 = "10000684VVV",
+ vsum2sws_3 = "10000688VVV",
+ vmrgow_3 = "1000068cVVV",
+ vshasigmad_4 = "100006c2VVYp",
+ vsrd_3 = "100006c4VVV",
+ ["vcmpgtud._3"] = "100006c7VVV",
+ vupklsw_2 = "100006ceV-V",
+ vupkslw_2 = "100006ceV-V",
+ vsubsbs_3 = "10000700VVV",
+ vclzb_2 = "10000702V-V",
+ vpopcntb_2 = "10000703V-V",
+ ["vcmpgtsb._3"] = "10000706VVV",
+ vsum4sbs_3 = "10000708VVV",
+ vsubshs_3 = "10000740VVV",
+ vclzh_2 = "10000742V-V",
+ vpopcnth_2 = "10000743V-V",
+ ["vcmpgtsh._3"] = "10000746VVV",
+ vsubsws_3 = "10000780VVV",
+ vclzw_2 = "10000782V-V",
+ vpopcntw_2 = "10000783V-V",
+ ["vcmpgtsw._3"] = "10000786VVV",
+ vsumsws_3 = "10000788VVV",
+ vmrgew_3 = "1000078cVVV",
+ vclzd_2 = "100007c2V-V",
+ vpopcntd_2 = "100007c3V-V",
+ ["vcmpbfp._3"] = "100007c6VVV",
+ ["vcmpgtsd._3"] = "100007c7VVV",
+
+ -- Primary opcode 19:
+ mcrf_2 = "4c000000XX",
+ isync_0 = "4c00012c",
+ crnor_3 = "4c000042CCC",
+ crnot_2 = "4c000042CC=",
+ crandc_3 = "4c000102CCC",
+ crxor_3 = "4c000182CCC",
+ crclr_1 = "4c000182C==",
+ crnand_3 = "4c0001c2CCC",
+ crand_3 = "4c000202CCC",
+ creqv_3 = "4c000242CCC",
+ crset_1 = "4c000242C==",
+ crorc_3 = "4c000342CCC",
+ cror_3 = "4c000382CCC",
+ crmove_2 = "4c000382CC=",
+ bclr_2 = "4c000020AA",
+ bclrl_2 = "4c000021AA",
+ bcctr_2 = "4c000420AA",
+ bcctrl_2 = "4c000421AA",
+ bctar_2 = "4c000460AA",
+ bctarl_2 = "4c000461AA",
+ blr_0 = "4e800020",
+ blrl_0 = "4e800021",
+ bctr_0 = "4e800420",
+ bctrl_0 = "4e800421",
+
+ -- Primary opcode 31:
+ cmpw_3 = "7c000000XRR",
+ cmpw_2 = "7c000000-RR",
+ cmpd_3 = "7c200000XRR",
+ cmpd_2 = "7c200000-RR",
+ tw_3 = "7c000008ARR",
+ lvsl_3 = "7c00000cVRR",
+ subfc_3 = "7c000010RRR.",
+ subc_3 = "7c000010RRR~.",
+ mulhdu_3 = "7c000012RRR.",
+ addc_3 = "7c000014RRR.",
+ mulhwu_3 = "7c000016RRR.",
+ isel_4 = "7c00001eRRRC",
+ isellt_3 = "7c00001eRRR",
+ iselgt_3 = "7c00005eRRR",
+ iseleq_3 = "7c00009eRRR",
+ mfcr_1 = "7c000026R",
+ mfocrf_2 = "7c100026RG",
+ mtcrf_2 = "7c000120GR",
+ mtocrf_2 = "7c100120GR",
+ lwarx_3 = "7c000028RR0R",
+ ldx_3 = "7c00002aRR0R",
+ lwzx_3 = "7c00002eRR0R",
+ slw_3 = "7c000030RR~R.",
+ cntlzw_2 = "7c000034RR~",
+ sld_3 = "7c000036RR~R.",
+ and_3 = "7c000038RR~R.",
+ cmplw_3 = "7c000040XRR",
+ cmplw_2 = "7c000040-RR",
+ cmpld_3 = "7c200040XRR",
+ cmpld_2 = "7c200040-RR",
+ lvsr_3 = "7c00004cVRR",
+ subf_3 = "7c000050RRR.",
+ sub_3 = "7c000050RRR~.",
+ lbarx_3 = "7c000068RR0R",
+ ldux_3 = "7c00006aRR0R",
+ dcbst_2 = "7c00006c-RR",
+ lwzux_3 = "7c00006eRR0R",
+ cntlzd_2 = "7c000074RR~",
+ andc_3 = "7c000078RR~R.",
+ td_3 = "7c000088ARR",
+ lvewx_3 = "7c00008eVRR",
+ mulhd_3 = "7c000092RRR.",
+ addg6s_3 = "7c000094RRR",
+ mulhw_3 = "7c000096RRR.",
+ dlmzb_3 = "7c00009cRR~R.",
+ ldarx_3 = "7c0000a8RR0R",
+ dcbf_2 = "7c0000ac-RR",
+ lbzx_3 = "7c0000aeRR0R",
+ lvx_3 = "7c0000ceVRR",
+ neg_2 = "7c0000d0RR.",
+ lharx_3 = "7c0000e8RR0R",
+ lbzux_3 = "7c0000eeRR0R",
+ popcntb_2 = "7c0000f4RR~",
+ not_2 = "7c0000f8RR~%.",
+ nor_3 = "7c0000f8RR~R.",
+ stvebx_3 = "7c00010eVRR",
+ subfe_3 = "7c000110RRR.",
+ sube_3 = "7c000110RRR~.",
+ adde_3 = "7c000114RRR.",
+ stdx_3 = "7c00012aRR0R",
+ ["stwcx._3"] = "7c00012dRR0R.",
+ stwx_3 = "7c00012eRR0R",
+ prtyw_2 = "7c000134RR~",
+ stvehx_3 = "7c00014eVRR",
+ stdux_3 = "7c00016aRR0R",
+ ["stqcx._3"] = "7c00016dR:R0R.",
+ stwux_3 = "7c00016eRR0R",
+ prtyd_2 = "7c000174RR~",
+ stvewx_3 = "7c00018eVRR",
+ subfze_2 = "7c000190RR.",
+ addze_2 = "7c000194RR.",
+ ["stdcx._3"] = "7c0001adRR0R.",
+ stbx_3 = "7c0001aeRR0R",
+ stvx_3 = "7c0001ceVRR",
+ subfme_2 = "7c0001d0RR.",
+ mulld_3 = "7c0001d2RRR.",
+ addme_2 = "7c0001d4RR.",
+ mullw_3 = "7c0001d6RRR.",
+ dcbtst_2 = "7c0001ec-RR",
+ stbux_3 = "7c0001eeRR0R",
+ bpermd_3 = "7c0001f8RR~R",
+ lvepxl_3 = "7c00020eVRR",
+ add_3 = "7c000214RRR.",
+ lqarx_3 = "7c000228R:R0R",
+ dcbt_2 = "7c00022c-RR",
+ lhzx_3 = "7c00022eRR0R",
+ cdtbcd_2 = "7c000234RR~",
+ eqv_3 = "7c000238RR~R.",
+ lvepx_3 = "7c00024eVRR",
+ eciwx_3 = "7c00026cRR0R",
+ lhzux_3 = "7c00026eRR0R",
+ cbcdtd_2 = "7c000274RR~",
+ xor_3 = "7c000278RR~R.",
+ mfspefscr_1 = "7c0082a6R",
+ mfxer_1 = "7c0102a6R",
+ mflr_1 = "7c0802a6R",
+ mfctr_1 = "7c0902a6R",
+ lwax_3 = "7c0002aaRR0R",
+ lhax_3 = "7c0002aeRR0R",
+ mftb_1 = "7c0c42e6R",
+ mftbu_1 = "7c0d42e6R",
+ lvxl_3 = "7c0002ceVRR",
+ lwaux_3 = "7c0002eaRR0R",
+ lhaux_3 = "7c0002eeRR0R",
+ popcntw_2 = "7c0002f4RR~",
+ divdeu_3 = "7c000312RRR.",
+ divweu_3 = "7c000316RRR.",
+ sthx_3 = "7c00032eRR0R",
+ orc_3 = "7c000338RR~R.",
+ ecowx_3 = "7c00036cRR0R",
+ sthux_3 = "7c00036eRR0R",
+ or_3 = "7c000378RR~R.",
+ mr_2 = "7c000378RR~%.",
+ divdu_3 = "7c000392RRR.",
+ divwu_3 = "7c000396RRR.",
+ mtspefscr_1 = "7c0083a6R",
+ mtxer_1 = "7c0103a6R",
+ mtlr_1 = "7c0803a6R",
+ mtctr_1 = "7c0903a6R",
+ dcbi_2 = "7c0003ac-RR",
+ nand_3 = "7c0003b8RR~R.",
+ dsn_2 = "7c0003c6-RR",
+ stvxl_3 = "7c0003ceVRR",
+ divd_3 = "7c0003d2RRR.",
+ divw_3 = "7c0003d6RRR.",
+ popcntd_2 = "7c0003f4RR~",
+ cmpb_3 = "7c0003f8RR~R.",
+ mcrxr_1 = "7c000400X",
+ lbdx_3 = "7c000406RRR",
+ subfco_3 = "7c000410RRR.",
+ subco_3 = "7c000410RRR~.",
+ addco_3 = "7c000414RRR.",
+ ldbrx_3 = "7c000428RR0R",
+ lswx_3 = "7c00042aRR0R",
+ lwbrx_3 = "7c00042cRR0R",
+ lfsx_3 = "7c00042eFR0R",
+ srw_3 = "7c000430RR~R.",
+ srd_3 = "7c000436RR~R.",
+ lhdx_3 = "7c000446RRR",
+ subfo_3 = "7c000450RRR.",
+ subo_3 = "7c000450RRR~.",
+ lfsux_3 = "7c00046eFR0R",
+ lwdx_3 = "7c000486RRR",
+ lswi_3 = "7c0004aaRR0A",
+ sync_0 = "7c0004ac",
+ lwsync_0 = "7c2004ac",
+ ptesync_0 = "7c4004ac",
+ lfdx_3 = "7c0004aeFR0R",
+ lddx_3 = "7c0004c6RRR",
+ nego_2 = "7c0004d0RR.",
+ lfdux_3 = "7c0004eeFR0R",
+ stbdx_3 = "7c000506RRR",
+ subfeo_3 = "7c000510RRR.",
+ subeo_3 = "7c000510RRR~.",
+ addeo_3 = "7c000514RRR.",
+ stdbrx_3 = "7c000528RR0R",
+ stswx_3 = "7c00052aRR0R",
+ stwbrx_3 = "7c00052cRR0R",
+ stfsx_3 = "7c00052eFR0R",
+ sthdx_3 = "7c000546RRR",
+ ["stbcx._3"] = "7c00056dRRR",
+ stfsux_3 = "7c00056eFR0R",
+ stwdx_3 = "7c000586RRR",
+ subfzeo_2 = "7c000590RR.",
+ addzeo_2 = "7c000594RR.",
+ stswi_3 = "7c0005aaRR0A",
+ ["sthcx._3"] = "7c0005adRRR",
+ stfdx_3 = "7c0005aeFR0R",
+ stddx_3 = "7c0005c6RRR",
+ subfmeo_2 = "7c0005d0RR.",
+ mulldo_3 = "7c0005d2RRR.",
+ addmeo_2 = "7c0005d4RR.",
+ mullwo_3 = "7c0005d6RRR.",
+ dcba_2 = "7c0005ec-RR",
+ stfdux_3 = "7c0005eeFR0R",
+ stvepxl_3 = "7c00060eVRR",
+ addo_3 = "7c000614RRR.",
+ lhbrx_3 = "7c00062cRR0R",
+ lfdpx_3 = "7c00062eF:RR",
+ sraw_3 = "7c000630RR~R.",
+ srad_3 = "7c000634RR~R.",
+ lfddx_3 = "7c000646FRR",
+ stvepx_3 = "7c00064eVRR",
+ srawi_3 = "7c000670RR~A.",
+ sradi_3 = "7c000674RR~H.",
+ eieio_0 = "7c0006ac",
+ lfiwax_3 = "7c0006aeFR0R",
+ divdeuo_3 = "7c000712RRR.",
+ divweuo_3 = "7c000716RRR.",
+ sthbrx_3 = "7c00072cRR0R",
+ stfdpx_3 = "7c00072eF:RR",
+ extsh_2 = "7c000734RR~.",
+ stfddx_3 = "7c000746FRR",
+ divdeo_3 = "7c000752RRR.",
+ divweo_3 = "7c000756RRR.",
+ extsb_2 = "7c000774RR~.",
+ divduo_3 = "7c000792RRR.",
+ divwou_3 = "7c000796RRR.",
+ icbi_2 = "7c0007ac-RR",
+ stfiwx_3 = "7c0007aeFR0R",
+ extsw_2 = "7c0007b4RR~.",
+ divdo_3 = "7c0007d2RRR.",
+ divwo_3 = "7c0007d6RRR.",
+ dcbz_2 = "7c0007ec-RR",
+
+ ["tbegin._1"] = "7c00051d1",
+ ["tbegin._0"] = "7c00051d",
+ ["tend._1"] = "7c00055dY",
+ ["tend._0"] = "7c00055d",
+ ["tendall._0"] = "7e00055d",
+ tcheck_1 = "7c00059cX",
+ ["tsr._1"] = "7c0005dd1",
+ ["tsuspend._0"] = "7c0005dd",
+ ["tresume._0"] = "7c2005dd",
+ ["tabortwc._3"] = "7c00061dARR",
+ ["tabortdc._3"] = "7c00065dARR",
+ ["tabortwci._3"] = "7c00069dARS",
+ ["tabortdci._3"] = "7c0006ddARS",
+ ["tabort._1"] = "7c00071d-R-",
+ ["treclaim._1"] = "7c00075d-R",
+ ["trechkpt._0"] = "7c0007dd",
+
+ lxsiwzx_3 = "7c000018QRR",
+ lxsiwax_3 = "7c000098QRR",
+ mfvsrd_2 = "7c000066-Rq",
+ mfvsrwz_2 = "7c0000e6-Rq",
+ stxsiwx_3 = "7c000118QRR",
+ mtvsrd_2 = "7c000166QR",
+ mtvsrwa_2 = "7c0001a6QR",
+ lxvdsx_3 = "7c000298QRR",
+ lxsspx_3 = "7c000418QRR",
+ lxsdx_3 = "7c000498QRR",
+ stxsspx_3 = "7c000518QRR",
+ stxsdx_3 = "7c000598QRR",
+ lxvw4x_3 = "7c000618QRR",
+ lxvd2x_3 = "7c000698QRR",
+ stxvw4x_3 = "7c000718QRR",
+ stxvd2x_3 = "7c000798QRR",
+
+ -- Primary opcode 30:
+ rldicl_4 = "78000000RR~HM.",
+ rldicr_4 = "78000004RR~HM.",
+ rldic_4 = "78000008RR~HM.",
+ rldimi_4 = "7800000cRR~HM.",
+ rldcl_4 = "78000010RR~RM.",
+ rldcr_4 = "78000012RR~RM.",
+
+ rotldi_3 = op_alias("rldicl_4", function(p)
+ p[4] = "0"
+ end),
+ rotrdi_3 = op_alias("rldicl_4", function(p)
+ p[3] = "64-("..p[3]..")"; p[4] = "0"
+ end),
+ rotld_3 = op_alias("rldcl_4", function(p)
+ p[4] = "0"
+ end),
+ sldi_3 = op_alias("rldicr_4", function(p)
+ p[4] = "63-("..p[3]..")"
+ end),
+ srdi_3 = op_alias("rldicl_4", function(p)
+ p[4] = p[3]; p[3] = "64-("..p[3]..")"
+ end),
+ clrldi_3 = op_alias("rldicl_4", function(p)
+ p[4] = p[3]; p[3] = "0"
+ end),
+ clrrdi_3 = op_alias("rldicr_4", function(p)
+ p[4] = "63-("..p[3]..")"; p[3] = "0"
+ end),
+
+ -- Primary opcode 56:
+ lq_2 = "e0000000R:D", -- NYI: displacement must be divisible by 8.
+
+ -- Primary opcode 57:
+ lfdp_2 = "e4000000F:D", -- NYI: displacement must be divisible by 4.
+
+ -- Primary opcode 59:
+ fdivs_3 = "ec000024FFF.",
+ fsubs_3 = "ec000028FFF.",
+ fadds_3 = "ec00002aFFF.",
+ fsqrts_2 = "ec00002cF-F.",
+ fres_2 = "ec000030F-F.",
+ fmuls_3 = "ec000032FF-F.",
+ frsqrtes_2 = "ec000034F-F.",
+ fmsubs_4 = "ec000038FFFF~.",
+ fmadds_4 = "ec00003aFFFF~.",
+ fnmsubs_4 = "ec00003cFFFF~.",
+ fnmadds_4 = "ec00003eFFFF~.",
+ fcfids_2 = "ec00069cF-F.",
+ fcfidus_2 = "ec00079cF-F.",
+
+ dadd_3 = "ec000004FFF.",
+ dqua_4 = "ec000006FFFZ.",
+ dmul_3 = "ec000044FFF.",
+ drrnd_4 = "ec000046FFFZ.",
+ dscli_3 = "ec000084FF6.",
+ dquai_4 = "ec000086SF~FZ.",
+ dscri_3 = "ec0000c4FF6.",
+ drintx_4 = "ec0000c61F~FZ.",
+ dcmpo_3 = "ec000104XFF",
+ dtstex_3 = "ec000144XFF",
+ dtstdc_3 = "ec000184XF6",
+ dtstdg_3 = "ec0001c4XF6",
+ drintn_4 = "ec0001c61F~FZ.",
+ dctdp_2 = "ec000204F-F.",
+ dctfix_2 = "ec000244F-F.",
+ ddedpd_3 = "ec000284ZF~F.",
+ dxex_2 = "ec0002c4F-F.",
+ dsub_3 = "ec000404FFF.",
+ ddiv_3 = "ec000444FFF.",
+ dcmpu_3 = "ec000504XFF",
+ dtstsf_3 = "ec000544XFF",
+ drsp_2 = "ec000604F-F.",
+ dcffix_2 = "ec000644F-F.",
+ denbcd_3 = "ec000684YF~F.",
+ diex_3 = "ec0006c4FFF.",
+
+ -- Primary opcode 60:
+ xsaddsp_3 = "f0000000QQQ",
+ xsmaddasp_3 = "f0000008QQQ",
+ xxsldwi_4 = "f0000010QQQz",
+ xsrsqrtesp_2 = "f0000028Q-Q",
+ xssqrtsp_2 = "f000002cQ-Q",
+ xxsel_4 = "f0000030QQQQ",
+ xssubsp_3 = "f0000040QQQ",
+ xsmaddmsp_3 = "f0000048QQQ",
+ xxpermdi_4 = "f0000050QQQz",
+ xsresp_2 = "f0000068Q-Q",
+ xsmulsp_3 = "f0000080QQQ",
+ xsmsubasp_3 = "f0000088QQQ",
+ xxmrghw_3 = "f0000090QQQ",
+ xsdivsp_3 = "f00000c0QQQ",
+ xsmsubmsp_3 = "f00000c8QQQ",
+ xsadddp_3 = "f0000100QQQ",
+ xsmaddadp_3 = "f0000108QQQ",
+ xscmpudp_3 = "f0000118XQQ",
+ xscvdpuxws_2 = "f0000120Q-Q",
+ xsrdpi_2 = "f0000124Q-Q",
+ xsrsqrtedp_2 = "f0000128Q-Q",
+ xssqrtdp_2 = "f000012cQ-Q",
+ xssubdp_3 = "f0000140QQQ",
+ xsmaddmdp_3 = "f0000148QQQ",
+ xscmpodp_3 = "f0000158XQQ",
+ xscvdpsxws_2 = "f0000160Q-Q",
+ xsrdpiz_2 = "f0000164Q-Q",
+ xsredp_2 = "f0000168Q-Q",
+ xsmuldp_3 = "f0000180QQQ",
+ xsmsubadp_3 = "f0000188QQQ",
+ xxmrglw_3 = "f0000190QQQ",
+ xsrdpip_2 = "f00001a4Q-Q",
+ xstsqrtdp_2 = "f00001a8X-Q",
+ xsrdpic_2 = "f00001acQ-Q",
+ xsdivdp_3 = "f00001c0QQQ",
+ xsmsubmdp_3 = "f00001c8QQQ",
+ xsrdpim_2 = "f00001e4Q-Q",
+ xstdivdp_3 = "f00001e8XQQ",
+ xvaddsp_3 = "f0000200QQQ",
+ xvmaddasp_3 = "f0000208QQQ",
+ xvcmpeqsp_3 = "f0000218QQQ",
+ xvcvspuxws_2 = "f0000220Q-Q",
+ xvrspi_2 = "f0000224Q-Q",
+ xvrsqrtesp_2 = "f0000228Q-Q",
+ xvsqrtsp_2 = "f000022cQ-Q",
+ xvsubsp_3 = "f0000240QQQ",
+ xvmaddmsp_3 = "f0000248QQQ",
+ xvcmpgtsp_3 = "f0000258QQQ",
+ xvcvspsxws_2 = "f0000260Q-Q",
+ xvrspiz_2 = "f0000264Q-Q",
+ xvresp_2 = "f0000268Q-Q",
+ xvmulsp_3 = "f0000280QQQ",
+ xvmsubasp_3 = "f0000288QQQ",
+ xxspltw_3 = "f0000290QQg~",
+ xvcmpgesp_3 = "f0000298QQQ",
+ xvcvuxwsp_2 = "f00002a0Q-Q",
+ xvrspip_2 = "f00002a4Q-Q",
+ xvtsqrtsp_2 = "f00002a8X-Q",
+ xvrspic_2 = "f00002acQ-Q",
+ xvdivsp_3 = "f00002c0QQQ",
+ xvmsubmsp_3 = "f00002c8QQQ",
+ xvcvsxwsp_2 = "f00002e0Q-Q",
+ xvrspim_2 = "f00002e4Q-Q",
+ xvtdivsp_3 = "f00002e8XQQ",
+ xvadddp_3 = "f0000300QQQ",
+ xvmaddadp_3 = "f0000308QQQ",
+ xvcmpeqdp_3 = "f0000318QQQ",
+ xvcvdpuxws_2 = "f0000320Q-Q",
+ xvrdpi_2 = "f0000324Q-Q",
+ xvrsqrtedp_2 = "f0000328Q-Q",
+ xvsqrtdp_2 = "f000032cQ-Q",
+ xvsubdp_3 = "f0000340QQQ",
+ xvmaddmdp_3 = "f0000348QQQ",
+ xvcmpgtdp_3 = "f0000358QQQ",
+ xvcvdpsxws_2 = "f0000360Q-Q",
+ xvrdpiz_2 = "f0000364Q-Q",
+ xvredp_2 = "f0000368Q-Q",
+ xvmuldp_3 = "f0000380QQQ",
+ xvmsubadp_3 = "f0000388QQQ",
+ xvcmpgedp_3 = "f0000398QQQ",
+ xvcvuxwdp_2 = "f00003a0Q-Q",
+ xvrdpip_2 = "f00003a4Q-Q",
+ xvtsqrtdp_2 = "f00003a8X-Q",
+ xvrdpic_2 = "f00003acQ-Q",
+ xvdivdp_3 = "f00003c0QQQ",
+ xvmsubmdp_3 = "f00003c8QQQ",
+ xvcvsxwdp_2 = "f00003e0Q-Q",
+ xvrdpim_2 = "f00003e4Q-Q",
+ xvtdivdp_3 = "f00003e8XQQ",
+ xsnmaddasp_3 = "f0000408QQQ",
+ xxland_3 = "f0000410QQQ",
+ xscvdpsp_2 = "f0000424Q-Q",
+ xscvdpspn_2 = "f000042cQ-Q",
+ xsnmaddmsp_3 = "f0000448QQQ",
+ xxlandc_3 = "f0000450QQQ",
+ xsrsp_2 = "f0000464Q-Q",
+ xsnmsubasp_3 = "f0000488QQQ",
+ xxlor_3 = "f0000490QQQ",
+ xscvuxdsp_2 = "f00004a0Q-Q",
+ xsnmsubmsp_3 = "f00004c8QQQ",
+ xxlxor_3 = "f00004d0QQQ",
+ xscvsxdsp_2 = "f00004e0Q-Q",
+ xsmaxdp_3 = "f0000500QQQ",
+ xsnmaddadp_3 = "f0000508QQQ",
+ xxlnor_3 = "f0000510QQQ",
+ xscvdpuxds_2 = "f0000520Q-Q",
+ xscvspdp_2 = "f0000524Q-Q",
+ xscvspdpn_2 = "f000052cQ-Q",
+ xsmindp_3 = "f0000540QQQ",
+ xsnmaddmdp_3 = "f0000548QQQ",
+ xxlorc_3 = "f0000550QQQ",
+ xscvdpsxds_2 = "f0000560Q-Q",
+ xsabsdp_2 = "f0000564Q-Q",
+ xscpsgndp_3 = "f0000580QQQ",
+ xsnmsubadp_3 = "f0000588QQQ",
+ xxlnand_3 = "f0000590QQQ",
+ xscvuxddp_2 = "f00005a0Q-Q",
+ xsnabsdp_2 = "f00005a4Q-Q",
+ xsnmsubmdp_3 = "f00005c8QQQ",
+ xxleqv_3 = "f00005d0QQQ",
+ xscvsxddp_2 = "f00005e0Q-Q",
+ xsnegdp_2 = "f00005e4Q-Q",
+ xvmaxsp_3 = "f0000600QQQ",
+ xvnmaddasp_3 = "f0000608QQQ",
+ ["xvcmpeqsp._3"] = "f0000618QQQ",
+ xvcvspuxds_2 = "f0000620Q-Q",
+ xvcvdpsp_2 = "f0000624Q-Q",
+ xvminsp_3 = "f0000640QQQ",
+ xvnmaddmsp_3 = "f0000648QQQ",
+ ["xvcmpgtsp._3"] = "f0000658QQQ",
+ xvcvspsxds_2 = "f0000660Q-Q",
+ xvabssp_2 = "f0000664Q-Q",
+ xvcpsgnsp_3 = "f0000680QQQ",
+ xvnmsubasp_3 = "f0000688QQQ",
+ ["xvcmpgesp._3"] = "f0000698QQQ",
+ xvcvuxdsp_2 = "f00006a0Q-Q",
+ xvnabssp_2 = "f00006a4Q-Q",
+ xvnmsubmsp_3 = "f00006c8QQQ",
+ xvcvsxdsp_2 = "f00006e0Q-Q",
+ xvnegsp_2 = "f00006e4Q-Q",
+ xvmaxdp_3 = "f0000700QQQ",
+ xvnmaddadp_3 = "f0000708QQQ",
+ ["xvcmpeqdp._3"] = "f0000718QQQ",
+ xvcvdpuxds_2 = "f0000720Q-Q",
+ xvcvspdp_2 = "f0000724Q-Q",
+ xvmindp_3 = "f0000740QQQ",
+ xvnmaddmdp_3 = "f0000748QQQ",
+ ["xvcmpgtdp._3"] = "f0000758QQQ",
+ xvcvdpsxds_2 = "f0000760Q-Q",
+ xvabsdp_2 = "f0000764Q-Q",
+ xvcpsgndp_3 = "f0000780QQQ",
+ xvnmsubadp_3 = "f0000788QQQ",
+ ["xvcmpgedp._3"] = "f0000798QQQ",
+ xvcvuxddp_2 = "f00007a0Q-Q",
+ xvnabsdp_2 = "f00007a4Q-Q",
+ xvnmsubmdp_3 = "f00007c8QQQ",
+ xvcvsxddp_2 = "f00007e0Q-Q",
+ xvnegdp_2 = "f00007e4Q-Q",
+
+ -- Primary opcode 61:
+ stfdp_2 = "f4000000F:D", -- NYI: displacement must be divisible by 4.
+
+ -- Primary opcode 62:
+ stq_2 = "f8000002R:D", -- NYI: displacement must be divisible by 8.
+
+ -- Primary opcode 63:
+ fdiv_3 = "fc000024FFF.",
+ fsub_3 = "fc000028FFF.",
+ fadd_3 = "fc00002aFFF.",
+ fsqrt_2 = "fc00002cF-F.",
+ fsel_4 = "fc00002eFFFF~.",
+ fre_2 = "fc000030F-F.",
+ fmul_3 = "fc000032FF-F.",
+ frsqrte_2 = "fc000034F-F.",
+ fmsub_4 = "fc000038FFFF~.",
+ fmadd_4 = "fc00003aFFFF~.",
+ fnmsub_4 = "fc00003cFFFF~.",
+ fnmadd_4 = "fc00003eFFFF~.",
+ fcmpu_3 = "fc000000XFF",
+ fcpsgn_3 = "fc000010FFF.",
+ fcmpo_3 = "fc000040XFF",
+ mtfsb1_1 = "fc00004cA",
+ fneg_2 = "fc000050F-F.",
+ mcrfs_2 = "fc000080XX",
+ mtfsb0_1 = "fc00008cA",
+ fmr_2 = "fc000090F-F.",
+ frsp_2 = "fc000018F-F.",
+ fctiw_2 = "fc00001cF-F.",
+ fctiwz_2 = "fc00001eF-F.",
+ ftdiv_2 = "fc000100X-F.",
+ fctiwu_2 = "fc00011cF-F.",
+ fctiwuz_2 = "fc00011eF-F.",
+ mtfsfi_2 = "fc00010cAA", -- NYI: upshift.
+ fnabs_2 = "fc000110F-F.",
+ ftsqrt_2 = "fc000140X-F.",
+ fabs_2 = "fc000210F-F.",
+ frin_2 = "fc000310F-F.",
+ friz_2 = "fc000350F-F.",
+ frip_2 = "fc000390F-F.",
+ frim_2 = "fc0003d0F-F.",
+ mffs_1 = "fc00048eF.",
+ -- NYI: mtfsf, mtfsb0, mtfsb1.
+ fctid_2 = "fc00065cF-F.",
+ fctidz_2 = "fc00065eF-F.",
+ fmrgow_3 = "fc00068cFFF",
+ fcfid_2 = "fc00069cF-F.",
+ fctidu_2 = "fc00075cF-F.",
+ fctiduz_2 = "fc00075eF-F.",
+ fmrgew_3 = "fc00078cFFF",
+ fcfidu_2 = "fc00079cF-F.",
+
+ daddq_3 = "fc000004F:F:F:.",
+ dquaq_4 = "fc000006F:F:F:Z.",
+ dmulq_3 = "fc000044F:F:F:.",
+ drrndq_4 = "fc000046F:F:F:Z.",
+ dscliq_3 = "fc000084F:F:6.",
+ dquaiq_4 = "fc000086SF:~F:Z.",
+ dscriq_3 = "fc0000c4F:F:6.",
+ drintxq_4 = "fc0000c61F:~F:Z.",
+ dcmpoq_3 = "fc000104XF:F:",
+ dtstexq_3 = "fc000144XF:F:",
+ dtstdcq_3 = "fc000184XF:6",
+ dtstdgq_3 = "fc0001c4XF:6",
+ drintnq_4 = "fc0001c61F:~F:Z.",
+ dctqpq_2 = "fc000204F:-F:.",
+ dctfixq_2 = "fc000244F:-F:.",
+ ddedpdq_3 = "fc000284ZF:~F:.",
+ dxexq_2 = "fc0002c4F:-F:.",
+ dsubq_3 = "fc000404F:F:F:.",
+ ddivq_3 = "fc000444F:F:F:.",
+ dcmpuq_3 = "fc000504XF:F:",
+ dtstsfq_3 = "fc000544XF:F:",
+ drdpq_2 = "fc000604F:-F:.",
+ dcffixq_2 = "fc000644F:-F:.",
+ denbcdq_3 = "fc000684YF:~F:.",
+ diexq_3 = "fc0006c4F:FF:.",
+
+ -- Primary opcode 4, SPE APU extension:
+ evaddw_3 = "10000200RRR",
+ evaddiw_3 = "10000202RAR~",
+ evsubw_3 = "10000204RRR~",
+ evsubiw_3 = "10000206RAR~",
+ evabs_2 = "10000208RR",
+ evneg_2 = "10000209RR",
+ evextsb_2 = "1000020aRR",
+ evextsh_2 = "1000020bRR",
+ evrndw_2 = "1000020cRR",
+ evcntlzw_2 = "1000020dRR",
+ evcntlsw_2 = "1000020eRR",
+ brinc_3 = "1000020fRRR",
+ evand_3 = "10000211RRR",
+ evandc_3 = "10000212RRR",
+ evxor_3 = "10000216RRR",
+ evor_3 = "10000217RRR",
+ evmr_2 = "10000217RR=",
+ evnor_3 = "10000218RRR",
+ evnot_2 = "10000218RR=",
+ eveqv_3 = "10000219RRR",
+ evorc_3 = "1000021bRRR",
+ evnand_3 = "1000021eRRR",
+ evsrwu_3 = "10000220RRR",
+ evsrws_3 = "10000221RRR",
+ evsrwiu_3 = "10000222RRA",
+ evsrwis_3 = "10000223RRA",
+ evslw_3 = "10000224RRR",
+ evslwi_3 = "10000226RRA",
+ evrlw_3 = "10000228RRR",
+ evsplati_2 = "10000229RS",
+ evrlwi_3 = "1000022aRRA",
+ evsplatfi_2 = "1000022bRS",
+ evmergehi_3 = "1000022cRRR",
+ evmergelo_3 = "1000022dRRR",
+ evcmpgtu_3 = "10000230XRR",
+ evcmpgtu_2 = "10000230-RR",
+ evcmpgts_3 = "10000231XRR",
+ evcmpgts_2 = "10000231-RR",
+ evcmpltu_3 = "10000232XRR",
+ evcmpltu_2 = "10000232-RR",
+ evcmplts_3 = "10000233XRR",
+ evcmplts_2 = "10000233-RR",
+ evcmpeq_3 = "10000234XRR",
+ evcmpeq_2 = "10000234-RR",
+ evsel_4 = "10000278RRRW",
+ evsel_3 = "10000278RRR",
+ evfsadd_3 = "10000280RRR",
+ evfssub_3 = "10000281RRR",
+ evfsabs_2 = "10000284RR",
+ evfsnabs_2 = "10000285RR",
+ evfsneg_2 = "10000286RR",
+ evfsmul_3 = "10000288RRR",
+ evfsdiv_3 = "10000289RRR",
+ evfscmpgt_3 = "1000028cXRR",
+ evfscmpgt_2 = "1000028c-RR",
+ evfscmplt_3 = "1000028dXRR",
+ evfscmplt_2 = "1000028d-RR",
+ evfscmpeq_3 = "1000028eXRR",
+ evfscmpeq_2 = "1000028e-RR",
+ evfscfui_2 = "10000290R-R",
+ evfscfsi_2 = "10000291R-R",
+ evfscfuf_2 = "10000292R-R",
+ evfscfsf_2 = "10000293R-R",
+ evfsctui_2 = "10000294R-R",
+ evfsctsi_2 = "10000295R-R",
+ evfsctuf_2 = "10000296R-R",
+ evfsctsf_2 = "10000297R-R",
+ evfsctuiz_2 = "10000298R-R",
+ evfsctsiz_2 = "1000029aR-R",
+ evfststgt_3 = "1000029cXRR",
+ evfststgt_2 = "1000029c-RR",
+ evfststlt_3 = "1000029dXRR",
+ evfststlt_2 = "1000029d-RR",
+ evfststeq_3 = "1000029eXRR",
+ evfststeq_2 = "1000029e-RR",
+ efsadd_3 = "100002c0RRR",
+ efssub_3 = "100002c1RRR",
+ efsabs_2 = "100002c4RR",
+ efsnabs_2 = "100002c5RR",
+ efsneg_2 = "100002c6RR",
+ efsmul_3 = "100002c8RRR",
+ efsdiv_3 = "100002c9RRR",
+ efscmpgt_3 = "100002ccXRR",
+ efscmpgt_2 = "100002cc-RR",
+ efscmplt_3 = "100002cdXRR",
+ efscmplt_2 = "100002cd-RR",
+ efscmpeq_3 = "100002ceXRR",
+ efscmpeq_2 = "100002ce-RR",
+ efscfd_2 = "100002cfR-R",
+ efscfui_2 = "100002d0R-R",
+ efscfsi_2 = "100002d1R-R",
+ efscfuf_2 = "100002d2R-R",
+ efscfsf_2 = "100002d3R-R",
+ efsctui_2 = "100002d4R-R",
+ efsctsi_2 = "100002d5R-R",
+ efsctuf_2 = "100002d6R-R",
+ efsctsf_2 = "100002d7R-R",
+ efsctuiz_2 = "100002d8R-R",
+ efsctsiz_2 = "100002daR-R",
+ efststgt_3 = "100002dcXRR",
+ efststgt_2 = "100002dc-RR",
+ efststlt_3 = "100002ddXRR",
+ efststlt_2 = "100002dd-RR",
+ efststeq_3 = "100002deXRR",
+ efststeq_2 = "100002de-RR",
+ efdadd_3 = "100002e0RRR",
+ efdsub_3 = "100002e1RRR",
+ efdcfuid_2 = "100002e2R-R",
+ efdcfsid_2 = "100002e3R-R",
+ efdabs_2 = "100002e4RR",
+ efdnabs_2 = "100002e5RR",
+ efdneg_2 = "100002e6RR",
+ efdmul_3 = "100002e8RRR",
+ efddiv_3 = "100002e9RRR",
+ efdctuidz_2 = "100002eaR-R",
+ efdctsidz_2 = "100002ebR-R",
+ efdcmpgt_3 = "100002ecXRR",
+ efdcmpgt_2 = "100002ec-RR",
+ efdcmplt_3 = "100002edXRR",
+ efdcmplt_2 = "100002ed-RR",
+ efdcmpeq_3 = "100002eeXRR",
+ efdcmpeq_2 = "100002ee-RR",
+ efdcfs_2 = "100002efR-R",
+ efdcfui_2 = "100002f0R-R",
+ efdcfsi_2 = "100002f1R-R",
+ efdcfuf_2 = "100002f2R-R",
+ efdcfsf_2 = "100002f3R-R",
+ efdctui_2 = "100002f4R-R",
+ efdctsi_2 = "100002f5R-R",
+ efdctuf_2 = "100002f6R-R",
+ efdctsf_2 = "100002f7R-R",
+ efdctuiz_2 = "100002f8R-R",
+ efdctsiz_2 = "100002faR-R",
+ efdtstgt_3 = "100002fcXRR",
+ efdtstgt_2 = "100002fc-RR",
+ efdtstlt_3 = "100002fdXRR",
+ efdtstlt_2 = "100002fd-RR",
+ efdtsteq_3 = "100002feXRR",
+ efdtsteq_2 = "100002fe-RR",
+ evlddx_3 = "10000300RR0R",
+ evldd_2 = "10000301R8",
+ evldwx_3 = "10000302RR0R",
+ evldw_2 = "10000303R8",
+ evldhx_3 = "10000304RR0R",
+ evldh_2 = "10000305R8",
+ evlwhex_3 = "10000310RR0R",
+ evlwhe_2 = "10000311R4",
+ evlwhoux_3 = "10000314RR0R",
+ evlwhou_2 = "10000315R4",
+ evlwhosx_3 = "10000316RR0R",
+ evlwhos_2 = "10000317R4",
+ evstddx_3 = "10000320RR0R",
+ evstdd_2 = "10000321R8",
+ evstdwx_3 = "10000322RR0R",
+ evstdw_2 = "10000323R8",
+ evstdhx_3 = "10000324RR0R",
+ evstdh_2 = "10000325R8",
+ evstwhex_3 = "10000330RR0R",
+ evstwhe_2 = "10000331R4",
+ evstwhox_3 = "10000334RR0R",
+ evstwho_2 = "10000335R4",
+ evstwwex_3 = "10000338RR0R",
+ evstwwe_2 = "10000339R4",
+ evstwwox_3 = "1000033cRR0R",
+ evstwwo_2 = "1000033dR4",
+ evmhessf_3 = "10000403RRR",
+ evmhossf_3 = "10000407RRR",
+ evmheumi_3 = "10000408RRR",
+ evmhesmi_3 = "10000409RRR",
+ evmhesmf_3 = "1000040bRRR",
+ evmhoumi_3 = "1000040cRRR",
+ evmhosmi_3 = "1000040dRRR",
+ evmhosmf_3 = "1000040fRRR",
+ evmhessfa_3 = "10000423RRR",
+ evmhossfa_3 = "10000427RRR",
+ evmheumia_3 = "10000428RRR",
+ evmhesmia_3 = "10000429RRR",
+ evmhesmfa_3 = "1000042bRRR",
+ evmhoumia_3 = "1000042cRRR",
+ evmhosmia_3 = "1000042dRRR",
+ evmhosmfa_3 = "1000042fRRR",
+ evmwhssf_3 = "10000447RRR",
+ evmwlumi_3 = "10000448RRR",
+ evmwhumi_3 = "1000044cRRR",
+ evmwhsmi_3 = "1000044dRRR",
+ evmwhsmf_3 = "1000044fRRR",
+ evmwssf_3 = "10000453RRR",
+ evmwumi_3 = "10000458RRR",
+ evmwsmi_3 = "10000459RRR",
+ evmwsmf_3 = "1000045bRRR",
+ evmwhssfa_3 = "10000467RRR",
+ evmwlumia_3 = "10000468RRR",
+ evmwhumia_3 = "1000046cRRR",
+ evmwhsmia_3 = "1000046dRRR",
+ evmwhsmfa_3 = "1000046fRRR",
+ evmwssfa_3 = "10000473RRR",
+ evmwumia_3 = "10000478RRR",
+ evmwsmia_3 = "10000479RRR",
+ evmwsmfa_3 = "1000047bRRR",
+ evmra_2 = "100004c4RR",
+ evdivws_3 = "100004c6RRR",
+ evdivwu_3 = "100004c7RRR",
+ evmwssfaa_3 = "10000553RRR",
+ evmwumiaa_3 = "10000558RRR",
+ evmwsmiaa_3 = "10000559RRR",
+ evmwsmfaa_3 = "1000055bRRR",
+ evmwssfan_3 = "100005d3RRR",
+ evmwumian_3 = "100005d8RRR",
+ evmwsmian_3 = "100005d9RRR",
+ evmwsmfan_3 = "100005dbRRR",
+ evmergehilo_3 = "1000022eRRR",
+ evmergelohi_3 = "1000022fRRR",
+ evlhhesplatx_3 = "10000308RR0R",
+ evlhhesplat_2 = "10000309R2",
+ evlhhousplatx_3 = "1000030cRR0R",
+ evlhhousplat_2 = "1000030dR2",
+ evlhhossplatx_3 = "1000030eRR0R",
+ evlhhossplat_2 = "1000030fR2",
+ evlwwsplatx_3 = "10000318RR0R",
+ evlwwsplat_2 = "10000319R4",
+ evlwhsplatx_3 = "1000031cRR0R",
+ evlwhsplat_2 = "1000031dR4",
+ evaddusiaaw_2 = "100004c0RR",
+ evaddssiaaw_2 = "100004c1RR",
+ evsubfusiaaw_2 = "100004c2RR",
+ evsubfssiaaw_2 = "100004c3RR",
+ evaddumiaaw_2 = "100004c8RR",
+ evaddsmiaaw_2 = "100004c9RR",
+ evsubfumiaaw_2 = "100004caRR",
+ evsubfsmiaaw_2 = "100004cbRR",
+ evmheusiaaw_3 = "10000500RRR",
+ evmhessiaaw_3 = "10000501RRR",
+ evmhessfaaw_3 = "10000503RRR",
+ evmhousiaaw_3 = "10000504RRR",
+ evmhossiaaw_3 = "10000505RRR",
+ evmhossfaaw_3 = "10000507RRR",
+ evmheumiaaw_3 = "10000508RRR",
+ evmhesmiaaw_3 = "10000509RRR",
+ evmhesmfaaw_3 = "1000050bRRR",
+ evmhoumiaaw_3 = "1000050cRRR",
+ evmhosmiaaw_3 = "1000050dRRR",
+ evmhosmfaaw_3 = "1000050fRRR",
+ evmhegumiaa_3 = "10000528RRR",
+ evmhegsmiaa_3 = "10000529RRR",
+ evmhegsmfaa_3 = "1000052bRRR",
+ evmhogumiaa_3 = "1000052cRRR",
+ evmhogsmiaa_3 = "1000052dRRR",
+ evmhogsmfaa_3 = "1000052fRRR",
+ evmwlusiaaw_3 = "10000540RRR",
+ evmwlssiaaw_3 = "10000541RRR",
+ evmwlumiaaw_3 = "10000548RRR",
+ evmwlsmiaaw_3 = "10000549RRR",
+ evmheusianw_3 = "10000580RRR",
+ evmhessianw_3 = "10000581RRR",
+ evmhessfanw_3 = "10000583RRR",
+ evmhousianw_3 = "10000584RRR",
+ evmhossianw_3 = "10000585RRR",
+ evmhossfanw_3 = "10000587RRR",
+ evmheumianw_3 = "10000588RRR",
+ evmhesmianw_3 = "10000589RRR",
+ evmhesmfanw_3 = "1000058bRRR",
+ evmhoumianw_3 = "1000058cRRR",
+ evmhosmianw_3 = "1000058dRRR",
+ evmhosmfanw_3 = "1000058fRRR",
+ evmhegumian_3 = "100005a8RRR",
+ evmhegsmian_3 = "100005a9RRR",
+ evmhegsmfan_3 = "100005abRRR",
+ evmhogumian_3 = "100005acRRR",
+ evmhogsmian_3 = "100005adRRR",
+ evmhogsmfan_3 = "100005afRRR",
+ evmwlusianw_3 = "100005c0RRR",
+ evmwlssianw_3 = "100005c1RRR",
+ evmwlumianw_3 = "100005c8RRR",
+ evmwlsmianw_3 = "100005c9RRR",
+
+ -- NYI: Book E instructions.
+}
+
+-- Add mnemonics for "." variants.
+do
+ local t = {}
+ for k,v in pairs(map_op) do
+ if type(v) == "string" and sub(v, -1) == "." then
+ local v2 = sub(v, 1, 7)..char(byte(v, 8)+1)..sub(v, 9, -2)
+ t[sub(k, 1, -3).."."..sub(k, -2)] = v2
+ end
+ end
+ for k,v in pairs(t) do
+ map_op[k] = v
+ end
+end
+
+-- Add more branch mnemonics.
+for cond,c in pairs(map_cond) do
+ local b1 = "b"..cond
+ local c1 = shl(band(c, 3), 16) + (c < 4 and 0x01000000 or 0)
+ -- bX[l]
+ map_op[b1.."_1"] = tohex(0x40800000 + c1).."K"
+ map_op[b1.."y_1"] = tohex(0x40a00000 + c1).."K"
+ map_op[b1.."l_1"] = tohex(0x40800001 + c1).."K"
+ map_op[b1.."_2"] = tohex(0x40800000 + c1).."-XK"
+ map_op[b1.."y_2"] = tohex(0x40a00000 + c1).."-XK"
+ map_op[b1.."l_2"] = tohex(0x40800001 + c1).."-XK"
+ -- bXlr[l]
+ map_op[b1.."lr_0"] = tohex(0x4c800020 + c1)
+ map_op[b1.."lrl_0"] = tohex(0x4c800021 + c1)
+ map_op[b1.."ctr_0"] = tohex(0x4c800420 + c1)
+ map_op[b1.."ctrl_0"] = tohex(0x4c800421 + c1)
+ -- bXctr[l]
+ map_op[b1.."lr_1"] = tohex(0x4c800020 + c1).."-X"
+ map_op[b1.."lrl_1"] = tohex(0x4c800021 + c1).."-X"
+ map_op[b1.."ctr_1"] = tohex(0x4c800420 + c1).."-X"
+ map_op[b1.."ctrl_1"] = tohex(0x4c800421 + c1).."-X"
+end
+
+------------------------------------------------------------------------------
+
+local function parse_gpr(expr)
+ local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$")
+ local tp = map_type[tname or expr]
+ if tp then
+ local reg = ovreg or tp.reg
+ if not reg then
+ werror("type `"..(tname or expr).."' needs a register override")
+ end
+ expr = reg
+ end
+ local r = match(expr, "^r([1-3]?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 31 then return r, tp end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_fpr(expr)
+ local r = match(expr, "^f([1-3]?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 31 then return r end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_vr(expr)
+ local r = match(expr, "^v([1-3]?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 31 then return r end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_vs(expr)
+ local r = match(expr, "^vs([1-6]?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 63 then return r end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_cr(expr)
+ local r = match(expr, "^cr([0-7])$")
+ if r then return tonumber(r) end
+ werror("bad condition register name `"..expr.."'")
+end
+
+local function parse_cond(expr)
+ local r, cond = match(expr, "^4%*cr([0-7])%+(%w%w)$")
+ if r then
+ r = tonumber(r)
+ local c = map_cond[cond]
+ if c and c < 4 then return r*4+c end
+ end
+ werror("bad condition bit name `"..expr.."'")
+end
+
+local parse_ctx = {}
+
+local loadenv = setfenv and function(s)
+ local code = loadstring(s, "")
+ if code then setfenv(code, parse_ctx) end
+ return code
+end or function(s)
+ return load(s, "", nil, parse_ctx)
+end
+
+-- Try to parse simple arithmetic, too, since some basic ops are aliases.
+local function parse_number(n)
+ local x = tonumber(n)
+ if x then return x end
+ local code = loadenv("return "..n)
+ if code then
+ local ok, y = pcall(code)
+ if ok then return y end
+ end
+ return nil
+end
+
+local function parse_imm(imm, bits, shift, scale, signed)
+ local n = parse_number(imm)
+ if n then
+ local m = sar(n, scale)
+ if shl(m, scale) == n then
+ if signed then
+ local s = sar(m, bits-1)
+ if s == 0 then return shl(m, shift)
+ elseif s == -1 then return shl(m + shl(1, bits), shift) end
+ else
+ if sar(m, bits) == 0 then return shl(m, shift) end
+ end
+ end
+ werror("out of range immediate `"..imm.."'")
+ elseif match(imm, "^[rfv]([1-3]?[0-9])$") or
+ match(imm, "^vs([1-6]?[0-9])$") or
+ match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then
+ werror("expected immediate operand, got register")
+ else
+ waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm)
+ return 0
+ end
+end
+
+local function parse_shiftmask(imm, isshift)
+ local n = parse_number(imm)
+ if n then
+ if shr(n, 6) == 0 then
+ local lsb = band(n, 31)
+ local msb = n - lsb
+ return isshift and (shl(lsb, 11)+shr(msb, 4)) or (shl(lsb, 6)+msb)
+ end
+ werror("out of range immediate `"..imm.."'")
+ elseif match(imm, "^r([1-3]?[0-9])$") or
+ match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then
+ werror("expected immediate operand, got register")
+ else
+ waction("IMMSH", isshift and 1 or 0, imm)
+ return 0;
+ end
+end
+
+local function parse_disp(disp)
+ local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$")
+ if imm then
+ local r = parse_gpr(reg)
+ if r == 0 then werror("cannot use r0 in displacement") end
+ return shl(r, 16) + parse_imm(imm, 16, 0, 0, true)
+ end
+ local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$")
+ if reg and tailr ~= "" then
+ local r, tp = parse_gpr(reg)
+ if r == 0 then werror("cannot use r0 in displacement") end
+ if tp then
+ waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr))
+ return shl(r, 16)
+ end
+ end
+ werror("bad displacement `"..disp.."'")
+end
+
+local function parse_u5disp(disp, scale)
+ local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$")
+ if imm then
+ local r = parse_gpr(reg)
+ if r == 0 then werror("cannot use r0 in displacement") end
+ return shl(r, 16) + parse_imm(imm, 5, 11, scale, false)
+ end
+ local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$")
+ if reg and tailr ~= "" then
+ local r, tp = parse_gpr(reg)
+ if r == 0 then werror("cannot use r0 in displacement") end
+ if tp then
+ waction("IMM", scale*1024+5*32+11, format(tp.ctypefmt, tailr))
+ return shl(r, 16)
+ end
+ end
+ werror("bad displacement `"..disp.."'")
+end
+
+local function parse_label(label, def)
+ local prefix = sub(label, 1, 2)
+ -- =>label (pc label reference)
+ if prefix == "=>" then
+ return "PC", 0, sub(label, 3)
+ end
+ -- ->name (global label reference)
+ if prefix == "->" then
+ return "LG", map_global[sub(label, 3)]
+ end
+ if def then
+ -- [1-9] (local label definition)
+ if match(label, "^[1-9]$") then
+ return "LG", 10+tonumber(label)
+ end
+ else
+ -- [<>][1-9] (local label reference)
+ local dir, lnum = match(label, "^([<>])([1-9])$")
+ if dir then -- Fwd: 1-9, Bkwd: 11-19.
+ return "LG", lnum + (dir == ">" and 0 or 10)
+ end
+ -- extern label (extern label reference)
+ local extname = match(label, "^extern%s+(%S+)$")
+ if extname then
+ return "EXT", map_extern[extname]
+ end
+ end
+ werror("bad label `"..label.."'")
+end
+
+------------------------------------------------------------------------------
+
+-- Handle opcodes defined with template strings.
+op_template = function(params, template, nparams)
+ if not params then return sub(template, 9) end
+ local op = tonumber(sub(template, 1, 8), 16)
+ local n, rs = 1, 26
+
+ -- Limit number of section buffer positions used by a single dasm_put().
+ -- A single opcode needs a maximum of 3 positions (rlwinm).
+ if secpos+3 > maxsecpos then wflush() end
+ local pos = wpos()
+
+ -- Process each character.
+ for p in gmatch(sub(template, 9), ".") do
+ if p == "R" then
+ rs = rs - 5; op = op + shl(parse_gpr(params[n]), rs); n = n + 1
+ elseif p == "F" then
+ rs = rs - 5; op = op + shl(parse_fpr(params[n]), rs); n = n + 1
+ elseif p == "V" then
+ rs = rs - 5; op = op + shl(parse_vr(params[n]), rs); n = n + 1
+ elseif p == "Q" then
+ local vs = parse_vs(params[n]); n = n + 1; rs = rs - 5
+ local sh = rs == 6 and 2 or 3 + band(shr(rs, 1), 3)
+ op = op + shl(band(vs, 31), rs) + shr(band(vs, 32), sh)
+ elseif p == "q" then
+ local vs = parse_vs(params[n]); n = n + 1
+ op = op + shl(band(vs, 31), 21) + shr(band(vs, 32), 5)
+ elseif p == "A" then
+ rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, false); n = n + 1
+ elseif p == "S" then
+ rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, true); n = n + 1
+ elseif p == "I" then
+ op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1
+ elseif p == "U" then
+ op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1
+ elseif p == "D" then
+ op = op + parse_disp(params[n]); n = n + 1
+ elseif p == "2" then
+ op = op + parse_u5disp(params[n], 1); n = n + 1
+ elseif p == "4" then
+ op = op + parse_u5disp(params[n], 2); n = n + 1
+ elseif p == "8" then
+ op = op + parse_u5disp(params[n], 3); n = n + 1
+ elseif p == "C" then
+ rs = rs - 5; op = op + shl(parse_cond(params[n]), rs); n = n + 1
+ elseif p == "X" then
+ rs = rs - 5; op = op + shl(parse_cr(params[n]), rs+2); n = n + 1
+ elseif p == "1" then
+ rs = rs - 5; op = op + parse_imm(params[n], 1, rs, 0, false); n = n + 1
+ elseif p == "g" then
+ rs = rs - 5; op = op + parse_imm(params[n], 2, rs, 0, false); n = n + 1
+ elseif p == "3" then
+ rs = rs - 5; op = op + parse_imm(params[n], 3, rs, 0, false); n = n + 1
+ elseif p == "P" then
+ rs = rs - 5; op = op + parse_imm(params[n], 4, rs, 0, false); n = n + 1
+ elseif p == "p" then
+ op = op + parse_imm(params[n], 4, rs, 0, false); n = n + 1
+ elseif p == "6" then
+ rs = rs - 6; op = op + parse_imm(params[n], 6, rs, 0, false); n = n + 1
+ elseif p == "Y" then
+ rs = rs - 5; op = op + parse_imm(params[n], 1, rs+4, 0, false); n = n + 1
+ elseif p == "y" then
+ rs = rs - 5; op = op + parse_imm(params[n], 1, rs+3, 0, false); n = n + 1
+ elseif p == "Z" then
+ rs = rs - 5; op = op + parse_imm(params[n], 2, rs+3, 0, false); n = n + 1
+ elseif p == "z" then
+ rs = rs - 5; op = op + parse_imm(params[n], 2, rs+2, 0, false); n = n + 1
+ elseif p == "W" then
+ op = op + parse_cr(params[n]); n = n + 1
+ elseif p == "G" then
+ op = op + parse_imm(params[n], 8, 12, 0, false); n = n + 1
+ elseif p == "H" then
+ op = op + parse_shiftmask(params[n], true); n = n + 1
+ elseif p == "M" then
+ op = op + parse_shiftmask(params[n], false); n = n + 1
+ elseif p == "J" or p == "K" then
+ local mode, n, s = parse_label(params[n], false)
+ if p == "K" then n = n + 2048 end
+ waction("REL_"..mode, n, s, 1)
+ n = n + 1
+ elseif p == "0" then
+ if band(shr(op, rs), 31) == 0 then werror("cannot use r0") end
+ elseif p == "=" or p == "%" then
+ local t = band(shr(op, p == "%" and rs+5 or rs), 31)
+ rs = rs - 5
+ op = op + shl(t, rs)
+ elseif p == "~" then
+ local mm = shl(31, rs)
+ local lo = band(op, mm)
+ local hi = band(op, shl(mm, 5))
+ op = op - lo - hi + shl(lo, 5) + shr(hi, 5)
+ elseif p == ":" then
+ if band(shr(op, rs), 1) ~= 0 then werror("register pair expected") end
+ elseif p == "-" then
+ rs = rs - 5
+ elseif p == "." then
+ -- Ignored.
+ else
+ assert(false)
+ end
+ end
+ wputpos(pos, op)
+end
+
+map_op[".template__"] = op_template
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode to mark the position where the action list is to be emitted.
+map_op[".actionlist_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeactions(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the global enum is to be emitted.
+map_op[".globals_1"] = function(params)
+ if not params then return "prefix" end
+ local prefix = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobals(out, prefix) end)
+end
+
+-- Pseudo-opcode to mark the position where the global names are to be emitted.
+map_op[".globalnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobalnames(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the extern names are to be emitted.
+map_op[".externnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeexternnames(out, name) end)
+end
+
+------------------------------------------------------------------------------
+
+-- Label pseudo-opcode (converted from trailing colon form).
+map_op[".label_1"] = function(params)
+ if not params then return "[1-9] | ->global | =>pcexpr" end
+ if secpos+1 > maxsecpos then wflush() end
+ local mode, n, s = parse_label(params[1], true)
+ if mode == "EXT" then werror("bad label definition") end
+ waction("LABEL_"..mode, n, s, 1)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcodes for data storage.
+map_op[".long_*"] = function(params)
+ if not params then return "imm..." end
+ for _,p in ipairs(params) do
+ local n = tonumber(p)
+ if not n then werror("bad immediate `"..p.."'") end
+ if n < 0 then n = n + 2^32 end
+ wputw(n)
+ if secpos+2 > maxsecpos then wflush() end
+ end
+end
+
+-- Alignment pseudo-opcode.
+map_op[".align_1"] = function(params)
+ if not params then return "numpow2" end
+ if secpos+1 > maxsecpos then wflush() end
+ local align = tonumber(params[1])
+ if align then
+ local x = align
+ -- Must be a power of 2 in the range (2 ... 256).
+ for i=1,8 do
+ x = x / 2
+ if x == 1 then
+ waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
+ return
+ end
+ end
+ end
+ werror("bad alignment")
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode for (primitive) type definitions (map to C types).
+map_op[".type_3"] = function(params, nparams)
+ if not params then
+ return nparams == 2 and "name, ctype" or "name, ctype, reg"
+ end
+ local name, ctype, reg = params[1], params[2], params[3]
+ if not match(name, "^[%a_][%w_]*$") then
+ werror("bad type name `"..name.."'")
+ end
+ local tp = map_type[name]
+ if tp then
+ werror("duplicate type `"..name.."'")
+ end
+ -- Add #type to defines. A bit unclean to put it in map_archdef.
+ map_archdef["#"..name] = "sizeof("..ctype..")"
+ -- Add new type and emit shortcut define.
+ local num = ctypenum + 1
+ map_type[name] = {
+ ctype = ctype,
+ ctypefmt = format("Dt%X(%%s)", num),
+ reg = reg,
+ }
+ wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
+ ctypenum = num
+end
+map_op[".type_2"] = map_op[".type_3"]
+
+-- Dump type definitions.
+local function dumptypes(out, lvl)
+ local t = {}
+ for name in pairs(map_type) do t[#t+1] = name end
+ sort(t)
+ out:write("Type definitions:\n")
+ for _,name in ipairs(t) do
+ local tp = map_type[name]
+ local reg = tp.reg or ""
+ out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
+ end
+ out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Set the current section.
+function _M.section(num)
+ waction("SECTION", num)
+ wflush(true) -- SECTION is a terminal action.
+end
+
+------------------------------------------------------------------------------
+
+-- Dump architecture description.
+function _M.dumparch(out)
+ out:write(format("DynASM %s version %s, released %s\n\n",
+ _info.arch, _info.version, _info.release))
+ dumpactions(out)
+end
+
+-- Dump all user defined elements.
+function _M.dumpdef(out, lvl)
+ dumptypes(out, lvl)
+ dumpglobals(out, lvl)
+ dumpexterns(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Pass callbacks from/to the DynASM core.
+function _M.passcb(wl, we, wf, ww)
+ wline, werror, wfatal, wwarn = wl, we, wf, ww
+ return wflush
+end
+
+-- Setup the arch-specific module.
+function _M.setup(arch, opt)
+ g_arch, g_opt = arch, opt
+end
+
+-- Merge the core maps and the arch-specific maps.
+function _M.mergemaps(map_coreop, map_def)
+ setmetatable(map_op, { __index = map_coreop })
+ setmetatable(map_def, { __index = map_archdef })
+ return map_op, map_def
+end
+
+return _M
+
+------------------------------------------------------------------------------
+
diff --git a/src/host/luajit-2.1.0-beta3/dynasm/dasm_proto.h b/src/host/luajit-2.1.0-beta3/dynasm/dasm_proto.h
new file mode 100644
index 00000000..59d9e2b2
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/dynasm/dasm_proto.h
@@ -0,0 +1,83 @@
+/*
+** DynASM encoding engine prototypes.
+** Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+** Released under the MIT license. See dynasm.lua for full copyright notice.
+*/
+
+#ifndef _DASM_PROTO_H
+#define _DASM_PROTO_H
+
+#include
+#include
+
+#define DASM_IDENT "DynASM 1.4.0"
+#define DASM_VERSION 10400 /* 1.4.0 */
+
+#ifndef Dst_DECL
+#define Dst_DECL dasm_State **Dst
+#endif
+
+#ifndef Dst_REF
+#define Dst_REF (*Dst)
+#endif
+
+#ifndef DASM_FDEF
+#define DASM_FDEF extern
+#endif
+
+#ifndef DASM_M_GROW
+#define DASM_M_GROW(ctx, t, p, sz, need) \
+ do { \
+ size_t _sz = (sz), _need = (need); \
+ if (_sz < _need) { \
+ if (_sz < 16) _sz = 16; \
+ while (_sz < _need) _sz += _sz; \
+ (p) = (t *)realloc((p), _sz); \
+ if ((p) == NULL) exit(1); \
+ (sz) = _sz; \
+ } \
+ } while(0)
+#endif
+
+#ifndef DASM_M_FREE
+#define DASM_M_FREE(ctx, p, sz) free(p)
+#endif
+
+/* Internal DynASM encoder state. */
+typedef struct dasm_State dasm_State;
+
+
+/* Initialize and free DynASM state. */
+DASM_FDEF void dasm_init(Dst_DECL, int maxsection);
+DASM_FDEF void dasm_free(Dst_DECL);
+
+/* Setup global array. Must be called before dasm_setup(). */
+DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl);
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc);
+
+/* Setup encoder. */
+DASM_FDEF void dasm_setup(Dst_DECL, const void *actionlist);
+
+/* Feed encoder with actions. Calls are generated by pre-processor. */
+DASM_FDEF void dasm_put(Dst_DECL, int start, ...);
+
+/* Link sections and return the resulting size. */
+DASM_FDEF int dasm_link(Dst_DECL, size_t *szp);
+
+/* Encode sections into buffer. */
+DASM_FDEF int dasm_encode(Dst_DECL, void *buffer);
+
+/* Get PC label offset. */
+DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc);
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch);
+#else
+#define dasm_checkstep(a, b) 0
+#endif
+
+
+#endif /* _DASM_PROTO_H */
diff --git a/src/host/luajit-2.1.0-beta3/dynasm/dasm_x64.lua b/src/host/luajit-2.1.0-beta3/dynasm/dasm_x64.lua
new file mode 100644
index 00000000..e8bdeb37
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/dynasm/dasm_x64.lua
@@ -0,0 +1,12 @@
+------------------------------------------------------------------------------
+-- DynASM x64 module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+-- This module just sets 64 bit mode for the combined x86/x64 module.
+-- All the interesting stuff is there.
+------------------------------------------------------------------------------
+
+x64 = true -- Using a global is an ugly, but effective solution.
+return require("dasm_x86")
diff --git a/src/host/luajit-2.1.0-beta3/dynasm/dasm_x86.h b/src/host/luajit-2.1.0-beta3/dynasm/dasm_x86.h
new file mode 100644
index 00000000..bc636357
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/dynasm/dasm_x86.h
@@ -0,0 +1,498 @@
+/*
+** DynASM x86 encoding engine.
+** Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+** Released under the MIT license. See dynasm.lua for full copyright notice.
+*/
+
+#include
+#include
+#include
+#include
+
+#define DASM_ARCH "x86"
+
+#ifndef DASM_EXTERN
+#define DASM_EXTERN(a,b,c,d) 0
+#endif
+
+/* Action definitions. DASM_STOP must be 255. */
+enum {
+ DASM_DISP = 233,
+ DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB,
+ DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC,
+ DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN,
+ DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP
+};
+
+/* Maximum number of section buffer positions for a single dasm_put() call. */
+#define DASM_MAXSECPOS 25
+
+/* DynASM encoder status codes. Action list offset or number are or'ed in. */
+#define DASM_S_OK 0x00000000
+#define DASM_S_NOMEM 0x01000000
+#define DASM_S_PHASE 0x02000000
+#define DASM_S_MATCH_SEC 0x03000000
+#define DASM_S_RANGE_I 0x11000000
+#define DASM_S_RANGE_SEC 0x12000000
+#define DASM_S_RANGE_LG 0x13000000
+#define DASM_S_RANGE_PC 0x14000000
+#define DASM_S_RANGE_VREG 0x15000000
+#define DASM_S_UNDEF_L 0x21000000
+#define DASM_S_UNDEF_PC 0x22000000
+
+/* Macros to convert positions (8 bit section + 24 bit index). */
+#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
+#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
+#define DASM_SEC2POS(sec) ((sec)<<24)
+#define DASM_POS2SEC(pos) ((pos)>>24)
+#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
+
+/* Action list type. */
+typedef const unsigned char *dasm_ActList;
+
+/* Per-section structure. */
+typedef struct dasm_Section {
+ int *rbuf; /* Biased buffer pointer (negative section bias). */
+ int *buf; /* True buffer pointer. */
+ size_t bsize; /* Buffer size in bytes. */
+ int pos; /* Biased buffer position. */
+ int epos; /* End of biased buffer position - max single put. */
+ int ofs; /* Byte offset into section. */
+} dasm_Section;
+
+/* Core structure holding the DynASM encoding state. */
+struct dasm_State {
+ size_t psize; /* Allocated size of this structure. */
+ dasm_ActList actionlist; /* Current actionlist pointer. */
+ int *lglabels; /* Local/global chain/pos ptrs. */
+ size_t lgsize;
+ int *pclabels; /* PC label chains/pos ptrs. */
+ size_t pcsize;
+ void **globals; /* Array of globals (bias -10). */
+ dasm_Section *section; /* Pointer to active section. */
+ size_t codesize; /* Total size of all code sections. */
+ int maxsection; /* 0 <= sectionidx < maxsection. */
+ int status; /* Status code. */
+ dasm_Section sections[1]; /* All sections. Alloc-extended. */
+};
+
+/* The size of the core structure depends on the max. number of sections. */
+#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
+
+
+/* Initialize DynASM state. */
+void dasm_init(Dst_DECL, int maxsection)
+{
+ dasm_State *D;
+ size_t psz = 0;
+ int i;
+ Dst_REF = NULL;
+ DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
+ D = Dst_REF;
+ D->psize = psz;
+ D->lglabels = NULL;
+ D->lgsize = 0;
+ D->pclabels = NULL;
+ D->pcsize = 0;
+ D->globals = NULL;
+ D->maxsection = maxsection;
+ for (i = 0; i < maxsection; i++) {
+ D->sections[i].buf = NULL; /* Need this for pass3. */
+ D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
+ D->sections[i].bsize = 0;
+ D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
+ }
+}
+
+/* Free DynASM state. */
+void dasm_free(Dst_DECL)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ for (i = 0; i < D->maxsection; i++)
+ if (D->sections[i].buf)
+ DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
+ if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
+ if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
+ DASM_M_FREE(Dst, D, D->psize);
+}
+
+/* Setup global label array. Must be called before dasm_setup(). */
+void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
+{
+ dasm_State *D = Dst_REF;
+ D->globals = gl - 10; /* Negative bias to compensate for locals. */
+ DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
+}
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+void dasm_growpc(Dst_DECL, unsigned int maxpc)
+{
+ dasm_State *D = Dst_REF;
+ size_t osz = D->pcsize;
+ DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
+ memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
+}
+
+/* Setup encoder. */
+void dasm_setup(Dst_DECL, const void *actionlist)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ D->actionlist = (dasm_ActList)actionlist;
+ D->status = DASM_S_OK;
+ D->section = &D->sections[0];
+ memset((void *)D->lglabels, 0, D->lgsize);
+ if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
+ for (i = 0; i < D->maxsection; i++) {
+ D->sections[i].pos = DASM_SEC2POS(i);
+ D->sections[i].ofs = 0;
+ }
+}
+
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) { \
+ D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0)
+#define CKPL(kind, st) \
+ do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
+ D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0)
+#else
+#define CK(x, st) ((void)0)
+#define CKPL(kind, st) ((void)0)
+#endif
+
+/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
+void dasm_put(Dst_DECL, int start, ...)
+{
+ va_list ap;
+ dasm_State *D = Dst_REF;
+ dasm_ActList p = D->actionlist + start;
+ dasm_Section *sec = D->section;
+ int pos = sec->pos, ofs = sec->ofs, mrm = -1;
+ int *b;
+
+ if (pos >= sec->epos) {
+ DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
+ sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
+ sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
+ sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
+ }
+
+ b = sec->rbuf;
+ b[pos++] = start;
+
+ va_start(ap, start);
+ while (1) {
+ int action = *p++;
+ if (action < DASM_DISP) {
+ ofs++;
+ } else if (action <= DASM_REL_A) {
+ int n = va_arg(ap, int);
+ b[pos++] = n;
+ switch (action) {
+ case DASM_DISP:
+ if (n == 0) { if (mrm < 0) mrm = p[-2]; if ((mrm&7) != 5) break; }
+ case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob;
+ case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */
+ case DASM_IMM_D: ofs += 4; break;
+ case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob;
+ case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break;
+ case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob;
+ case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break;
+ case DASM_SPACE: p++; ofs += n; break;
+ case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */
+ case DASM_VREG: CK((n&-16) == 0 && (n != 4 || (*p>>5) != 2), RANGE_VREG);
+ if (*p < 0x40 && p[1] == DASM_DISP) mrm = n;
+ if (*p < 0x20 && (n&7) == 4) ofs++;
+ switch ((*p++ >> 3) & 3) {
+ case 3: n |= b[pos-3];
+ case 2: n |= b[pos-2];
+ case 1: if (n <= 7) { b[pos-1] |= 0x10; ofs--; }
+ }
+ continue;
+ }
+ mrm = -1;
+ } else {
+ int *pl, n;
+ switch (action) {
+ case DASM_REL_LG:
+ case DASM_IMM_LG:
+ n = *p++; pl = D->lglabels + n;
+ /* Bkwd rel or global. */
+ if (n <= 246) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
+ pl -= 246; n = *pl;
+ if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
+ goto linkrel;
+ case DASM_REL_PC:
+ case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
+ putrel:
+ n = *pl;
+ if (n < 0) { /* Label exists. Get label pos and store it. */
+ b[pos] = -n;
+ } else {
+ linkrel:
+ b[pos] = n; /* Else link to rel chain, anchored at label. */
+ *pl = pos;
+ }
+ pos++;
+ ofs += 4; /* Maximum offset needed. */
+ if (action == DASM_REL_LG || action == DASM_REL_PC)
+ b[pos++] = ofs; /* Store pass1 offset estimate. */
+ break;
+ case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel;
+ case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
+ putlabel:
+ n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; }
+ *pl = -pos; /* Label exists now. */
+ b[pos++] = ofs; /* Store pass1 offset estimate. */
+ break;
+ case DASM_ALIGN:
+ ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */
+ b[pos++] = ofs; /* Store pass1 offset estimate. */
+ break;
+ case DASM_EXTERN: p += 2; ofs += 4; break;
+ case DASM_ESC: p++; ofs++; break;
+ case DASM_MARK: mrm = p[-2]; break;
+ case DASM_SECTION:
+ n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n];
+ case DASM_STOP: goto stop;
+ }
+ }
+ }
+stop:
+ va_end(ap);
+ sec->pos = pos;
+ sec->ofs = ofs;
+}
+#undef CK
+
+/* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */
+int dasm_link(Dst_DECL, size_t *szp)
+{
+ dasm_State *D = Dst_REF;
+ int secnum;
+ int ofs = 0;
+
+#ifdef DASM_CHECKS
+ *szp = 0;
+ if (D->status != DASM_S_OK) return D->status;
+ {
+ int pc;
+ for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
+ if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
+ }
+#endif
+
+ { /* Handle globals not defined in this translation unit. */
+ int idx;
+ for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
+ int n = D->lglabels[idx];
+ /* Undefined label: Collapse rel chain and replace with marker (< 0). */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
+ }
+ }
+
+ /* Combine all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->rbuf;
+ int pos = DASM_SEC2POS(secnum);
+ int lastpos = sec->pos;
+
+ while (pos != lastpos) {
+ dasm_ActList p = D->actionlist + b[pos++];
+ while (1) {
+ int op, action = *p++;
+ switch (action) {
+ case DASM_REL_LG: p++; op = p[-3]; goto rel_pc;
+ case DASM_REL_PC: op = p[-2]; rel_pc: {
+ int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0);
+ if (shrink) { /* Shrinkable branch opcode? */
+ int lofs, lpos = b[pos];
+ if (lpos < 0) goto noshrink; /* Ext global? */
+ lofs = *DASM_POS2PTR(D, lpos);
+ if (lpos > pos) { /* Fwd label: add cumulative section offsets. */
+ int i;
+ for (i = secnum; i < DASM_POS2SEC(lpos); i++)
+ lofs += D->sections[i].ofs;
+ } else {
+ lofs -= ofs; /* Bkwd label: unfix offset. */
+ }
+ lofs -= b[pos+1]; /* Short branch ok? */
+ if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */
+ else { noshrink: shrink = 0; } /* No, cannot shrink op. */
+ }
+ b[pos+1] = shrink;
+ pos += 2;
+ break;
+ }
+ case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++;
+ case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W:
+ case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB:
+ case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break;
+ case DASM_LABEL_LG: p++;
+ case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */
+ case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */
+ case DASM_EXTERN: p += 2; break;
+ case DASM_ESC: p++; break;
+ case DASM_MARK: break;
+ case DASM_SECTION: case DASM_STOP: goto stop;
+ }
+ }
+ stop: (void)0;
+ }
+ ofs += sec->ofs; /* Next section starts right after current section. */
+ }
+
+ D->codesize = ofs; /* Total size of all code sections */
+ *szp = ofs;
+ return DASM_S_OK;
+}
+
+#define dasmb(x) *cp++ = (unsigned char)(x)
+#ifndef DASM_ALIGNED_WRITES
+#define dasmw(x) \
+ do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0)
+#define dasmd(x) \
+ do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0)
+#else
+#define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0)
+#define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0)
+#endif
+
+/* Pass 3: Encode sections. */
+int dasm_encode(Dst_DECL, void *buffer)
+{
+ dasm_State *D = Dst_REF;
+ unsigned char *base = (unsigned char *)buffer;
+ unsigned char *cp = base;
+ int secnum;
+
+ /* Encode all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->buf;
+ int *endb = sec->rbuf + sec->pos;
+
+ while (b != endb) {
+ dasm_ActList p = D->actionlist + *b++;
+ unsigned char *mark = NULL;
+ while (1) {
+ int action = *p++;
+ int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0;
+ switch (action) {
+ case DASM_DISP: if (!mark) mark = cp; {
+ unsigned char *mm = mark;
+ if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL;
+ if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7;
+ if (mrm != 5) { mm[-1] -= 0x80; break; } }
+ if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40;
+ }
+ case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break;
+ case DASM_IMM_DB: if (((n+128)&-256) == 0) {
+ db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb;
+ } else mark = NULL;
+ case DASM_IMM_D: wd: dasmd(n); break;
+ case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL;
+ case DASM_IMM_W: dasmw(n); break;
+ case DASM_VREG: {
+ int t = *p++;
+ unsigned char *ex = cp - (t&7);
+ if ((n & 8) && t < 0xa0) {
+ if (*ex & 0x80) ex[1] ^= 0x20 << (t>>6); else *ex ^= 1 << (t>>6);
+ n &= 7;
+ } else if (n & 0x10) {
+ if (*ex & 0x80) {
+ *ex = 0xc5; ex[1] = (ex[1] & 0x80) | ex[2]; ex += 2;
+ }
+ while (++ex < cp) ex[-1] = *ex;
+ if (mark) mark--;
+ cp--;
+ n &= 7;
+ }
+ if (t >= 0xc0) n <<= 4;
+ else if (t >= 0x40) n <<= 3;
+ else if (n == 4 && t < 0x20) { cp[-1] ^= n; *cp++ = 0x20; }
+ cp[-1] ^= n;
+ break;
+ }
+ case DASM_REL_LG: p++; if (n >= 0) goto rel_pc;
+ b++; n = (int)(ptrdiff_t)D->globals[-n];
+ case DASM_REL_A: rel_a: n -= (int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */
+ case DASM_REL_PC: rel_pc: {
+ int shrink = *b++;
+ int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; }
+ n = *pb - ((int)(cp-base) + 4-shrink);
+ if (shrink == 0) goto wd;
+ if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb;
+ goto wb;
+ }
+ case DASM_IMM_LG:
+ p++; if (n < 0) { n = (int)(ptrdiff_t)D->globals[-n]; goto wd; }
+ case DASM_IMM_PC: {
+ int *pb = DASM_POS2PTR(D, n);
+ n = *pb < 0 ? pb[1] : (*pb + (int)(ptrdiff_t)base);
+ goto wd;
+ }
+ case DASM_LABEL_LG: {
+ int idx = *p++;
+ if (idx >= 10)
+ D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n));
+ break;
+ }
+ case DASM_LABEL_PC: case DASM_SETLABEL: break;
+ case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; }
+ case DASM_ALIGN:
+ n = *p++;
+ while (((cp-base) & n)) *cp++ = 0x90; /* nop */
+ break;
+ case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd;
+ case DASM_MARK: mark = cp; break;
+ case DASM_ESC: action = *p++;
+ default: *cp++ = action; break;
+ case DASM_SECTION: case DASM_STOP: goto stop;
+ }
+ }
+ stop: (void)0;
+ }
+ }
+
+ if (base + D->codesize != cp) /* Check for phase errors. */
+ return DASM_S_PHASE;
+ return DASM_S_OK;
+}
+
+/* Get PC label offset. */
+int dasm_getpclabel(Dst_DECL, unsigned int pc)
+{
+ dasm_State *D = Dst_REF;
+ if (pc*sizeof(int) < D->pcsize) {
+ int pos = D->pclabels[pc];
+ if (pos < 0) return *DASM_POS2PTR(D, -pos);
+ if (pos > 0) return -1; /* Undefined. */
+ }
+ return -2; /* Unused or out of range. */
+}
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+int dasm_checkstep(Dst_DECL, int secmatch)
+{
+ dasm_State *D = Dst_REF;
+ if (D->status == DASM_S_OK) {
+ int i;
+ for (i = 1; i <= 9; i++) {
+ if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; }
+ D->lglabels[i] = 0;
+ }
+ }
+ if (D->status == DASM_S_OK && secmatch >= 0 &&
+ D->section != &D->sections[secmatch])
+ D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections);
+ return D->status;
+}
+#endif
+
diff --git a/src/host/luajit-2.1.0-beta3/dynasm/dasm_x86.lua b/src/host/luajit-2.1.0-beta3/dynasm/dasm_x86.lua
new file mode 100644
index 00000000..4c031e2c
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/dynasm/dasm_x86.lua
@@ -0,0 +1,2274 @@
+------------------------------------------------------------------------------
+-- DynASM x86/x64 module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+
+local x64 = x64
+
+-- Module information:
+local _info = {
+ arch = x64 and "x64" or "x86",
+ description = "DynASM x86/x64 module",
+ version = "1.4.0",
+ vernum = 10400,
+ release = "2015-10-18",
+ author = "Mike Pall",
+ license = "MIT",
+}
+
+-- Exported glue functions for the arch-specific module.
+local _M = { _info = _info }
+
+-- Cache library functions.
+local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
+local assert, unpack, setmetatable = assert, unpack or table.unpack, setmetatable
+local _s = string
+local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
+local find, match, gmatch, gsub = _s.find, _s.match, _s.gmatch, _s.gsub
+local concat, sort, remove = table.concat, table.sort, table.remove
+local bit = bit or require("bit")
+local band, bxor, shl, shr = bit.band, bit.bxor, bit.lshift, bit.rshift
+
+-- Inherited tables and callbacks.
+local g_opt, g_arch
+local wline, werror, wfatal, wwarn
+
+-- Action name list.
+-- CHECK: Keep this in sync with the C code!
+local action_names = {
+ -- int arg, 1 buffer pos:
+ "DISP", "IMM_S", "IMM_B", "IMM_W", "IMM_D", "IMM_WB", "IMM_DB",
+ -- action arg (1 byte), int arg, 1 buffer pos (reg/num):
+ "VREG", "SPACE",
+ -- ptrdiff_t arg, 1 buffer pos (address): !x64
+ "SETLABEL", "REL_A",
+ -- action arg (1 byte) or int arg, 2 buffer pos (link, offset):
+ "REL_LG", "REL_PC",
+ -- action arg (1 byte) or int arg, 1 buffer pos (link):
+ "IMM_LG", "IMM_PC",
+ -- action arg (1 byte) or int arg, 1 buffer pos (offset):
+ "LABEL_LG", "LABEL_PC",
+ -- action arg (1 byte), 1 buffer pos (offset):
+ "ALIGN",
+ -- action args (2 bytes), no buffer pos.
+ "EXTERN",
+ -- action arg (1 byte), no buffer pos.
+ "ESC",
+ -- no action arg, no buffer pos.
+ "MARK",
+ -- action arg (1 byte), no buffer pos, terminal action:
+ "SECTION",
+ -- no args, no buffer pos, terminal action:
+ "STOP"
+}
+
+-- Maximum number of section buffer positions for dasm_put().
+-- CHECK: Keep this in sync with the C code!
+local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
+
+-- Action name -> action number (dynamically generated below).
+local map_action = {}
+-- First action number. Everything below does not need to be escaped.
+local actfirst = 256-#action_names
+
+-- Action list buffer and string (only used to remove dupes).
+local actlist = {}
+local actstr = ""
+
+-- Argument list for next dasm_put(). Start with offset 0 into action list.
+local actargs = { 0 }
+
+-- Current number of section buffer positions for dasm_put().
+local secpos = 1
+
+-- VREG kind encodings, pre-shifted by 5 bits.
+local map_vreg = {
+ ["modrm.rm.m"] = 0x00,
+ ["modrm.rm.r"] = 0x20,
+ ["opcode"] = 0x20,
+ ["sib.base"] = 0x20,
+ ["sib.index"] = 0x40,
+ ["modrm.reg"] = 0x80,
+ ["vex.v"] = 0xa0,
+ ["imm.hi"] = 0xc0,
+}
+
+-- Current number of VREG actions contributing to REX/VEX shrinkage.
+local vreg_shrink_count = 0
+
+------------------------------------------------------------------------------
+
+-- Compute action numbers for action names.
+for n,name in ipairs(action_names) do
+ local num = actfirst + n - 1
+ map_action[name] = num
+end
+
+-- Dump action names and numbers.
+local function dumpactions(out)
+ out:write("DynASM encoding engine action codes:\n")
+ for n,name in ipairs(action_names) do
+ local num = map_action[name]
+ out:write(format(" %-10s %02X %d\n", name, num, num))
+ end
+ out:write("\n")
+end
+
+-- Write action list buffer as a huge static C array.
+local function writeactions(out, name)
+ local nn = #actlist
+ local last = actlist[nn] or 255
+ actlist[nn] = nil -- Remove last byte.
+ if nn == 0 then nn = 1 end
+ out:write("static const unsigned char ", name, "[", nn, "] = {\n")
+ local s = " "
+ for n,b in ipairs(actlist) do
+ s = s..b..","
+ if #s >= 75 then
+ assert(out:write(s, "\n"))
+ s = " "
+ end
+ end
+ out:write(s, last, "\n};\n\n") -- Add last byte back.
+end
+
+------------------------------------------------------------------------------
+
+-- Add byte to action list.
+local function wputxb(n)
+ assert(n >= 0 and n <= 255 and n % 1 == 0, "byte out of range")
+ actlist[#actlist+1] = n
+end
+
+-- Add action to list with optional arg. Advance buffer pos, too.
+local function waction(action, a, num)
+ wputxb(assert(map_action[action], "bad action name `"..action.."'"))
+ if a then actargs[#actargs+1] = a end
+ if a or num then secpos = secpos + (num or 1) end
+end
+
+-- Optionally add a VREG action.
+local function wvreg(kind, vreg, psz, sk, defer)
+ if not vreg then return end
+ waction("VREG", vreg)
+ local b = assert(map_vreg[kind], "bad vreg kind `"..vreg.."'")
+ if b < (sk or 0) then
+ vreg_shrink_count = vreg_shrink_count + 1
+ end
+ if not defer then
+ b = b + vreg_shrink_count * 8
+ vreg_shrink_count = 0
+ end
+ wputxb(b + (psz or 0))
+end
+
+-- Add call to embedded DynASM C code.
+local function wcall(func, args)
+ wline(format("dasm_%s(Dst, %s);", func, concat(args, ", ")), true)
+end
+
+-- Delete duplicate action list chunks. A tad slow, but so what.
+local function dedupechunk(offset)
+ local al, as = actlist, actstr
+ local chunk = char(unpack(al, offset+1, #al))
+ local orig = find(as, chunk, 1, true)
+ if orig then
+ actargs[1] = orig-1 -- Replace with original offset.
+ for i=offset+1,#al do al[i] = nil end -- Kill dupe.
+ else
+ actstr = as..chunk
+ end
+end
+
+-- Flush action list (intervening C code or buffer pos overflow).
+local function wflush(term)
+ local offset = actargs[1]
+ if #actlist == offset then return end -- Nothing to flush.
+ if not term then waction("STOP") end -- Terminate action list.
+ dedupechunk(offset)
+ wcall("put", actargs) -- Add call to dasm_put().
+ actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
+ secpos = 1 -- The actionlist offset occupies a buffer position, too.
+end
+
+-- Put escaped byte.
+local function wputb(n)
+ if n >= actfirst then waction("ESC") end -- Need to escape byte.
+ wputxb(n)
+end
+
+------------------------------------------------------------------------------
+
+-- Global label name -> global label number. With auto assignment on 1st use.
+local next_global = 10
+local map_global = setmetatable({}, { __index = function(t, name)
+ if not match(name, "^[%a_][%w_@]*$") then werror("bad global label") end
+ local n = next_global
+ if n > 246 then werror("too many global labels") end
+ next_global = n + 1
+ t[name] = n
+ return n
+end})
+
+-- Dump global labels.
+local function dumpglobals(out, lvl)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("Global labels:\n")
+ for i=10,next_global-1 do
+ out:write(format(" %s\n", t[i]))
+ end
+ out:write("\n")
+end
+
+-- Write global label enum.
+local function writeglobals(out, prefix)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("enum {\n")
+ for i=10,next_global-1 do
+ out:write(" ", prefix, gsub(t[i], "@.*", ""), ",\n")
+ end
+ out:write(" ", prefix, "_MAX\n};\n")
+end
+
+-- Write global label names.
+local function writeglobalnames(out, name)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=10,next_global-1 do
+ out:write(" \"", t[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Extern label name -> extern label number. With auto assignment on 1st use.
+local next_extern = -1
+local map_extern = setmetatable({}, { __index = function(t, name)
+ -- No restrictions on the name for now.
+ local n = next_extern
+ if n < -256 then werror("too many extern labels") end
+ next_extern = n - 1
+ t[name] = n
+ return n
+end})
+
+-- Dump extern labels.
+local function dumpexterns(out, lvl)
+ local t = {}
+ for name, n in pairs(map_extern) do t[-n] = name end
+ out:write("Extern labels:\n")
+ for i=1,-next_extern-1 do
+ out:write(format(" %s\n", t[i]))
+ end
+ out:write("\n")
+end
+
+-- Write extern label names.
+local function writeexternnames(out, name)
+ local t = {}
+ for name, n in pairs(map_extern) do t[-n] = name end
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=1,-next_extern-1 do
+ out:write(" \"", t[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Arch-specific maps.
+local map_archdef = {} -- Ext. register name -> int. name.
+local map_reg_rev = {} -- Int. register name -> ext. name.
+local map_reg_num = {} -- Int. register name -> register number.
+local map_reg_opsize = {} -- Int. register name -> operand size.
+local map_reg_valid_base = {} -- Int. register name -> valid base register?
+local map_reg_valid_index = {} -- Int. register name -> valid index register?
+local map_reg_needrex = {} -- Int. register name -> need rex vs. no rex.
+local reg_list = {} -- Canonical list of int. register names.
+
+local map_type = {} -- Type name -> { ctype, reg }
+local ctypenum = 0 -- Type number (for _PTx macros).
+
+local addrsize = x64 and "q" or "d" -- Size for address operands.
+
+-- Helper functions to fill register maps.
+local function mkrmap(sz, cl, names)
+ local cname = format("@%s", sz)
+ reg_list[#reg_list+1] = cname
+ map_archdef[cl] = cname
+ map_reg_rev[cname] = cl
+ map_reg_num[cname] = -1
+ map_reg_opsize[cname] = sz
+ if sz == addrsize or sz == "d" then
+ map_reg_valid_base[cname] = true
+ map_reg_valid_index[cname] = true
+ end
+ if names then
+ for n,name in ipairs(names) do
+ local iname = format("@%s%x", sz, n-1)
+ reg_list[#reg_list+1] = iname
+ map_archdef[name] = iname
+ map_reg_rev[iname] = name
+ map_reg_num[iname] = n-1
+ map_reg_opsize[iname] = sz
+ if sz == "b" and n > 4 then map_reg_needrex[iname] = false end
+ if sz == addrsize or sz == "d" then
+ map_reg_valid_base[iname] = true
+ map_reg_valid_index[iname] = true
+ end
+ end
+ end
+ for i=0,(x64 and sz ~= "f") and 15 or 7 do
+ local needrex = sz == "b" and i > 3
+ local iname = format("@%s%x%s", sz, i, needrex and "R" or "")
+ if needrex then map_reg_needrex[iname] = true end
+ local name
+ if sz == "o" or sz == "y" then name = format("%s%d", cl, i)
+ elseif sz == "f" then name = format("st%d", i)
+ else name = format("r%d%s", i, sz == addrsize and "" or sz) end
+ map_archdef[name] = iname
+ if not map_reg_rev[iname] then
+ reg_list[#reg_list+1] = iname
+ map_reg_rev[iname] = name
+ map_reg_num[iname] = i
+ map_reg_opsize[iname] = sz
+ if sz == addrsize or sz == "d" then
+ map_reg_valid_base[iname] = true
+ map_reg_valid_index[iname] = true
+ end
+ end
+ end
+ reg_list[#reg_list+1] = ""
+end
+
+-- Integer registers (qword, dword, word and byte sized).
+if x64 then
+ mkrmap("q", "Rq", {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"})
+end
+mkrmap("d", "Rd", {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"})
+mkrmap("w", "Rw", {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"})
+mkrmap("b", "Rb", {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"})
+map_reg_valid_index[map_archdef.esp] = false
+if x64 then map_reg_valid_index[map_archdef.rsp] = false end
+if x64 then map_reg_needrex[map_archdef.Rb] = true end
+map_archdef["Ra"] = "@"..addrsize
+
+-- FP registers (internally tword sized, but use "f" as operand size).
+mkrmap("f", "Rf")
+
+-- SSE registers (oword sized, but qword and dword accessible).
+mkrmap("o", "xmm")
+
+-- AVX registers (yword sized, but oword, qword and dword accessible).
+mkrmap("y", "ymm")
+
+-- Operand size prefixes to codes.
+local map_opsize = {
+ byte = "b", word = "w", dword = "d", qword = "q", oword = "o", yword = "y",
+ tword = "t", aword = addrsize,
+}
+
+-- Operand size code to number.
+local map_opsizenum = {
+ b = 1, w = 2, d = 4, q = 8, o = 16, y = 32, t = 10,
+}
+
+-- Operand size code to name.
+local map_opsizename = {
+ b = "byte", w = "word", d = "dword", q = "qword", o = "oword", y = "yword",
+ t = "tword", f = "fpword",
+}
+
+-- Valid index register scale factors.
+local map_xsc = {
+ ["1"] = 0, ["2"] = 1, ["4"] = 2, ["8"] = 3,
+}
+
+-- Condition codes.
+local map_cc = {
+ o = 0, no = 1, b = 2, nb = 3, e = 4, ne = 5, be = 6, nbe = 7,
+ s = 8, ns = 9, p = 10, np = 11, l = 12, nl = 13, le = 14, nle = 15,
+ c = 2, nae = 2, nc = 3, ae = 3, z = 4, nz = 5, na = 6, a = 7,
+ pe = 10, po = 11, nge = 12, ge = 13, ng = 14, g = 15,
+}
+
+
+-- Reverse defines for registers.
+function _M.revdef(s)
+ return gsub(s, "@%w+", map_reg_rev)
+end
+
+-- Dump register names and numbers
+local function dumpregs(out)
+ out:write("Register names, sizes and internal numbers:\n")
+ for _,reg in ipairs(reg_list) do
+ if reg == "" then
+ out:write("\n")
+ else
+ local name = map_reg_rev[reg]
+ local num = map_reg_num[reg]
+ local opsize = map_opsizename[map_reg_opsize[reg]]
+ out:write(format(" %-5s %-8s %s\n", name, opsize,
+ num < 0 and "(variable)" or num))
+ end
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Put action for label arg (IMM_LG, IMM_PC, REL_LG, REL_PC).
+local function wputlabel(aprefix, imm, num)
+ if type(imm) == "number" then
+ if imm < 0 then
+ waction("EXTERN")
+ wputxb(aprefix == "IMM_" and 0 or 1)
+ imm = -imm-1
+ else
+ waction(aprefix.."LG", nil, num);
+ end
+ wputxb(imm)
+ else
+ waction(aprefix.."PC", imm, num)
+ end
+end
+
+-- Put signed byte or arg.
+local function wputsbarg(n)
+ if type(n) == "number" then
+ if n < -128 or n > 127 then
+ werror("signed immediate byte out of range")
+ end
+ if n < 0 then n = n + 256 end
+ wputb(n)
+ else waction("IMM_S", n) end
+end
+
+-- Put unsigned byte or arg.
+local function wputbarg(n)
+ if type(n) == "number" then
+ if n < 0 or n > 255 then
+ werror("unsigned immediate byte out of range")
+ end
+ wputb(n)
+ else waction("IMM_B", n) end
+end
+
+-- Put unsigned word or arg.
+local function wputwarg(n)
+ if type(n) == "number" then
+ if shr(n, 16) ~= 0 then
+ werror("unsigned immediate word out of range")
+ end
+ wputb(band(n, 255)); wputb(shr(n, 8));
+ else waction("IMM_W", n) end
+end
+
+-- Put signed or unsigned dword or arg.
+local function wputdarg(n)
+ local tn = type(n)
+ if tn == "number" then
+ wputb(band(n, 255))
+ wputb(band(shr(n, 8), 255))
+ wputb(band(shr(n, 16), 255))
+ wputb(shr(n, 24))
+ elseif tn == "table" then
+ wputlabel("IMM_", n[1], 1)
+ else
+ waction("IMM_D", n)
+ end
+end
+
+-- Put operand-size dependent number or arg (defaults to dword).
+local function wputszarg(sz, n)
+ if not sz or sz == "d" or sz == "q" then wputdarg(n)
+ elseif sz == "w" then wputwarg(n)
+ elseif sz == "b" then wputbarg(n)
+ elseif sz == "s" then wputsbarg(n)
+ else werror("bad operand size") end
+end
+
+-- Put multi-byte opcode with operand-size dependent modifications.
+local function wputop(sz, op, rex, vex, vregr, vregxb)
+ local psz, sk = 0, nil
+ if vex then
+ local tail
+ if vex.m == 1 and band(rex, 11) == 0 then
+ if x64 and vregxb then
+ sk = map_vreg["modrm.reg"]
+ else
+ wputb(0xc5)
+ tail = shl(bxor(band(rex, 4), 4), 5)
+ psz = 3
+ end
+ end
+ if not tail then
+ wputb(0xc4)
+ wputb(shl(bxor(band(rex, 7), 7), 5) + vex.m)
+ tail = shl(band(rex, 8), 4)
+ psz = 4
+ end
+ local reg, vreg = 0, nil
+ if vex.v then
+ reg = vex.v.reg
+ if not reg then werror("bad vex operand") end
+ if reg < 0 then reg = 0; vreg = vex.v.vreg end
+ end
+ if sz == "y" or vex.l then tail = tail + 4 end
+ wputb(tail + shl(bxor(reg, 15), 3) + vex.p)
+ wvreg("vex.v", vreg)
+ rex = 0
+ if op >= 256 then werror("bad vex opcode") end
+ else
+ if rex ~= 0 then
+ if not x64 then werror("bad operand size") end
+ elseif (vregr or vregxb) and x64 then
+ rex = 0x10
+ sk = map_vreg["vex.v"]
+ end
+ end
+ local r
+ if sz == "w" then wputb(102) end
+ -- Needs >32 bit numbers, but only for crc32 eax, word [ebx]
+ if op >= 4294967296 then r = op%4294967296 wputb((op-r)/4294967296) op = r end
+ if op >= 16777216 then wputb(shr(op, 24)); op = band(op, 0xffffff) end
+ if op >= 65536 then
+ if rex ~= 0 then
+ local opc3 = band(op, 0xffff00)
+ if opc3 == 0x0f3a00 or opc3 == 0x0f3800 then
+ wputb(64 + band(rex, 15)); rex = 0; psz = 2
+ end
+ end
+ wputb(shr(op, 16)); op = band(op, 0xffff); psz = psz + 1
+ end
+ if op >= 256 then
+ local b = shr(op, 8)
+ if b == 15 and rex ~= 0 then wputb(64 + band(rex, 15)); rex = 0; psz = 2 end
+ wputb(b); op = band(op, 255); psz = psz + 1
+ end
+ if rex ~= 0 then wputb(64 + band(rex, 15)); psz = 2 end
+ if sz == "b" then op = op - 1 end
+ wputb(op)
+ return psz, sk
+end
+
+-- Put ModRM or SIB formatted byte.
+local function wputmodrm(m, s, rm, vs, vrm)
+ assert(m < 4 and s < 16 and rm < 16, "bad modrm operands")
+ wputb(shl(m, 6) + shl(band(s, 7), 3) + band(rm, 7))
+end
+
+-- Put ModRM/SIB plus optional displacement.
+local function wputmrmsib(t, imark, s, vsreg, psz, sk)
+ local vreg, vxreg
+ local reg, xreg = t.reg, t.xreg
+ if reg and reg < 0 then reg = 0; vreg = t.vreg end
+ if xreg and xreg < 0 then xreg = 0; vxreg = t.vxreg end
+ if s < 0 then s = 0 end
+
+ -- Register mode.
+ if sub(t.mode, 1, 1) == "r" then
+ wputmodrm(3, s, reg)
+ wvreg("modrm.reg", vsreg, psz+1, sk, vreg)
+ wvreg("modrm.rm.r", vreg, psz+1, sk)
+ return
+ end
+
+ local disp = t.disp
+ local tdisp = type(disp)
+ -- No base register?
+ if not reg then
+ local riprel = false
+ if xreg then
+ -- Indexed mode with index register only.
+ -- [xreg*xsc+disp] -> (0, s, esp) (xsc, xreg, ebp)
+ wputmodrm(0, s, 4)
+ if imark == "I" then waction("MARK") end
+ wvreg("modrm.reg", vsreg, psz+1, sk, vxreg)
+ wputmodrm(t.xsc, xreg, 5)
+ wvreg("sib.index", vxreg, psz+2, sk)
+ else
+ -- Pure 32 bit displacement.
+ if x64 and tdisp ~= "table" then
+ wputmodrm(0, s, 4) -- [disp] -> (0, s, esp) (0, esp, ebp)
+ wvreg("modrm.reg", vsreg, psz+1, sk)
+ if imark == "I" then waction("MARK") end
+ wputmodrm(0, 4, 5)
+ else
+ riprel = x64
+ wputmodrm(0, s, 5) -- [disp|rip-label] -> (0, s, ebp)
+ wvreg("modrm.reg", vsreg, psz+1, sk)
+ if imark == "I" then waction("MARK") end
+ end
+ end
+ if riprel then -- Emit rip-relative displacement.
+ if match("UWSiI", imark) then
+ 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)
+ else
+ wputdarg(disp)
+ end
+ return
+ end
+
+ local m
+ if tdisp == "number" then -- Check displacement size at assembly time.
+ if disp == 0 and band(reg, 7) ~= 5 then -- [ebp] -> [ebp+0] (in SIB, too)
+ if not vreg then m = 0 end -- Force DISP to allow [Rd(5)] -> [ebp+0]
+ elseif disp >= -128 and disp <= 127 then m = 1
+ else m = 2 end
+ elseif tdisp == "table" then
+ m = 2
+ end
+
+ -- Index register present or esp as base register: need SIB encoding.
+ if xreg or band(reg, 7) == 4 then
+ wputmodrm(m or 2, s, 4) -- ModRM.
+ if m == nil or imark == "I" then waction("MARK") end
+ wvreg("modrm.reg", vsreg, psz+1, sk, vxreg or vreg)
+ wputmodrm(t.xsc or 0, xreg or 4, reg) -- SIB.
+ wvreg("sib.index", vxreg, psz+2, sk, vreg)
+ wvreg("sib.base", vreg, psz+2, sk)
+ else
+ wputmodrm(m or 2, s, reg) -- ModRM.
+ if (imark == "I" and (m == 1 or m == 2)) or
+ (m == nil and (vsreg or vreg)) then waction("MARK") end
+ wvreg("modrm.reg", vsreg, psz+1, sk, vreg)
+ wvreg("modrm.rm.m", vreg, psz+1, sk)
+ end
+
+ -- Put displacement.
+ if m == 1 then wputsbarg(disp)
+ elseif m == 2 then wputdarg(disp)
+ elseif m == nil then waction("DISP", disp) end
+end
+
+------------------------------------------------------------------------------
+
+-- Return human-readable operand mode string.
+local function opmodestr(op, args)
+ local m = {}
+ for i=1,#args do
+ local a = args[i]
+ m[#m+1] = sub(a.mode, 1, 1)..(a.opsize or "?")
+ end
+ return op.." "..concat(m, ",")
+end
+
+-- Convert number to valid integer or nil.
+local function toint(expr)
+ local n = tonumber(expr)
+ if n then
+ if n % 1 ~= 0 or n < -2147483648 or n > 4294967295 then
+ werror("bad integer number `"..expr.."'")
+ end
+ return n
+ end
+end
+
+-- Parse immediate expression.
+local function immexpr(expr)
+ -- &expr (pointer)
+ if sub(expr, 1, 1) == "&" then
+ return "iPJ", format("(ptrdiff_t)(%s)", sub(expr,2))
+ end
+
+ local prefix = sub(expr, 1, 2)
+ -- =>expr (pc label reference)
+ if prefix == "=>" then
+ return "iJ", sub(expr, 3)
+ end
+ -- ->name (global label reference)
+ if prefix == "->" then
+ return "iJ", map_global[sub(expr, 3)]
+ end
+
+ -- [<>][1-9] (local label reference)
+ local dir, lnum = match(expr, "^([<>])([1-9])$")
+ if dir then -- Fwd: 247-255, Bkwd: 1-9.
+ return "iJ", lnum + (dir == ">" and 246 or 0)
+ end
+
+ local extname = match(expr, "^extern%s+(%S+)$")
+ if extname then
+ return "iJ", map_extern[extname]
+ end
+
+ -- expr (interpreted as immediate)
+ return "iI", expr
+end
+
+-- Parse displacement expression: +-num, +-expr, +-opsize*num
+local function dispexpr(expr)
+ local disp = expr == "" and 0 or toint(expr)
+ if disp then return disp end
+ local c, dispt = match(expr, "^([+-])%s*(.+)$")
+ if c == "+" then
+ expr = dispt
+ elseif not c then
+ werror("bad displacement expression `"..expr.."'")
+ end
+ local opsize, tailops = match(dispt, "^(%w+)%s*%*%s*(.+)$")
+ local ops, imm = map_opsize[opsize], toint(tailops)
+ if ops and imm then
+ if c == "-" then imm = -imm end
+ return imm*map_opsizenum[ops]
+ end
+ local mode, iexpr = immexpr(dispt)
+ if mode == "iJ" then
+ if c == "-" then werror("cannot invert label reference") end
+ return { iexpr }
+ end
+ return expr -- Need to return original signed expression.
+end
+
+-- Parse register or type expression.
+local function rtexpr(expr)
+ if not expr then return end
+ local tname, ovreg = match(expr, "^([%w_]+):(@[%w_]+)$")
+ local tp = map_type[tname or expr]
+ if tp then
+ local reg = ovreg or tp.reg
+ local rnum = map_reg_num[reg]
+ if not rnum then
+ werror("type `"..(tname or expr).."' needs a register override")
+ end
+ if not map_reg_valid_base[reg] then
+ werror("bad base register override `"..(map_reg_rev[reg] or reg).."'")
+ end
+ return reg, rnum, tp
+ end
+ return expr, map_reg_num[expr]
+end
+
+-- Parse operand and return { mode, opsize, reg, xreg, xsc, disp, imm }.
+local function parseoperand(param)
+ local t = {}
+
+ local expr = param
+ local opsize, tailops = match(param, "^(%w+)%s*(.+)$")
+ if opsize then
+ t.opsize = map_opsize[opsize]
+ if t.opsize then expr = tailops end
+ end
+
+ local br = match(expr, "^%[%s*(.-)%s*%]$")
+ repeat
+ if br then
+ t.mode = "xm"
+
+ -- [disp]
+ t.disp = toint(br)
+ if t.disp then
+ t.mode = x64 and "xm" or "xmO"
+ break
+ end
+
+ -- [reg...]
+ local tp
+ local reg, tailr = match(br, "^([@%w_:]+)%s*(.*)$")
+ reg, t.reg, tp = rtexpr(reg)
+ if not t.reg then
+ -- [expr]
+ t.mode = x64 and "xm" or "xmO"
+ t.disp = dispexpr("+"..br)
+ break
+ end
+
+ if t.reg == -1 then
+ t.vreg, tailr = match(tailr, "^(%b())(.*)$")
+ if not t.vreg then werror("bad variable register expression") end
+ end
+
+ -- [xreg*xsc] or [xreg*xsc+-disp] or [xreg*xsc+-expr]
+ local xsc, tailsc = match(tailr, "^%*%s*([1248])%s*(.*)$")
+ if xsc then
+ if not map_reg_valid_index[reg] then
+ werror("bad index register `"..map_reg_rev[reg].."'")
+ end
+ t.xsc = map_xsc[xsc]
+ t.xreg = t.reg
+ t.vxreg = t.vreg
+ t.reg = nil
+ t.vreg = nil
+ t.disp = dispexpr(tailsc)
+ break
+ end
+ if not map_reg_valid_base[reg] then
+ werror("bad base register `"..map_reg_rev[reg].."'")
+ end
+
+ -- [reg] or [reg+-disp]
+ t.disp = toint(tailr) or (tailr == "" and 0)
+ if t.disp then break end
+
+ -- [reg+xreg...]
+ local xreg, tailx = match(tailr, "^+%s*([@%w_:]+)%s*(.*)$")
+ xreg, t.xreg, tp = rtexpr(xreg)
+ if not t.xreg then
+ -- [reg+-expr]
+ t.disp = dispexpr(tailr)
+ break
+ end
+ if not map_reg_valid_index[xreg] then
+ werror("bad index register `"..map_reg_rev[xreg].."'")
+ end
+
+ if t.xreg == -1 then
+ t.vxreg, tailx = match(tailx, "^(%b())(.*)$")
+ if not t.vxreg then werror("bad variable register expression") end
+ end
+
+ -- [reg+xreg*xsc...]
+ local xsc, tailsc = match(tailx, "^%*%s*([1248])%s*(.*)$")
+ if xsc then
+ t.xsc = map_xsc[xsc]
+ tailx = tailsc
+ end
+
+ -- [...] or [...+-disp] or [...+-expr]
+ t.disp = dispexpr(tailx)
+ else
+ -- imm or opsize*imm
+ local imm = toint(expr)
+ if not imm and sub(expr, 1, 1) == "*" and t.opsize then
+ imm = toint(sub(expr, 2))
+ if imm then
+ imm = imm * map_opsizenum[t.opsize]
+ t.opsize = nil
+ end
+ end
+ if imm then
+ if t.opsize then werror("bad operand size override") end
+ local m = "i"
+ if imm == 1 then m = m.."1" end
+ if imm >= 4294967168 and imm <= 4294967295 then imm = imm-4294967296 end
+ if imm >= -128 and imm <= 127 then m = m.."S" end
+ t.imm = imm
+ t.mode = m
+ break
+ end
+
+ local tp
+ local reg, tailr = match(expr, "^([@%w_:]+)%s*(.*)$")
+ reg, t.reg, tp = rtexpr(reg)
+ if t.reg then
+ if t.reg == -1 then
+ t.vreg, tailr = match(tailr, "^(%b())(.*)$")
+ if not t.vreg then werror("bad variable register expression") end
+ end
+ -- reg
+ if tailr == "" then
+ if t.opsize then werror("bad operand size override") end
+ t.opsize = map_reg_opsize[reg]
+ if t.opsize == "f" then
+ t.mode = t.reg == 0 and "fF" or "f"
+ else
+ if reg == "@w4" or (x64 and reg == "@d4") then
+ wwarn("bad idea, try again with `"..(x64 and "rsp'" or "esp'"))
+ end
+ t.mode = t.reg == 0 and "rmR" or (reg == "@b1" and "rmC" or "rm")
+ end
+ t.needrex = map_reg_needrex[reg]
+ break
+ end
+
+ -- type[idx], type[idx].field, type->field -> [reg+offset_expr]
+ if not tp then werror("bad operand `"..param.."'") end
+ t.mode = "xm"
+ t.disp = format(tp.ctypefmt, tailr)
+ else
+ t.mode, t.imm = immexpr(expr)
+ if sub(t.mode, -1) == "J" then
+ if t.opsize and t.opsize ~= addrsize then
+ werror("bad operand size override")
+ end
+ t.opsize = addrsize
+ end
+ end
+ end
+ until true
+ return t
+end
+
+------------------------------------------------------------------------------
+-- x86 Template String Description
+-- ===============================
+--
+-- Each template string is a list of [match:]pattern pairs,
+-- separated by "|". The first match wins. No match means a
+-- bad or unsupported combination of operand modes or sizes.
+--
+-- The match part and the ":" is omitted if the operation has
+-- no operands. Otherwise the first N characters are matched
+-- against the mode strings of each of the N operands.
+--
+-- The mode string for each operand type is (see parseoperand()):
+-- Integer register: "rm", +"R" for eax, ax, al, +"C" for cl
+-- FP register: "f", +"F" for st0
+-- Index operand: "xm", +"O" for [disp] (pure offset)
+-- Immediate: "i", +"S" for signed 8 bit, +"1" for 1,
+-- +"I" for arg, +"P" for pointer
+-- Any: +"J" for valid jump targets
+--
+-- So a match character "m" (mixed) matches both an integer register
+-- and an index operand (to be encoded with the ModRM/SIB scheme).
+-- But "r" matches only a register and "x" only an index operand
+-- (e.g. for FP memory access operations).
+--
+-- The operand size match string starts right after the mode match
+-- characters and ends before the ":". "dwb" or "qdwb" is assumed, if empty.
+-- The effective data size of the operation is matched against this list.
+--
+-- If only the regular "b", "w", "d", "q", "t" operand sizes are
+-- present, then all operands must be the same size. Unspecified sizes
+-- are ignored, but at least one operand must have a size or the pattern
+-- won't match (use the "byte", "word", "dword", "qword", "tword"
+-- operand size overrides. E.g.: mov dword [eax], 1).
+--
+-- If the list has a "1" or "2" prefix, the operand size is taken
+-- from the respective operand and any other operand sizes are ignored.
+-- If the list contains only ".", all operand sizes are ignored.
+-- If the list has a "/" prefix, the concatenated (mixed) operand sizes
+-- are compared to the match.
+--
+-- E.g. "rrdw" matches for either two dword registers or two word
+-- registers. "Fx2dq" matches an st0 operand plus an index operand
+-- pointing to a dword (float) or qword (double).
+--
+-- Every character after the ":" is part of the pattern string:
+-- Hex chars are accumulated to form the opcode (left to right).
+-- "n" disables the standard opcode mods
+-- (otherwise: -1 for "b", o16 prefix for "w", rex.w for "q")
+-- "X" Force REX.W.
+-- "r"/"R" adds the reg. number from the 1st/2nd operand to the opcode.
+-- "m"/"M" generates ModRM/SIB from the 1st/2nd operand.
+-- The spare 3 bits are either filled with the last hex digit or
+-- the result from a previous "r"/"R". The opcode is restored.
+-- "u" Use VEX encoding, vvvv unused.
+-- "v"/"V" Use VEX encoding, vvvv from 1st/2nd operand (the operand is
+-- removed from the list used by future characters).
+-- "L" Force VEX.L
+--
+-- All of the following characters force a flush of the opcode:
+-- "o"/"O" stores a pure 32 bit disp (offset) from the 1st/2nd operand.
+-- "s" stores a 4 bit immediate from the last register operand,
+-- followed by 4 zero bits.
+-- "S" stores a signed 8 bit immediate from the last operand.
+-- "U" stores an unsigned 8 bit immediate from the last operand.
+-- "W" stores an unsigned 16 bit immediate from the last operand.
+-- "i" stores an operand sized immediate from the last operand.
+-- "I" dito, but generates an action code to optionally modify
+-- the opcode (+2) for a signed 8 bit immediate.
+-- "J" generates one of the REL action codes from the last operand.
+--
+------------------------------------------------------------------------------
+
+-- Template strings for x86 instructions. Ordered by first opcode byte.
+-- Unimplemented opcodes (deliberate omissions) are marked with *.
+local map_op = {
+ -- 00-05: add...
+ -- 06: *push es
+ -- 07: *pop es
+ -- 08-0D: or...
+ -- 0E: *push cs
+ -- 0F: two byte opcode prefix
+ -- 10-15: adc...
+ -- 16: *push ss
+ -- 17: *pop ss
+ -- 18-1D: sbb...
+ -- 1E: *push ds
+ -- 1F: *pop ds
+ -- 20-25: and...
+ es_0 = "26",
+ -- 27: *daa
+ -- 28-2D: sub...
+ cs_0 = "2E",
+ -- 2F: *das
+ -- 30-35: xor...
+ ss_0 = "36",
+ -- 37: *aaa
+ -- 38-3D: cmp...
+ ds_0 = "3E",
+ -- 3F: *aas
+ inc_1 = x64 and "m:FF0m" or "rdw:40r|m:FF0m",
+ dec_1 = x64 and "m:FF1m" or "rdw:48r|m:FF1m",
+ push_1 = (x64 and "rq:n50r|rw:50r|mq:nFF6m|mw:FF6m" or
+ "rdw:50r|mdw:FF6m").."|S.:6AS|ib:n6Ai|i.:68i",
+ pop_1 = x64 and "rq:n58r|rw:58r|mq:n8F0m|mw:8F0m" or "rdw:58r|mdw:8F0m",
+ -- 60: *pusha, *pushad, *pushaw
+ -- 61: *popa, *popad, *popaw
+ -- 62: *bound rdw,x
+ -- 63: x86: *arpl mw,rw
+ movsxd_2 = x64 and "rm/qd:63rM",
+ fs_0 = "64",
+ gs_0 = "65",
+ o16_0 = "66",
+ a16_0 = not x64 and "67" or nil,
+ a32_0 = x64 and "67",
+ -- 68: push idw
+ -- 69: imul rdw,mdw,idw
+ -- 6A: push ib
+ -- 6B: imul rdw,mdw,S
+ -- 6C: *insb
+ -- 6D: *insd, *insw
+ -- 6E: *outsb
+ -- 6F: *outsd, *outsw
+ -- 70-7F: jcc lb
+ -- 80: add... mb,i
+ -- 81: add... mdw,i
+ -- 82: *undefined
+ -- 83: add... mdw,S
+ test_2 = "mr:85Rm|rm:85rM|Ri:A9ri|mi:F70mi",
+ -- 86: xchg rb,mb
+ -- 87: xchg rdw,mdw
+ -- 88: mov mb,r
+ -- 89: mov mdw,r
+ -- 8A: mov r,mb
+ -- 8B: mov r,mdw
+ -- 8C: *mov mdw,seg
+ lea_2 = "rx1dq:8DrM",
+ -- 8E: *mov seg,mdw
+ -- 8F: pop mdw
+ nop_0 = "90",
+ xchg_2 = "Rrqdw:90R|rRqdw:90r|rm:87rM|mr:87Rm",
+ cbw_0 = "6698",
+ cwde_0 = "98",
+ cdqe_0 = "4898",
+ cwd_0 = "6699",
+ cdq_0 = "99",
+ cqo_0 = "4899",
+ -- 9A: *call iw:idw
+ wait_0 = "9B",
+ fwait_0 = "9B",
+ pushf_0 = "9C",
+ pushfd_0 = not x64 and "9C",
+ pushfq_0 = x64 and "9C",
+ popf_0 = "9D",
+ popfd_0 = not x64 and "9D",
+ popfq_0 = x64 and "9D",
+ sahf_0 = "9E",
+ lahf_0 = "9F",
+ mov_2 = "OR:A3o|RO:A1O|mr:89Rm|rm:8BrM|rib:nB0ri|ridw:B8ri|mi:C70mi",
+ movsb_0 = "A4",
+ movsw_0 = "66A5",
+ movsd_0 = "A5",
+ cmpsb_0 = "A6",
+ cmpsw_0 = "66A7",
+ cmpsd_0 = "A7",
+ -- A8: test Rb,i
+ -- A9: test Rdw,i
+ stosb_0 = "AA",
+ stosw_0 = "66AB",
+ stosd_0 = "AB",
+ lodsb_0 = "AC",
+ lodsw_0 = "66AD",
+ lodsd_0 = "AD",
+ scasb_0 = "AE",
+ scasw_0 = "66AF",
+ scasd_0 = "AF",
+ -- B0-B7: mov rb,i
+ -- B8-BF: mov rdw,i
+ -- C0: rol... mb,i
+ -- C1: rol... mdw,i
+ ret_1 = "i.:nC2W",
+ ret_0 = "C3",
+ -- C4: *les rdw,mq
+ -- C5: *lds rdw,mq
+ -- C6: mov mb,i
+ -- C7: mov mdw,i
+ -- C8: *enter iw,ib
+ leave_0 = "C9",
+ -- CA: *retf iw
+ -- CB: *retf
+ int3_0 = "CC",
+ int_1 = "i.:nCDU",
+ into_0 = "CE",
+ -- CF: *iret
+ -- D0: rol... mb,1
+ -- D1: rol... mdw,1
+ -- D2: rol... mb,cl
+ -- D3: rol... mb,cl
+ -- D4: *aam ib
+ -- D5: *aad ib
+ -- D6: *salc
+ -- D7: *xlat
+ -- D8-DF: floating point ops
+ -- E0: *loopne
+ -- E1: *loope
+ -- E2: *loop
+ -- E3: *jcxz, *jecxz
+ -- E4: *in Rb,ib
+ -- E5: *in Rdw,ib
+ -- E6: *out ib,Rb
+ -- E7: *out ib,Rdw
+ call_1 = x64 and "mq:nFF2m|J.:E8nJ" or "md:FF2m|J.:E8J",
+ jmp_1 = x64 and "mq:nFF4m|J.:E9nJ" or "md:FF4m|J.:E9J", -- short: EB
+ -- EA: *jmp iw:idw
+ -- EB: jmp ib
+ -- EC: *in Rb,dx
+ -- ED: *in Rdw,dx
+ -- EE: *out dx,Rb
+ -- EF: *out dx,Rdw
+ lock_0 = "F0",
+ int1_0 = "F1",
+ repne_0 = "F2",
+ repnz_0 = "F2",
+ rep_0 = "F3",
+ repe_0 = "F3",
+ repz_0 = "F3",
+ -- F4: *hlt
+ cmc_0 = "F5",
+ -- F6: test... mb,i; div... mb
+ -- F7: test... mdw,i; div... mdw
+ clc_0 = "F8",
+ stc_0 = "F9",
+ -- FA: *cli
+ cld_0 = "FC",
+ std_0 = "FD",
+ -- FE: inc... mb
+ -- FF: inc... mdw
+
+ -- misc ops
+ not_1 = "m:F72m",
+ neg_1 = "m:F73m",
+ mul_1 = "m:F74m",
+ imul_1 = "m:F75m",
+ div_1 = "m:F76m",
+ idiv_1 = "m:F77m",
+
+ imul_2 = "rmqdw:0FAFrM|rIqdw:69rmI|rSqdw:6BrmS|riqdw:69rmi",
+ imul_3 = "rmIqdw:69rMI|rmSqdw:6BrMS|rmiqdw:69rMi",
+
+ movzx_2 = "rm/db:0FB6rM|rm/qb:|rm/wb:0FB6rM|rm/dw:0FB7rM|rm/qw:",
+ movsx_2 = "rm/db:0FBErM|rm/qb:|rm/wb:0FBErM|rm/dw:0FBFrM|rm/qw:",
+
+ bswap_1 = "rqd:0FC8r",
+ bsf_2 = "rmqdw:0FBCrM",
+ bsr_2 = "rmqdw:0FBDrM",
+ bt_2 = "mrqdw:0FA3Rm|miqdw:0FBA4mU",
+ btc_2 = "mrqdw:0FBBRm|miqdw:0FBA7mU",
+ btr_2 = "mrqdw:0FB3Rm|miqdw:0FBA6mU",
+ bts_2 = "mrqdw:0FABRm|miqdw:0FBA5mU",
+
+ shld_3 = "mriqdw:0FA4RmU|mrC/qq:0FA5Rm|mrC/dd:|mrC/ww:",
+ shrd_3 = "mriqdw:0FACRmU|mrC/qq:0FADRm|mrC/dd:|mrC/ww:",
+
+ rdtsc_0 = "0F31", -- P1+
+ rdpmc_0 = "0F33", -- P6+
+ cpuid_0 = "0FA2", -- P1+
+
+ -- floating point ops
+ fst_1 = "ff:DDD0r|xd:D92m|xq:nDD2m",
+ fstp_1 = "ff:DDD8r|xd:D93m|xq:nDD3m|xt:DB7m",
+ fld_1 = "ff:D9C0r|xd:D90m|xq:nDD0m|xt:DB5m",
+
+ fpop_0 = "DDD8", -- Alias for fstp st0.
+
+ fist_1 = "xw:nDF2m|xd:DB2m",
+ fistp_1 = "xw:nDF3m|xd:DB3m|xq:nDF7m",
+ fild_1 = "xw:nDF0m|xd:DB0m|xq:nDF5m",
+
+ fxch_0 = "D9C9",
+ fxch_1 = "ff:D9C8r",
+ fxch_2 = "fFf:D9C8r|Fff:D9C8R",
+
+ fucom_1 = "ff:DDE0r",
+ fucom_2 = "Fff:DDE0R",
+ fucomp_1 = "ff:DDE8r",
+ fucomp_2 = "Fff:DDE8R",
+ fucomi_1 = "ff:DBE8r", -- P6+
+ fucomi_2 = "Fff:DBE8R", -- P6+
+ fucomip_1 = "ff:DFE8r", -- P6+
+ fucomip_2 = "Fff:DFE8R", -- P6+
+ fcomi_1 = "ff:DBF0r", -- P6+
+ fcomi_2 = "Fff:DBF0R", -- P6+
+ fcomip_1 = "ff:DFF0r", -- P6+
+ fcomip_2 = "Fff:DFF0R", -- P6+
+ fucompp_0 = "DAE9",
+ fcompp_0 = "DED9",
+
+ fldenv_1 = "x.:D94m",
+ fnstenv_1 = "x.:D96m",
+ fstenv_1 = "x.:9BD96m",
+ fldcw_1 = "xw:nD95m",
+ fstcw_1 = "xw:n9BD97m",
+ fnstcw_1 = "xw:nD97m",
+ fstsw_1 = "Rw:n9BDFE0|xw:n9BDD7m",
+ fnstsw_1 = "Rw:nDFE0|xw:nDD7m",
+ fclex_0 = "9BDBE2",
+ fnclex_0 = "DBE2",
+
+ fnop_0 = "D9D0",
+ -- D9D1-D9DF: unassigned
+
+ fchs_0 = "D9E0",
+ fabs_0 = "D9E1",
+ -- D9E2: unassigned
+ -- D9E3: unassigned
+ ftst_0 = "D9E4",
+ fxam_0 = "D9E5",
+ -- D9E6: unassigned
+ -- D9E7: unassigned
+ fld1_0 = "D9E8",
+ fldl2t_0 = "D9E9",
+ fldl2e_0 = "D9EA",
+ fldpi_0 = "D9EB",
+ fldlg2_0 = "D9EC",
+ fldln2_0 = "D9ED",
+ fldz_0 = "D9EE",
+ -- D9EF: unassigned
+
+ f2xm1_0 = "D9F0",
+ fyl2x_0 = "D9F1",
+ fptan_0 = "D9F2",
+ fpatan_0 = "D9F3",
+ fxtract_0 = "D9F4",
+ fprem1_0 = "D9F5",
+ fdecstp_0 = "D9F6",
+ fincstp_0 = "D9F7",
+ fprem_0 = "D9F8",
+ fyl2xp1_0 = "D9F9",
+ fsqrt_0 = "D9FA",
+ fsincos_0 = "D9FB",
+ frndint_0 = "D9FC",
+ fscale_0 = "D9FD",
+ fsin_0 = "D9FE",
+ fcos_0 = "D9FF",
+
+ -- SSE, SSE2
+ andnpd_2 = "rmo:660F55rM",
+ andnps_2 = "rmo:0F55rM",
+ andpd_2 = "rmo:660F54rM",
+ andps_2 = "rmo:0F54rM",
+ clflush_1 = "x.:0FAE7m",
+ cmppd_3 = "rmio:660FC2rMU",
+ cmpps_3 = "rmio:0FC2rMU",
+ cmpsd_3 = "rrio:F20FC2rMU|rxi/oq:",
+ cmpss_3 = "rrio:F30FC2rMU|rxi/od:",
+ comisd_2 = "rro:660F2FrM|rx/oq:",
+ comiss_2 = "rro:0F2FrM|rx/od:",
+ cvtdq2pd_2 = "rro:F30FE6rM|rx/oq:",
+ cvtdq2ps_2 = "rmo:0F5BrM",
+ cvtpd2dq_2 = "rmo:F20FE6rM",
+ cvtpd2ps_2 = "rmo:660F5ArM",
+ cvtpi2pd_2 = "rx/oq:660F2ArM",
+ cvtpi2ps_2 = "rx/oq:0F2ArM",
+ cvtps2dq_2 = "rmo:660F5BrM",
+ cvtps2pd_2 = "rro:0F5ArM|rx/oq:",
+ cvtsd2si_2 = "rr/do:F20F2DrM|rr/qo:|rx/dq:|rxq:",
+ cvtsd2ss_2 = "rro:F20F5ArM|rx/oq:",
+ cvtsi2sd_2 = "rm/od:F20F2ArM|rm/oq:F20F2ArXM",
+ cvtsi2ss_2 = "rm/od:F30F2ArM|rm/oq:F30F2ArXM",
+ cvtss2sd_2 = "rro:F30F5ArM|rx/od:",
+ cvtss2si_2 = "rr/do:F30F2DrM|rr/qo:|rxd:|rx/qd:",
+ cvttpd2dq_2 = "rmo:660FE6rM",
+ cvttps2dq_2 = "rmo:F30F5BrM",
+ cvttsd2si_2 = "rr/do:F20F2CrM|rr/qo:|rx/dq:|rxq:",
+ cvttss2si_2 = "rr/do:F30F2CrM|rr/qo:|rxd:|rx/qd:",
+ fxsave_1 = "x.:0FAE0m",
+ fxrstor_1 = "x.:0FAE1m",
+ ldmxcsr_1 = "xd:0FAE2m",
+ lfence_0 = "0FAEE8",
+ maskmovdqu_2 = "rro:660FF7rM",
+ mfence_0 = "0FAEF0",
+ movapd_2 = "rmo:660F28rM|mro:660F29Rm",
+ movaps_2 = "rmo:0F28rM|mro:0F29Rm",
+ movd_2 = "rm/od:660F6ErM|rm/oq:660F6ErXM|mr/do:660F7ERm|mr/qo:",
+ movdqa_2 = "rmo:660F6FrM|mro:660F7FRm",
+ movdqu_2 = "rmo:F30F6FrM|mro:F30F7FRm",
+ movhlps_2 = "rro:0F12rM",
+ movhpd_2 = "rx/oq:660F16rM|xr/qo:n660F17Rm",
+ movhps_2 = "rx/oq:0F16rM|xr/qo:n0F17Rm",
+ movlhps_2 = "rro:0F16rM",
+ movlpd_2 = "rx/oq:660F12rM|xr/qo:n660F13Rm",
+ movlps_2 = "rx/oq:0F12rM|xr/qo:n0F13Rm",
+ movmskpd_2 = "rr/do:660F50rM",
+ movmskps_2 = "rr/do:0F50rM",
+ movntdq_2 = "xro:660FE7Rm",
+ movnti_2 = "xrqd:0FC3Rm",
+ movntpd_2 = "xro:660F2BRm",
+ movntps_2 = "xro:0F2BRm",
+ movq_2 = "rro:F30F7ErM|rx/oq:|xr/qo:n660FD6Rm",
+ movsd_2 = "rro:F20F10rM|rx/oq:|xr/qo:nF20F11Rm",
+ movss_2 = "rro:F30F10rM|rx/od:|xr/do:F30F11Rm",
+ movupd_2 = "rmo:660F10rM|mro:660F11Rm",
+ movups_2 = "rmo:0F10rM|mro:0F11Rm",
+ orpd_2 = "rmo:660F56rM",
+ orps_2 = "rmo:0F56rM",
+ pause_0 = "F390",
+ pextrw_3 = "rri/do:660FC5rMU|xri/wo:660F3A15nRmU", -- Mem op: SSE4.1 only.
+ pinsrw_3 = "rri/od:660FC4rMU|rxi/ow:",
+ pmovmskb_2 = "rr/do:660FD7rM",
+ prefetchnta_1 = "xb:n0F180m",
+ prefetcht0_1 = "xb:n0F181m",
+ prefetcht1_1 = "xb:n0F182m",
+ prefetcht2_1 = "xb:n0F183m",
+ pshufd_3 = "rmio:660F70rMU",
+ pshufhw_3 = "rmio:F30F70rMU",
+ pshuflw_3 = "rmio:F20F70rMU",
+ pslld_2 = "rmo:660FF2rM|rio:660F726mU",
+ pslldq_2 = "rio:660F737mU",
+ psllq_2 = "rmo:660FF3rM|rio:660F736mU",
+ psllw_2 = "rmo:660FF1rM|rio:660F716mU",
+ psrad_2 = "rmo:660FE2rM|rio:660F724mU",
+ psraw_2 = "rmo:660FE1rM|rio:660F714mU",
+ psrld_2 = "rmo:660FD2rM|rio:660F722mU",
+ psrldq_2 = "rio:660F733mU",
+ psrlq_2 = "rmo:660FD3rM|rio:660F732mU",
+ psrlw_2 = "rmo:660FD1rM|rio:660F712mU",
+ rcpps_2 = "rmo:0F53rM",
+ rcpss_2 = "rro:F30F53rM|rx/od:",
+ rsqrtps_2 = "rmo:0F52rM",
+ rsqrtss_2 = "rmo:F30F52rM",
+ sfence_0 = "0FAEF8",
+ shufpd_3 = "rmio:660FC6rMU",
+ shufps_3 = "rmio:0FC6rMU",
+ stmxcsr_1 = "xd:0FAE3m",
+ ucomisd_2 = "rro:660F2ErM|rx/oq:",
+ ucomiss_2 = "rro:0F2ErM|rx/od:",
+ unpckhpd_2 = "rmo:660F15rM",
+ unpckhps_2 = "rmo:0F15rM",
+ unpcklpd_2 = "rmo:660F14rM",
+ unpcklps_2 = "rmo:0F14rM",
+ xorpd_2 = "rmo:660F57rM",
+ xorps_2 = "rmo:0F57rM",
+
+ -- SSE3 ops
+ fisttp_1 = "xw:nDF1m|xd:DB1m|xq:nDD1m",
+ addsubpd_2 = "rmo:660FD0rM",
+ addsubps_2 = "rmo:F20FD0rM",
+ haddpd_2 = "rmo:660F7CrM",
+ haddps_2 = "rmo:F20F7CrM",
+ hsubpd_2 = "rmo:660F7DrM",
+ hsubps_2 = "rmo:F20F7DrM",
+ lddqu_2 = "rxo:F20FF0rM",
+ movddup_2 = "rmo:F20F12rM",
+ movshdup_2 = "rmo:F30F16rM",
+ movsldup_2 = "rmo:F30F12rM",
+
+ -- SSSE3 ops
+ pabsb_2 = "rmo:660F381CrM",
+ pabsd_2 = "rmo:660F381ErM",
+ pabsw_2 = "rmo:660F381DrM",
+ palignr_3 = "rmio:660F3A0FrMU",
+ phaddd_2 = "rmo:660F3802rM",
+ phaddsw_2 = "rmo:660F3803rM",
+ phaddw_2 = "rmo:660F3801rM",
+ phsubd_2 = "rmo:660F3806rM",
+ phsubsw_2 = "rmo:660F3807rM",
+ phsubw_2 = "rmo:660F3805rM",
+ pmaddubsw_2 = "rmo:660F3804rM",
+ pmulhrsw_2 = "rmo:660F380BrM",
+ pshufb_2 = "rmo:660F3800rM",
+ psignb_2 = "rmo:660F3808rM",
+ psignd_2 = "rmo:660F380ArM",
+ psignw_2 = "rmo:660F3809rM",
+
+ -- SSE4.1 ops
+ blendpd_3 = "rmio:660F3A0DrMU",
+ blendps_3 = "rmio:660F3A0CrMU",
+ blendvpd_3 = "rmRo:660F3815rM",
+ blendvps_3 = "rmRo:660F3814rM",
+ dppd_3 = "rmio:660F3A41rMU",
+ dpps_3 = "rmio:660F3A40rMU",
+ extractps_3 = "mri/do:660F3A17RmU|rri/qo:660F3A17RXmU",
+ insertps_3 = "rrio:660F3A41rMU|rxi/od:",
+ movntdqa_2 = "rxo:660F382ArM",
+ mpsadbw_3 = "rmio:660F3A42rMU",
+ packusdw_2 = "rmo:660F382BrM",
+ pblendvb_3 = "rmRo:660F3810rM",
+ pblendw_3 = "rmio:660F3A0ErMU",
+ pcmpeqq_2 = "rmo:660F3829rM",
+ pextrb_3 = "rri/do:660F3A14nRmU|rri/qo:|xri/bo:",
+ pextrd_3 = "mri/do:660F3A16RmU",
+ pextrq_3 = "mri/qo:660F3A16RmU",
+ -- pextrw is SSE2, mem operand is SSE4.1 only
+ phminposuw_2 = "rmo:660F3841rM",
+ pinsrb_3 = "rri/od:660F3A20nrMU|rxi/ob:",
+ pinsrd_3 = "rmi/od:660F3A22rMU",
+ pinsrq_3 = "rmi/oq:660F3A22rXMU",
+ pmaxsb_2 = "rmo:660F383CrM",
+ pmaxsd_2 = "rmo:660F383DrM",
+ pmaxud_2 = "rmo:660F383FrM",
+ pmaxuw_2 = "rmo:660F383ErM",
+ pminsb_2 = "rmo:660F3838rM",
+ pminsd_2 = "rmo:660F3839rM",
+ pminud_2 = "rmo:660F383BrM",
+ pminuw_2 = "rmo:660F383ArM",
+ pmovsxbd_2 = "rro:660F3821rM|rx/od:",
+ pmovsxbq_2 = "rro:660F3822rM|rx/ow:",
+ pmovsxbw_2 = "rro:660F3820rM|rx/oq:",
+ pmovsxdq_2 = "rro:660F3825rM|rx/oq:",
+ pmovsxwd_2 = "rro:660F3823rM|rx/oq:",
+ pmovsxwq_2 = "rro:660F3824rM|rx/od:",
+ pmovzxbd_2 = "rro:660F3831rM|rx/od:",
+ pmovzxbq_2 = "rro:660F3832rM|rx/ow:",
+ pmovzxbw_2 = "rro:660F3830rM|rx/oq:",
+ pmovzxdq_2 = "rro:660F3835rM|rx/oq:",
+ pmovzxwd_2 = "rro:660F3833rM|rx/oq:",
+ pmovzxwq_2 = "rro:660F3834rM|rx/od:",
+ pmuldq_2 = "rmo:660F3828rM",
+ pmulld_2 = "rmo:660F3840rM",
+ ptest_2 = "rmo:660F3817rM",
+ roundpd_3 = "rmio:660F3A09rMU",
+ roundps_3 = "rmio:660F3A08rMU",
+ roundsd_3 = "rrio:660F3A0BrMU|rxi/oq:",
+ roundss_3 = "rrio:660F3A0ArMU|rxi/od:",
+
+ -- SSE4.2 ops
+ crc32_2 = "rmqd:F20F38F1rM|rm/dw:66F20F38F1rM|rm/db:F20F38F0rM|rm/qb:",
+ pcmpestri_3 = "rmio:660F3A61rMU",
+ pcmpestrm_3 = "rmio:660F3A60rMU",
+ pcmpgtq_2 = "rmo:660F3837rM",
+ pcmpistri_3 = "rmio:660F3A63rMU",
+ pcmpistrm_3 = "rmio:660F3A62rMU",
+ popcnt_2 = "rmqdw:F30FB8rM",
+
+ -- SSE4a
+ extrq_2 = "rro:660F79rM",
+ extrq_3 = "riio:660F780mUU",
+ insertq_2 = "rro:F20F79rM",
+ insertq_4 = "rriio:F20F78rMUU",
+ lzcnt_2 = "rmqdw:F30FBDrM",
+ movntsd_2 = "xr/qo:nF20F2BRm",
+ movntss_2 = "xr/do:F30F2BRm",
+ -- popcnt is also in SSE4.2
+
+ -- AES-NI
+ aesdec_2 = "rmo:660F38DErM",
+ aesdeclast_2 = "rmo:660F38DFrM",
+ aesenc_2 = "rmo:660F38DCrM",
+ aesenclast_2 = "rmo:660F38DDrM",
+ aesimc_2 = "rmo:660F38DBrM",
+ aeskeygenassist_3 = "rmio:660F3ADFrMU",
+ pclmulqdq_3 = "rmio:660F3A44rMU",
+
+ -- AVX FP ops
+ vaddsubpd_3 = "rrmoy:660FVD0rM",
+ vaddsubps_3 = "rrmoy:F20FVD0rM",
+ vandpd_3 = "rrmoy:660FV54rM",
+ vandps_3 = "rrmoy:0FV54rM",
+ vandnpd_3 = "rrmoy:660FV55rM",
+ vandnps_3 = "rrmoy:0FV55rM",
+ vblendpd_4 = "rrmioy:660F3AV0DrMU",
+ vblendps_4 = "rrmioy:660F3AV0CrMU",
+ vblendvpd_4 = "rrmroy:660F3AV4BrMs",
+ vblendvps_4 = "rrmroy:660F3AV4ArMs",
+ vbroadcastf128_2 = "rx/yo:660F38u1ArM",
+ vcmppd_4 = "rrmioy:660FVC2rMU",
+ vcmpps_4 = "rrmioy:0FVC2rMU",
+ vcmpsd_4 = "rrrio:F20FVC2rMU|rrxi/ooq:",
+ vcmpss_4 = "rrrio:F30FVC2rMU|rrxi/ood:",
+ vcomisd_2 = "rro:660Fu2FrM|rx/oq:",
+ vcomiss_2 = "rro:0Fu2FrM|rx/od:",
+ vcvtdq2pd_2 = "rro:F30FuE6rM|rx/oq:|rm/yo:",
+ vcvtdq2ps_2 = "rmoy:0Fu5BrM",
+ vcvtpd2dq_2 = "rmoy:F20FuE6rM",
+ vcvtpd2ps_2 = "rmoy:660Fu5ArM",
+ vcvtps2dq_2 = "rmoy:660Fu5BrM",
+ vcvtps2pd_2 = "rro:0Fu5ArM|rx/oq:|rm/yo:",
+ vcvtsd2si_2 = "rr/do:F20Fu2DrM|rx/dq:|rr/qo:|rxq:",
+ vcvtsd2ss_3 = "rrro:F20FV5ArM|rrx/ooq:",
+ vcvtsi2sd_3 = "rrm/ood:F20FV2ArM|rrm/ooq:F20FVX2ArM",
+ vcvtsi2ss_3 = "rrm/ood:F30FV2ArM|rrm/ooq:F30FVX2ArM",
+ vcvtss2sd_3 = "rrro:F30FV5ArM|rrx/ood:",
+ vcvtss2si_2 = "rr/do:F30Fu2DrM|rxd:|rr/qo:|rx/qd:",
+ vcvttpd2dq_2 = "rmo:660FuE6rM|rm/oy:660FuLE6rM",
+ vcvttps2dq_2 = "rmoy:F30Fu5BrM",
+ vcvttsd2si_2 = "rr/do:F20Fu2CrM|rx/dq:|rr/qo:|rxq:",
+ vcvttss2si_2 = "rr/do:F30Fu2CrM|rxd:|rr/qo:|rx/qd:",
+ vdppd_4 = "rrmio:660F3AV41rMU",
+ vdpps_4 = "rrmioy:660F3AV40rMU",
+ vextractf128_3 = "mri/oy:660F3AuL19RmU",
+ vextractps_3 = "mri/do:660F3Au17RmU",
+ vhaddpd_3 = "rrmoy:660FV7CrM",
+ vhaddps_3 = "rrmoy:F20FV7CrM",
+ vhsubpd_3 = "rrmoy:660FV7DrM",
+ vhsubps_3 = "rrmoy:F20FV7DrM",
+ vinsertf128_4 = "rrmi/yyo:660F3AV18rMU",
+ vinsertps_4 = "rrrio:660F3AV21rMU|rrxi/ood:",
+ vldmxcsr_1 = "xd:0FuAE2m",
+ vmaskmovps_3 = "rrxoy:660F38V2CrM|xrroy:660F38V2ERm",
+ vmaskmovpd_3 = "rrxoy:660F38V2DrM|xrroy:660F38V2FRm",
+ vmovapd_2 = "rmoy:660Fu28rM|mroy:660Fu29Rm",
+ vmovaps_2 = "rmoy:0Fu28rM|mroy:0Fu29Rm",
+ vmovd_2 = "rm/od:660Fu6ErM|rm/oq:660FuX6ErM|mr/do:660Fu7ERm|mr/qo:",
+ vmovq_2 = "rro:F30Fu7ErM|rx/oq:|xr/qo:660FuD6Rm",
+ vmovddup_2 = "rmy:F20Fu12rM|rro:|rx/oq:",
+ vmovhlps_3 = "rrro:0FV12rM",
+ vmovhpd_2 = "xr/qo:660Fu17Rm",
+ vmovhpd_3 = "rrx/ooq:660FV16rM",
+ vmovhps_2 = "xr/qo:0Fu17Rm",
+ vmovhps_3 = "rrx/ooq:0FV16rM",
+ vmovlhps_3 = "rrro:0FV16rM",
+ vmovlpd_2 = "xr/qo:660Fu13Rm",
+ vmovlpd_3 = "rrx/ooq:660FV12rM",
+ vmovlps_2 = "xr/qo:0Fu13Rm",
+ vmovlps_3 = "rrx/ooq:0FV12rM",
+ vmovmskpd_2 = "rr/do:660Fu50rM|rr/dy:660FuL50rM",
+ vmovmskps_2 = "rr/do:0Fu50rM|rr/dy:0FuL50rM",
+ vmovntpd_2 = "xroy:660Fu2BRm",
+ vmovntps_2 = "xroy:0Fu2BRm",
+ vmovsd_2 = "rx/oq:F20Fu10rM|xr/qo:F20Fu11Rm",
+ vmovsd_3 = "rrro:F20FV10rM",
+ vmovshdup_2 = "rmoy:F30Fu16rM",
+ vmovsldup_2 = "rmoy:F30Fu12rM",
+ vmovss_2 = "rx/od:F30Fu10rM|xr/do:F30Fu11Rm",
+ vmovss_3 = "rrro:F30FV10rM",
+ vmovupd_2 = "rmoy:660Fu10rM|mroy:660Fu11Rm",
+ vmovups_2 = "rmoy:0Fu10rM|mroy:0Fu11Rm",
+ vorpd_3 = "rrmoy:660FV56rM",
+ vorps_3 = "rrmoy:0FV56rM",
+ vpermilpd_3 = "rrmoy:660F38V0DrM|rmioy:660F3Au05rMU",
+ vpermilps_3 = "rrmoy:660F38V0CrM|rmioy:660F3Au04rMU",
+ vperm2f128_4 = "rrmiy:660F3AV06rMU",
+ vptestpd_2 = "rmoy:660F38u0FrM",
+ vptestps_2 = "rmoy:660F38u0ErM",
+ vrcpps_2 = "rmoy:0Fu53rM",
+ vrcpss_3 = "rrro:F30FV53rM|rrx/ood:",
+ vrsqrtps_2 = "rmoy:0Fu52rM",
+ vrsqrtss_3 = "rrro:F30FV52rM|rrx/ood:",
+ vroundpd_3 = "rmioy:660F3AV09rMU",
+ vroundps_3 = "rmioy:660F3AV08rMU",
+ vroundsd_4 = "rrrio:660F3AV0BrMU|rrxi/ooq:",
+ vroundss_4 = "rrrio:660F3AV0ArMU|rrxi/ood:",
+ vshufpd_4 = "rrmioy:660FVC6rMU",
+ vshufps_4 = "rrmioy:0FVC6rMU",
+ vsqrtps_2 = "rmoy:0Fu51rM",
+ vsqrtss_2 = "rro:F30Fu51rM|rx/od:",
+ vsqrtpd_2 = "rmoy:660Fu51rM",
+ vsqrtsd_2 = "rro:F20Fu51rM|rx/oq:",
+ vstmxcsr_1 = "xd:0FuAE3m",
+ vucomisd_2 = "rro:660Fu2ErM|rx/oq:",
+ vucomiss_2 = "rro:0Fu2ErM|rx/od:",
+ vunpckhpd_3 = "rrmoy:660FV15rM",
+ vunpckhps_3 = "rrmoy:0FV15rM",
+ vunpcklpd_3 = "rrmoy:660FV14rM",
+ vunpcklps_3 = "rrmoy:0FV14rM",
+ vxorpd_3 = "rrmoy:660FV57rM",
+ vxorps_3 = "rrmoy:0FV57rM",
+ vzeroall_0 = "0FuL77",
+ vzeroupper_0 = "0Fu77",
+
+ -- AVX2 FP ops
+ vbroadcastss_2 = "rx/od:660F38u18rM|rx/yd:|rro:|rr/yo:",
+ vbroadcastsd_2 = "rx/yq:660F38u19rM|rr/yo:",
+ -- *vgather* (!vsib)
+ vpermpd_3 = "rmiy:660F3AuX01rMU",
+ vpermps_3 = "rrmy:660F38V16rM",
+
+ -- AVX, AVX2 integer ops
+ -- In general, xmm requires AVX, ymm requires AVX2.
+ vaesdec_3 = "rrmo:660F38VDErM",
+ vaesdeclast_3 = "rrmo:660F38VDFrM",
+ vaesenc_3 = "rrmo:660F38VDCrM",
+ vaesenclast_3 = "rrmo:660F38VDDrM",
+ vaesimc_2 = "rmo:660F38uDBrM",
+ vaeskeygenassist_3 = "rmio:660F3AuDFrMU",
+ vlddqu_2 = "rxoy:F20FuF0rM",
+ vmaskmovdqu_2 = "rro:660FuF7rM",
+ vmovdqa_2 = "rmoy:660Fu6FrM|mroy:660Fu7FRm",
+ vmovdqu_2 = "rmoy:F30Fu6FrM|mroy:F30Fu7FRm",
+ vmovntdq_2 = "xroy:660FuE7Rm",
+ vmovntdqa_2 = "rxoy:660F38u2ArM",
+ vmpsadbw_4 = "rrmioy:660F3AV42rMU",
+ vpabsb_2 = "rmoy:660F38u1CrM",
+ vpabsd_2 = "rmoy:660F38u1ErM",
+ vpabsw_2 = "rmoy:660F38u1DrM",
+ vpackusdw_3 = "rrmoy:660F38V2BrM",
+ vpalignr_4 = "rrmioy:660F3AV0FrMU",
+ vpblendvb_4 = "rrmroy:660F3AV4CrMs",
+ vpblendw_4 = "rrmioy:660F3AV0ErMU",
+ vpclmulqdq_4 = "rrmio:660F3AV44rMU",
+ vpcmpeqq_3 = "rrmoy:660F38V29rM",
+ vpcmpestri_3 = "rmio:660F3Au61rMU",
+ vpcmpestrm_3 = "rmio:660F3Au60rMU",
+ vpcmpgtq_3 = "rrmoy:660F38V37rM",
+ vpcmpistri_3 = "rmio:660F3Au63rMU",
+ vpcmpistrm_3 = "rmio:660F3Au62rMU",
+ vpextrb_3 = "rri/do:660F3Au14nRmU|rri/qo:|xri/bo:",
+ vpextrw_3 = "rri/do:660FuC5rMU|xri/wo:660F3Au15nRmU",
+ vpextrd_3 = "mri/do:660F3Au16RmU",
+ vpextrq_3 = "mri/qo:660F3Au16RmU",
+ vphaddw_3 = "rrmoy:660F38V01rM",
+ vphaddd_3 = "rrmoy:660F38V02rM",
+ vphaddsw_3 = "rrmoy:660F38V03rM",
+ vphminposuw_2 = "rmo:660F38u41rM",
+ vphsubw_3 = "rrmoy:660F38V05rM",
+ vphsubd_3 = "rrmoy:660F38V06rM",
+ vphsubsw_3 = "rrmoy:660F38V07rM",
+ vpinsrb_4 = "rrri/ood:660F3AV20rMU|rrxi/oob:",
+ vpinsrw_4 = "rrri/ood:660FVC4rMU|rrxi/oow:",
+ vpinsrd_4 = "rrmi/ood:660F3AV22rMU",
+ vpinsrq_4 = "rrmi/ooq:660F3AVX22rMU",
+ vpmaddubsw_3 = "rrmoy:660F38V04rM",
+ vpmaxsb_3 = "rrmoy:660F38V3CrM",
+ vpmaxsd_3 = "rrmoy:660F38V3DrM",
+ vpmaxuw_3 = "rrmoy:660F38V3ErM",
+ vpmaxud_3 = "rrmoy:660F38V3FrM",
+ vpminsb_3 = "rrmoy:660F38V38rM",
+ vpminsd_3 = "rrmoy:660F38V39rM",
+ vpminuw_3 = "rrmoy:660F38V3ArM",
+ vpminud_3 = "rrmoy:660F38V3BrM",
+ vpmovmskb_2 = "rr/do:660FuD7rM|rr/dy:660FuLD7rM",
+ vpmovsxbw_2 = "rroy:660F38u20rM|rx/oq:|rx/yo:",
+ vpmovsxbd_2 = "rroy:660F38u21rM|rx/od:|rx/yq:",
+ vpmovsxbq_2 = "rroy:660F38u22rM|rx/ow:|rx/yd:",
+ vpmovsxwd_2 = "rroy:660F38u23rM|rx/oq:|rx/yo:",
+ vpmovsxwq_2 = "rroy:660F38u24rM|rx/od:|rx/yq:",
+ vpmovsxdq_2 = "rroy:660F38u25rM|rx/oq:|rx/yo:",
+ vpmovzxbw_2 = "rroy:660F38u30rM|rx/oq:|rx/yo:",
+ vpmovzxbd_2 = "rroy:660F38u31rM|rx/od:|rx/yq:",
+ vpmovzxbq_2 = "rroy:660F38u32rM|rx/ow:|rx/yd:",
+ vpmovzxwd_2 = "rroy:660F38u33rM|rx/oq:|rx/yo:",
+ vpmovzxwq_2 = "rroy:660F38u34rM|rx/od:|rx/yq:",
+ vpmovzxdq_2 = "rroy:660F38u35rM|rx/oq:|rx/yo:",
+ vpmuldq_3 = "rrmoy:660F38V28rM",
+ vpmulhrsw_3 = "rrmoy:660F38V0BrM",
+ vpmulld_3 = "rrmoy:660F38V40rM",
+ vpshufb_3 = "rrmoy:660F38V00rM",
+ vpshufd_3 = "rmioy:660Fu70rMU",
+ vpshufhw_3 = "rmioy:F30Fu70rMU",
+ vpshuflw_3 = "rmioy:F20Fu70rMU",
+ vpsignb_3 = "rrmoy:660F38V08rM",
+ vpsignw_3 = "rrmoy:660F38V09rM",
+ vpsignd_3 = "rrmoy:660F38V0ArM",
+ vpslldq_3 = "rrioy:660Fv737mU",
+ vpsllw_3 = "rrmoy:660FVF1rM|rrioy:660Fv716mU",
+ vpslld_3 = "rrmoy:660FVF2rM|rrioy:660Fv726mU",
+ vpsllq_3 = "rrmoy:660FVF3rM|rrioy:660Fv736mU",
+ vpsraw_3 = "rrmoy:660FVE1rM|rrioy:660Fv714mU",
+ vpsrad_3 = "rrmoy:660FVE2rM|rrioy:660Fv724mU",
+ vpsrldq_3 = "rrioy:660Fv733mU",
+ vpsrlw_3 = "rrmoy:660FVD1rM|rrioy:660Fv712mU",
+ vpsrld_3 = "rrmoy:660FVD2rM|rrioy:660Fv722mU",
+ vpsrlq_3 = "rrmoy:660FVD3rM|rrioy:660Fv732mU",
+ vptest_2 = "rmoy:660F38u17rM",
+
+ -- AVX2 integer ops
+ vbroadcasti128_2 = "rx/yo:660F38u5ArM",
+ vinserti128_4 = "rrmi/yyo:660F3AV38rMU",
+ vextracti128_3 = "mri/oy:660F3AuL39RmU",
+ vpblendd_4 = "rrmioy:660F3AV02rMU",
+ vpbroadcastb_2 = "rro:660F38u78rM|rx/ob:|rr/yo:|rx/yb:",
+ vpbroadcastw_2 = "rro:660F38u79rM|rx/ow:|rr/yo:|rx/yw:",
+ vpbroadcastd_2 = "rro:660F38u58rM|rx/od:|rr/yo:|rx/yd:",
+ vpbroadcastq_2 = "rro:660F38u59rM|rx/oq:|rr/yo:|rx/yq:",
+ vpermd_3 = "rrmy:660F38V36rM",
+ vpermq_3 = "rmiy:660F3AuX00rMU",
+ -- *vpgather* (!vsib)
+ vperm2i128_4 = "rrmiy:660F3AV46rMU",
+ vpmaskmovd_3 = "rrxoy:660F38V8CrM|xrroy:660F38V8ERm",
+ vpmaskmovq_3 = "rrxoy:660F38VX8CrM|xrroy:660F38VX8ERm",
+ vpsllvd_3 = "rrmoy:660F38V47rM",
+ vpsllvq_3 = "rrmoy:660F38VX47rM",
+ vpsravd_3 = "rrmoy:660F38V46rM",
+ vpsrlvd_3 = "rrmoy:660F38V45rM",
+ vpsrlvq_3 = "rrmoy:660F38VX45rM",
+
+ -- Intel ADX
+ adcx_2 = "rmqd:660F38F6rM",
+ adox_2 = "rmqd:F30F38F6rM",
+}
+
+------------------------------------------------------------------------------
+
+-- Arithmetic ops.
+for name,n in pairs{ add = 0, ["or"] = 1, adc = 2, sbb = 3,
+ ["and"] = 4, sub = 5, xor = 6, cmp = 7 } do
+ local n8 = shl(n, 3)
+ map_op[name.."_2"] = format(
+ "mr:%02XRm|rm:%02XrM|mI1qdw:81%XmI|mS1qdw:83%XmS|Ri1qdwb:%02Xri|mi1qdwb:81%Xmi",
+ 1+n8, 3+n8, n, n, 5+n8, n)
+end
+
+-- Shift ops.
+for name,n in pairs{ rol = 0, ror = 1, rcl = 2, rcr = 3,
+ shl = 4, shr = 5, sar = 7, sal = 4 } do
+ map_op[name.."_2"] = format("m1:D1%Xm|mC1qdwb:D3%Xm|mi:C1%XmU", n, n, n)
+end
+
+-- Conditional ops.
+for cc,n in pairs(map_cc) do
+ map_op["j"..cc.."_1"] = format("J.:n0F8%XJ", n) -- short: 7%X
+ map_op["set"..cc.."_1"] = format("mb:n0F9%X2m", n)
+ map_op["cmov"..cc.."_2"] = format("rmqdw:0F4%XrM", n) -- P6+
+end
+
+-- FP arithmetic ops.
+for name,n in pairs{ add = 0, mul = 1, com = 2, comp = 3,
+ sub = 4, subr = 5, div = 6, divr = 7 } do
+ local nc = 0xc0 + shl(n, 3)
+ local nr = nc + (n < 4 and 0 or (n % 2 == 0 and 8 or -8))
+ local fn = "f"..name
+ map_op[fn.."_1"] = format("ff:D8%02Xr|xd:D8%Xm|xq:nDC%Xm", nc, n, n)
+ if n == 2 or n == 3 then
+ map_op[fn.."_2"] = format("Fff:D8%02XR|Fx2d:D8%XM|Fx2q:nDC%XM", nc, n, n)
+ else
+ map_op[fn.."_2"] = format("Fff:D8%02XR|fFf:DC%02Xr|Fx2d:D8%XM|Fx2q:nDC%XM", nc, nr, n, n)
+ map_op[fn.."p_1"] = format("ff:DE%02Xr", nr)
+ map_op[fn.."p_2"] = format("fFf:DE%02Xr", nr)
+ end
+ map_op["fi"..name.."_1"] = format("xd:DA%Xm|xw:nDE%Xm", n, n)
+end
+
+-- FP conditional moves.
+for cc,n in pairs{ b=0, e=1, be=2, u=3, nb=4, ne=5, nbe=6, nu=7 } do
+ local nc = 0xdac0 + shl(band(n, 3), 3) + shl(band(n, 4), 6)
+ map_op["fcmov"..cc.."_1"] = format("ff:%04Xr", nc) -- P6+
+ map_op["fcmov"..cc.."_2"] = format("Fff:%04XR", nc) -- P6+
+end
+
+-- SSE / AVX FP arithmetic ops.
+for name,n in pairs{ sqrt = 1, add = 8, mul = 9,
+ sub = 12, min = 13, div = 14, max = 15 } do
+ map_op[name.."ps_2"] = format("rmo:0F5%XrM", n)
+ map_op[name.."ss_2"] = format("rro:F30F5%XrM|rx/od:", n)
+ map_op[name.."pd_2"] = format("rmo:660F5%XrM", n)
+ map_op[name.."sd_2"] = format("rro:F20F5%XrM|rx/oq:", n)
+ if n ~= 1 then
+ map_op["v"..name.."ps_3"] = format("rrmoy:0FV5%XrM", n)
+ map_op["v"..name.."ss_3"] = format("rrro:F30FV5%XrM|rrx/ood:", n)
+ map_op["v"..name.."pd_3"] = format("rrmoy:660FV5%XrM", n)
+ map_op["v"..name.."sd_3"] = format("rrro:F20FV5%XrM|rrx/ooq:", n)
+ end
+end
+
+-- SSE2 / AVX / AVX2 integer arithmetic ops (66 0F leaf).
+for name,n in pairs{
+ paddb = 0xFC, paddw = 0xFD, paddd = 0xFE, paddq = 0xD4,
+ paddsb = 0xEC, paddsw = 0xED, packssdw = 0x6B,
+ packsswb = 0x63, packuswb = 0x67, paddusb = 0xDC,
+ paddusw = 0xDD, pand = 0xDB, pandn = 0xDF, pavgb = 0xE0,
+ pavgw = 0xE3, pcmpeqb = 0x74, pcmpeqd = 0x76,
+ pcmpeqw = 0x75, pcmpgtb = 0x64, pcmpgtd = 0x66,
+ pcmpgtw = 0x65, pmaddwd = 0xF5, pmaxsw = 0xEE,
+ pmaxub = 0xDE, pminsw = 0xEA, pminub = 0xDA,
+ pmulhuw = 0xE4, pmulhw = 0xE5, pmullw = 0xD5,
+ pmuludq = 0xF4, por = 0xEB, psadbw = 0xF6, psubb = 0xF8,
+ psubw = 0xF9, psubd = 0xFA, psubq = 0xFB, psubsb = 0xE8,
+ psubsw = 0xE9, psubusb = 0xD8, psubusw = 0xD9,
+ punpckhbw = 0x68, punpckhwd = 0x69, punpckhdq = 0x6A,
+ punpckhqdq = 0x6D, punpcklbw = 0x60, punpcklwd = 0x61,
+ punpckldq = 0x62, punpcklqdq = 0x6C, pxor = 0xEF
+} do
+ map_op[name.."_2"] = format("rmo:660F%02XrM", n)
+ map_op["v"..name.."_3"] = format("rrmoy:660FV%02XrM", n)
+end
+
+------------------------------------------------------------------------------
+
+local map_vexarg = { u = false, v = 1, V = 2 }
+
+-- Process pattern string.
+local function dopattern(pat, args, sz, op, needrex)
+ local digit, addin, vex
+ local opcode = 0
+ local szov = sz
+ local narg = 1
+ local rex = 0
+
+ -- Limit number of section buffer positions used by a single dasm_put().
+ -- A single opcode needs a maximum of 6 positions.
+ if secpos+6 > maxsecpos then wflush() end
+
+ -- Process each character.
+ for c in gmatch(pat.."|", ".") do
+ if match(c, "%x") then -- Hex digit.
+ digit = byte(c) - 48
+ if digit > 48 then digit = digit - 39
+ elseif digit > 16 then digit = digit - 7 end
+ opcode = opcode*16 + digit
+ addin = nil
+ elseif c == "n" then -- Disable operand size mods for opcode.
+ szov = nil
+ elseif c == "X" then -- Force REX.W.
+ rex = 8
+ elseif c == "L" then -- Force VEX.L.
+ vex.l = true
+ elseif c == "r" then -- Merge 1st operand regno. into opcode.
+ addin = args[1]; opcode = opcode + (addin.reg % 8)
+ if narg < 2 then narg = 2 end
+ elseif c == "R" then -- Merge 2nd operand regno. into opcode.
+ addin = args[2]; opcode = opcode + (addin.reg % 8)
+ narg = 3
+ elseif c == "m" or c == "M" then -- Encode ModRM/SIB.
+ local s
+ if addin then
+ s = addin.reg
+ opcode = opcode - band(s, 7) -- Undo regno opcode merge.
+ else
+ s = band(opcode, 15) -- Undo last digit.
+ opcode = shr(opcode, 4)
+ end
+ local nn = c == "m" and 1 or 2
+ local t = args[nn]
+ if narg <= nn then narg = nn + 1 end
+ if szov == "q" and rex == 0 then rex = rex + 8 end
+ if t.reg and t.reg > 7 then rex = rex + 1 end
+ if t.xreg and t.xreg > 7 then rex = rex + 2 end
+ if s > 7 then rex = rex + 4 end
+ if needrex then rex = rex + 16 end
+ local psz, sk = wputop(szov, opcode, rex, vex, s < 0, t.vreg or t.vxreg)
+ opcode = nil
+ local imark = sub(pat, -1) -- Force a mark (ugly).
+ -- Put ModRM/SIB with regno/last digit as spare.
+ wputmrmsib(t, imark, s, addin and addin.vreg, psz, sk)
+ addin = nil
+ elseif map_vexarg[c] ~= nil then -- Encode using VEX prefix
+ local b = band(opcode, 255); opcode = shr(opcode, 8)
+ local m = 1
+ if b == 0x38 then m = 2
+ elseif b == 0x3a then m = 3 end
+ if m ~= 1 then b = band(opcode, 255); opcode = shr(opcode, 8) end
+ if b ~= 0x0f then
+ werror("expected `0F', `0F38', or `0F3A' to precede `"..c..
+ "' in pattern `"..pat.."' for `"..op.."'")
+ end
+ local v = map_vexarg[c]
+ if v then v = remove(args, v) end
+ b = band(opcode, 255)
+ local p = 0
+ if b == 0x66 then p = 1
+ elseif b == 0xf3 then p = 2
+ elseif b == 0xf2 then p = 3 end
+ if p ~= 0 then opcode = shr(opcode, 8) end
+ if opcode ~= 0 then wputop(nil, opcode, 0); opcode = 0 end
+ vex = { m = m, p = p, v = v }
+ else
+ if opcode then -- Flush opcode.
+ if szov == "q" and rex == 0 then rex = rex + 8 end
+ if needrex then rex = rex + 16 end
+ if addin and addin.reg == -1 then
+ local psz, sk = wputop(szov, opcode - 7, rex, vex, true)
+ wvreg("opcode", addin.vreg, psz, sk)
+ else
+ if addin and addin.reg > 7 then rex = rex + 1 end
+ wputop(szov, opcode, rex, vex)
+ end
+ opcode = nil
+ end
+ if c == "|" then break end
+ if c == "o" then -- Offset (pure 32 bit displacement).
+ wputdarg(args[1].disp); if narg < 2 then narg = 2 end
+ elseif c == "O" then
+ wputdarg(args[2].disp); narg = 3
+ else
+ -- Anything else is an immediate operand.
+ local a = args[narg]
+ narg = narg + 1
+ local mode, imm = a.mode, a.imm
+ if mode == "iJ" and not match("iIJ", c) then
+ werror("bad operand size for label")
+ end
+ if c == "S" then
+ wputsbarg(imm)
+ elseif c == "U" then
+ wputbarg(imm)
+ elseif c == "W" then
+ wputwarg(imm)
+ elseif c == "i" or c == "I" then
+ if mode == "iJ" then
+ wputlabel("IMM_", imm, 1)
+ elseif mode == "iI" and c == "I" then
+ waction(sz == "w" and "IMM_WB" or "IMM_DB", imm)
+ else
+ wputszarg(sz, imm)
+ end
+ elseif c == "J" then
+ if mode == "iPJ" then
+ waction("REL_A", imm) -- !x64 (secpos)
+ else
+ wputlabel("REL_", imm, 2)
+ end
+ elseif c == "s" then
+ local reg = a.reg
+ if reg < 0 then
+ wputb(0)
+ wvreg("imm.hi", a.vreg)
+ else
+ wputb(shl(reg, 4))
+ end
+ else
+ werror("bad char `"..c.."' in pattern `"..pat.."' for `"..op.."'")
+ end
+ end
+ end
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Mapping of operand modes to short names. Suppress output with '#'.
+local map_modename = {
+ r = "reg", R = "eax", C = "cl", x = "mem", m = "mrm", i = "imm",
+ f = "stx", F = "st0", J = "lbl", ["1"] = "1",
+ I = "#", S = "#", O = "#",
+}
+
+-- Return a table/string showing all possible operand modes.
+local function templatehelp(template, nparams)
+ if nparams == 0 then return "" end
+ local t = {}
+ for tm in gmatch(template, "[^%|]+") do
+ local s = map_modename[sub(tm, 1, 1)]
+ s = s..gsub(sub(tm, 2, nparams), ".", function(c)
+ return ", "..map_modename[c]
+ end)
+ if not match(s, "#") then t[#t+1] = s end
+ end
+ return t
+end
+
+-- Match operand modes against mode match part of template.
+local function matchtm(tm, args)
+ for i=1,#args do
+ if not match(args[i].mode, sub(tm, i, i)) then return end
+ end
+ return true
+end
+
+-- Handle opcodes defined with template strings.
+map_op[".template__"] = function(params, template, nparams)
+ if not params then return templatehelp(template, nparams) end
+ local args = {}
+
+ -- Zero-operand opcodes have no match part.
+ if #params == 0 then
+ dopattern(template, args, "d", params.op, nil)
+ return
+ end
+
+ -- Determine common operand size (coerce undefined size) or flag as mixed.
+ local sz, szmix, needrex
+ for i,p in ipairs(params) do
+ args[i] = parseoperand(p)
+ local nsz = args[i].opsize
+ if nsz then
+ if sz and sz ~= nsz then szmix = true else sz = nsz end
+ end
+ local nrex = args[i].needrex
+ if nrex ~= nil then
+ if needrex == nil then
+ needrex = nrex
+ elseif needrex ~= nrex then
+ werror("bad mix of byte-addressable registers")
+ end
+ end
+ end
+
+ -- Try all match:pattern pairs (separated by '|').
+ local gotmatch, lastpat
+ for tm in gmatch(template, "[^%|]+") do
+ -- Split off size match (starts after mode match) and pattern string.
+ local szm, pat = match(tm, "^(.-):(.*)$", #args+1)
+ if pat == "" then pat = lastpat else lastpat = pat end
+ if matchtm(tm, args) then
+ local prefix = sub(szm, 1, 1)
+ if prefix == "/" then -- Exactly match leading operand sizes.
+ for i = #szm,1,-1 do
+ if i == 1 then
+ dopattern(pat, args, sz, params.op, needrex) -- Process pattern.
+ return
+ elseif args[i-1].opsize ~= sub(szm, i, i) then
+ break
+ end
+ end
+ else -- Match common operand size.
+ local szp = sz
+ if szm == "" then szm = x64 and "qdwb" or "dwb" end -- Default sizes.
+ if prefix == "1" then szp = args[1].opsize; szmix = nil
+ elseif prefix == "2" then szp = args[2].opsize; szmix = nil end
+ if not szmix and (prefix == "." or match(szm, szp or "#")) then
+ dopattern(pat, args, szp, params.op, needrex) -- Process pattern.
+ return
+ end
+ end
+ gotmatch = true
+ end
+ end
+
+ local msg = "bad operand mode"
+ if gotmatch then
+ if szmix then
+ msg = "mixed operand size"
+ else
+ msg = sz and "bad operand size" or "missing operand size"
+ end
+ end
+
+ werror(msg.." in `"..opmodestr(params.op, args).."'")
+end
+
+------------------------------------------------------------------------------
+
+-- x64-specific opcode for 64 bit immediates and displacements.
+if x64 then
+ function map_op.mov64_2(params)
+ if not params then return { "reg, imm", "reg, [disp]", "[disp], reg" } end
+ if secpos+2 > maxsecpos then wflush() end
+ local opcode, op64, sz, rex, vreg
+ local op64 = match(params[1], "^%[%s*(.-)%s*%]$")
+ if op64 then
+ local a = parseoperand(params[2])
+ if a.mode ~= "rmR" then werror("bad operand mode") end
+ sz = a.opsize
+ rex = sz == "q" and 8 or 0
+ opcode = 0xa3
+ else
+ op64 = match(params[2], "^%[%s*(.-)%s*%]$")
+ local a = parseoperand(params[1])
+ if op64 then
+ if a.mode ~= "rmR" then werror("bad operand mode") end
+ sz = a.opsize
+ rex = sz == "q" and 8 or 0
+ opcode = 0xa1
+ else
+ if sub(a.mode, 1, 1) ~= "r" or a.opsize ~= "q" then
+ werror("bad operand mode")
+ end
+ op64 = params[2]
+ if a.reg == -1 then
+ vreg = a.vreg
+ opcode = 0xb8
+ else
+ opcode = 0xb8 + band(a.reg, 7)
+ end
+ rex = a.reg > 7 and 9 or 8
+ end
+ end
+ local psz, sk = wputop(sz, opcode, rex, nil, vreg)
+ wvreg("opcode", vreg, psz, sk)
+ waction("IMM_D", format("(unsigned int)(%s)", op64))
+ waction("IMM_D", format("(unsigned int)((%s)>>32)", op64))
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcodes for data storage.
+local function op_data(params)
+ if not params then return "imm..." end
+ local sz = sub(params.op, 2, 2)
+ if sz == "a" then sz = addrsize end
+ for _,p in ipairs(params) do
+ local a = parseoperand(p)
+ if sub(a.mode, 1, 1) ~= "i" or (a.opsize and a.opsize ~= sz) then
+ werror("bad mode or size in `"..p.."'")
+ end
+ if a.mode == "iJ" then
+ wputlabel("IMM_", a.imm, 1)
+ else
+ wputszarg(sz, a.imm)
+ end
+ if secpos+2 > maxsecpos then wflush() end
+ end
+end
+
+map_op[".byte_*"] = op_data
+map_op[".sbyte_*"] = op_data
+map_op[".word_*"] = op_data
+map_op[".dword_*"] = op_data
+map_op[".aword_*"] = op_data
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode to mark the position where the action list is to be emitted.
+map_op[".actionlist_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeactions(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the global enum is to be emitted.
+map_op[".globals_1"] = function(params)
+ if not params then return "prefix" end
+ local prefix = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobals(out, prefix) end)
+end
+
+-- Pseudo-opcode to mark the position where the global names are to be emitted.
+map_op[".globalnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobalnames(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the extern names are to be emitted.
+map_op[".externnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeexternnames(out, name) end)
+end
+
+------------------------------------------------------------------------------
+
+-- Label pseudo-opcode (converted from trailing colon form).
+map_op[".label_2"] = function(params)
+ if not params then return "[1-9] | ->global | =>pcexpr [, addr]" end
+ if secpos+2 > maxsecpos then wflush() end
+ local a = parseoperand(params[1])
+ local mode, imm = a.mode, a.imm
+ if type(imm) == "number" and (mode == "iJ" or (imm >= 1 and imm <= 9)) then
+ -- Local label (1: ... 9:) or global label (->global:).
+ waction("LABEL_LG", nil, 1)
+ wputxb(imm)
+ elseif mode == "iJ" then
+ -- PC label (=>pcexpr:).
+ waction("LABEL_PC", imm)
+ else
+ werror("bad label definition")
+ end
+ -- SETLABEL must immediately follow LABEL_LG/LABEL_PC.
+ local addr = params[2]
+ if addr then
+ local a = parseoperand(addr)
+ if a.mode == "iPJ" then
+ waction("SETLABEL", a.imm)
+ else
+ werror("bad label assignment")
+ end
+ end
+end
+map_op[".label_1"] = map_op[".label_2"]
+
+------------------------------------------------------------------------------
+
+-- Alignment pseudo-opcode.
+map_op[".align_1"] = function(params)
+ if not params then return "numpow2" end
+ if secpos+1 > maxsecpos then wflush() end
+ local align = tonumber(params[1]) or map_opsizenum[map_opsize[params[1]]]
+ if align then
+ local x = align
+ -- Must be a power of 2 in the range (2 ... 256).
+ for i=1,8 do
+ x = x / 2
+ if x == 1 then
+ waction("ALIGN", nil, 1)
+ wputxb(align-1) -- Action byte is 2**n-1.
+ return
+ end
+ end
+ end
+ werror("bad alignment")
+end
+
+-- Spacing pseudo-opcode.
+map_op[".space_2"] = function(params)
+ if not params then return "num [, filler]" end
+ if secpos+1 > maxsecpos then wflush() end
+ waction("SPACE", params[1])
+ local fill = params[2]
+ if fill then
+ fill = tonumber(fill)
+ if not fill or fill < 0 or fill > 255 then werror("bad filler") end
+ end
+ wputxb(fill or 0)
+end
+map_op[".space_1"] = map_op[".space_2"]
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode for (primitive) type definitions (map to C types).
+map_op[".type_3"] = function(params, nparams)
+ if not params then
+ return nparams == 2 and "name, ctype" or "name, ctype, reg"
+ end
+ local name, ctype, reg = params[1], params[2], params[3]
+ if not match(name, "^[%a_][%w_]*$") then
+ werror("bad type name `"..name.."'")
+ end
+ local tp = map_type[name]
+ if tp then
+ werror("duplicate type `"..name.."'")
+ end
+ if reg and not map_reg_valid_base[reg] then
+ werror("bad base register `"..(map_reg_rev[reg] or reg).."'")
+ end
+ -- Add #type to defines. A bit unclean to put it in map_archdef.
+ map_archdef["#"..name] = "sizeof("..ctype..")"
+ -- Add new type and emit shortcut define.
+ local num = ctypenum + 1
+ map_type[name] = {
+ ctype = ctype,
+ ctypefmt = format("Dt%X(%%s)", num),
+ reg = reg,
+ }
+ wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
+ ctypenum = num
+end
+map_op[".type_2"] = map_op[".type_3"]
+
+-- Dump type definitions.
+local function dumptypes(out, lvl)
+ local t = {}
+ for name in pairs(map_type) do t[#t+1] = name end
+ sort(t)
+ out:write("Type definitions:\n")
+ for _,name in ipairs(t) do
+ local tp = map_type[name]
+ local reg = tp.reg and map_reg_rev[tp.reg] or ""
+ out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
+ end
+ out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Set the current section.
+function _M.section(num)
+ waction("SECTION")
+ wputxb(num)
+ wflush(true) -- SECTION is a terminal action.
+end
+
+------------------------------------------------------------------------------
+
+-- Dump architecture description.
+function _M.dumparch(out)
+ out:write(format("DynASM %s version %s, released %s\n\n",
+ _info.arch, _info.version, _info.release))
+ dumpregs(out)
+ dumpactions(out)
+end
+
+-- Dump all user defined elements.
+function _M.dumpdef(out, lvl)
+ dumptypes(out, lvl)
+ dumpglobals(out, lvl)
+ dumpexterns(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Pass callbacks from/to the DynASM core.
+function _M.passcb(wl, we, wf, ww)
+ wline, werror, wfatal, wwarn = wl, we, wf, ww
+ return wflush
+end
+
+-- Setup the arch-specific module.
+function _M.setup(arch, opt)
+ g_arch, g_opt = arch, opt
+end
+
+-- Merge the core maps and the arch-specific maps.
+function _M.mergemaps(map_coreop, map_def)
+ setmetatable(map_op, { __index = map_coreop })
+ setmetatable(map_def, { __index = map_archdef })
+ return map_op, map_def
+end
+
+return _M
+
+------------------------------------------------------------------------------
+
diff --git a/src/host/luajit-2.1.0-beta3/dynasm/dynasm.lua b/src/host/luajit-2.1.0-beta3/dynasm/dynasm.lua
new file mode 100644
index 00000000..5ec21a79
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/dynasm/dynasm.lua
@@ -0,0 +1,1094 @@
+------------------------------------------------------------------------------
+-- DynASM. A dynamic assembler for code generation engines.
+-- Originally designed and implemented for LuaJIT.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- See below for full copyright notice.
+------------------------------------------------------------------------------
+
+-- Application information.
+local _info = {
+ name = "DynASM",
+ description = "A dynamic assembler for code generation engines",
+ version = "1.4.0",
+ vernum = 10400,
+ release = "2015-10-18",
+ author = "Mike Pall",
+ url = "http://luajit.org/dynasm.html",
+ license = "MIT",
+ copyright = [[
+Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+[ MIT license: http://www.opensource.org/licenses/mit-license.php ]
+]],
+}
+
+-- Cache library functions.
+local type, pairs, ipairs = type, pairs, ipairs
+local pcall, error, assert = pcall, error, assert
+local _s = string
+local sub, match, gmatch, gsub = _s.sub, _s.match, _s.gmatch, _s.gsub
+local format, rep, upper = _s.format, _s.rep, _s.upper
+local _t = table
+local insert, remove, concat, sort = _t.insert, _t.remove, _t.concat, _t.sort
+local exit = os.exit
+local io = io
+local stdin, stdout, stderr = io.stdin, io.stdout, io.stderr
+
+------------------------------------------------------------------------------
+
+-- Program options.
+local g_opt = {}
+
+-- Global state for current file.
+local g_fname, g_curline, g_indent, g_lineno, g_synclineno, g_arch
+local g_errcount = 0
+
+-- Write buffer for output file.
+local g_wbuffer, g_capbuffer
+
+------------------------------------------------------------------------------
+
+-- Write an output line (or callback function) to the buffer.
+local function wline(line, needindent)
+ local buf = g_capbuffer or g_wbuffer
+ buf[#buf+1] = needindent and g_indent..line or line
+ g_synclineno = g_synclineno + 1
+end
+
+-- Write assembler line as a comment, if requestd.
+local function wcomment(aline)
+ if g_opt.comment then
+ wline(g_opt.comment..aline..g_opt.endcomment, true)
+ end
+end
+
+-- Resync CPP line numbers.
+local function wsync()
+ if g_synclineno ~= g_lineno and g_opt.cpp then
+ wline("#line "..g_lineno..' "'..g_fname..'"')
+ g_synclineno = g_lineno
+ end
+end
+
+-- Dummy action flush function. Replaced with arch-specific function later.
+local function wflush(term)
+end
+
+-- Dump all buffered output lines.
+local function wdumplines(out, buf)
+ for _,line in ipairs(buf) do
+ if type(line) == "string" then
+ assert(out:write(line, "\n"))
+ else
+ -- Special callback to dynamically insert lines after end of processing.
+ line(out)
+ end
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Emit an error. Processing continues with next statement.
+local function werror(msg)
+ error(format("%s:%s: error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0)
+end
+
+-- Emit a fatal error. Processing stops.
+local function wfatal(msg)
+ g_errcount = "fatal"
+ werror(msg)
+end
+
+-- Print a warning. Processing continues.
+local function wwarn(msg)
+ stderr:write(format("%s:%s: warning: %s:\n%s\n",
+ g_fname, g_lineno, msg, g_curline))
+end
+
+-- Print caught error message. But suppress excessive errors.
+local function wprinterr(...)
+ if type(g_errcount) == "number" then
+ -- Regular error.
+ g_errcount = g_errcount + 1
+ if g_errcount < 21 then -- Seems to be a reasonable limit.
+ stderr:write(...)
+ elseif g_errcount == 21 then
+ stderr:write(g_fname,
+ ":*: warning: too many errors (suppressed further messages).\n")
+ end
+ else
+ -- Fatal error.
+ stderr:write(...)
+ return true -- Stop processing.
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Map holding all option handlers.
+local opt_map = {}
+local opt_current
+
+-- Print error and exit with error status.
+local function opterror(...)
+ stderr:write("dynasm.lua: ERROR: ", ...)
+ stderr:write("\n")
+ exit(1)
+end
+
+-- Get option parameter.
+local function optparam(args)
+ local argn = args.argn
+ local p = args[argn]
+ if not p then
+ opterror("missing parameter for option `", opt_current, "'.")
+ end
+ args.argn = argn + 1
+ return p
+end
+
+------------------------------------------------------------------------------
+
+-- Core pseudo-opcodes.
+local map_coreop = {}
+-- Dummy opcode map. Replaced by arch-specific map.
+local map_op = {}
+
+-- Forward declarations.
+local dostmt
+local readfile
+
+------------------------------------------------------------------------------
+
+-- Map for defines (initially empty, chains to arch-specific map).
+local map_def = {}
+
+-- Pseudo-opcode to define a substitution.
+map_coreop[".define_2"] = function(params, nparams)
+ if not params then return nparams == 1 and "name" or "name, subst" end
+ local name, def = params[1], params[2] or "1"
+ if not match(name, "^[%a_][%w_]*$") then werror("bad or duplicate define") end
+ map_def[name] = def
+end
+map_coreop[".define_1"] = map_coreop[".define_2"]
+
+-- Define a substitution on the command line.
+function opt_map.D(args)
+ local namesubst = optparam(args)
+ local name, subst = match(namesubst, "^([%a_][%w_]*)=(.*)$")
+ if name then
+ map_def[name] = subst
+ elseif match(namesubst, "^[%a_][%w_]*$") then
+ map_def[namesubst] = "1"
+ else
+ opterror("bad define")
+ end
+end
+
+-- Undefine a substitution on the command line.
+function opt_map.U(args)
+ local name = optparam(args)
+ if match(name, "^[%a_][%w_]*$") then
+ map_def[name] = nil
+ else
+ opterror("bad define")
+ end
+end
+
+-- Helper for definesubst.
+local gotsubst
+
+local function definesubst_one(word)
+ local subst = map_def[word]
+ if subst then gotsubst = word; return subst else return word end
+end
+
+-- Iteratively substitute defines.
+local function definesubst(stmt)
+ -- Limit number of iterations.
+ for i=1,100 do
+ gotsubst = false
+ stmt = gsub(stmt, "#?[%w_]+", definesubst_one)
+ if not gotsubst then break end
+ end
+ if gotsubst then wfatal("recursive define involving `"..gotsubst.."'") end
+ return stmt
+end
+
+-- Dump all defines.
+local function dumpdefines(out, lvl)
+ local t = {}
+ for name in pairs(map_def) do
+ t[#t+1] = name
+ end
+ sort(t)
+ out:write("Defines:\n")
+ for _,name in ipairs(t) do
+ local subst = map_def[name]
+ if g_arch then subst = g_arch.revdef(subst) end
+ out:write(format(" %-20s %s\n", name, subst))
+ end
+ out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Support variables for conditional assembly.
+local condlevel = 0
+local condstack = {}
+
+-- Evaluate condition with a Lua expression. Substitutions already performed.
+local function cond_eval(cond)
+ local func, err
+ if setfenv then
+ func, err = loadstring("return "..cond, "=expr")
+ else
+ -- No globals. All unknown identifiers evaluate to nil.
+ func, err = load("return "..cond, "=expr", "t", {})
+ end
+ if func then
+ if setfenv then
+ setfenv(func, {}) -- No globals. All unknown identifiers evaluate to nil.
+ end
+ local ok, res = pcall(func)
+ if ok then
+ if res == 0 then return false end -- Oh well.
+ return not not res
+ end
+ err = res
+ end
+ wfatal("bad condition: "..err)
+end
+
+-- Skip statements until next conditional pseudo-opcode at the same level.
+local function stmtskip()
+ local dostmt_save = dostmt
+ local lvl = 0
+ dostmt = function(stmt)
+ local op = match(stmt, "^%s*(%S+)")
+ if op == ".if" then
+ lvl = lvl + 1
+ elseif lvl ~= 0 then
+ if op == ".endif" then lvl = lvl - 1 end
+ elseif op == ".elif" or op == ".else" or op == ".endif" then
+ dostmt = dostmt_save
+ dostmt(stmt)
+ end
+ end
+end
+
+-- Pseudo-opcodes for conditional assembly.
+map_coreop[".if_1"] = function(params)
+ if not params then return "condition" end
+ local lvl = condlevel + 1
+ local res = cond_eval(params[1])
+ condlevel = lvl
+ condstack[lvl] = res
+ if not res then stmtskip() end
+end
+
+map_coreop[".elif_1"] = function(params)
+ if not params then return "condition" end
+ if condlevel == 0 then wfatal(".elif without .if") end
+ local lvl = condlevel
+ local res = condstack[lvl]
+ if res then
+ if res == "else" then wfatal(".elif after .else") end
+ else
+ res = cond_eval(params[1])
+ if res then
+ condstack[lvl] = res
+ return
+ end
+ end
+ stmtskip()
+end
+
+map_coreop[".else_0"] = function(params)
+ if condlevel == 0 then wfatal(".else without .if") end
+ local lvl = condlevel
+ local res = condstack[lvl]
+ condstack[lvl] = "else"
+ if res then
+ if res == "else" then wfatal(".else after .else") end
+ stmtskip()
+ end
+end
+
+map_coreop[".endif_0"] = function(params)
+ local lvl = condlevel
+ if lvl == 0 then wfatal(".endif without .if") end
+ condlevel = lvl - 1
+end
+
+-- Check for unfinished conditionals.
+local function checkconds()
+ if g_errcount ~= "fatal" and condlevel ~= 0 then
+ wprinterr(g_fname, ":*: error: unbalanced conditional\n")
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Search for a file in the given path and open it for reading.
+local function pathopen(path, name)
+ local dirsep = package and match(package.path, "\\") and "\\" or "/"
+ for _,p in ipairs(path) do
+ local fullname = p == "" and name or p..dirsep..name
+ local fin = io.open(fullname, "r")
+ if fin then
+ g_fname = fullname
+ return fin
+ end
+ end
+end
+
+-- Include a file.
+map_coreop[".include_1"] = function(params)
+ if not params then return "filename" end
+ local name = params[1]
+ -- Save state. Ugly, I know. but upvalues are fast.
+ local gf, gl, gcl, gi = g_fname, g_lineno, g_curline, g_indent
+ -- Read the included file.
+ local fatal = readfile(pathopen(g_opt.include, name) or
+ wfatal("include file `"..name.."' not found"))
+ -- Restore state.
+ g_synclineno = -1
+ g_fname, g_lineno, g_curline, g_indent = gf, gl, gcl, gi
+ if fatal then wfatal("in include file") end
+end
+
+-- Make .include and conditionals initially available, too.
+map_op[".include_1"] = map_coreop[".include_1"]
+map_op[".if_1"] = map_coreop[".if_1"]
+map_op[".elif_1"] = map_coreop[".elif_1"]
+map_op[".else_0"] = map_coreop[".else_0"]
+map_op[".endif_0"] = map_coreop[".endif_0"]
+
+------------------------------------------------------------------------------
+
+-- Support variables for macros.
+local mac_capture, mac_lineno, mac_name
+local mac_active = {}
+local mac_list = {}
+
+-- Pseudo-opcode to define a macro.
+map_coreop[".macro_*"] = function(mparams)
+ if not mparams then return "name [, params...]" end
+ -- Split off and validate macro name.
+ local name = remove(mparams, 1)
+ if not name then werror("missing macro name") end
+ if not (match(name, "^[%a_][%w_%.]*$") or match(name, "^%.[%w_%.]*$")) then
+ wfatal("bad macro name `"..name.."'")
+ end
+ -- Validate macro parameter names.
+ local mdup = {}
+ for _,mp in ipairs(mparams) do
+ if not match(mp, "^[%a_][%w_]*$") then
+ wfatal("bad macro parameter name `"..mp.."'")
+ end
+ if mdup[mp] then wfatal("duplicate macro parameter name `"..mp.."'") end
+ mdup[mp] = true
+ end
+ -- Check for duplicate or recursive macro definitions.
+ local opname = name.."_"..#mparams
+ if map_op[opname] or map_op[name.."_*"] then
+ wfatal("duplicate macro `"..name.."' ("..#mparams.." parameters)")
+ end
+ if mac_capture then wfatal("recursive macro definition") end
+
+ -- Enable statement capture.
+ local lines = {}
+ mac_lineno = g_lineno
+ mac_name = name
+ mac_capture = function(stmt) -- Statement capture function.
+ -- Stop macro definition with .endmacro pseudo-opcode.
+ if not match(stmt, "^%s*.endmacro%s*$") then
+ lines[#lines+1] = stmt
+ return
+ end
+ mac_capture = nil
+ mac_lineno = nil
+ mac_name = nil
+ mac_list[#mac_list+1] = opname
+ -- Add macro-op definition.
+ map_op[opname] = function(params)
+ if not params then return mparams, lines end
+ -- Protect against recursive macro invocation.
+ if mac_active[opname] then wfatal("recursive macro invocation") end
+ mac_active[opname] = true
+ -- Setup substitution map.
+ local subst = {}
+ for i,mp in ipairs(mparams) do subst[mp] = params[i] end
+ local mcom
+ if g_opt.maccomment and g_opt.comment then
+ mcom = " MACRO "..name.." ("..#mparams..")"
+ wcomment("{"..mcom)
+ end
+ -- Loop through all captured statements
+ for _,stmt in ipairs(lines) do
+ -- Substitute macro parameters.
+ local st = gsub(stmt, "[%w_]+", subst)
+ st = definesubst(st)
+ st = gsub(st, "%s*%.%.%s*", "") -- Token paste a..b.
+ if mcom and sub(st, 1, 1) ~= "|" then wcomment(st) end
+ -- Emit statement. Use a protected call for better diagnostics.
+ local ok, err = pcall(dostmt, st)
+ if not ok then
+ -- Add the captured statement to the error.
+ wprinterr(err, "\n", g_indent, "| ", stmt,
+ "\t[MACRO ", name, " (", #mparams, ")]\n")
+ end
+ end
+ if mcom then wcomment("}"..mcom) end
+ mac_active[opname] = nil
+ end
+ end
+end
+
+-- An .endmacro pseudo-opcode outside of a macro definition is an error.
+map_coreop[".endmacro_0"] = function(params)
+ wfatal(".endmacro without .macro")
+end
+
+-- Dump all macros and their contents (with -PP only).
+local function dumpmacros(out, lvl)
+ sort(mac_list)
+ out:write("Macros:\n")
+ for _,opname in ipairs(mac_list) do
+ local name = sub(opname, 1, -3)
+ local params, lines = map_op[opname]()
+ out:write(format(" %-20s %s\n", name, concat(params, ", ")))
+ if lvl > 1 then
+ for _,line in ipairs(lines) do
+ out:write(" |", line, "\n")
+ end
+ out:write("\n")
+ end
+ end
+ out:write("\n")
+end
+
+-- Check for unfinished macro definitions.
+local function checkmacros()
+ if mac_capture then
+ wprinterr(g_fname, ":", mac_lineno,
+ ": error: unfinished .macro `", mac_name ,"'\n")
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Support variables for captures.
+local cap_lineno, cap_name
+local cap_buffers = {}
+local cap_used = {}
+
+-- Start a capture.
+map_coreop[".capture_1"] = function(params)
+ if not params then return "name" end
+ wflush()
+ local name = params[1]
+ if not match(name, "^[%a_][%w_]*$") then
+ wfatal("bad capture name `"..name.."'")
+ end
+ if cap_name then
+ wfatal("already capturing to `"..cap_name.."' since line "..cap_lineno)
+ end
+ cap_name = name
+ cap_lineno = g_lineno
+ -- Create or continue a capture buffer and start the output line capture.
+ local buf = cap_buffers[name]
+ if not buf then buf = {}; cap_buffers[name] = buf end
+ g_capbuffer = buf
+ g_synclineno = 0
+end
+
+-- Stop a capture.
+map_coreop[".endcapture_0"] = function(params)
+ wflush()
+ if not cap_name then wfatal(".endcapture without a valid .capture") end
+ cap_name = nil
+ cap_lineno = nil
+ g_capbuffer = nil
+ g_synclineno = 0
+end
+
+-- Dump a capture buffer.
+map_coreop[".dumpcapture_1"] = function(params)
+ if not params then return "name" end
+ wflush()
+ local name = params[1]
+ if not match(name, "^[%a_][%w_]*$") then
+ wfatal("bad capture name `"..name.."'")
+ end
+ cap_used[name] = true
+ wline(function(out)
+ local buf = cap_buffers[name]
+ if buf then wdumplines(out, buf) end
+ end)
+ g_synclineno = 0
+end
+
+-- Dump all captures and their buffers (with -PP only).
+local function dumpcaptures(out, lvl)
+ out:write("Captures:\n")
+ for name,buf in pairs(cap_buffers) do
+ out:write(format(" %-20s %4s)\n", name, "("..#buf))
+ if lvl > 1 then
+ local bar = rep("=", 76)
+ out:write(" ", bar, "\n")
+ for _,line in ipairs(buf) do
+ out:write(" ", line, "\n")
+ end
+ out:write(" ", bar, "\n\n")
+ end
+ end
+ out:write("\n")
+end
+
+-- Check for unfinished or unused captures.
+local function checkcaptures()
+ if cap_name then
+ wprinterr(g_fname, ":", cap_lineno,
+ ": error: unfinished .capture `", cap_name,"'\n")
+ return
+ end
+ for name in pairs(cap_buffers) do
+ if not cap_used[name] then
+ wprinterr(g_fname, ":*: error: missing .dumpcapture ", name ,"\n")
+ end
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Sections names.
+local map_sections = {}
+
+-- Pseudo-opcode to define code sections.
+-- TODO: Data sections, BSS sections. Needs extra C code and API.
+map_coreop[".section_*"] = function(params)
+ if not params then return "name..." end
+ if #map_sections > 0 then werror("duplicate section definition") end
+ wflush()
+ for sn,name in ipairs(params) do
+ local opname = "."..name.."_0"
+ if not match(name, "^[%a][%w_]*$") or
+ map_op[opname] or map_op["."..name.."_*"] then
+ werror("bad section name `"..name.."'")
+ end
+ map_sections[#map_sections+1] = name
+ wline(format("#define DASM_SECTION_%s\t%d", upper(name), sn-1))
+ map_op[opname] = function(params) g_arch.section(sn-1) end
+ end
+ wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections))
+end
+
+-- Dump all sections.
+local function dumpsections(out, lvl)
+ out:write("Sections:\n")
+ for _,name in ipairs(map_sections) do
+ out:write(format(" %s\n", name))
+ end
+ out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Replacement for customized Lua, which lacks the package library.
+local prefix = ""
+if not require then
+ function require(name)
+ local fp = assert(io.open(prefix..name..".lua"))
+ local s = fp:read("*a")
+ assert(fp:close())
+ return assert(loadstring(s, "@"..name..".lua"))()
+ end
+end
+
+-- Load architecture-specific module.
+local function loadarch(arch)
+ if not match(arch, "^[%w_]+$") then return "bad arch name" end
+ local ok, m_arch = pcall(require, "dasm_"..arch)
+ if not ok then return "cannot load module: "..m_arch end
+ g_arch = m_arch
+ wflush = m_arch.passcb(wline, werror, wfatal, wwarn)
+ m_arch.setup(arch, g_opt)
+ map_op, map_def = m_arch.mergemaps(map_coreop, map_def)
+end
+
+-- Dump architecture description.
+function opt_map.dumparch(args)
+ local name = optparam(args)
+ if not g_arch then
+ local err = loadarch(name)
+ if err then opterror(err) end
+ end
+
+ local t = {}
+ for name in pairs(map_coreop) do t[#t+1] = name end
+ for name in pairs(map_op) do t[#t+1] = name end
+ sort(t)
+
+ local out = stdout
+ local _arch = g_arch._info
+ out:write(format("%s version %s, released %s, %s\n",
+ _info.name, _info.version, _info.release, _info.url))
+ g_arch.dumparch(out)
+
+ local pseudo = true
+ out:write("Pseudo-Opcodes:\n")
+ for _,sname in ipairs(t) do
+ local name, nparam = match(sname, "^(.+)_([0-9%*])$")
+ if name then
+ if pseudo and sub(name, 1, 1) ~= "." then
+ out:write("\nOpcodes:\n")
+ pseudo = false
+ end
+ local f = map_op[sname]
+ local s
+ if nparam ~= "*" then nparam = nparam + 0 end
+ if nparam == 0 then
+ s = ""
+ elseif type(f) == "string" then
+ s = map_op[".template__"](nil, f, nparam)
+ else
+ s = f(nil, nparam)
+ end
+ if type(s) == "table" then
+ for _,s2 in ipairs(s) do
+ out:write(format(" %-12s %s\n", name, s2))
+ end
+ else
+ out:write(format(" %-12s %s\n", name, s))
+ end
+ end
+ end
+ out:write("\n")
+ exit(0)
+end
+
+-- Pseudo-opcode to set the architecture.
+-- Only initially available (map_op is replaced when called).
+map_op[".arch_1"] = function(params)
+ if not params then return "name" end
+ local err = loadarch(params[1])
+ if err then wfatal(err) end
+ wline(format("#if DASM_VERSION != %d", _info.vernum))
+ wline('#error "Version mismatch between DynASM and included encoding engine"')
+ wline("#endif")
+end
+
+-- Dummy .arch pseudo-opcode to improve the error report.
+map_coreop[".arch_1"] = function(params)
+ if not params then return "name" end
+ wfatal("duplicate .arch statement")
+end
+
+------------------------------------------------------------------------------
+
+-- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'.
+map_coreop[".nop_*"] = function(params)
+ if not params then return "[ignored...]" end
+end
+
+-- Pseudo-opcodes to raise errors.
+map_coreop[".error_1"] = function(params)
+ if not params then return "message" end
+ werror(params[1])
+end
+
+map_coreop[".fatal_1"] = function(params)
+ if not params then return "message" end
+ wfatal(params[1])
+end
+
+-- Dump all user defined elements.
+local function dumpdef(out)
+ local lvl = g_opt.dumpdef
+ if lvl == 0 then return end
+ dumpsections(out, lvl)
+ dumpdefines(out, lvl)
+ if g_arch then g_arch.dumpdef(out, lvl) end
+ dumpmacros(out, lvl)
+ dumpcaptures(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Helper for splitstmt.
+local splitlvl
+
+local function splitstmt_one(c)
+ if c == "(" then
+ splitlvl = ")"..splitlvl
+ elseif c == "[" then
+ splitlvl = "]"..splitlvl
+ elseif c == "{" then
+ splitlvl = "}"..splitlvl
+ elseif c == ")" or c == "]" or c == "}" then
+ if sub(splitlvl, 1, 1) ~= c then werror("unbalanced (), [] or {}") end
+ splitlvl = sub(splitlvl, 2)
+ elseif splitlvl == "" then
+ return " \0 "
+ end
+ return c
+end
+
+-- Split statement into (pseudo-)opcode and params.
+local function splitstmt(stmt)
+ -- Convert label with trailing-colon into .label statement.
+ local label = match(stmt, "^%s*(.+):%s*$")
+ if label then return ".label", {label} end
+
+ -- Split at commas and equal signs, but obey parentheses and brackets.
+ splitlvl = ""
+ stmt = gsub(stmt, "[,%(%)%[%]{}]", splitstmt_one)
+ if splitlvl ~= "" then werror("unbalanced () or []") end
+
+ -- Split off opcode.
+ local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$")
+ if not op then werror("bad statement syntax") end
+
+ -- Split parameters.
+ local params = {}
+ for p in gmatch(other, "%s*(%Z+)%z?") do
+ params[#params+1] = gsub(p, "%s+$", "")
+ end
+ if #params > 16 then werror("too many parameters") end
+
+ params.op = op
+ return op, params
+end
+
+-- Process a single statement.
+dostmt = function(stmt)
+ -- Ignore empty statements.
+ if match(stmt, "^%s*$") then return end
+
+ -- Capture macro defs before substitution.
+ if mac_capture then return mac_capture(stmt) end
+ stmt = definesubst(stmt)
+
+ -- Emit C code without parsing the line.
+ if sub(stmt, 1, 1) == "|" then
+ local tail = sub(stmt, 2)
+ wflush()
+ if sub(tail, 1, 2) == "//" then wcomment(tail) else wline(tail, true) end
+ return
+ end
+
+ -- Split into (pseudo-)opcode and params.
+ local op, params = splitstmt(stmt)
+
+ -- Get opcode handler (matching # of parameters or generic handler).
+ local f = map_op[op.."_"..#params] or map_op[op.."_*"]
+ if not f then
+ if not g_arch then wfatal("first statement must be .arch") end
+ -- Improve error report.
+ for i=0,9 do
+ if map_op[op.."_"..i] then
+ werror("wrong number of parameters for `"..op.."'")
+ end
+ end
+ werror("unknown statement `"..op.."'")
+ end
+
+ -- Call opcode handler or special handler for template strings.
+ if type(f) == "string" then
+ map_op[".template__"](params, f)
+ else
+ f(params)
+ end
+end
+
+-- Process a single line.
+local function doline(line)
+ if g_opt.flushline then wflush() end
+
+ -- Assembler line?
+ local indent, aline = match(line, "^(%s*)%|(.*)$")
+ if not aline then
+ -- No, plain C code line, need to flush first.
+ wflush()
+ wsync()
+ wline(line, false)
+ return
+ end
+
+ g_indent = indent -- Remember current line indentation.
+
+ -- Emit C code (even from macros). Avoids echo and line parsing.
+ if sub(aline, 1, 1) == "|" then
+ if not mac_capture then
+ wsync()
+ elseif g_opt.comment then
+ wsync()
+ wcomment(aline)
+ end
+ dostmt(aline)
+ return
+ end
+
+ -- Echo assembler line as a comment.
+ if g_opt.comment then
+ wsync()
+ wcomment(aline)
+ end
+
+ -- Strip assembler comments.
+ aline = gsub(aline, "//.*$", "")
+
+ -- Split line into statements at semicolons.
+ if match(aline, ";") then
+ for stmt in gmatch(aline, "[^;]+") do dostmt(stmt) end
+ else
+ dostmt(aline)
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Write DynASM header.
+local function dasmhead(out)
+ out:write(format([[
+/*
+** This file has been pre-processed with DynASM.
+** %s
+** DynASM version %s, DynASM %s version %s
+** DO NOT EDIT! The original file is in "%s".
+*/
+
+]], _info.url,
+ _info.version, g_arch._info.arch, g_arch._info.version,
+ g_fname))
+end
+
+-- Read input file.
+readfile = function(fin)
+ g_indent = ""
+ g_lineno = 0
+ g_synclineno = -1
+
+ -- Process all lines.
+ for line in fin:lines() do
+ g_lineno = g_lineno + 1
+ g_curline = line
+ local ok, err = pcall(doline, line)
+ if not ok and wprinterr(err, "\n") then return true end
+ end
+ wflush()
+
+ -- Close input file.
+ assert(fin == stdin or fin:close())
+end
+
+-- Write output file.
+local function writefile(outfile)
+ local fout
+
+ -- Open output file.
+ if outfile == nil or outfile == "-" then
+ fout = stdout
+ else
+ fout = assert(io.open(outfile, "w"))
+ end
+
+ -- Write all buffered lines
+ wdumplines(fout, g_wbuffer)
+
+ -- Close output file.
+ assert(fout == stdout or fout:close())
+
+ -- Optionally dump definitions.
+ dumpdef(fout == stdout and stderr or stdout)
+end
+
+-- Translate an input file to an output file.
+local function translate(infile, outfile)
+ g_wbuffer = {}
+ g_indent = ""
+ g_lineno = 0
+ g_synclineno = -1
+
+ -- Put header.
+ wline(dasmhead)
+
+ -- Read input file.
+ local fin
+ if infile == "-" then
+ g_fname = "(stdin)"
+ fin = stdin
+ else
+ g_fname = infile
+ fin = assert(io.open(infile, "r"))
+ end
+ readfile(fin)
+
+ -- Check for errors.
+ if not g_arch then
+ wprinterr(g_fname, ":*: error: missing .arch directive\n")
+ end
+ checkconds()
+ checkmacros()
+ checkcaptures()
+
+ if g_errcount ~= 0 then
+ stderr:write(g_fname, ":*: info: ", g_errcount, " error",
+ (type(g_errcount) == "number" and g_errcount > 1) and "s" or "",
+ " in input file -- no output file generated.\n")
+ dumpdef(stderr)
+ exit(1)
+ end
+
+ -- Write output file.
+ writefile(outfile)
+end
+
+------------------------------------------------------------------------------
+
+-- Print help text.
+function opt_map.help()
+ stdout:write("DynASM -- ", _info.description, ".\n")
+ stdout:write("DynASM ", _info.version, " ", _info.release, " ", _info.url, "\n")
+ stdout:write[[
+
+Usage: dynasm [OPTION]... INFILE.dasc|-
+
+ -h, --help Display this help text.
+ -V, --version Display version and copyright information.
+
+ -o, --outfile FILE Output file name (default is stdout).
+ -I, --include DIR Add directory to the include search path.
+
+ -c, --ccomment Use /* */ comments for assembler lines.
+ -C, --cppcomment Use // comments for assembler lines (default).
+ -N, --nocomment Suppress assembler lines in output.
+ -M, --maccomment Show macro expansions as comments (default off).
+
+ -L, --nolineno Suppress CPP line number information in output.
+ -F, --flushline Flush action list for every line.
+
+ -D NAME[=SUBST] Define a substitution.
+ -U NAME Undefine a substitution.
+
+ -P, --dumpdef Dump defines, macros, etc. Repeat for more output.
+ -A, --dumparch ARCH Load architecture ARCH and dump description.
+]]
+ exit(0)
+end
+
+-- Print version information.
+function opt_map.version()
+ stdout:write(format("%s version %s, released %s\n%s\n\n%s",
+ _info.name, _info.version, _info.release, _info.url, _info.copyright))
+ exit(0)
+end
+
+-- Misc. options.
+function opt_map.outfile(args) g_opt.outfile = optparam(args) end
+function opt_map.include(args) insert(g_opt.include, 1, optparam(args)) end
+function opt_map.ccomment() g_opt.comment = "/*|"; g_opt.endcomment = " */" end
+function opt_map.cppcomment() g_opt.comment = "//|"; g_opt.endcomment = "" end
+function opt_map.nocomment() g_opt.comment = false end
+function opt_map.maccomment() g_opt.maccomment = true end
+function opt_map.nolineno() g_opt.cpp = false end
+function opt_map.flushline() g_opt.flushline = true end
+function opt_map.dumpdef() g_opt.dumpdef = g_opt.dumpdef + 1 end
+
+------------------------------------------------------------------------------
+
+-- Short aliases for long options.
+local opt_alias = {
+ h = "help", ["?"] = "help", V = "version",
+ o = "outfile", I = "include",
+ c = "ccomment", C = "cppcomment", N = "nocomment", M = "maccomment",
+ L = "nolineno", F = "flushline",
+ P = "dumpdef", A = "dumparch",
+}
+
+-- Parse single option.
+local function parseopt(opt, args)
+ opt_current = #opt == 1 and "-"..opt or "--"..opt
+ local f = opt_map[opt] or opt_map[opt_alias[opt]]
+ if not f then
+ opterror("unrecognized option `", opt_current, "'. Try `--help'.\n")
+ end
+ f(args)
+end
+
+-- Parse arguments.
+local function parseargs(args)
+ -- Default options.
+ g_opt.comment = "//|"
+ g_opt.endcomment = ""
+ g_opt.cpp = true
+ g_opt.dumpdef = 0
+ g_opt.include = { "" }
+
+ -- Process all option arguments.
+ args.argn = 1
+ repeat
+ local a = args[args.argn]
+ if not a then break end
+ local lopt, opt = match(a, "^%-(%-?)(.+)")
+ if not opt then break end
+ args.argn = args.argn + 1
+ if lopt == "" then
+ -- Loop through short options.
+ for o in gmatch(opt, ".") do parseopt(o, args) end
+ else
+ -- Long option.
+ parseopt(opt, args)
+ end
+ until false
+
+ -- Check for proper number of arguments.
+ local nargs = #args - args.argn + 1
+ if nargs ~= 1 then
+ if nargs == 0 then
+ if g_opt.dumpdef > 0 then return dumpdef(stdout) end
+ end
+ opt_map.help()
+ end
+
+ -- Translate a single input file to a single output file
+ -- TODO: Handle multiple files?
+ translate(args[args.argn], g_opt.outfile)
+end
+
+------------------------------------------------------------------------------
+
+-- Add the directory dynasm.lua resides in to the Lua module search path.
+local arg = arg
+if arg and arg[0] then
+ prefix = match(arg[0], "^(.*[/\\])")
+ if package and prefix then package.path = prefix.."?.lua;"..package.path end
+end
+
+-- Start DynASM.
+parseargs{...}
+
+------------------------------------------------------------------------------
+
diff --git a/src/host/luajit-2.1.0-beta3/etc/luajit.1 b/src/host/luajit-2.1.0-beta3/etc/luajit.1
new file mode 100644
index 00000000..0d263db7
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/etc/luajit.1
@@ -0,0 +1,88 @@
+.TH luajit 1 "" "" "LuaJIT documentation"
+.SH NAME
+luajit \- Just-In-Time Compiler for the Lua Language
+\fB
+.SH SYNOPSIS
+.B luajit
+[\fIoptions\fR]... [\fIscript\fR [\fIargs\fR]...]
+.SH "WEB SITE"
+.IR http://luajit.org
+.SH DESCRIPTION
+.PP
+This is the command-line program to run Lua programs with \fBLuaJIT\fR.
+.PP
+\fBLuaJIT\fR is a just-in-time (JIT) compiler for the Lua language.
+The virtual machine (VM) is based on a fast interpreter combined with
+a trace compiler. It can significantly improve the performance of Lua programs.
+.PP
+\fBLuaJIT\fR is API\- and ABI-compatible with the VM of the standard
+Lua\ 5.1 interpreter. When embedding the VM into an application,
+the built library can be used as a drop-in replacement.
+.SH OPTIONS
+.TP
+.BI "\-e " chunk
+Run the given chunk of Lua code.
+.TP
+.BI "\-l " library
+Load the named library, just like \fBrequire("\fR\fIlibrary\fR\fB")\fR.
+.TP
+.BI "\-b " ...
+Save or list bytecode. Run without arguments to get help on options.
+.TP
+.BI "\-j " command
+Perform LuaJIT control command (optional space after \fB\-j\fR).
+.TP
+.BI "\-O" [opt]
+Control LuaJIT optimizations.
+.TP
+.B "\-i"
+Run in interactive mode.
+.TP
+.B "\-v"
+Show \fBLuaJIT\fR version.
+.TP
+.B "\-E"
+Ignore environment variables.
+.TP
+.B "\-\-"
+Stop processing options.
+.TP
+.B "\-"
+Read script from stdin instead.
+.PP
+After all options are processed, the given \fIscript\fR is run.
+The arguments are passed in the global \fIarg\fR table.
+.PP
+Interactive mode is only entered, if no \fIscript\fR and no \fB\-e\fR
+option is given. Interactive mode can be left with EOF (\fICtrl\-Z\fB).
+.SH EXAMPLES
+.TP
+luajit hello.lua world
+
+Prints "Hello world", assuming \fIhello.lua\fR contains:
+.br
+ print("Hello", arg[1])
+.TP
+luajit \-e "local x=0; for i=1,1e9 do x=x+i end; print(x)"
+
+Calculates the sum of the numbers from 1 to 1000000000.
+.br
+And finishes in a reasonable amount of time, too.
+.TP
+luajit \-jv \-e "for i=1,10 do for j=1,10 do for k=1,100 do end end end"
+
+Runs some nested loops and shows the resulting traces.
+.SH COPYRIGHT
+.PP
+\fBLuaJIT\fR is Copyright \(co 2005-2017 Mike Pall.
+.br
+\fBLuaJIT\fR is open source software, released under the MIT license.
+.SH SEE ALSO
+.PP
+More details in the provided HTML docs or at:
+.IR http://luajit.org
+.br
+More about the Lua language can be found at:
+.IR http://lua.org/docs.html
+.PP
+lua(1)
diff --git a/src/host/luajit-2.1.0-beta3/etc/luajit.pc b/src/host/luajit-2.1.0-beta3/etc/luajit.pc
new file mode 100644
index 00000000..a78f1746
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/etc/luajit.pc
@@ -0,0 +1,25 @@
+# Package information for LuaJIT to be used by pkg-config.
+majver=2
+minver=1
+relver=0
+version=${majver}.${minver}.${relver}-beta3
+abiver=5.1
+
+prefix=/usr/local
+multilib=lib
+exec_prefix=${prefix}
+libdir=${exec_prefix}/${multilib}
+libname=luajit-${abiver}
+includedir=${prefix}/include/luajit-${majver}.${minver}
+
+INSTALL_LMOD=${prefix}/share/lua/${abiver}
+INSTALL_CMOD=${prefix}/${multilib}/lua/${abiver}
+
+Name: LuaJIT
+Description: Just-in-time compiler for Lua
+URL: http://luajit.org
+Version: ${version}
+Requires:
+Libs: -L${libdir} -l${libname}
+Libs.private: -Wl,-E -lm -ldl
+Cflags: -I${includedir}
diff --git a/src/host/luajit-2.1.0-beta3/src/Makefile b/src/host/luajit-2.1.0-beta3/src/Makefile
new file mode 100644
index 00000000..f56465d1
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/Makefile
@@ -0,0 +1,716 @@
+##############################################################################
+# LuaJIT Makefile. Requires GNU Make.
+#
+# Please read doc/install.html before changing any variables!
+#
+# Suitable for POSIX platforms (Linux, *BSD, OSX etc.).
+# Also works with MinGW and Cygwin on Windows.
+# Please check msvcbuild.bat for building with MSVC on Windows.
+#
+# Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
+##############################################################################
+
+MAJVER= 2
+MINVER= 1
+RELVER= 0
+ABIVER= 5.1
+NODOTABIVER= 51
+
+##############################################################################
+############################# COMPILER OPTIONS #############################
+##############################################################################
+# These options mainly affect the speed of the JIT compiler itself, not the
+# speed of the JIT-compiled code. Turn any of the optional settings on by
+# removing the '#' in front of them. Make sure you force a full recompile
+# with "make clean", followed by "make" if you change any options.
+#
+DEFAULT_CC = gcc
+#
+# LuaJIT builds as a native 32 or 64 bit binary by default.
+CC= $(DEFAULT_CC)
+#
+# Use this if you want to force a 32 bit build on a 64 bit multilib OS.
+#CC= $(DEFAULT_CC) -m32
+#
+# Since the assembler part does NOT maintain a frame pointer, it's pointless
+# to slow down the C part by not omitting it. Debugging, tracebacks and
+# unwinding are not affected -- the assembler part has frame unwind
+# information and GCC emits it where needed (x64) or with -g (see CCDEBUG).
+CCOPT= -O2 -fomit-frame-pointer
+# Use this if you want to generate a smaller binary (but it's slower):
+#CCOPT= -Os -fomit-frame-pointer
+# Note: it's no longer recommended to use -O3 with GCC 4.x.
+# The I-Cache bloat usually outweighs the benefits from aggressive inlining.
+#
+# Target-specific compiler options:
+#
+# x86/x64 only: For GCC 4.2 or higher and if you don't intend to distribute
+# the binaries to a different machine you could also use: -march=native
+#
+CCOPT_x86= -march=i686 -msse -msse2 -mfpmath=sse
+CCOPT_x64=
+CCOPT_arm=
+CCOPT_arm64=
+CCOPT_ppc=
+CCOPT_mips=
+#
+CCDEBUG=
+# Uncomment the next line to generate debug information:
+#CCDEBUG= -g
+#
+CCWARN= -Wall
+# Uncomment the next line to enable more warnings:
+#CCWARN+= -Wextra -Wdeclaration-after-statement -Wredundant-decls -Wshadow -Wpointer-arith
+#
+##############################################################################
+
+##############################################################################
+################################ BUILD MODE ################################
+##############################################################################
+# The default build mode is mixed mode on POSIX. On Windows this is the same
+# as dynamic mode.
+#
+# Mixed mode creates a static + dynamic library and a statically linked luajit.
+BUILDMODE= mixed
+#
+# Static mode creates a static library and a statically linked luajit.
+#BUILDMODE= static
+#
+# Dynamic mode creates a dynamic library and a dynamically linked luajit.
+# Note: this executable will only run when the library is installed!
+#BUILDMODE= dynamic
+#
+##############################################################################
+
+##############################################################################
+################################# FEATURES #################################
+##############################################################################
+# Enable/disable these features as needed, but make sure you force a full
+# recompile with "make clean", followed by "make".
+XCFLAGS=
+#
+# Permanently disable the FFI extension to reduce the size of the LuaJIT
+# executable. But please consider that the FFI library is compiled-in,
+# but NOT loaded by default. It only allocates any memory, if you actually
+# make use of it.
+#XCFLAGS+= -DLUAJIT_DISABLE_FFI
+#
+# Features from Lua 5.2 that are unlikely to break existing code are
+# enabled by default. Some other features that *might* break some existing
+# code (e.g. __pairs or os.execute() return values) can be enabled here.
+# Note: this does not provide full compatibility with Lua 5.2 at this time.
+#XCFLAGS+= -DLUAJIT_ENABLE_LUA52COMPAT
+#
+# Disable the JIT compiler, i.e. turn LuaJIT into a pure interpreter.
+#XCFLAGS+= -DLUAJIT_DISABLE_JIT
+#
+# Some architectures (e.g. PPC) can use either single-number (1) or
+# dual-number (2) mode. Uncomment one of these lines to override the
+# default mode. Please see LJ_ARCH_NUMMODE in lj_arch.h for details.
+#XCFLAGS+= -DLUAJIT_NUMMODE=1
+#XCFLAGS+= -DLUAJIT_NUMMODE=2
+#
+# Enable GC64 mode for x64.
+#XCFLAGS+= -DLUAJIT_ENABLE_GC64
+#
+##############################################################################
+
+##############################################################################
+############################ DEBUGGING SUPPORT #############################
+##############################################################################
+# Enable these options as needed, but make sure you force a full recompile
+# with "make clean", followed by "make".
+# Note that most of these are NOT suitable for benchmarking or release mode!
+#
+# Use the system provided memory allocator (realloc) instead of the
+# bundled memory allocator. This is slower, but sometimes helpful for
+# debugging. This option cannot be enabled on x64 without GC64, since
+# realloc usually doesn't return addresses in the right address range.
+# OTOH this option is mandatory for Valgrind's memcheck tool on x64 and
+# the only way to get useful results from it for all other architectures.
+#XCFLAGS+= -DLUAJIT_USE_SYSMALLOC
+#
+# This define is required to run LuaJIT under Valgrind. The Valgrind
+# header files must be installed. You should enable debug information, too.
+# Use --suppressions=lj.supp to avoid some false positives.
+#XCFLAGS+= -DLUAJIT_USE_VALGRIND
+#
+# This is the client for the GDB JIT API. GDB 7.0 or higher is required
+# to make use of it. See lj_gdbjit.c for details. Enabling this causes
+# a non-negligible overhead, even when not running under GDB.
+#XCFLAGS+= -DLUAJIT_USE_GDBJIT
+#
+# Turn on assertions for the Lua/C API to debug problems with lua_* calls.
+# This is rather slow -- use only while developing C libraries/embeddings.
+#XCFLAGS+= -DLUA_USE_APICHECK
+#
+# Turn on assertions for the whole LuaJIT VM. This significantly slows down
+# everything. Use only if you suspect a problem with LuaJIT itself.
+#XCFLAGS+= -DLUA_USE_ASSERT
+#
+##############################################################################
+# You probably don't need to change anything below this line!
+##############################################################################
+
+##############################################################################
+# Host system detection.
+##############################################################################
+
+ifeq (Windows,$(findstring Windows,$(OS))$(MSYSTEM)$(TERM))
+ HOST_SYS= Windows
+ HOST_RM= del
+else
+ HOST_SYS:= $(shell uname -s)
+ ifneq (,$(findstring MINGW,$(HOST_SYS)))
+ HOST_SYS= Windows
+ HOST_MSYS= mingw
+ endif
+ ifneq (,$(findstring CYGWIN,$(HOST_SYS)))
+ HOST_SYS= Windows
+ HOST_MSYS= cygwin
+ endif
+endif
+
+##############################################################################
+# Flags and options for host and target.
+##############################################################################
+
+# You can override the following variables at the make command line:
+# CC HOST_CC STATIC_CC DYNAMIC_CC
+# CFLAGS HOST_CFLAGS TARGET_CFLAGS
+# LDFLAGS HOST_LDFLAGS TARGET_LDFLAGS TARGET_SHLDFLAGS
+# LIBS HOST_LIBS TARGET_LIBS
+# CROSS HOST_SYS TARGET_SYS TARGET_FLAGS
+#
+# Cross-compilation examples:
+# make HOST_CC="gcc -m32" CROSS=i586-mingw32msvc- TARGET_SYS=Windows
+# make HOST_CC="gcc -m32" CROSS=powerpc-linux-gnu-
+
+ASOPTIONS= $(CCOPT) $(CCWARN) $(XCFLAGS) $(CFLAGS)
+CCOPTIONS= $(CCDEBUG) $(ASOPTIONS)
+LDOPTIONS= $(CCDEBUG) $(LDFLAGS)
+
+HOST_CC= $(CC)
+HOST_RM= rm -f
+# If left blank, minilua is built and used. You can supply an installed
+# copy of (plain) Lua 5.1 or 5.2, plus Lua BitOp. E.g. with: HOST_LUA=lua
+HOST_LUA=
+
+HOST_XCFLAGS= -I.
+HOST_XLDFLAGS=
+HOST_XLIBS=
+HOST_ACFLAGS= $(CCOPTIONS) $(HOST_XCFLAGS) $(TARGET_ARCH) $(HOST_CFLAGS)
+HOST_ALDFLAGS= $(LDOPTIONS) $(HOST_XLDFLAGS) $(HOST_LDFLAGS)
+HOST_ALIBS= $(HOST_XLIBS) $(LIBS) $(HOST_LIBS)
+
+STATIC_CC = $(CROSS)$(CC)
+DYNAMIC_CC = $(CROSS)$(CC) -fPIC
+TARGET_CC= $(STATIC_CC)
+TARGET_STCC= $(STATIC_CC)
+TARGET_DYNCC= $(DYNAMIC_CC)
+TARGET_LD= $(CROSS)$(CC)
+TARGET_AR= $(CROSS)ar rcus 2>/dev/null
+TARGET_STRIP= $(CROSS)strip
+
+TARGET_LIBPATH= $(or $(PREFIX),/usr/local)/$(or $(MULTILIB),lib)
+TARGET_SONAME= libluajit-$(ABIVER).so.$(MAJVER)
+TARGET_DYLIBNAME= libluajit-$(ABIVER).$(MAJVER).dylib
+TARGET_DYLIBPATH= $(TARGET_LIBPATH)/$(TARGET_DYLIBNAME)
+TARGET_DLLNAME= lua$(NODOTABIVER).dll
+TARGET_XSHLDFLAGS= -shared -fPIC -Wl,-soname,$(TARGET_SONAME)
+TARGET_DYNXLDOPTS=
+
+TARGET_LFSFLAGS= -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+TARGET_XCFLAGS= $(TARGET_LFSFLAGS) -U_FORTIFY_SOURCE
+TARGET_XLDFLAGS=
+TARGET_XLIBS= -lm
+TARGET_TCFLAGS= $(CCOPTIONS) $(TARGET_XCFLAGS) $(TARGET_FLAGS) $(TARGET_CFLAGS)
+TARGET_ACFLAGS= $(CCOPTIONS) $(TARGET_XCFLAGS) $(TARGET_FLAGS) $(TARGET_CFLAGS)
+TARGET_ASFLAGS= $(ASOPTIONS) $(TARGET_XCFLAGS) $(TARGET_FLAGS) $(TARGET_CFLAGS)
+TARGET_ALDFLAGS= $(LDOPTIONS) $(TARGET_XLDFLAGS) $(TARGET_FLAGS) $(TARGET_LDFLAGS)
+TARGET_ASHLDFLAGS= $(LDOPTIONS) $(TARGET_XSHLDFLAGS) $(TARGET_FLAGS) $(TARGET_SHLDFLAGS)
+TARGET_ALIBS= $(TARGET_XLIBS) $(LIBS) $(TARGET_LIBS)
+
+TARGET_TESTARCH=$(shell $(TARGET_CC) $(TARGET_TCFLAGS) -E lj_arch.h -dM)
+ifneq (,$(findstring LJ_TARGET_X64 ,$(TARGET_TESTARCH)))
+ TARGET_LJARCH= x64
+else
+ifneq (,$(findstring LJ_TARGET_X86 ,$(TARGET_TESTARCH)))
+ TARGET_LJARCH= x86
+else
+ifneq (,$(findstring LJ_TARGET_ARM ,$(TARGET_TESTARCH)))
+ TARGET_LJARCH= arm
+else
+ifneq (,$(findstring LJ_TARGET_ARM64 ,$(TARGET_TESTARCH)))
+ ifneq (,$(findstring __AARCH64EB__ ,$(TARGET_TESTARCH)))
+ TARGET_ARCH= -D__AARCH64EB__=1
+ endif
+ TARGET_LJARCH= arm64
+else
+ifneq (,$(findstring LJ_TARGET_PPC ,$(TARGET_TESTARCH)))
+ ifneq (,$(findstring LJ_LE 1,$(TARGET_TESTARCH)))
+ TARGET_ARCH= -DLJ_ARCH_ENDIAN=LUAJIT_LE
+ else
+ TARGET_ARCH= -DLJ_ARCH_ENDIAN=LUAJIT_BE
+ endif
+ TARGET_LJARCH= ppc
+else
+ifneq (,$(findstring LJ_TARGET_MIPS ,$(TARGET_TESTARCH)))
+ ifneq (,$(findstring MIPSEL ,$(TARGET_TESTARCH)))
+ TARGET_ARCH= -D__MIPSEL__=1
+ endif
+ ifneq (,$(findstring LJ_TARGET_MIPS64 ,$(TARGET_TESTARCH)))
+ TARGET_LJARCH= mips64
+ else
+ TARGET_LJARCH= mips
+ endif
+else
+ $(error Unsupported target architecture)
+endif
+endif
+endif
+endif
+endif
+endif
+
+ifneq (,$(findstring LJ_TARGET_PS3 1,$(TARGET_TESTARCH)))
+ TARGET_SYS= PS3
+ TARGET_ARCH+= -D__CELLOS_LV2__
+ TARGET_XCFLAGS+= -DLUAJIT_USE_SYSMALLOC
+ TARGET_XLIBS+= -lpthread
+endif
+
+TARGET_XCFLAGS+= $(CCOPT_$(TARGET_LJARCH))
+TARGET_ARCH+= $(patsubst %,-DLUAJIT_TARGET=LUAJIT_ARCH_%,$(TARGET_LJARCH))
+
+ifneq (,$(PREFIX))
+ifneq (/usr/local,$(PREFIX))
+ TARGET_XCFLAGS+= -DLUA_ROOT=\"$(PREFIX)\"
+ ifneq (/usr,$(PREFIX))
+ TARGET_DYNXLDOPTS= -Wl,-rpath,$(TARGET_LIBPATH)
+ endif
+endif
+endif
+ifneq (,$(MULTILIB))
+ TARGET_XCFLAGS+= -DLUA_MULTILIB=\"$(MULTILIB)\"
+endif
+ifneq (,$(LMULTILIB))
+ TARGET_XCFLAGS+= -DLUA_LMULTILIB=\"$(LMULTILIB)\"
+endif
+
+##############################################################################
+# Target system detection.
+##############################################################################
+
+TARGET_SYS?= $(HOST_SYS)
+ifeq (Windows,$(TARGET_SYS))
+ TARGET_STRIP+= --strip-unneeded
+ TARGET_XSHLDFLAGS= -shared
+ TARGET_DYNXLDOPTS=
+else
+ifeq (,$(shell $(TARGET_CC) -o /dev/null -c -x c /dev/null -fno-stack-protector 2>/dev/null || echo 1))
+ TARGET_XCFLAGS+= -fno-stack-protector
+endif
+ifeq (Darwin,$(TARGET_SYS))
+ ifeq (,$(MACOSX_DEPLOYMENT_TARGET))
+ export MACOSX_DEPLOYMENT_TARGET=10.4
+ endif
+ TARGET_STRIP+= -x
+ TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC
+ TARGET_DYNXLDOPTS=
+ TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER)
+ ifeq (x64,$(TARGET_LJARCH))
+ TARGET_XLDFLAGS+= -pagezero_size 10000 -image_base 100000000
+ TARGET_XSHLDFLAGS+= -image_base 7fff04c4a000
+ endif
+else
+ifeq (iOS,$(TARGET_SYS))
+ TARGET_STRIP+= -x
+ TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC
+ TARGET_DYNXLDOPTS=
+ TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER)
+ ifeq (arm64,$(TARGET_LJARCH))
+ TARGET_XCFLAGS+= -fno-omit-frame-pointer
+ endif
+else
+ ifneq (SunOS,$(TARGET_SYS))
+ ifneq (PS3,$(TARGET_SYS))
+ TARGET_XLDFLAGS+= -Wl,-E
+ endif
+ endif
+ ifeq (Linux,$(TARGET_SYS))
+ TARGET_XLIBS+= -ldl
+ endif
+ ifeq (GNU/kFreeBSD,$(TARGET_SYS))
+ TARGET_XLIBS+= -ldl
+ endif
+endif
+endif
+endif
+
+ifneq ($(HOST_SYS),$(TARGET_SYS))
+ ifeq (Windows,$(TARGET_SYS))
+ HOST_XCFLAGS+= -malign-double -DLUAJIT_OS=LUAJIT_OS_WINDOWS
+ else
+ ifeq (Linux,$(TARGET_SYS))
+ HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_LINUX
+ else
+ ifeq (Darwin,$(TARGET_SYS))
+ HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_OSX
+ else
+ ifeq (iOS,$(TARGET_SYS))
+ HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_OSX
+ else
+ HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_OTHER
+ endif
+ endif
+ endif
+ endif
+endif
+
+ifneq (,$(CCDEBUG))
+ TARGET_STRIP= @:
+endif
+
+##############################################################################
+# Files and pathnames.
+##############################################################################
+
+MINILUA_O= host/minilua.o
+MINILUA_LIBS= -lm
+MINILUA_T= host/minilua
+MINILUA_X= $(MINILUA_T)
+
+ifeq (,$(HOST_LUA))
+ HOST_LUA= $(MINILUA_X)
+ DASM_DEP= $(MINILUA_T)
+endif
+
+DASM_DIR= ../dynasm
+DASM= $(HOST_LUA) $(DASM_DIR)/dynasm.lua
+DASM_XFLAGS=
+DASM_AFLAGS=
+DASM_ARCH= $(TARGET_LJARCH)
+
+ifneq (,$(findstring LJ_LE 1,$(TARGET_TESTARCH)))
+ DASM_AFLAGS+= -D ENDIAN_LE
+else
+ DASM_AFLAGS+= -D ENDIAN_BE
+endif
+ifneq (,$(findstring LJ_ARCH_BITS 64,$(TARGET_TESTARCH)))
+ DASM_AFLAGS+= -D P64
+endif
+ifneq (,$(findstring LJ_HASJIT 1,$(TARGET_TESTARCH)))
+ DASM_AFLAGS+= -D JIT
+endif
+ifneq (,$(findstring LJ_HASFFI 1,$(TARGET_TESTARCH)))
+ DASM_AFLAGS+= -D FFI
+endif
+ifneq (,$(findstring LJ_DUALNUM 1,$(TARGET_TESTARCH)))
+ DASM_AFLAGS+= -D DUALNUM
+endif
+ifneq (,$(findstring LJ_ARCH_HASFPU 1,$(TARGET_TESTARCH)))
+ DASM_AFLAGS+= -D FPU
+ TARGET_ARCH+= -DLJ_ARCH_HASFPU=1
+else
+ TARGET_ARCH+= -DLJ_ARCH_HASFPU=0
+endif
+ifeq (,$(findstring LJ_ABI_SOFTFP 1,$(TARGET_TESTARCH)))
+ DASM_AFLAGS+= -D HFABI
+ TARGET_ARCH+= -DLJ_ABI_SOFTFP=0
+else
+ TARGET_ARCH+= -DLJ_ABI_SOFTFP=1
+endif
+ifneq (,$(findstring LJ_NO_UNWIND 1,$(TARGET_TESTARCH)))
+ DASM_AFLAGS+= -D NO_UNWIND
+ TARGET_ARCH+= -DLUAJIT_NO_UNWIND
+endif
+DASM_AFLAGS+= -D VER=$(subst LJ_ARCH_VERSION_,,$(filter LJ_ARCH_VERSION_%,$(subst LJ_ARCH_VERSION ,LJ_ARCH_VERSION_,$(TARGET_TESTARCH))))
+ifeq (Windows,$(TARGET_SYS))
+ DASM_AFLAGS+= -D WIN
+endif
+ifeq (x64,$(TARGET_LJARCH))
+ ifeq (,$(findstring LJ_FR2 1,$(TARGET_TESTARCH)))
+ DASM_ARCH= x86
+ endif
+else
+ifeq (arm,$(TARGET_LJARCH))
+ ifeq (iOS,$(TARGET_SYS))
+ DASM_AFLAGS+= -D IOS
+ endif
+else
+ifeq (ppc,$(TARGET_LJARCH))
+ ifneq (,$(findstring LJ_ARCH_SQRT 1,$(TARGET_TESTARCH)))
+ DASM_AFLAGS+= -D SQRT
+ endif
+ ifneq (,$(findstring LJ_ARCH_ROUND 1,$(TARGET_TESTARCH)))
+ DASM_AFLAGS+= -D ROUND
+ endif
+ ifneq (,$(findstring LJ_ARCH_PPC32ON64 1,$(TARGET_TESTARCH)))
+ DASM_AFLAGS+= -D GPR64
+ endif
+ ifeq (PS3,$(TARGET_SYS))
+ DASM_AFLAGS+= -D PPE -D TOC
+ endif
+ ifneq (,$(findstring LJ_ARCH_PPC64 ,$(TARGET_TESTARCH)))
+ DASM_ARCH= ppc64
+ endif
+endif
+endif
+endif
+
+DASM_FLAGS= $(DASM_XFLAGS) $(DASM_AFLAGS)
+DASM_DASC= vm_$(DASM_ARCH).dasc
+
+BUILDVM_O= host/buildvm.o host/buildvm_asm.o host/buildvm_peobj.o \
+ host/buildvm_lib.o host/buildvm_fold.o
+BUILDVM_T= host/buildvm
+BUILDVM_X= $(BUILDVM_T)
+
+HOST_O= $(MINILUA_O) $(BUILDVM_O)
+HOST_T= $(MINILUA_T) $(BUILDVM_T)
+
+LJVM_S= lj_vm.S
+LJVM_O= lj_vm.o
+LJVM_BOUT= $(LJVM_S)
+LJVM_MODE= elfasm
+
+LJLIB_O= lib_base.o lib_math.o lib_bit.o lib_string.o lib_table.o \
+ lib_io.o lib_os.o lib_package.o lib_debug.o lib_jit.o lib_ffi.o
+LJLIB_C= $(LJLIB_O:.o=.c)
+
+LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o lj_buf.o \
+ lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \
+ lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o lj_strscan.o \
+ lj_strfmt.o lj_strfmt_num.o lj_api.o lj_profile.o \
+ lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o lj_load.o \
+ lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \
+ lj_opt_dce.o lj_opt_loop.o lj_opt_split.o lj_opt_sink.o \
+ lj_mcode.o lj_snap.o lj_record.o lj_crecord.o lj_ffrecord.o \
+ lj_asm.o lj_trace.o lj_gdbjit.o \
+ lj_ctype.o lj_cdata.o lj_cconv.o lj_ccall.o lj_ccallback.o \
+ lj_carith.o lj_clib.o lj_cparse.o \
+ lj_lib.o lj_alloc.o lib_aux.o \
+ $(LJLIB_O) lib_init.o
+
+LJVMCORE_O= $(LJVM_O) $(LJCORE_O)
+LJVMCORE_DYNO= $(LJVMCORE_O:.o=_dyn.o)
+
+LIB_VMDEF= jit/vmdef.lua
+LIB_VMDEFP= $(LIB_VMDEF)
+
+LUAJIT_O= luajit.o
+LUAJIT_A= libluajit.a
+LUAJIT_SO= libluajit.so
+LUAJIT_T= luajit
+
+ALL_T= $(LUAJIT_T) $(LUAJIT_A) $(LUAJIT_SO) $(HOST_T)
+ALL_HDRGEN= lj_bcdef.h lj_ffdef.h lj_libdef.h lj_recdef.h lj_folddef.h \
+ host/buildvm_arch.h
+ALL_GEN= $(LJVM_S) $(ALL_HDRGEN) $(LIB_VMDEFP)
+WIN_RM= *.obj *.lib *.exp *.dll *.exe *.manifest *.pdb *.ilk
+ALL_RM= $(ALL_T) $(ALL_GEN) *.o host/*.o $(WIN_RM)
+
+##############################################################################
+# Build mode handling.
+##############################################################################
+
+# Mixed mode defaults.
+TARGET_O= $(LUAJIT_A)
+TARGET_T= $(LUAJIT_T) $(LUAJIT_SO)
+TARGET_DEP= $(LIB_VMDEF) $(LUAJIT_SO)
+
+ifeq (Windows,$(TARGET_SYS))
+ TARGET_DYNCC= $(STATIC_CC)
+ LJVM_MODE= peobj
+ LJVM_BOUT= $(LJVM_O)
+ LUAJIT_T= luajit.exe
+ ifeq (cygwin,$(HOST_MSYS))
+ LUAJIT_SO= cyg$(TARGET_DLLNAME)
+ else
+ LUAJIT_SO= $(TARGET_DLLNAME)
+ endif
+ # Mixed mode is not supported on Windows. And static mode doesn't work well.
+ # C modules cannot be loaded, because they bind to lua51.dll.
+ ifneq (static,$(BUILDMODE))
+ BUILDMODE= dynamic
+ TARGET_XCFLAGS+= -DLUA_BUILD_AS_DLL
+ endif
+endif
+ifeq (Darwin,$(TARGET_SYS))
+ LJVM_MODE= machasm
+endif
+ifeq (iOS,$(TARGET_SYS))
+ LJVM_MODE= machasm
+endif
+ifeq (SunOS,$(TARGET_SYS))
+ BUILDMODE= static
+endif
+ifeq (PS3,$(TARGET_SYS))
+ BUILDMODE= static
+endif
+
+ifeq (Windows,$(HOST_SYS))
+ MINILUA_T= host/minilua.exe
+ BUILDVM_T= host/buildvm.exe
+ ifeq (,$(HOST_MSYS))
+ MINILUA_X= host\minilua
+ BUILDVM_X= host\buildvm
+ ALL_RM:= $(subst /,\,$(ALL_RM))
+ endif
+endif
+
+ifeq (static,$(BUILDMODE))
+ TARGET_DYNCC= @:
+ TARGET_T= $(LUAJIT_T)
+ TARGET_DEP= $(LIB_VMDEF)
+else
+ifeq (dynamic,$(BUILDMODE))
+ ifneq (Windows,$(TARGET_SYS))
+ TARGET_CC= $(DYNAMIC_CC)
+ endif
+ TARGET_DYNCC= @:
+ LJVMCORE_DYNO= $(LJVMCORE_O)
+ TARGET_O= $(LUAJIT_SO)
+ TARGET_XLDFLAGS+= $(TARGET_DYNXLDOPTS)
+else
+ifeq (Darwin,$(TARGET_SYS))
+ TARGET_DYNCC= @:
+ LJVMCORE_DYNO= $(LJVMCORE_O)
+endif
+ifeq (iOS,$(TARGET_SYS))
+ TARGET_DYNCC= @:
+ LJVMCORE_DYNO= $(LJVMCORE_O)
+endif
+endif
+endif
+
+Q= @
+E= @echo
+#Q=
+#E= @:
+
+##############################################################################
+# Make targets.
+##############################################################################
+
+default all: $(TARGET_T)
+
+amalg:
+ @grep "^[+|]" ljamalg.c
+ $(MAKE) all "LJCORE_O=ljamalg.o"
+
+clean:
+ $(HOST_RM) $(ALL_RM)
+
+libbc:
+ ./$(LUAJIT_T) host/genlibbc.lua -o host/buildvm_libbc.h $(LJLIB_C)
+ $(MAKE) all
+
+depend:
+ @for file in $(ALL_HDRGEN); do \
+ test -f $$file || touch $$file; \
+ done
+ @$(HOST_CC) $(HOST_ACFLAGS) -MM *.c host/*.c | \
+ sed -e "s| [^ ]*/dasm_\S*\.h||g" \
+ -e "s|^\([^l ]\)|host/\1|" \
+ -e "s| lj_target_\S*\.h| lj_target_*.h|g" \
+ -e "s| lj_emit_\S*\.h| lj_emit_*.h|g" \
+ -e "s| lj_asm_\S*\.h| lj_asm_*.h|g" >Makefile.dep
+ @for file in $(ALL_HDRGEN); do \
+ test -s $$file || $(HOST_RM) $$file; \
+ done
+
+.PHONY: default all amalg clean libbc depend
+
+##############################################################################
+# Rules for generated files.
+##############################################################################
+
+$(MINILUA_T): $(MINILUA_O)
+ $(E) "HOSTLINK $@"
+ $(Q)$(HOST_CC) $(HOST_ALDFLAGS) -o $@ $(MINILUA_O) $(MINILUA_LIBS) $(HOST_ALIBS)
+
+host/buildvm_arch.h: $(DASM_DASC) $(DASM_DEP) $(DASM_DIR)/*.lua
+ $(E) "DYNASM $@"
+ $(Q)$(DASM) $(DASM_FLAGS) -o $@ $(DASM_DASC)
+
+host/buildvm.o: $(DASM_DIR)/dasm_*.h
+
+$(BUILDVM_T): $(BUILDVM_O)
+ $(E) "HOSTLINK $@"
+ $(Q)$(HOST_CC) $(HOST_ALDFLAGS) -o $@ $(BUILDVM_O) $(HOST_ALIBS)
+
+$(LJVM_BOUT): $(BUILDVM_T)
+ $(E) "BUILDVM $@"
+ $(Q)$(BUILDVM_X) -m $(LJVM_MODE) -o $@
+
+lj_bcdef.h: $(BUILDVM_T) $(LJLIB_C)
+ $(E) "BUILDVM $@"
+ $(Q)$(BUILDVM_X) -m bcdef -o $@ $(LJLIB_C)
+
+lj_ffdef.h: $(BUILDVM_T) $(LJLIB_C)
+ $(E) "BUILDVM $@"
+ $(Q)$(BUILDVM_X) -m ffdef -o $@ $(LJLIB_C)
+
+lj_libdef.h: $(BUILDVM_T) $(LJLIB_C)
+ $(E) "BUILDVM $@"
+ $(Q)$(BUILDVM_X) -m libdef -o $@ $(LJLIB_C)
+
+lj_recdef.h: $(BUILDVM_T) $(LJLIB_C)
+ $(E) "BUILDVM $@"
+ $(Q)$(BUILDVM_X) -m recdef -o $@ $(LJLIB_C)
+
+$(LIB_VMDEF): $(BUILDVM_T) $(LJLIB_C)
+ $(E) "BUILDVM $@"
+ $(Q)$(BUILDVM_X) -m vmdef -o $(LIB_VMDEFP) $(LJLIB_C)
+
+lj_folddef.h: $(BUILDVM_T) lj_opt_fold.c
+ $(E) "BUILDVM $@"
+ $(Q)$(BUILDVM_X) -m folddef -o $@ lj_opt_fold.c
+
+##############################################################################
+# Object file rules.
+##############################################################################
+
+%.o: %.c
+ $(E) "CC $@"
+ $(Q)$(TARGET_DYNCC) $(TARGET_ACFLAGS) -c -o $(@:.o=_dyn.o) $<
+ $(Q)$(TARGET_CC) $(TARGET_ACFLAGS) -c -o $@ $<
+
+%.o: %.S
+ $(E) "ASM $@"
+ $(Q)$(TARGET_DYNCC) $(TARGET_ASFLAGS) -c -o $(@:.o=_dyn.o) $<
+ $(Q)$(TARGET_CC) $(TARGET_ASFLAGS) -c -o $@ $<
+
+$(LUAJIT_O):
+ $(E) "CC $@"
+ $(Q)$(TARGET_STCC) $(TARGET_ACFLAGS) -c -o $@ $<
+
+$(HOST_O): %.o: %.c
+ $(E) "HOSTCC $@"
+ $(Q)$(HOST_CC) $(HOST_ACFLAGS) -c -o $@ $<
+
+include Makefile.dep
+
+##############################################################################
+# Target file rules.
+##############################################################################
+
+$(LUAJIT_A): $(LJVMCORE_O)
+ $(E) "AR $@"
+ $(Q)$(TARGET_AR) $@ $(LJVMCORE_O)
+
+# The dependency on _O, but linking with _DYNO is intentional.
+$(LUAJIT_SO): $(LJVMCORE_O)
+ $(E) "DYNLINK $@"
+ $(Q)$(TARGET_LD) $(TARGET_ASHLDFLAGS) -o $@ $(LJVMCORE_DYNO) $(TARGET_ALIBS)
+ $(Q)$(TARGET_STRIP) $@
+
+$(LUAJIT_T): $(TARGET_O) $(LUAJIT_O) $(TARGET_DEP)
+ $(E) "LINK $@"
+ $(Q)$(TARGET_LD) $(TARGET_ALDFLAGS) -o $@ $(LUAJIT_O) $(TARGET_O) $(TARGET_ALIBS)
+ $(Q)$(TARGET_STRIP) $@
+ $(E) "OK Successfully built LuaJIT"
+
+##############################################################################
diff --git a/src/host/luajit-2.1.0-beta3/src/Makefile.dep b/src/host/luajit-2.1.0-beta3/src/Makefile.dep
new file mode 100644
index 00000000..2b1cb5ef
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/Makefile.dep
@@ -0,0 +1,246 @@
+lib_aux.o: lib_aux.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \
+ lj_arch.h lj_err.h lj_errmsg.h lj_state.h lj_trace.h lj_jit.h lj_ir.h \
+ lj_dispatch.h lj_bc.h lj_traceerr.h lj_lib.h lj_alloc.h
+lib_base.o: lib_base.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
+ lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h \
+ lj_tab.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_cconv.h \
+ lj_ff.h lj_ffdef.h lj_dispatch.h lj_jit.h lj_ir.h lj_char.h lj_strscan.h \
+ lj_strfmt.h lj_lib.h lj_libdef.h
+lib_bit.o: lib_bit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
+ lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_strscan.h \
+ lj_strfmt.h lj_ctype.h lj_cdata.h lj_cconv.h lj_carith.h lj_ff.h \
+ lj_ffdef.h lj_lib.h lj_libdef.h
+lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
+ lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_lib.h \
+ lj_libdef.h
+lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
+ lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h \
+ lj_ctype.h lj_cparse.h lj_cdata.h lj_cconv.h lj_carith.h lj_ccall.h \
+ lj_ccallback.h lj_clib.h lj_strfmt.h lj_ff.h lj_ffdef.h lj_lib.h \
+ lj_libdef.h
+lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h
+lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
+ lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_state.h \
+ lj_strfmt.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h
+lib_jit.o: lib_jit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
+ lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h \
+ lj_state.h lj_bc.h lj_ctype.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h \
+ lj_target.h lj_target_*.h lj_trace.h lj_dispatch.h lj_traceerr.h \
+ lj_vm.h lj_vmevent.h lj_lib.h luajit.h lj_libdef.h
+lib_math.o: lib_math.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
+ lj_def.h lj_arch.h lj_lib.h lj_vm.h lj_libdef.h
+lib_os.o: lib_os.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
+ lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_lib.h \
+ lj_libdef.h
+lib_package.o: lib_package.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
+ lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h
+lib_string.o: lib_string.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
+ lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h \
+ lj_tab.h lj_meta.h lj_state.h lj_ff.h lj_ffdef.h lj_bcdump.h lj_lex.h \
+ lj_char.h lj_strfmt.h lj_lib.h lj_libdef.h
+lib_table.o: lib_table.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
+ lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h \
+ lj_tab.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h
+lj_alloc.o: lj_alloc.c lj_def.h lua.h luaconf.h lj_arch.h lj_alloc.h
+lj_api.o: lj_api.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
+ lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_tab.h lj_func.h lj_udata.h \
+ lj_meta.h lj_state.h lj_bc.h lj_frame.h lj_trace.h lj_jit.h lj_ir.h \
+ lj_dispatch.h lj_traceerr.h lj_vm.h lj_strscan.h lj_strfmt.h
+lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
+ lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_ir.h lj_jit.h \
+ lj_ircall.h lj_iropt.h lj_mcode.h lj_trace.h lj_dispatch.h lj_traceerr.h \
+ lj_snap.h lj_asm.h lj_vm.h lj_target.h lj_target_*.h lj_emit_*.h \
+ lj_asm_*.h
+lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \
+ lj_bcdef.h
+lj_bcread.o: lj_bcread.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_bc.h \
+ lj_ctype.h lj_cdata.h lualib.h lj_lex.h lj_bcdump.h lj_state.h \
+ lj_strfmt.h
+lj_bcwrite.o: lj_bcwrite.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_gc.h lj_buf.h lj_str.h lj_bc.h lj_ctype.h lj_dispatch.h lj_jit.h \
+ lj_ir.h lj_strfmt.h lj_bcdump.h lj_lex.h lj_err.h lj_errmsg.h lj_vm.h
+lj_buf.o: lj_buf.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
+ lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_strfmt.h
+lj_carith.o: lj_carith.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_meta.h lj_ir.h lj_ctype.h \
+ lj_cconv.h lj_cdata.h lj_carith.h lj_strscan.h
+lj_ccall.o: lj_ccall.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_cconv.h lj_cdata.h \
+ lj_ccall.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \
+ lj_traceerr.h
+lj_ccallback.o: lj_ccallback.c lj_obj.h lua.h luaconf.h lj_def.h \
+ lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_state.h lj_frame.h \
+ lj_bc.h lj_ctype.h lj_cconv.h lj_ccall.h lj_ccallback.h lj_target.h \
+ lj_target_*.h lj_mcode.h lj_jit.h lj_ir.h lj_trace.h lj_dispatch.h \
+ lj_traceerr.h lj_vm.h
+lj_cconv.o: lj_cconv.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_gc.h lj_cdata.h lj_cconv.h \
+ lj_ccallback.h
+lj_cdata.o: lj_cdata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_cconv.h lj_cdata.h
+lj_char.o: lj_char.c lj_char.h lj_def.h lua.h luaconf.h
+lj_clib.o: lj_clib.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
+ lj_err.h lj_errmsg.h lj_tab.h lj_str.h lj_udata.h lj_ctype.h lj_cconv.h \
+ lj_cdata.h lj_clib.h lj_strfmt.h
+lj_cparse.o: lj_cparse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_ctype.h lj_cparse.h \
+ lj_frame.h lj_bc.h lj_vm.h lj_char.h lj_strscan.h lj_strfmt.h
+lj_crecord.o: lj_crecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_err.h lj_errmsg.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_gc.h \
+ lj_cdata.h lj_cparse.h lj_cconv.h lj_carith.h lj_clib.h lj_ccall.h \
+ lj_ff.h lj_ffdef.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h lj_trace.h \
+ lj_dispatch.h lj_traceerr.h lj_record.h lj_ffrecord.h lj_snap.h \
+ lj_crecord.h lj_strfmt.h
+lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_strfmt.h lj_ctype.h \
+ lj_ccallback.h lj_buf.h
+lj_debug.o: lj_debug.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_err.h lj_errmsg.h lj_debug.h lj_buf.h lj_gc.h lj_str.h lj_tab.h \
+ lj_state.h lj_frame.h lj_bc.h lj_strfmt.h lj_jit.h lj_ir.h
+lj_dispatch.o: lj_dispatch.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_func.h lj_tab.h \
+ lj_meta.h lj_debug.h lj_state.h lj_frame.h lj_bc.h lj_ff.h lj_ffdef.h \
+ lj_strfmt.h lj_jit.h lj_ir.h lj_ccallback.h lj_ctype.h lj_trace.h \
+ lj_dispatch.h lj_traceerr.h lj_profile.h lj_vm.h luajit.h
+lj_err.o: lj_err.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_err.h \
+ lj_errmsg.h lj_debug.h lj_str.h lj_func.h lj_state.h lj_frame.h lj_bc.h \
+ lj_ff.h lj_ffdef.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h \
+ lj_traceerr.h lj_vm.h lj_strfmt.h
+lj_ffrecord.o: lj_ffrecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ff.h \
+ lj_ffdef.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h lj_trace.h \
+ lj_dispatch.h lj_traceerr.h lj_record.h lj_ffrecord.h lj_crecord.h \
+ lj_vm.h lj_strscan.h lj_strfmt.h lj_recdef.h
+lj_func.o: lj_func.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
+ lj_func.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \
+ lj_traceerr.h lj_vm.h
+lj_gc.o: lj_gc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
+ lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_func.h lj_udata.h \
+ lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_cdata.h lj_trace.h \
+ lj_jit.h lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h
+lj_gdbjit.o: lj_gdbjit.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_frame.h lj_bc.h lj_buf.h \
+ lj_str.h lj_strfmt.h lj_jit.h lj_ir.h lj_dispatch.h
+lj_ir.o: lj_ir.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
+ lj_buf.h lj_str.h lj_tab.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h \
+ lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_ctype.h lj_cdata.h \
+ lj_carith.h lj_vm.h lj_strscan.h lj_strfmt.h lj_lib.h
+lj_lex.o: lj_lex.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
+ lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_ctype.h lj_cdata.h \
+ lualib.h lj_state.h lj_lex.h lj_parse.h lj_char.h lj_strscan.h \
+ lj_strfmt.h
+lj_lib.o: lj_lib.c lauxlib.h lua.h luaconf.h lj_obj.h lj_def.h lj_arch.h \
+ lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h lj_bc.h \
+ lj_dispatch.h lj_jit.h lj_ir.h lj_vm.h lj_strscan.h lj_strfmt.h lj_lex.h \
+ lj_bcdump.h lj_lib.h
+lj_load.o: lj_load.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \
+ lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_func.h \
+ lj_frame.h lj_bc.h lj_vm.h lj_lex.h lj_bcdump.h lj_parse.h
+lj_mcode.o: lj_mcode.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_gc.h lj_err.h lj_errmsg.h lj_jit.h lj_ir.h lj_mcode.h lj_trace.h \
+ lj_dispatch.h lj_bc.h lj_traceerr.h lj_vm.h
+lj_meta.o: lj_meta.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
+ lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_meta.h lj_frame.h \
+ lj_bc.h lj_vm.h lj_strscan.h lj_strfmt.h lj_lib.h
+lj_obj.o: lj_obj.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h
+lj_opt_dce.o: lj_opt_dce.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_ir.h lj_jit.h lj_iropt.h
+lj_opt_fold.o: lj_opt_fold.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_buf.h lj_gc.h lj_str.h lj_tab.h lj_ir.h lj_jit.h lj_ircall.h \
+ lj_iropt.h lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_ctype.h \
+ lj_carith.h lj_vm.h lj_strscan.h lj_strfmt.h lj_folddef.h
+lj_opt_loop.o: lj_opt_loop.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_ir.h lj_jit.h \
+ lj_iropt.h lj_trace.h lj_dispatch.h lj_bc.h lj_traceerr.h lj_snap.h \
+ lj_vm.h
+lj_opt_mem.o: lj_opt_mem.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_tab.h lj_ir.h lj_jit.h lj_iropt.h lj_ircall.h
+lj_opt_narrow.o: lj_opt_narrow.c lj_obj.h lua.h luaconf.h lj_def.h \
+ lj_arch.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h lj_trace.h lj_dispatch.h \
+ lj_traceerr.h lj_vm.h lj_strscan.h
+lj_opt_sink.o: lj_opt_sink.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_ir.h lj_jit.h lj_iropt.h lj_target.h lj_target_*.h
+lj_opt_split.o: lj_opt_split.c lj_obj.h lua.h luaconf.h lj_def.h \
+ lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_ir.h \
+ lj_jit.h lj_ircall.h lj_iropt.h lj_dispatch.h lj_bc.h lj_vm.h
+lj_parse.o: lj_parse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_buf.h lj_str.h lj_tab.h \
+ lj_func.h lj_state.h lj_bc.h lj_ctype.h lj_strfmt.h lj_lex.h lj_parse.h \
+ lj_vm.h lj_vmevent.h
+lj_profile.o: lj_profile.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_buf.h lj_gc.h lj_str.h lj_frame.h lj_bc.h lj_debug.h lj_dispatch.h \
+ lj_jit.h lj_ir.h lj_trace.h lj_traceerr.h lj_profile.h luajit.h
+lj_record.o: lj_record.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \
+ lj_ctype.h lj_gc.h lj_ff.h lj_ffdef.h lj_debug.h lj_ir.h lj_jit.h \
+ lj_ircall.h lj_iropt.h lj_trace.h lj_dispatch.h lj_traceerr.h \
+ lj_record.h lj_ffrecord.h lj_snap.h lj_vm.h
+lj_snap.o: lj_snap.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
+ lj_tab.h lj_state.h lj_frame.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h \
+ lj_trace.h lj_dispatch.h lj_traceerr.h lj_snap.h lj_target.h \
+ lj_target_*.h lj_ctype.h lj_cdata.h
+lj_state.o: lj_state.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_func.h \
+ lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_trace.h lj_jit.h \
+ lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h lj_lex.h lj_alloc.h luajit.h
+lj_str.o: lj_str.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
+ lj_err.h lj_errmsg.h lj_str.h lj_char.h
+lj_strfmt.o: lj_strfmt.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_buf.h lj_gc.h lj_str.h lj_state.h lj_char.h lj_strfmt.h
+lj_strfmt_num.o: lj_strfmt_num.c lj_obj.h lua.h luaconf.h lj_def.h \
+ lj_arch.h lj_buf.h lj_gc.h lj_str.h lj_strfmt.h
+lj_strscan.o: lj_strscan.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_char.h lj_strscan.h
+lj_tab.o: lj_tab.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
+ lj_err.h lj_errmsg.h lj_tab.h
+lj_trace.o: lj_trace.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h lj_frame.h lj_bc.h \
+ lj_state.h lj_ir.h lj_jit.h lj_iropt.h lj_mcode.h lj_trace.h \
+ lj_dispatch.h lj_traceerr.h lj_snap.h lj_gdbjit.h lj_record.h lj_asm.h \
+ lj_vm.h lj_vmevent.h lj_target.h lj_target_*.h
+lj_udata.o: lj_udata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_gc.h lj_udata.h
+lj_vmevent.o: lj_vmevent.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_str.h lj_tab.h lj_state.h lj_dispatch.h lj_bc.h lj_jit.h lj_ir.h \
+ lj_vm.h lj_vmevent.h
+lj_vmmath.o: lj_vmmath.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_ir.h lj_vm.h
+ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_gc.c lj_obj.h lj_def.h \
+ lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h \
+ lj_func.h lj_udata.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h \
+ lj_cdata.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_traceerr.h \
+ lj_vm.h lj_err.c lj_debug.h lj_ff.h lj_ffdef.h lj_strfmt.h lj_char.c \
+ lj_char.h lj_bc.c lj_bcdef.h lj_obj.c lj_buf.c lj_str.c lj_tab.c \
+ lj_func.c lj_udata.c lj_meta.c lj_strscan.h lj_lib.h lj_debug.c \
+ lj_state.c lj_lex.h lj_alloc.h luajit.h lj_dispatch.c lj_ccallback.h \
+ lj_profile.h lj_vmevent.c lj_vmevent.h lj_vmmath.c lj_strscan.c \
+ lj_strfmt.c lj_strfmt_num.c lj_api.c lj_profile.c lj_lex.c lualib.h \
+ lj_parse.h lj_parse.c lj_bcread.c lj_bcdump.h lj_bcwrite.c lj_load.c \
+ lj_ctype.c lj_cdata.c lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h \
+ lj_ccallback.c lj_target.h lj_target_*.h lj_mcode.h lj_carith.c \
+ lj_carith.h lj_clib.c lj_clib.h lj_cparse.c lj_cparse.h lj_lib.c lj_ir.c \
+ lj_ircall.h lj_iropt.h lj_opt_mem.c lj_opt_fold.c lj_folddef.h \
+ lj_opt_narrow.c lj_opt_dce.c lj_opt_loop.c lj_snap.h lj_opt_split.c \
+ lj_opt_sink.c lj_mcode.c lj_snap.c lj_record.c lj_record.h lj_ffrecord.h \
+ lj_crecord.c lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h \
+ lj_emit_*.h lj_asm_*.h lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c \
+ lib_aux.c lib_base.c lj_libdef.h lib_math.c lib_string.c lib_table.c \
+ lib_io.c lib_os.c lib_package.c lib_debug.c lib_bit.c lib_jit.c \
+ lib_ffi.c lib_init.c
+luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h
+host/buildvm.o: host/buildvm.c host/buildvm.h lj_def.h lua.h luaconf.h \
+ lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_gc.h lj_obj.h lj_bc.h lj_ir.h \
+ lj_ircall.h lj_ir.h lj_jit.h lj_frame.h lj_bc.h lj_dispatch.h lj_ctype.h \
+ lj_gc.h lj_ccall.h lj_ctype.h luajit.h \
+ host/buildvm_arch.h lj_traceerr.h
+host/buildvm_asm.o: host/buildvm_asm.c host/buildvm.h lj_def.h lua.h luaconf.h \
+ lj_arch.h lj_bc.h lj_def.h lj_arch.h
+host/buildvm_fold.o: host/buildvm_fold.c host/buildvm.h lj_def.h lua.h \
+ luaconf.h lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_ir.h lj_obj.h
+host/buildvm_lib.o: host/buildvm_lib.c host/buildvm.h lj_def.h lua.h luaconf.h \
+ lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_bc.h lj_lib.h lj_obj.h \
+ host/buildvm_libbc.h
+host/buildvm_peobj.o: host/buildvm_peobj.c host/buildvm.h lj_def.h lua.h \
+ luaconf.h lj_arch.h lj_bc.h lj_def.h lj_arch.h
+host/minilua.o: host/minilua.c
diff --git a/src/host/luajit-2.1.0-beta3/src/host/README b/src/host/luajit-2.1.0-beta3/src/host/README
new file mode 100644
index 00000000..abfcdaa7
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/host/README
@@ -0,0 +1,4 @@
+The files in this directory are only used during the build process of LuaJIT.
+For cross-compilation, they must be executed on the host, not on the target.
+
+These files should NOT be installed!
diff --git a/src/host/luajit-2.1.0-beta3/src/host/buildvm b/src/host/luajit-2.1.0-beta3/src/host/buildvm
new file mode 100755
index 00000000..d0aa4b7f
Binary files /dev/null and b/src/host/luajit-2.1.0-beta3/src/host/buildvm differ
diff --git a/src/host/luajit-2.1.0-beta3/src/host/buildvm.c b/src/host/luajit-2.1.0-beta3/src/host/buildvm.c
new file mode 100644
index 00000000..de23fabd
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/host/buildvm.c
@@ -0,0 +1,518 @@
+/*
+** LuaJIT VM builder.
+** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
+**
+** This is a tool to build the hand-tuned assembler code required for
+** LuaJIT's bytecode interpreter. It supports a variety of output formats
+** to feed different toolchains (see usage() below).
+**
+** This tool is not particularly optimized because it's only used while
+** _building_ LuaJIT. There's no point in distributing or installing it.
+** Only the object code generated by this tool is linked into LuaJIT.
+**
+** Caveat: some memory is not free'd, error handling is lazy.
+** It's a one-shot tool -- any effort fixing this would be wasted.
+*/
+
+#include "buildvm.h"
+#include "lj_obj.h"
+#include "lj_gc.h"
+#include "lj_bc.h"
+#include "lj_ir.h"
+#include "lj_ircall.h"
+#include "lj_frame.h"
+#include "lj_dispatch.h"
+#if LJ_HASFFI
+#include "lj_ctype.h"
+#include "lj_ccall.h"
+#endif
+#include "luajit.h"
+
+#if defined(_WIN32)
+#include
+#include
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+/* DynASM glue definitions. */
+#define Dst ctx
+#define Dst_DECL BuildCtx *ctx
+#define Dst_REF (ctx->D)
+#define DASM_CHECKS 1
+
+#include "../dynasm/dasm_proto.h"
+
+/* Glue macros for DynASM. */
+static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type);
+
+#define DASM_EXTERN(ctx, addr, idx, type) \
+ collect_reloc(ctx, addr, idx, type)
+
+/* ------------------------------------------------------------------------ */
+
+/* Avoid trouble if cross-compiling for an x86 target. Speed doesn't matter. */
+#define DASM_ALIGNED_WRITES 1
+
+/* Embed architecture-specific DynASM encoder. */
+#if LJ_TARGET_X86ORX64
+#include "../dynasm/dasm_x86.h"
+#elif LJ_TARGET_ARM
+#include "../dynasm/dasm_arm.h"
+#elif LJ_TARGET_ARM64
+#include "../dynasm/dasm_arm64.h"
+#elif LJ_TARGET_PPC
+#include "../dynasm/dasm_ppc.h"
+#elif LJ_TARGET_MIPS
+#include "../dynasm/dasm_mips.h"
+#else
+#error "No support for this architecture (yet)"
+#endif
+
+/* Embed generated architecture-specific backend. */
+#include "buildvm_arch.h"
+
+/* ------------------------------------------------------------------------ */
+
+void owrite(BuildCtx *ctx, const void *ptr, size_t sz)
+{
+ if (fwrite(ptr, 1, sz, ctx->fp) != sz) {
+ fprintf(stderr, "Error: cannot write to output file: %s\n",
+ strerror(errno));
+ exit(1);
+ }
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* Emit code as raw bytes. Only used for DynASM debugging. */
+static void emit_raw(BuildCtx *ctx)
+{
+ owrite(ctx, ctx->code, ctx->codesz);
+}
+
+/* -- Build machine code -------------------------------------------------- */
+
+static const char *sym_decorate(BuildCtx *ctx,
+ const char *prefix, const char *suffix)
+{
+ char name[256];
+ char *p;
+#if LJ_64
+ const char *symprefix = ctx->mode == BUILD_machasm ? "_" : "";
+#elif LJ_TARGET_XBOX360
+ const char *symprefix = "";
+#else
+ const char *symprefix = ctx->mode != BUILD_elfasm ? "_" : "";
+#endif
+ sprintf(name, "%s%s%s", symprefix, prefix, suffix);
+ p = strchr(name, '@');
+ if (p) {
+#if LJ_TARGET_X86ORX64
+ if (!LJ_64 && (ctx->mode == BUILD_coffasm || ctx->mode == BUILD_peobj))
+ name[0] = name[1] == 'R' ? '_' : '@'; /* Just for _RtlUnwind@16. */
+ else
+ *p = '\0';
+#elif LJ_TARGET_PPC && !LJ_TARGET_CONSOLE
+ /* Keep @plt etc. */
+#else
+ *p = '\0';
+#endif
+ }
+ p = (char *)malloc(strlen(name)+1); /* MSVC doesn't like strdup. */
+ strcpy(p, name);
+ return p;
+}
+
+#define NRELOCSYM (sizeof(extnames)/sizeof(extnames[0])-1)
+
+static int relocmap[NRELOCSYM];
+
+/* Collect external relocations. */
+static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type)
+{
+ if (ctx->nreloc >= BUILD_MAX_RELOC) {
+ fprintf(stderr, "Error: too many relocations, increase BUILD_MAX_RELOC.\n");
+ exit(1);
+ }
+ if (relocmap[idx] < 0) {
+ relocmap[idx] = ctx->nrelocsym;
+ ctx->relocsym[ctx->nrelocsym] = sym_decorate(ctx, "", extnames[idx]);
+ ctx->nrelocsym++;
+ }
+ ctx->reloc[ctx->nreloc].ofs = (int32_t)(addr - ctx->code);
+ ctx->reloc[ctx->nreloc].sym = relocmap[idx];
+ ctx->reloc[ctx->nreloc].type = type;
+ ctx->nreloc++;
+#if LJ_TARGET_XBOX360
+ return (int)(ctx->code - addr) + 4; /* Encode symbol offset of .text. */
+#else
+ return 0; /* Encode symbol offset of 0. */
+#endif
+}
+
+/* Naive insertion sort. Performance doesn't matter here. */
+static void sym_insert(BuildCtx *ctx, int32_t ofs,
+ const char *prefix, const char *suffix)
+{
+ ptrdiff_t i = ctx->nsym++;
+ while (i > 0) {
+ if (ctx->sym[i-1].ofs <= ofs)
+ break;
+ ctx->sym[i] = ctx->sym[i-1];
+ i--;
+ }
+ ctx->sym[i].ofs = ofs;
+ ctx->sym[i].name = sym_decorate(ctx, prefix, suffix);
+}
+
+/* Build the machine code. */
+static int build_code(BuildCtx *ctx)
+{
+ int status;
+ int i;
+
+ /* Initialize DynASM structures. */
+ ctx->nglob = GLOB__MAX;
+ ctx->glob = (void **)malloc(ctx->nglob*sizeof(void *));
+ memset(ctx->glob, 0, ctx->nglob*sizeof(void *));
+ ctx->nreloc = 0;
+
+ ctx->globnames = globnames;
+ ctx->extnames = extnames;
+ ctx->relocsym = (const char **)malloc(NRELOCSYM*sizeof(const char *));
+ ctx->nrelocsym = 0;
+ for (i = 0; i < (int)NRELOCSYM; i++) relocmap[i] = -1;
+
+ ctx->dasm_ident = DASM_IDENT;
+ ctx->dasm_arch = DASM_ARCH;
+
+ dasm_init(Dst, DASM_MAXSECTION);
+ dasm_setupglobal(Dst, ctx->glob, ctx->nglob);
+ dasm_setup(Dst, build_actionlist);
+
+ /* Call arch-specific backend to emit the code. */
+ ctx->npc = build_backend(ctx);
+
+ /* Finalize the code. */
+ (void)dasm_checkstep(Dst, -1);
+ if ((status = dasm_link(Dst, &ctx->codesz))) return status;
+ ctx->code = (uint8_t *)malloc(ctx->codesz);
+ if ((status = dasm_encode(Dst, (void *)ctx->code))) return status;
+
+ /* Allocate symbol table and bytecode offsets. */
+ ctx->beginsym = sym_decorate(ctx, "", LABEL_PREFIX "vm_asm_begin");
+ ctx->sym = (BuildSym *)malloc((ctx->npc+ctx->nglob+1)*sizeof(BuildSym));
+ ctx->nsym = 0;
+ ctx->bc_ofs = (int32_t *)malloc(ctx->npc*sizeof(int32_t));
+
+ /* Collect the opcodes (PC labels). */
+ for (i = 0; i < ctx->npc; i++) {
+ int32_t ofs = dasm_getpclabel(Dst, i);
+ if (ofs < 0) return 0x22000000|i;
+ ctx->bc_ofs[i] = ofs;
+ if ((LJ_HASJIT ||
+ !(i == BC_JFORI || i == BC_JFORL || i == BC_JITERL || i == BC_JLOOP ||
+ i == BC_IFORL || i == BC_IITERL || i == BC_ILOOP)) &&
+ (LJ_HASFFI || i != BC_KCDATA))
+ sym_insert(ctx, ofs, LABEL_PREFIX_BC, bc_names[i]);
+ }
+
+ /* Collect the globals (named labels). */
+ for (i = 0; i < ctx->nglob; i++) {
+ const char *gl = globnames[i];
+ int len = (int)strlen(gl);
+ if (!ctx->glob[i]) {
+ fprintf(stderr, "Error: undefined global %s\n", gl);
+ exit(2);
+ }
+ /* Skip the _Z symbols. */
+ if (!(len >= 2 && gl[len-2] == '_' && gl[len-1] == 'Z'))
+ sym_insert(ctx, (int32_t)((uint8_t *)(ctx->glob[i]) - ctx->code),
+ LABEL_PREFIX, globnames[i]);
+ }
+
+ /* Close the address range. */
+ sym_insert(ctx, (int32_t)ctx->codesz, "", "");
+ ctx->nsym--;
+
+ dasm_free(Dst);
+
+ return 0;
+}
+
+/* -- Generate VM enums --------------------------------------------------- */
+
+const char *const bc_names[] = {
+#define BCNAME(name, ma, mb, mc, mt) #name,
+BCDEF(BCNAME)
+#undef BCNAME
+ NULL
+};
+
+const char *const ir_names[] = {
+#define IRNAME(name, m, m1, m2) #name,
+IRDEF(IRNAME)
+#undef IRNAME
+ NULL
+};
+
+const char *const irt_names[] = {
+#define IRTNAME(name, size) #name,
+IRTDEF(IRTNAME)
+#undef IRTNAME
+ NULL
+};
+
+const char *const irfpm_names[] = {
+#define FPMNAME(name) #name,
+IRFPMDEF(FPMNAME)
+#undef FPMNAME
+ NULL
+};
+
+const char *const irfield_names[] = {
+#define FLNAME(name, ofs) #name,
+IRFLDEF(FLNAME)
+#undef FLNAME
+ NULL
+};
+
+const char *const ircall_names[] = {
+#define IRCALLNAME(cond, name, nargs, kind, type, flags) #name,
+IRCALLDEF(IRCALLNAME)
+#undef IRCALLNAME
+ NULL
+};
+
+static const char *const trace_errors[] = {
+#define TREDEF(name, msg) msg,
+#include "lj_traceerr.h"
+ NULL
+};
+
+static const char *lower(char *buf, const char *s)
+{
+ char *p = buf;
+ while (*s) {
+ *p++ = (*s >= 'A' && *s <= 'Z') ? *s+0x20 : *s;
+ s++;
+ }
+ *p = '\0';
+ return buf;
+}
+
+/* Emit C source code for bytecode-related definitions. */
+static void emit_bcdef(BuildCtx *ctx)
+{
+ int i;
+ fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
+ fprintf(ctx->fp, "LJ_DATADEF const uint16_t lj_bc_ofs[] = {\n");
+ for (i = 0; i < ctx->npc; i++) {
+ if (i != 0)
+ fprintf(ctx->fp, ",\n");
+ fprintf(ctx->fp, "%d", ctx->bc_ofs[i]);
+ }
+}
+
+/* Emit VM definitions as Lua code for debug modules. */
+static void emit_vmdef(BuildCtx *ctx)
+{
+ char buf[80];
+ int i;
+ fprintf(ctx->fp, "-- This is a generated file. DO NOT EDIT!\n\n");
+ fprintf(ctx->fp, "return {\n\n");
+
+ fprintf(ctx->fp, "bcnames = \"");
+ for (i = 0; bc_names[i]; i++) fprintf(ctx->fp, "%-6s", bc_names[i]);
+ fprintf(ctx->fp, "\",\n\n");
+
+ fprintf(ctx->fp, "irnames = \"");
+ for (i = 0; ir_names[i]; i++) fprintf(ctx->fp, "%-6s", ir_names[i]);
+ fprintf(ctx->fp, "\",\n\n");
+
+ fprintf(ctx->fp, "irfpm = { [0]=");
+ for (i = 0; irfpm_names[i]; i++)
+ fprintf(ctx->fp, "\"%s\", ", lower(buf, irfpm_names[i]));
+ fprintf(ctx->fp, "},\n\n");
+
+ fprintf(ctx->fp, "irfield = { [0]=");
+ for (i = 0; irfield_names[i]; i++) {
+ char *p;
+ lower(buf, irfield_names[i]);
+ p = strchr(buf, '_');
+ if (p) *p = '.';
+ fprintf(ctx->fp, "\"%s\", ", buf);
+ }
+ fprintf(ctx->fp, "},\n\n");
+
+ fprintf(ctx->fp, "ircall = {\n[0]=");
+ for (i = 0; ircall_names[i]; i++)
+ fprintf(ctx->fp, "\"%s\",\n", ircall_names[i]);
+ fprintf(ctx->fp, "},\n\n");
+
+ fprintf(ctx->fp, "traceerr = {\n[0]=");
+ for (i = 0; trace_errors[i]; i++)
+ fprintf(ctx->fp, "\"%s\",\n", trace_errors[i]);
+ fprintf(ctx->fp, "},\n\n");
+}
+
+/* -- Argument parsing ---------------------------------------------------- */
+
+/* Build mode names. */
+static const char *const modenames[] = {
+#define BUILDNAME(name) #name,
+BUILDDEF(BUILDNAME)
+#undef BUILDNAME
+ NULL
+};
+
+/* Print usage information and exit. */
+static void usage(void)
+{
+ int i;
+ fprintf(stderr, LUAJIT_VERSION " VM builder.\n");
+ fprintf(stderr, LUAJIT_COPYRIGHT ", " LUAJIT_URL "\n");
+ fprintf(stderr, "Target architecture: " LJ_ARCH_NAME "\n\n");
+ fprintf(stderr, "Usage: buildvm -m mode [-o outfile] [infiles...]\n\n");
+ fprintf(stderr, "Available modes:\n");
+ for (i = 0; i < BUILD__MAX; i++)
+ fprintf(stderr, " %s\n", modenames[i]);
+ exit(1);
+}
+
+/* Parse the output mode name. */
+static BuildMode parsemode(const char *mode)
+{
+ int i;
+ for (i = 0; modenames[i]; i++)
+ if (!strcmp(mode, modenames[i]))
+ return (BuildMode)i;
+ usage();
+ return (BuildMode)-1;
+}
+
+/* Parse arguments. */
+static void parseargs(BuildCtx *ctx, char **argv)
+{
+ const char *a;
+ int i;
+ ctx->mode = (BuildMode)-1;
+ ctx->outname = "-";
+ for (i = 1; (a = argv[i]) != NULL; i++) {
+ if (a[0] != '-')
+ break;
+ switch (a[1]) {
+ case '-':
+ if (a[2]) goto err;
+ i++;
+ goto ok;
+ case '\0':
+ goto ok;
+ case 'm':
+ i++;
+ if (a[2] || argv[i] == NULL) goto err;
+ ctx->mode = parsemode(argv[i]);
+ break;
+ case 'o':
+ i++;
+ if (a[2] || argv[i] == NULL) goto err;
+ ctx->outname = argv[i];
+ break;
+ default: err:
+ usage();
+ break;
+ }
+ }
+ok:
+ ctx->args = argv+i;
+ if (ctx->mode == (BuildMode)-1) goto err;
+}
+
+int main(int argc, char **argv)
+{
+ BuildCtx ctx_;
+ BuildCtx *ctx = &ctx_;
+ int status, binmode;
+
+ if (sizeof(void *) != 4*LJ_32+8*LJ_64) {
+ fprintf(stderr,"Error: pointer size mismatch in cross-build.\n");
+ fprintf(stderr,"Try: make HOST_CC=\"gcc -m32\" CROSS=...\n\n");
+ return 1;
+ }
+
+ UNUSED(argc);
+ parseargs(ctx, argv);
+
+ if ((status = build_code(ctx))) {
+ fprintf(stderr,"Error: DASM error %08x\n", status);
+ return 1;
+ }
+
+ switch (ctx->mode) {
+ case BUILD_peobj:
+ case BUILD_raw:
+ binmode = 1;
+ break;
+ default:
+ binmode = 0;
+ break;
+ }
+
+ if (ctx->outname[0] == '-' && ctx->outname[1] == '\0') {
+ ctx->fp = stdout;
+#if defined(_WIN32)
+ if (binmode)
+ _setmode(_fileno(stdout), _O_BINARY); /* Yuck. */
+#endif
+ } else if (!(ctx->fp = fopen(ctx->outname, binmode ? "wb" : "w"))) {
+ fprintf(stderr, "Error: cannot open output file '%s': %s\n",
+ ctx->outname, strerror(errno));
+ exit(1);
+ }
+
+ switch (ctx->mode) {
+ case BUILD_elfasm:
+ case BUILD_coffasm:
+ case BUILD_machasm:
+ emit_asm(ctx);
+ emit_asm_debug(ctx);
+ break;
+ case BUILD_peobj:
+ emit_peobj(ctx);
+ break;
+ case BUILD_raw:
+ emit_raw(ctx);
+ break;
+ case BUILD_bcdef:
+ emit_bcdef(ctx);
+ emit_lib(ctx);
+ break;
+ case BUILD_vmdef:
+ emit_vmdef(ctx);
+ emit_lib(ctx);
+ fprintf(ctx->fp, "}\n\n");
+ break;
+ case BUILD_ffdef:
+ case BUILD_libdef:
+ case BUILD_recdef:
+ emit_lib(ctx);
+ break;
+ case BUILD_folddef:
+ emit_fold(ctx);
+ break;
+ default:
+ break;
+ }
+
+ fflush(ctx->fp);
+ if (ferror(ctx->fp)) {
+ fprintf(stderr, "Error: cannot write to output file: %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ fclose(ctx->fp);
+
+ return 0;
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/host/buildvm.h b/src/host/luajit-2.1.0-beta3/src/host/buildvm.h
new file mode 100644
index 00000000..b90428dc
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/host/buildvm.h
@@ -0,0 +1,105 @@
+/*
+** LuaJIT VM builder.
+** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#ifndef _BUILDVM_H
+#define _BUILDVM_H
+
+#include
+#include
+#include
+#include
+#include
+
+#include "lj_def.h"
+#include "lj_arch.h"
+
+/* Hardcoded limits. Increase as needed. */
+#define BUILD_MAX_RELOC 200 /* Max. number of relocations. */
+#define BUILD_MAX_FOLD 4096 /* Max. number of fold rules. */
+
+/* Prefix for scanned library definitions. */
+#define LIBDEF_PREFIX "LJLIB_"
+
+/* Prefix for scanned fold definitions. */
+#define FOLDDEF_PREFIX "LJFOLD"
+
+/* Prefixes for generated labels. */
+#define LABEL_PREFIX "lj_"
+#define LABEL_PREFIX_BC LABEL_PREFIX "BC_"
+#define LABEL_PREFIX_FF LABEL_PREFIX "ff_"
+#define LABEL_PREFIX_CF LABEL_PREFIX "cf_"
+#define LABEL_PREFIX_FFH LABEL_PREFIX "ffh_"
+#define LABEL_PREFIX_LIBCF LABEL_PREFIX "lib_cf_"
+#define LABEL_PREFIX_LIBINIT LABEL_PREFIX "lib_init_"
+
+/* Forward declaration. */
+struct dasm_State;
+
+/* Build modes. */
+#define BUILDDEF(_) \
+ _(elfasm) _(coffasm) _(machasm) _(peobj) _(raw) \
+ _(bcdef) _(ffdef) _(libdef) _(recdef) _(vmdef) \
+ _(folddef)
+
+typedef enum {
+#define BUILDENUM(name) BUILD_##name,
+BUILDDEF(BUILDENUM)
+#undef BUILDENUM
+ BUILD__MAX
+} BuildMode;
+
+/* Code relocation. */
+typedef struct BuildReloc {
+ int32_t ofs;
+ int sym;
+ int type;
+} BuildReloc;
+
+typedef struct BuildSym {
+ const char *name;
+ int32_t ofs;
+} BuildSym;
+
+/* Build context structure. */
+typedef struct BuildCtx {
+ /* DynASM state pointer. Should be first member. */
+ struct dasm_State *D;
+ /* Parsed command line. */
+ BuildMode mode;
+ FILE *fp;
+ const char *outname;
+ char **args;
+ /* Code and symbols generated by DynASM. */
+ uint8_t *code;
+ size_t codesz;
+ int npc, nglob, nsym, nreloc, nrelocsym;
+ void **glob;
+ BuildSym *sym;
+ const char **relocsym;
+ int32_t *bc_ofs;
+ const char *beginsym;
+ /* Strings generated by DynASM. */
+ const char *const *globnames;
+ const char *const *extnames;
+ const char *dasm_ident;
+ const char *dasm_arch;
+ /* Relocations. */
+ BuildReloc reloc[BUILD_MAX_RELOC];
+} BuildCtx;
+
+extern void owrite(BuildCtx *ctx, const void *ptr, size_t sz);
+extern void emit_asm(BuildCtx *ctx);
+extern void emit_peobj(BuildCtx *ctx);
+extern void emit_lib(BuildCtx *ctx);
+extern void emit_fold(BuildCtx *ctx);
+
+extern const char *const bc_names[];
+extern const char *const ir_names[];
+extern const char *const irt_names[];
+extern const char *const irfpm_names[];
+extern const char *const irfield_names[];
+extern const char *const ircall_names[];
+
+#endif
diff --git a/src/host/luajit-2.1.0-beta3/src/host/buildvm.o b/src/host/luajit-2.1.0-beta3/src/host/buildvm.o
new file mode 100644
index 00000000..127ec8d3
Binary files /dev/null and b/src/host/luajit-2.1.0-beta3/src/host/buildvm.o differ
diff --git a/src/host/luajit-2.1.0-beta3/src/host/buildvm_arch.h b/src/host/luajit-2.1.0-beta3/src/host/buildvm_arch.h
new file mode 100644
index 00000000..7c6fac73
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/host/buildvm_arch.h
@@ -0,0 +1,7525 @@
+/*
+** This file has been pre-processed with DynASM.
+** http://luajit.org/dynasm.html
+** DynASM version 1.4.0, DynASM x64 version 1.4.0
+** DO NOT EDIT! The original file is in "vm_x86.dasc".
+*/
+
+#line 1 "vm_x86.dasc"
+//|// Low-level VM code for x86 CPUs.
+//|// Bytecode interpreter, fast functions and helper functions.
+//|// Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
+//|
+//|.if P64
+//|.arch x64
+#if DASM_VERSION != 10400
+#error "Version mismatch between DynASM and included encoding engine"
+#endif
+#line 7 "vm_x86.dasc"
+//|.else
+//|.arch x86
+//|.endif
+//|.section code_op, code_sub
+#define DASM_SECTION_CODE_OP 0
+#define DASM_SECTION_CODE_SUB 1
+#define DASM_MAXSECTION 2
+#line 11 "vm_x86.dasc"
+//|
+//|.actionlist build_actionlist
+static const unsigned char build_actionlist[13914] = {
+ 254,1,248,10,252,247,195,237,15,132,244,11,131,227,252,248,41,218,72,141,
+ 76,25,252,248,139,90,252,252,199,68,10,4,237,248,12,131,192,1,15,132,244,
+ 13,137,68,36,4,252,247,195,237,15,132,244,14,248,15,129,252,243,239,252,247,
+ 195,237,15,133,244,10,65,199,134,233,237,131,227,252,248,41,211,252,247,219,
+ 131,232,1,15,132,244,248,248,1,255,72,139,44,10,72,137,106,252,248,131,194,
+ 8,131,232,1,15,133,244,1,248,2,139,108,36,24,137,157,233,248,3,139,68,36,
+ 4,139,76,36,16,248,4,57,193,15,133,244,252,248,5,131,252,234,8,137,149,233,
+ 248,16,72,139,76,36,32,72,137,141,233,49,192,248,17,72,131,196,40,65,94,65,
+ 95,91,93,195,248,6,15,130,244,253,59,149,233,15,135,244,254,255,199,66,252,
+ 252,237,131,194,8,131,192,1,252,233,244,4,248,7,133,201,15,132,244,5,41,193,
+ 141,20,202,252,233,244,5,248,8,137,149,233,137,68,36,4,137,206,137,252,239,
+ 232,251,1,0,139,149,233,252,233,244,3,248,13,176,235,252,233,244,18,248,19,
+ 137,252,240,72,137,252,252,248,18,255,139,108,36,24,139,173,233,199,133,233,
+ 237,252,233,244,17,248,20,139,124,36,24,137,198,72,131,196,40,65,94,65,95,
+ 91,93,252,233,251,1,1,248,21,72,129,231,239,72,137,252,252,248,22,139,108,
+ 36,24,72,199,193,252,248,252,255,252,255,252,255,184,237,139,149,233,68,139,
+ 181,233,65,129,198,239,139,90,252,252,199,66,252,252,237,65,199,134,233,237,
+ 252,233,244,12,248,23,255,190,237,252,233,244,248,248,24,131,232,8,252,233,
+ 244,247,248,25,141,68,194,252,248,248,1,15,182,139,233,131,195,4,137,149,
+ 233,137,133,233,137,92,36,28,137,206,248,2,137,252,239,232,251,1,0,139,149,
+ 233,139,133,233,139,106,252,248,41,208,193,232,3,131,192,1,139,157,233,139,
+ 11,15,182,252,233,15,182,205,131,195,4,65,252,255,36,252,238,248,26,85,83,
+ 65,87,65,86,72,131,252,236,40,137,252,253,137,124,36,24,137,252,241,187,237,
+ 49,192,76,141,188,253,36,233,68,139,181,233,255,65,129,198,239,137,68,36,
+ 28,72,137,68,36,32,137,68,36,16,137,68,36,20,76,137,189,233,56,133,233,15,
+ 132,244,248,65,137,174,233,65,199,134,233,237,136,133,233,139,149,233,139,
+ 133,233,41,200,193,232,3,131,192,1,41,209,139,90,252,252,137,68,36,4,252,
+ 247,195,237,15,132,244,14,252,233,244,15,248,27,85,83,65,87,65,86,72,131,
+ 252,236,40,187,237,137,76,36,20,252,233,244,247,248,28,255,85,83,65,87,65,
+ 86,72,131,252,236,40,187,237,248,1,137,84,36,16,137,252,253,137,124,36,24,
+ 137,252,241,68,139,181,233,76,139,189,233,76,137,124,36,32,137,108,36,28,
+ 65,129,198,239,72,137,165,233,248,2,65,137,174,233,65,199,134,233,237,139,
+ 149,233,1,203,41,211,139,133,233,41,200,193,232,3,131,192,1,248,29,139,105,
+ 252,248,129,121,253,252,252,239,15,133,244,30,248,31,137,202,137,90,252,252,
+ 139,157,233,139,11,15,182,252,233,15,182,205,131,195,4,65,252,255,36,252,
+ 238,248,32,255,85,83,65,87,65,86,72,131,252,236,40,137,252,253,137,124,36,
+ 24,137,108,36,28,68,139,189,233,68,43,189,233,68,139,181,233,199,68,36,20,
+ 0,0,0,0,68,137,124,36,16,65,129,198,239,76,139,189,233,76,137,124,36,32,72,
+ 137,165,233,65,137,174,233,252,255,209,133,192,15,132,244,16,137,193,187,
+ 237,252,233,244,2,248,11,1,209,131,227,252,248,137,213,41,218,199,68,193,
+ 252,252,237,137,200,139,93,252,244,72,99,77,252,240,131,252,249,1,15,134,
+ 244,247,76,141,61,245,76,1,252,249,68,139,122,252,248,69,139,191,233,255,
+ 69,139,191,233,252,255,225,248,1,15,132,244,33,41,213,193,252,237,3,141,69,
+ 252,255,252,233,244,34,248,35,15,182,75,252,255,131,252,237,16,141,12,202,
+ 41,252,233,15,132,244,36,252,247,217,193,252,233,3,139,124,36,24,137,151,
+ 233,137,202,72,139,8,72,137,77,0,137,252,238,252,233,244,37,248,38,137,4,
+ 36,199,68,36,4,237,72,141,4,36,128,123,252,252,235,15,133,244,247,65,141,
+ 142,233,137,41,199,65,4,237,255,137,205,252,233,244,248,248,39,15,182,67,
+ 252,254,252,242,15,42,192,252,242,15,17,4,36,72,141,4,36,252,233,244,247,
+ 248,40,15,182,67,252,254,141,4,194,248,1,15,182,107,252,255,141,44,252,234,
+ 248,2,139,124,36,24,137,151,233,137,252,238,72,137,194,137,252,253,137,92,
+ 36,28,232,251,1,2,139,149,233,133,192,15,132,244,249,248,36,15,182,75,252,
+ 253,72,139,40,72,137,44,202,139,3,15,182,204,15,182,232,131,195,4,193,232,
+ 16,65,252,255,36,252,238,248,3,139,141,233,137,89,252,244,141,153,233,41,
+ 211,139,105,252,248,184,237,252,233,244,31,248,41,255,137,252,239,137,213,
+ 137,198,232,251,1,3,15,182,75,252,253,137,252,234,133,192,15,133,244,42,199,
+ 68,202,4,237,252,233,244,43,248,44,137,4,36,199,68,36,4,237,72,141,4,36,128,
+ 123,252,252,235,15,133,244,247,65,141,142,233,137,41,199,65,4,237,137,205,
+ 252,233,244,248,248,45,15,182,67,252,254,252,242,15,42,192,252,242,15,17,
+ 4,36,72,141,4,36,252,233,244,247,248,46,15,182,67,252,254,141,4,194,248,1,
+ 255,15,182,107,252,255,141,44,252,234,248,2,139,124,36,24,137,151,233,137,
+ 252,238,72,137,194,137,252,253,137,92,36,28,232,251,1,4,139,149,233,133,192,
+ 15,132,244,249,15,182,75,252,253,72,139,44,202,72,137,40,248,47,139,3,15,
+ 182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,248,3,139,141,
+ 233,137,89,252,244,15,182,67,252,253,72,139,44,194,72,137,105,16,141,153,
+ 233,41,211,139,105,252,248,184,237,252,233,244,31,248,48,139,124,36,24,137,
+ 252,238,137,151,233,137,213,137,194,137,92,36,28,232,251,1,5,15,182,75,252,
+ 253,137,252,234,252,233,244,49,248,50,139,108,36,24,137,149,233,141,52,202,
+ 141,20,194,137,252,239,15,182,75,252,252,137,92,36,28,232,251,1,6,248,3,255,
+ 139,149,233,131,252,248,1,15,135,244,51,248,4,141,91,4,15,130,244,252,248,
+ 5,15,183,67,252,254,141,156,253,131,233,248,6,139,3,15,182,204,15,182,232,
+ 131,195,4,193,232,16,65,252,255,36,252,238,248,52,131,195,4,129,120,253,4,
+ 239,15,130,244,5,252,233,244,6,248,53,129,120,253,4,239,252,233,244,4,248,
+ 54,255,131,252,235,4,137,206,137,252,233,139,108,36,24,137,149,233,137,194,
+ 137,252,239,137,92,36,28,232,251,1,7,252,233,244,3,248,55,131,252,235,4,139,
+ 108,36,24,137,149,233,137,252,239,139,115,252,252,137,92,36,28,232,251,1,
+ 8,252,233,244,3,248,56,139,108,36,24,137,149,233,137,206,15,183,83,252,254,
+ 137,252,239,137,92,36,28,232,251,1,9,139,149,233,252,233,244,6,248,57,248,
+ 58,65,141,4,199,252,233,244,247,248,59,248,60,65,141,4,199,141,44,252,234,
+ 149,252,233,244,248,248,61,255,141,4,194,137,197,252,233,244,248,248,62,248,
+ 63,141,4,194,248,1,141,44,252,234,248,2,141,12,202,68,15,182,67,252,252,137,
+ 206,137,193,139,124,36,24,137,151,233,137,252,234,137,252,253,137,92,36,28,
+ 232,251,1,10,139,149,233,133,192,15,132,244,47,248,51,137,193,41,208,137,
+ 89,252,244,141,152,233,184,237,252,233,244,29,248,64,139,108,36,24,137,149,
+ 233,141,52,194,137,252,239,137,92,36,28,232,251,1,11,139,149,233,255,133,
+ 192,15,133,244,51,15,183,67,252,254,139,60,194,252,233,244,65,255,252,233,
+ 244,51,255,248,66,141,76,202,8,248,30,137,76,36,4,137,4,36,131,252,233,8,
+ 139,108,36,24,137,149,233,137,206,141,20,193,137,252,239,137,92,36,28,232,
+ 251,1,12,139,149,233,139,76,36,4,139,4,36,139,105,252,248,131,192,1,65,57,
+ 215,15,132,244,67,137,202,137,90,252,252,139,157,233,139,11,15,182,252,233,
+ 15,182,205,131,195,4,65,252,255,36,252,238,248,68,139,108,36,24,137,149,233,
+ 137,206,137,252,239,137,92,36,28,232,251,1,13,139,149,233,139,67,252,252,
+ 15,182,204,15,182,232,193,232,16,65,252,255,164,253,252,238,233,248,69,129,
+ 252,248,239,15,130,244,70,139,106,4,129,252,253,239,15,131,244,70,139,90,
+ 252,252,137,68,36,4,137,106,252,252,139,42,137,106,252,248,131,232,2,15,132,
+ 244,248,255,137,209,248,1,131,193,8,72,139,41,72,137,105,252,248,131,232,
+ 1,15,133,244,1,248,2,139,68,36,4,252,233,244,71,248,72,129,252,248,239,15,
+ 130,244,70,139,106,4,137,252,233,193,252,249,15,131,252,249,252,254,15,132,
+ 244,249,184,237,252,247,213,57,232,15,71,197,248,2,139,106,252,248,139,132,
+ 253,197,233,139,90,252,252,199,66,252,252,237,137,66,252,248,252,233,244,
+ 73,248,3,255,184,237,252,233,244,2,248,74,129,252,248,239,15,130,244,70,139,
+ 106,4,139,90,252,252,129,252,253,239,15,133,244,252,248,1,139,42,139,173,
+ 233,248,2,133,252,237,199,66,252,252,237,15,132,244,73,65,139,134,233,199,
+ 66,252,252,237,137,106,252,248,139,141,233,255,35,136,233,105,201,239,3,141,
+ 233,248,3,129,185,233,239,15,133,244,250,57,129,233,15,132,244,251,248,4,
+ 139,137,233,133,201,15,133,244,3,252,233,244,73,248,5,139,105,4,129,252,253,
+ 239,255,15,132,244,73,139,1,137,106,252,252,137,66,252,248,252,233,244,73,
+ 248,6,129,252,253,239,15,132,244,1,129,252,253,239,15,135,244,254,129,252,
+ 253,239,15,134,244,253,189,237,252,233,244,254,248,7,189,237,248,8,255,252,
+ 247,213,65,139,172,253,174,233,252,233,244,2,248,75,129,252,248,239,15,130,
+ 244,70,129,122,253,4,239,15,133,244,70,139,42,131,189,233,0,15,133,244,70,
+ 129,122,253,12,239,15,133,244,70,139,66,8,137,133,233,139,90,252,252,199,
+ 66,252,252,237,137,106,252,248,252,246,133,233,235,255,15,132,244,247,128,
+ 165,233,235,65,139,134,233,65,137,174,233,137,133,233,248,1,252,233,244,73,
+ 248,76,129,252,248,239,15,130,244,70,129,122,253,4,239,15,133,244,70,137,
+ 213,139,50,141,82,8,139,124,36,24,232,251,1,14,137,252,234,72,139,40,139,
+ 90,252,252,72,137,106,252,248,252,233,244,73,248,77,255,129,252,248,239,15,
+ 133,244,70,129,122,253,4,239,15,131,244,70,252,242,15,16,2,252,233,244,78,
+ 248,79,129,252,248,239,15,130,244,70,139,90,252,252,129,122,253,4,239,15,
+ 133,244,249,139,2,248,2,199,66,252,252,237,137,66,252,248,252,233,244,73,
+ 248,3,255,129,122,253,4,239,15,135,244,70,65,131,190,233,0,15,133,244,70,
+ 65,139,174,233,65,59,174,233,15,130,244,247,232,244,80,248,1,139,108,36,24,
+ 137,149,233,137,92,36,28,137,214,137,252,239,232,251,1,15,139,149,233,252,
+ 233,244,2,248,81,129,252,248,239,255,15,130,244,70,15,132,244,248,248,1,129,
+ 122,253,4,239,15,133,244,70,139,108,36,24,137,149,233,137,149,233,139,90,
+ 252,252,139,50,141,82,8,137,252,239,137,92,36,28,232,251,1,16,139,149,233,
+ 133,192,15,132,244,249,72,139,106,8,72,139,66,16,72,137,106,252,248,72,137,
+ 2,248,82,184,237,252,233,244,83,248,2,199,66,12,237,255,252,233,244,1,248,
+ 3,199,66,252,252,237,252,233,244,73,248,84,129,252,248,239,15,130,244,70,
+ 139,42,129,122,253,4,239,15,133,244,70,255,131,189,233,0,15,133,244,70,255,
+ 139,106,252,248,139,133,233,139,90,252,252,199,66,252,252,237,137,66,252,
+ 248,199,66,12,237,184,237,252,233,244,83,248,85,129,252,248,239,15,130,244,
+ 70,129,122,253,4,239,15,133,244,70,129,122,253,12,239,15,131,244,70,139,90,
+ 252,252,252,242,15,16,66,8,72,189,237,237,102,72,15,110,205,252,242,15,88,
+ 193,252,242,15,44,192,252,242,15,17,66,252,248,139,42,59,133,233,255,15,131,
+ 244,248,193,224,3,3,133,233,248,1,129,120,253,4,239,15,132,244,86,72,139,
+ 40,72,137,42,252,233,244,82,248,2,131,189,233,0,15,132,244,86,137,252,239,
+ 137,213,137,198,232,251,1,3,137,252,234,133,192,15,133,244,1,248,86,184,237,
+ 252,233,244,83,248,87,255,139,106,252,248,139,133,233,139,90,252,252,199,
+ 66,252,252,237,137,66,252,248,15,87,192,252,242,15,17,66,8,184,237,252,233,
+ 244,83,248,88,129,252,248,239,15,130,244,70,141,74,8,131,232,1,187,237,248,
+ 1,65,15,182,174,233,193,252,237,235,131,229,1,1,252,235,252,233,244,29,248,
+ 89,129,252,248,239,15,130,244,70,255,129,122,253,12,239,15,133,244,70,139,
+ 106,4,137,106,12,199,66,4,237,139,42,139,90,8,137,106,8,137,26,141,74,16,
+ 131,232,2,187,237,252,233,244,1,248,90,129,252,248,239,15,130,244,70,139,
+ 42,139,90,252,252,137,92,36,28,137,44,36,129,122,253,4,239,15,133,244,70,
+ 72,131,189,233,0,15,133,244,70,128,189,233,235,255,15,135,244,70,139,141,
+ 233,15,132,244,247,59,141,233,15,132,244,70,248,1,141,92,193,252,240,59,157,
+ 233,15,135,244,70,137,157,233,139,108,36,24,137,149,233,131,194,8,137,149,
+ 233,141,108,194,232,72,41,221,57,203,15,132,244,249,248,2,72,139,4,43,72,
+ 137,67,252,248,131,252,235,8,57,203,15,133,244,2,248,3,255,137,206,139,60,
+ 36,232,244,26,139,108,36,24,139,28,36,139,149,233,65,137,174,233,65,199,134,
+ 233,237,129,252,248,239,15,135,244,254,248,4,139,139,233,68,139,187,233,137,
+ 139,233,68,137,252,251,41,203,15,132,244,252,141,4,26,193,252,235,3,59,133,
+ 233,15,135,244,255,137,213,72,41,205,248,5,255,72,139,1,72,137,4,41,131,193,
+ 8,68,57,252,249,15,133,244,5,248,6,141,67,2,199,66,252,252,237,248,7,139,
+ 92,36,28,137,68,36,4,72,199,193,252,248,252,255,252,255,252,255,252,247,195,
+ 237,15,132,244,14,252,233,244,15,248,8,199,66,252,252,237,139,139,233,131,
+ 252,233,8,137,139,233,72,139,1,72,137,2,184,237,252,233,244,7,248,9,139,12,
+ 36,68,137,185,233,255,137,222,137,252,239,232,251,1,0,139,28,36,139,149,233,
+ 252,233,244,4,248,91,139,106,252,248,139,173,233,139,90,252,252,137,92,36,
+ 28,137,44,36,72,131,189,233,0,15,133,244,70,128,189,233,235,15,135,244,70,
+ 139,141,233,15,132,244,247,59,141,233,15,132,244,70,248,1,255,141,92,193,
+ 252,248,59,157,233,15,135,244,70,137,157,233,139,108,36,24,137,149,233,137,
+ 149,233,141,108,194,252,240,72,41,221,57,203,15,132,244,249,248,2,72,139,
+ 4,43,72,137,67,252,248,131,252,235,8,57,203,15,133,244,2,248,3,137,206,139,
+ 60,36,232,244,26,139,108,36,24,139,28,36,139,149,233,65,137,174,233,65,199,
+ 134,233,237,129,252,248,239,255,15,135,244,254,248,4,139,139,233,68,139,187,
+ 233,137,139,233,68,137,252,251,41,203,15,132,244,252,141,4,26,193,252,235,
+ 3,59,133,233,15,135,244,255,137,213,72,41,205,248,5,72,139,1,72,137,4,41,
+ 131,193,8,68,57,252,249,15,133,244,5,248,6,141,67,1,248,7,139,92,36,28,137,
+ 68,36,4,49,201,252,247,195,237,15,132,244,14,255,252,233,244,15,248,8,137,
+ 222,137,252,239,232,251,1,17,248,9,139,12,36,68,137,185,233,137,222,137,252,
+ 239,232,251,1,0,139,28,36,139,149,233,252,233,244,4,248,92,139,108,36,24,
+ 72,252,247,133,233,237,15,132,244,70,137,149,233,141,68,194,252,248,137,133,
+ 233,49,192,72,137,133,233,176,235,136,133,233,252,233,244,17,248,93,248,94,
+ 255,139,90,252,252,221,90,252,248,252,233,244,73,248,95,129,252,248,239,15,
+ 130,244,70,129,122,253,4,239,15,131,244,70,252,242,15,16,2,72,184,237,237,
+ 102,72,15,110,200,15,84,193,248,78,139,90,252,252,252,242,15,17,66,252,248,
+ 248,73,184,237,248,83,137,68,36,4,248,71,252,247,195,237,15,133,244,253,248,
+ 5,255,56,67,252,255,15,135,244,252,15,182,75,252,253,72,252,247,209,141,20,
+ 202,139,3,15,182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,
+ 248,6,199,68,194,252,244,237,131,192,1,252,233,244,5,248,7,72,199,193,252,
+ 248,252,255,252,255,252,255,252,233,244,15,248,96,129,122,253,4,239,15,131,
+ 244,70,252,242,15,16,2,232,244,97,252,233,244,78,248,98,129,122,253,4,239,
+ 255,15,131,244,70,252,242,15,16,2,232,244,99,252,233,244,78,248,100,129,252,
+ 248,239,15,130,244,70,129,122,253,4,239,15,131,244,70,252,242,15,81,2,252,
+ 233,244,78,248,101,129,252,248,239,15,133,244,70,255,129,122,253,4,239,15,
+ 131,244,70,252,242,15,16,2,137,213,232,251,1,18,137,252,234,252,233,244,78,
+ 248,102,129,252,248,239,15,130,244,70,129,122,253,4,239,15,131,244,70,252,
+ 242,15,16,2,137,213,232,251,1,19,137,252,234,252,233,244,78,248,103,129,252,
+ 248,239,15,130,244,70,129,122,253,4,239,255,15,131,244,70,252,242,15,16,2,
+ 137,213,232,251,1,20,137,252,234,252,233,244,78,248,104,129,252,248,239,15,
+ 130,244,70,129,122,253,4,239,15,131,244,70,252,242,15,16,2,137,213,232,251,
+ 1,21,137,252,234,252,233,244,78,248,105,129,252,248,239,15,130,244,70,129,
+ 122,253,4,239,15,131,244,70,255,252,242,15,16,2,137,213,232,251,1,22,137,
+ 252,234,252,233,244,78,248,106,129,252,248,239,15,130,244,70,129,122,253,
+ 4,239,15,131,244,70,252,242,15,16,2,137,213,232,251,1,23,137,252,234,252,
+ 233,244,78,248,107,129,252,248,239,15,130,244,70,129,122,253,4,239,15,131,
+ 244,70,252,242,15,16,2,137,213,232,251,1,24,137,252,234,252,233,244,78,248,
+ 108,255,129,252,248,239,15,130,244,70,129,122,253,4,239,15,131,244,70,252,
+ 242,15,16,2,137,213,232,251,1,25,137,252,234,252,233,244,78,248,109,129,252,
+ 248,239,15,130,244,70,129,122,253,4,239,15,131,244,70,252,242,15,16,2,137,
+ 213,232,251,1,26,137,252,234,252,233,244,78,248,110,129,252,248,239,255,15,
+ 130,244,70,129,122,253,4,239,15,131,244,70,252,242,15,16,2,137,213,232,251,
+ 1,27,137,252,234,252,233,244,78,248,111,129,252,248,239,15,130,244,70,129,
+ 122,253,4,239,15,131,244,70,252,242,15,16,2,137,213,232,251,1,28,137,252,
+ 234,252,233,244,78,248,112,129,252,248,239,15,130,244,70,255,129,122,253,
+ 4,239,15,131,244,70,252,242,15,16,2,137,213,232,251,1,29,137,252,234,252,
+ 233,244,78,248,113,129,252,248,239,15,130,244,70,129,122,253,4,239,15,131,
+ 244,70,129,122,253,12,239,15,131,244,70,252,242,15,16,2,252,242,15,16,74,
+ 8,137,213,232,251,1,30,137,252,234,252,233,244,78,248,114,129,252,248,239,
+ 255,15,130,244,70,129,122,253,4,239,15,131,244,70,129,122,253,12,239,15,131,
+ 244,70,252,242,15,16,2,252,242,15,16,74,8,137,213,232,251,1,31,137,252,234,
+ 252,233,244,78,248,115,129,252,248,239,15,130,244,70,129,122,253,4,239,15,
+ 131,244,70,129,122,253,12,239,15,131,244,70,255,252,242,15,16,2,252,242,15,
+ 16,74,8,137,213,232,251,1,32,137,252,234,252,233,244,78,248,116,129,252,248,
+ 239,15,130,244,70,129,122,253,4,239,15,131,244,70,129,122,253,12,239,15,131,
+ 244,70,221,66,8,221,2,217,252,253,221,217,252,233,244,94,248,117,129,252,
+ 248,239,15,130,244,70,139,106,4,129,252,253,239,255,15,131,244,70,139,90,
+ 252,252,139,2,137,106,252,252,137,66,252,248,209,229,129,252,253,0,0,224,
+ 252,255,15,131,244,249,9,232,15,132,244,249,184,252,254,3,0,0,129,252,253,
+ 0,0,32,0,15,130,244,250,248,1,193,252,237,21,41,197,252,242,15,42,197,139,
+ 106,252,252,129,229,252,255,252,255,15,128,129,205,0,0,224,63,137,106,252,
+ 252,248,2,252,242,15,17,2,184,237,252,233,244,83,248,3,15,87,192,252,233,
+ 244,2,248,4,252,242,15,16,2,72,189,237,237,255,102,72,15,110,205,252,242,
+ 15,89,193,252,242,15,17,66,252,248,139,106,252,252,184,52,4,0,0,209,229,252,
+ 233,244,1,248,118,129,252,248,239,15,130,244,70,129,122,253,4,239,15,131,
+ 244,70,252,242,15,16,2,139,106,4,139,90,252,252,209,229,129,252,253,0,0,224,
+ 252,255,15,132,244,250,15,40,224,232,244,119,252,242,15,92,224,248,1,252,
+ 242,15,17,66,252,248,252,242,15,17,34,139,66,252,252,139,106,4,49,232,15,
+ 136,244,249,248,2,184,237,252,233,244,83,248,3,255,129,252,245,0,0,0,128,
+ 137,106,4,252,233,244,2,248,4,15,87,228,252,233,244,1,248,120,185,2,0,0,0,
+ 129,122,253,4,239,15,131,244,70,252,242,15,16,2,248,5,57,193,15,131,244,78,
+ 129,124,253,202,252,252,239,15,131,244,70,248,6,252,242,15,16,76,202,252,
+ 248,248,7,252,242,15,93,193,131,193,1,252,233,244,5,248,121,255,185,2,0,0,
+ 0,129,122,253,4,239,15,131,244,70,252,242,15,16,2,248,5,57,193,15,131,244,
+ 78,129,124,253,202,252,252,239,15,131,244,70,248,6,252,242,15,16,76,202,252,
+ 248,248,7,252,242,15,95,193,131,193,1,252,233,244,5,248,122,129,252,248,239,
+ 15,133,244,70,129,122,253,4,239,15,133,244,70,255,139,42,139,90,252,252,131,
+ 189,233,1,15,130,244,86,15,182,173,233,252,242,15,42,197,252,233,244,78,248,
+ 123,65,139,174,233,65,59,174,233,15,130,244,247,232,244,80,248,1,129,252,
+ 248,239,15,133,244,70,129,122,253,4,239,15,131,244,70,255,252,242,15,44,42,
+ 129,252,253,252,255,0,0,0,15,135,244,70,137,108,36,4,199,68,36,8,1,0,0,0,
+ 72,141,68,36,4,248,124,139,108,36,24,137,149,233,139,84,36,8,72,137,198,137,
+ 252,239,137,92,36,28,232,251,1,33,248,125,139,149,233,139,90,252,252,199,
+ 66,252,252,237,137,66,252,248,252,233,244,73,248,126,65,139,174,233,65,59,
+ 174,233,15,130,244,247,232,244,80,248,1,199,68,36,4,252,255,252,255,252,255,
+ 252,255,129,252,248,239,15,130,244,70,255,15,134,244,247,129,122,253,20,239,
+ 15,131,244,70,252,242,15,44,106,16,137,108,36,4,248,1,129,122,253,4,239,15,
+ 133,244,70,129,122,253,12,239,15,131,244,70,139,42,137,108,36,8,139,173,233,
+ 252,242,15,44,74,8,139,68,36,4,57,197,15,130,244,251,248,2,133,201,15,142,
+ 244,253,248,3,255,139,108,36,8,41,200,15,140,244,127,141,172,253,13,233,131,
+ 192,1,248,4,137,68,36,8,137,232,252,233,244,124,248,5,15,140,244,252,141,
+ 68,40,1,252,233,244,2,248,6,137,232,252,233,244,2,248,7,15,132,244,254,1,
+ 252,233,131,193,1,15,143,244,3,248,8,255,185,1,0,0,0,252,233,244,3,248,127,
+ 49,192,252,233,244,4,248,128,129,252,248,239,15,130,244,70,65,139,174,233,
+ 65,59,174,233,15,130,244,247,232,244,80,248,1,129,122,253,4,239,15,133,244,
+ 70,255,139,108,36,24,65,141,190,233,137,149,233,139,50,139,135,233,137,175,
+ 233,137,135,233,137,92,36,28,232,251,1,34,137,199,232,251,1,35,252,233,244,
+ 125,248,129,129,252,248,239,15,130,244,70,65,139,174,233,65,59,174,233,15,
+ 130,244,247,232,244,80,248,1,129,122,253,4,239,255,15,133,244,70,139,108,
+ 36,24,65,141,190,233,137,149,233,139,50,139,135,233,137,175,233,137,135,233,
+ 137,92,36,28,232,251,1,36,137,199,232,251,1,35,252,233,244,125,248,130,129,
+ 252,248,239,15,130,244,70,65,139,174,233,65,59,174,233,15,130,244,247,232,
+ 244,80,248,1,255,129,122,253,4,239,15,133,244,70,139,108,36,24,65,141,190,
+ 233,137,149,233,139,50,139,135,233,137,175,233,137,135,233,137,92,36,28,232,
+ 251,1,37,137,199,232,251,1,35,252,233,244,125,248,131,129,252,248,239,15,
+ 130,244,70,129,122,253,4,239,15,131,244,70,252,242,15,16,2,72,189,237,237,
+ 255,102,72,15,110,205,252,242,15,88,193,102,15,126,197,248,2,252,233,244,
+ 132,248,133,129,252,248,239,15,130,244,70,72,189,237,237,102,72,15,110,205,
+ 129,122,253,4,239,15,131,244,70,252,242,15,16,2,252,242,15,88,193,102,15,
+ 126,197,248,2,137,68,36,4,141,68,194,252,240,248,1,57,208,15,134,244,132,
+ 129,120,253,4,239,15,131,244,134,255,252,242,15,16,0,252,242,15,88,193,102,
+ 15,126,193,33,205,131,232,8,252,233,244,1,248,135,129,252,248,239,15,130,
+ 244,70,72,189,237,237,102,72,15,110,205,129,122,253,4,239,15,131,244,70,252,
+ 242,15,16,2,252,242,15,88,193,102,15,126,197,248,2,137,68,36,4,141,68,194,
+ 252,240,248,1,57,208,15,134,244,132,129,120,253,4,239,15,131,244,134,252,
+ 242,15,16,0,252,242,15,88,193,102,15,126,193,9,205,131,232,8,252,233,244,
+ 1,248,136,255,129,252,248,239,15,130,244,70,72,189,237,237,102,72,15,110,
+ 205,129,122,253,4,239,15,131,244,70,252,242,15,16,2,252,242,15,88,193,102,
+ 15,126,197,248,2,137,68,36,4,141,68,194,252,240,248,1,57,208,15,134,244,132,
+ 129,120,253,4,239,15,131,244,134,252,242,15,16,0,252,242,15,88,193,102,15,
+ 126,193,49,205,131,232,8,252,233,244,1,248,137,129,252,248,239,255,15,130,
+ 244,70,129,122,253,4,239,15,131,244,70,252,242,15,16,2,72,189,237,237,102,
+ 72,15,110,205,252,242,15,88,193,102,15,126,197,248,2,15,205,252,233,244,132,
+ 248,138,129,252,248,239,15,130,244,70,129,122,253,4,239,15,131,244,70,252,
+ 242,15,16,2,72,189,237,237,255,102,72,15,110,205,252,242,15,88,193,102,15,
+ 126,197,248,2,252,247,213,248,132,252,242,15,42,197,252,233,244,78,248,134,
+ 139,68,36,4,252,233,244,70,248,139,129,252,248,239,15,130,244,70,129,122,
+ 253,4,239,15,131,244,70,129,122,253,12,239,15,131,244,70,252,242,15,16,2,
+ 252,242,15,16,74,8,72,189,237,237,255,102,72,15,110,213,252,242,15,88,194,
+ 252,242,15,88,202,102,15,126,197,102,15,126,201,211,229,252,233,244,132,248,
+ 140,129,252,248,239,15,130,244,70,129,122,253,4,239,15,131,244,70,129,122,
+ 253,12,239,15,131,244,70,252,242,15,16,2,252,242,15,16,74,8,72,189,237,237,
+ 102,72,15,110,213,252,242,15,88,194,252,242,15,88,202,102,15,126,197,102,
+ 15,126,201,211,252,237,252,233,244,132,248,141,129,252,248,239,15,130,244,
+ 70,255,129,122,253,4,239,15,131,244,70,129,122,253,12,239,15,131,244,70,252,
+ 242,15,16,2,252,242,15,16,74,8,72,189,237,237,102,72,15,110,213,252,242,15,
+ 88,194,252,242,15,88,202,102,15,126,197,102,15,126,201,211,252,253,252,233,
+ 244,132,248,142,129,252,248,239,15,130,244,70,129,122,253,4,239,15,131,244,
+ 70,129,122,253,12,239,15,131,244,70,255,252,242,15,16,2,252,242,15,16,74,
+ 8,72,189,237,237,102,72,15,110,213,252,242,15,88,194,252,242,15,88,202,102,
+ 15,126,197,102,15,126,201,211,197,252,233,244,132,248,143,129,252,248,239,
+ 15,130,244,70,129,122,253,4,239,15,131,244,70,129,122,253,12,239,15,131,244,
+ 70,252,242,15,16,2,252,242,15,16,74,8,72,189,237,237,102,72,15,110,213,252,
+ 242,15,88,194,252,242,15,88,202,102,15,126,197,102,15,126,201,211,205,252,
+ 233,244,132,248,144,255,184,237,252,233,244,70,248,145,184,237,248,70,139,
+ 108,36,24,139,90,252,252,137,92,36,28,137,149,233,141,68,194,252,248,141,
+ 136,233,137,133,233,139,66,252,248,59,141,233,15,135,244,251,137,252,239,
+ 252,255,144,233,139,149,233,133,192,15,143,244,83,248,1,139,141,233,41,209,
+ 193,252,233,3,133,192,141,65,1,139,106,252,248,15,133,244,34,255,139,157,
+ 233,139,11,15,182,252,233,15,182,205,131,195,4,65,252,255,36,252,238,248,
+ 34,137,209,252,247,195,237,15,133,244,249,15,182,107,252,253,72,252,247,213,
+ 141,20,252,234,252,233,244,29,248,3,137,221,131,229,252,248,41,252,234,252,
+ 233,244,29,248,5,190,237,137,252,239,232,251,1,0,139,149,233,49,192,252,233,
+ 244,1,248,80,93,72,137,108,36,8,139,108,36,24,137,92,36,28,137,149,233,141,
+ 68,194,252,248,137,252,239,137,133,233,232,251,1,38,139,149,233,255,139,133,
+ 233,41,208,193,232,3,131,192,1,72,139,108,36,8,85,195,248,146,65,15,182,134,
+ 233,168,235,15,133,244,251,168,235,15,133,244,247,168,235,15,132,244,247,
+ 65,252,255,142,233,252,233,244,247,248,147,65,15,182,134,233,168,235,15,133,
+ 244,251,255,252,233,244,247,248,148,65,15,182,134,233,168,235,15,133,244,
+ 251,168,235,15,132,244,251,65,252,255,142,233,15,132,244,247,168,235,15,132,
+ 244,251,248,1,139,108,36,24,137,149,233,137,222,137,252,239,232,251,1,39,
+ 248,3,255,139,149,233,248,4,15,182,75,252,253,248,5,15,182,107,252,252,15,
+ 183,67,252,254,65,252,255,164,253,252,238,233,248,149,131,195,4,139,77,232,
+ 137,76,36,4,252,233,244,4,248,150,139,106,252,248,139,173,233,15,182,133,
+ 233,141,4,194,139,108,36,24,137,149,233,137,133,233,137,222,65,141,190,233,
+ 73,137,174,233,137,92,36,28,232,251,1,40,252,233,244,3,248,151,137,92,36,
+ 28,252,233,244,247,248,152,255,137,92,36,28,131,203,1,248,1,141,68,194,252,
+ 248,139,108,36,24,137,149,233,137,133,233,137,222,137,252,239,232,251,1,41,
+ 199,68,36,28,0,0,0,0,131,227,252,254,139,149,233,72,137,193,139,133,233,41,
+ 208,72,137,205,15,182,75,252,253,193,232,3,131,192,1,252,255,229,248,153,
+ 139,77,232,137,12,36,68,137,116,36,8,68,139,116,36,4,15,182,75,252,253,141,
+ 12,202,65,131,252,238,1,15,132,244,248,248,1,72,139,40,72,137,41,131,192,
+ 8,131,193,8,65,131,252,238,1,15,133,244,1,248,2,15,182,67,252,253,15,182,
+ 107,252,255,1,232,141,68,194,252,248,248,3,57,200,15,135,244,255,68,139,116,
+ 36,8,139,4,36,15,183,168,233,15,183,128,233,57,232,15,132,244,47,255,133,
+ 192,15,133,245,65,137,174,233,139,108,36,24,137,149,233,137,222,65,141,190,
+ 233,73,137,174,233,232,251,1,42,139,149,233,252,233,244,47,248,9,199,65,4,
+ 237,131,193,8,252,233,244,3,248,154,255,139,108,36,24,137,149,233,137,222,
+ 137,252,239,232,251,1,43,139,149,233,131,252,235,4,252,233,244,47,255,248,
+ 155,65,85,65,84,65,83,65,82,65,81,65,80,87,86,85,72,141,108,36,88,85,83,82,
+ 81,80,15,182,69,252,248,138,101,252,240,76,137,125,252,248,76,137,117,252,
+ 240,68,139,117,0,65,139,142,233,65,199,134,233,237,65,137,134,233,65,137,
+ 142,233,72,129,252,236,239,72,131,197,128,252,242,68,15,17,125,252,248,252,
+ 242,68,15,17,117,252,240,252,242,68,15,17,109,232,252,242,68,15,17,101,224,
+ 252,242,68,15,17,93,216,252,242,68,15,17,85,208,252,242,68,15,17,77,200,252,
+ 242,68,15,17,69,192,252,242,15,17,125,184,252,242,15,17,117,176,252,242,15,
+ 17,109,168,252,242,15,17,101,160,252,242,15,17,93,152,252,242,15,17,85,144,
+ 252,242,15,17,77,136,252,242,15,17,69,128,65,139,174,233,65,139,150,233,73,
+ 137,174,233,137,149,233,72,137,230,65,141,190,233,65,199,134,233,0,0,0,0,
+ 232,251,1,44,72,139,141,233,72,129,225,239,72,137,204,137,169,233,139,149,
+ 233,139,153,233,252,233,244,247,248,156,255,72,131,196,16,248,1,76,139,108,
+ 36,8,76,139,36,36,133,192,15,136,244,255,139,108,36,24,137,68,36,4,68,139,
+ 122,252,248,69,139,191,233,69,139,191,233,137,149,233,65,199,134,233,0,0,
+ 0,0,65,199,134,233,237,139,3,15,182,204,15,182,232,131,195,4,193,232,16,129,
+ 252,253,239,15,130,244,249,129,252,253,239,15,131,244,250,248,2,139,68,36,
+ 4,248,3,65,252,255,36,252,238,248,4,139,66,252,252,169,237,255,15,133,244,
+ 2,15,182,64,252,253,72,252,247,208,68,139,124,194,252,248,69,139,191,233,
+ 69,139,191,233,252,233,244,2,248,9,252,247,216,137,252,239,137,198,232,251,
+ 1,1,248,157,248,97,72,184,237,237,102,72,15,110,208,72,184,237,237,102,72,
+ 15,110,216,15,40,200,102,15,84,202,102,15,46,217,15,134,244,247,102,15,85,
+ 208,252,242,15,88,203,252,242,15,92,203,102,15,86,202,72,184,237,237,102,
+ 72,15,110,208,252,242,15,194,193,1,102,15,84,194,252,242,15,92,200,15,40,
+ 193,248,1,195,248,158,248,99,72,184,237,237,255,102,72,15,110,208,72,184,
+ 237,237,102,72,15,110,216,15,40,200,102,15,84,202,102,15,46,217,15,134,244,
+ 247,102,15,85,208,252,242,15,88,203,252,242,15,92,203,102,15,86,202,72,184,
+ 237,237,102,72,15,110,208,252,242,15,194,193,6,102,15,84,194,252,242,15,92,
+ 200,15,40,193,248,1,195,248,159,248,119,72,184,237,237,102,72,15,110,208,
+ 72,184,237,237,102,72,15,110,216,15,40,200,102,15,84,202,102,15,46,217,15,
+ 134,244,247,102,15,85,208,15,40,193,252,242,15,88,203,252,242,15,92,203,72,
+ 184,237,237,102,72,15,110,216,252,242,15,194,193,1,102,15,84,195,252,242,
+ 15,92,200,102,15,86,202,15,40,193,248,1,195,248,160,255,15,40,232,252,242,
+ 15,94,193,72,184,237,237,102,72,15,110,208,72,184,237,237,102,72,15,110,216,
+ 15,40,224,102,15,84,226,102,15,46,220,15,134,244,247,102,15,85,208,252,242,
+ 15,88,227,252,242,15,92,227,102,15,86,226,72,184,237,237,102,72,15,110,208,
+ 252,242,15,194,196,1,102,15,84,194,252,242,15,92,224,15,40,197,252,242,15,
+ 89,204,252,242,15,92,193,195,248,1,252,242,15,89,200,15,40,197,252,242,15,
+ 92,193,195,248,161,131,252,248,1,15,142,244,252,248,1,169,1,0,0,0,15,133,
+ 244,248,252,242,15,89,192,209,232,252,233,244,1,248,2,209,232,15,132,244,
+ 251,255,15,40,200,248,3,252,242,15,89,192,209,232,15,132,244,250,15,131,244,
+ 3,252,242,15,89,200,252,233,244,3,248,4,252,242,15,89,193,248,5,195,248,6,
+ 15,132,244,5,15,130,244,253,252,247,216,232,244,1,72,184,237,237,102,72,15,
+ 110,200,252,242,15,94,200,15,40,193,195,248,7,72,184,237,237,255,102,72,15,
+ 110,192,195,248,162,137,252,248,83,49,201,15,162,137,6,137,94,4,137,78,8,
+ 137,86,12,91,195,248,163,255,204,255,204,248,164,83,65,87,65,86,72,131,252,
+ 236,40,68,141,181,233,139,157,233,15,183,192,137,131,233,72,137,187,233,72,
+ 137,179,233,72,137,147,233,72,137,139,233,252,242,15,17,131,233,252,242,15,
+ 17,139,233,252,242,15,17,147,233,252,242,15,17,155,233,72,141,132,253,36,
+ 233,76,137,131,233,76,137,139,233,252,242,15,17,163,233,252,242,15,17,171,
+ 233,252,242,15,17,179,233,252,242,15,17,187,233,255,72,137,131,233,72,137,
+ 230,137,92,36,28,137,223,232,251,1,45,65,199,134,233,237,139,144,233,139,
+ 128,233,41,208,139,106,252,248,193,232,3,131,192,1,139,157,233,139,11,15,
+ 182,252,233,15,182,205,131,195,4,65,252,255,36,252,238,248,33,139,76,36,24,
+ 65,139,158,233,72,137,139,233,137,145,233,137,169,233,137,223,137,198,232,
+ 251,1,46,72,139,131,233,252,242,15,16,131,233,252,233,244,17,248,165,85,72,
+ 137,229,83,72,137,252,251,139,131,233,72,41,196,15,182,139,233,131,252,233,
+ 1,15,136,244,248,248,1,255,72,139,132,253,203,233,72,137,132,253,204,233,
+ 131,252,233,1,15,137,244,1,248,2,15,182,131,233,72,139,187,233,72,139,179,
+ 233,72,139,147,233,72,139,139,233,76,139,131,233,76,139,139,233,133,192,15,
+ 132,244,251,15,40,131,233,15,40,139,233,15,40,147,233,15,40,155,233,131,252,
+ 248,4,15,134,244,251,255,15,40,163,233,15,40,171,233,15,40,179,233,15,40,
+ 187,233,248,5,252,255,147,233,72,137,131,233,15,41,131,233,72,137,147,233,
+ 15,41,139,233,72,139,93,252,248,201,195,255,249,255,129,124,253,202,4,239,
+ 15,131,244,50,129,124,253,194,4,239,15,131,244,50,248,1,252,242,15,16,4,194,
+ 248,2,131,195,4,102,15,46,4,202,248,3,255,15,134,244,247,255,15,135,244,247,
+ 255,15,130,244,247,255,15,131,244,247,255,15,183,67,252,254,141,156,253,131,
+ 233,248,1,139,3,15,182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,
+ 252,238,255,139,108,194,4,131,195,4,255,129,252,253,239,15,131,244,251,129,
+ 124,253,202,4,239,15,131,244,251,248,1,252,242,15,16,4,202,248,2,102,15,46,
+ 4,194,248,4,255,15,138,244,248,15,133,244,248,255,15,138,244,248,15,132,244,
+ 247,255,248,1,15,183,67,252,254,141,156,253,131,233,248,2,255,248,2,15,183,
+ 67,252,254,141,156,253,131,233,248,1,255,252,233,244,9,255,248,5,129,252,
+ 253,239,15,132,244,55,129,124,253,202,4,239,15,132,244,55,57,108,202,4,15,
+ 133,244,2,129,252,253,239,15,131,244,1,139,12,202,139,4,194,57,193,15,132,
+ 244,1,129,252,253,239,15,135,244,2,129,252,253,239,15,130,244,2,255,139,169,
+ 233,133,252,237,15,132,244,2,252,246,133,233,235,15,133,244,2,255,49,252,
+ 237,255,189,1,0,0,0,255,252,233,244,54,255,248,3,129,252,253,239,255,15,133,
+ 244,9,255,252,233,244,55,255,72,252,247,208,139,108,202,4,131,195,4,129,252,
+ 253,239,15,133,244,249,139,12,202,65,59,12,135,255,139,108,202,4,131,195,
+ 4,255,129,252,253,239,15,131,244,249,248,1,252,242,65,15,16,4,199,248,2,102,
+ 15,46,4,202,248,4,255,72,252,247,208,139,108,202,4,131,195,4,57,197,255,15,
+ 133,244,249,15,183,67,252,254,141,156,253,131,233,248,2,139,3,15,182,204,
+ 15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,248,3,129,252,253,239,
+ 15,133,244,2,252,233,244,55,255,15,132,244,248,129,252,253,239,15,132,244,
+ 55,15,183,67,252,254,141,156,253,131,233,248,2,139,3,15,182,204,15,182,232,
+ 131,195,4,193,232,16,65,252,255,36,252,238,255,139,108,194,4,131,195,4,129,
+ 252,253,239,255,137,108,202,4,139,44,194,137,44,202,255,3,68,202,4,15,133,
+ 244,56,139,3,15,182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,252,
+ 238,255,129,124,253,202,4,239,15,131,244,56,139,3,15,182,204,15,182,232,131,
+ 195,4,193,232,16,65,252,255,36,252,238,255,72,139,44,194,72,137,44,202,139,
+ 3,15,182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,255,49,
+ 252,237,129,124,253,194,4,239,129,213,239,137,108,202,4,139,3,15,182,204,
+ 15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,255,129,124,253,194,
+ 4,239,15,131,244,61,252,242,15,16,4,194,72,184,237,237,102,72,15,110,200,
+ 15,87,193,252,242,15,17,4,202,139,3,15,182,204,15,182,232,131,195,4,193,232,
+ 16,65,252,255,36,252,238,255,129,124,253,194,4,239,15,133,244,248,139,4,194,
+ 15,87,192,252,242,15,42,128,233,248,1,252,242,15,17,4,202,139,3,15,182,204,
+ 15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,248,2,129,124,253,194,
+ 4,239,15,133,244,64,139,60,194,255,139,175,233,131,252,253,0,15,133,244,255,
+ 248,3,255,248,65,137,213,232,251,1,47,252,242,15,42,192,137,252,234,15,182,
+ 75,252,253,252,233,244,1,255,248,9,252,246,133,233,235,15,133,244,3,252,233,
+ 244,64,255,15,182,252,236,15,182,192,255,129,124,253,252,234,4,239,15,131,
+ 244,58,252,242,15,16,4,252,234,252,242,65,15,88,4,199,255,129,124,253,252,
+ 234,4,239,15,131,244,60,252,242,65,15,16,4,199,252,242,15,88,4,252,234,255,
+ 129,124,253,252,234,4,239,15,131,244,63,129,124,253,194,4,239,15,131,244,
+ 63,252,242,15,16,4,252,234,252,242,15,88,4,194,255,129,124,253,252,234,4,
+ 239,15,131,244,58,252,242,15,16,4,252,234,252,242,65,15,92,4,199,255,129,
+ 124,253,252,234,4,239,15,131,244,60,252,242,65,15,16,4,199,252,242,15,92,
+ 4,252,234,255,129,124,253,252,234,4,239,15,131,244,63,129,124,253,194,4,239,
+ 15,131,244,63,252,242,15,16,4,252,234,252,242,15,92,4,194,255,129,124,253,
+ 252,234,4,239,15,131,244,58,252,242,15,16,4,252,234,252,242,65,15,89,4,199,
+ 255,129,124,253,252,234,4,239,15,131,244,60,252,242,65,15,16,4,199,252,242,
+ 15,89,4,252,234,255,129,124,253,252,234,4,239,15,131,244,63,129,124,253,194,
+ 4,239,15,131,244,63,252,242,15,16,4,252,234,252,242,15,89,4,194,255,129,124,
+ 253,252,234,4,239,15,131,244,58,252,242,15,16,4,252,234,252,242,65,15,94,
+ 4,199,255,129,124,253,252,234,4,239,15,131,244,60,252,242,65,15,16,4,199,
+ 252,242,15,94,4,252,234,255,129,124,253,252,234,4,239,15,131,244,63,129,124,
+ 253,194,4,239,15,131,244,63,252,242,15,16,4,252,234,252,242,15,94,4,194,255,
+ 129,124,253,252,234,4,239,15,131,244,58,252,242,15,16,4,252,234,252,242,65,
+ 15,16,12,199,255,129,124,253,252,234,4,239,15,131,244,60,252,242,65,15,16,
+ 4,199,252,242,15,16,12,252,234,255,129,124,253,252,234,4,239,15,131,244,63,
+ 129,124,253,194,4,239,15,131,244,63,252,242,15,16,4,252,234,252,242,15,16,
+ 12,194,255,248,166,232,244,160,252,242,15,17,4,202,139,3,15,182,204,15,182,
+ 232,131,195,4,193,232,16,65,252,255,36,252,238,255,252,233,244,166,255,137,
+ 213,232,251,1,30,15,182,75,252,253,137,252,234,252,242,15,17,4,202,139,3,
+ 15,182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,255,15,182,
+ 252,236,15,182,192,139,124,36,24,137,151,233,141,52,194,137,194,41,252,234,
+ 248,37,137,252,253,137,92,36,28,232,251,1,48,139,149,233,133,192,15,133,244,
+ 51,15,182,107,252,255,15,182,75,252,253,72,139,4,252,234,72,137,4,202,139,
+ 3,15,182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,255,72,
+ 252,247,208,65,139,4,135,199,68,202,4,237,137,4,202,139,3,15,182,204,15,182,
+ 232,131,195,4,193,232,16,65,252,255,36,252,238,255,15,191,192,252,242,15,
+ 42,192,252,242,15,17,4,202,139,3,15,182,204,15,182,232,131,195,4,193,232,
+ 16,65,252,255,36,252,238,255,252,242,65,15,16,4,199,252,242,15,17,4,202,139,
+ 3,15,182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,255,72,
+ 252,247,208,137,68,202,4,139,3,15,182,204,15,182,232,131,195,4,193,232,16,
+ 65,252,255,36,252,238,255,141,76,202,12,141,68,194,4,189,237,137,105,252,
+ 248,248,1,137,41,131,193,8,57,193,15,134,244,1,139,3,15,182,204,15,182,232,
+ 131,195,4,193,232,16,65,252,255,36,252,238,255,139,106,252,248,139,172,253,
+ 133,233,139,173,233,72,139,69,0,72,137,4,202,139,3,15,182,204,15,182,232,
+ 131,195,4,193,232,16,65,252,255,36,252,238,255,139,106,252,248,139,172,253,
+ 141,233,128,189,233,0,139,173,233,139,12,194,139,68,194,4,137,77,0,137,69,
+ 4,15,132,244,247,252,246,133,233,235,15,133,244,248,248,1,139,3,15,182,204,
+ 15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,248,2,129,232,239,129,
+ 252,248,239,15,134,244,1,252,246,129,233,235,15,132,244,1,255,137,252,238,
+ 137,213,65,141,190,233,232,251,1,49,137,252,234,252,233,244,1,255,72,252,
+ 247,208,139,106,252,248,139,172,253,141,233,65,139,12,135,139,133,233,137,
+ 8,199,64,4,237,252,246,133,233,235,15,133,244,248,248,1,139,3,15,182,204,
+ 15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,248,2,252,246,129,233,
+ 235,15,132,244,1,128,189,233,0,15,132,244,1,137,213,137,198,65,141,190,233,
+ 232,251,1,49,137,252,234,252,233,244,1,255,139,106,252,248,252,242,65,15,
+ 16,4,199,139,172,253,141,233,139,141,233,252,242,15,17,1,139,3,15,182,204,
+ 15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,255,72,252,247,208,
+ 139,106,252,248,139,172,253,141,233,139,141,233,137,65,4,139,3,15,182,204,
+ 15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,255,141,156,253,131,
+ 233,139,108,36,24,131,189,233,0,15,132,244,247,137,149,233,141,52,202,137,
+ 252,239,232,251,1,50,139,149,233,248,1,139,3,15,182,204,15,182,232,131,195,
+ 4,193,232,16,65,252,255,36,252,238,255,72,252,247,208,139,108,36,24,137,149,
+ 233,139,82,252,248,65,139,52,135,137,252,239,137,92,36,28,232,251,1,51,139,
+ 149,233,15,182,75,252,253,137,4,202,199,68,202,4,237,139,3,15,182,204,15,
+ 182,232,131,195,4,193,232,16,65,252,255,36,252,238,255,139,108,36,24,137,
+ 149,233,65,139,142,233,65,59,142,233,137,92,36,28,15,131,244,251,248,1,137,
+ 194,37,252,255,7,0,0,193,252,234,11,61,252,255,7,0,0,15,132,244,249,248,2,
+ 137,252,239,137,198,232,251,1,52,139,149,233,15,182,75,252,253,137,4,202,
+ 199,68,202,4,237,139,3,15,182,204,15,182,232,131,195,4,193,232,16,65,252,
+ 255,36,252,238,248,3,184,1,8,0,0,252,233,244,2,248,5,137,252,239,232,251,
+ 1,53,15,183,67,252,254,252,233,244,1,255,72,252,247,208,139,108,36,24,65,
+ 139,142,233,137,92,36,28,65,59,142,233,137,149,233,15,131,244,249,248,2,65,
+ 139,52,135,137,252,239,232,251,1,54,139,149,233,15,182,75,252,253,137,4,202,
+ 199,68,202,4,237,139,3,15,182,204,15,182,232,131,195,4,193,232,16,65,252,
+ 255,36,252,238,248,3,137,252,239,232,251,1,53,15,183,67,252,254,72,252,247,
+ 208,252,233,244,2,255,72,252,247,208,139,106,252,248,139,173,233,65,139,4,
+ 135,252,233,244,167,255,72,252,247,208,139,106,252,248,139,173,233,65,139,
+ 4,135,252,233,244,168,255,15,182,252,236,15,182,192,129,124,253,252,234,4,
+ 239,15,133,244,40,139,44,252,234,129,124,253,194,4,239,15,131,244,251,252,
+ 242,15,16,4,194,252,242,15,44,192,252,242,15,42,200,102,15,46,193,15,133,
+ 244,40,59,133,233,15,131,244,40,193,224,3,3,133,233,129,120,253,4,239,15,
+ 132,244,248,72,139,40,72,137,44,202,248,1,139,3,15,182,204,15,182,232,131,
+ 195,4,193,232,16,65,252,255,36,252,238,248,2,131,189,233,0,15,132,244,249,
+ 255,139,141,233,252,246,129,233,235,15,132,244,40,15,182,75,252,253,248,3,
+ 199,68,202,4,237,252,233,244,1,248,5,129,124,253,194,4,239,15,133,244,40,
+ 139,4,194,252,233,244,167,255,15,182,252,236,15,182,192,72,252,247,208,65,
+ 139,4,135,129,124,253,252,234,4,239,15,133,244,38,139,44,252,234,248,167,
+ 139,141,233,35,136,233,105,201,239,3,141,233,248,1,129,185,233,239,15,133,
+ 244,250,57,129,233,15,133,244,250,129,121,253,4,239,15,132,244,251,255,15,
+ 182,67,252,253,72,139,41,72,137,44,194,248,2,139,3,15,182,204,15,182,232,
+ 131,195,4,193,232,16,65,252,255,36,252,238,248,3,15,182,67,252,253,199,68,
+ 194,4,237,252,233,244,2,248,4,139,137,233,133,201,15,133,244,1,248,5,139,
+ 141,233,133,201,15,132,244,3,252,246,129,233,235,15,133,244,3,252,233,244,
+ 38,255,15,182,252,236,15,182,192,129,124,253,252,234,4,239,15,133,244,39,
+ 139,44,252,234,59,133,233,15,131,244,39,193,224,3,3,133,233,129,120,253,4,
+ 239,15,132,244,248,72,139,40,72,137,44,202,248,1,139,3,15,182,204,15,182,
+ 232,131,195,4,193,232,16,65,252,255,36,252,238,248,2,131,189,233,0,15,132,
+ 244,249,139,141,233,252,246,129,233,235,15,132,244,39,255,15,182,75,252,253,
+ 248,3,199,68,202,4,237,252,233,244,1,255,15,182,252,236,15,182,192,139,44,
+ 252,234,252,242,15,44,4,194,59,133,233,15,131,244,41,193,224,3,3,133,233,
+ 248,42,72,139,40,72,137,44,202,248,43,139,3,15,182,204,15,182,232,131,195,
+ 4,193,232,16,65,252,255,36,252,238,255,15,182,252,236,15,182,192,129,124,
+ 253,252,234,4,239,15,133,244,46,139,44,252,234,129,124,253,194,4,239,15,131,
+ 244,251,252,242,15,16,4,194,252,242,15,44,192,252,242,15,42,200,102,15,46,
+ 193,15,133,244,46,59,133,233,15,131,244,46,193,224,3,3,133,233,129,120,253,
+ 4,239,15,132,244,249,248,1,252,246,133,233,235,15,133,244,253,248,2,255,72,
+ 139,44,202,72,137,40,139,3,15,182,204,15,182,232,131,195,4,193,232,16,65,
+ 252,255,36,252,238,248,3,131,189,233,0,15,132,244,1,139,141,233,252,246,129,
+ 233,235,15,132,244,46,15,182,75,252,253,252,233,244,1,248,5,129,124,253,194,
+ 4,239,15,133,244,46,139,4,194,252,233,244,168,248,7,128,165,233,235,255,65,
+ 139,142,233,65,137,174,233,137,141,233,15,182,75,252,253,252,233,244,2,255,
+ 15,182,252,236,15,182,192,72,252,247,208,65,139,4,135,129,124,253,252,234,
+ 4,239,15,133,244,44,139,44,252,234,248,168,139,141,233,35,136,233,105,201,
+ 239,198,133,233,0,3,141,233,248,1,129,185,233,239,15,133,244,251,57,129,233,
+ 15,133,244,251,129,121,253,4,239,15,132,244,250,248,2,255,252,246,133,233,
+ 235,15,133,244,253,248,3,15,182,67,252,253,72,139,44,194,72,137,41,139,3,
+ 15,182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,248,4,131,
+ 189,233,0,15,132,244,2,137,12,36,139,141,233,252,246,129,233,235,15,132,244,
+ 44,139,12,36,252,233,244,2,248,5,139,137,233,133,201,15,133,244,1,255,139,
+ 141,233,133,201,15,132,244,252,252,246,129,233,235,15,132,244,44,248,6,137,
+ 4,36,199,68,36,4,237,137,108,36,8,139,124,36,24,137,151,233,72,141,20,36,
+ 137,252,238,137,252,253,137,92,36,28,232,251,1,55,139,149,233,139,108,36,
+ 8,137,193,252,233,244,2,248,7,128,165,233,235,65,139,134,233,65,137,174,233,
+ 137,133,233,255,252,233,244,3,255,15,182,252,236,15,182,192,129,124,253,252,
+ 234,4,239,15,133,244,45,139,44,252,234,59,133,233,15,131,244,45,193,224,3,
+ 3,133,233,129,120,253,4,239,15,132,244,249,248,1,252,246,133,233,235,15,133,
+ 244,253,248,2,72,139,12,202,72,137,8,139,3,15,182,204,15,182,232,131,195,
+ 4,193,232,16,65,252,255,36,252,238,248,3,131,189,233,0,15,132,244,1,255,139,
+ 141,233,252,246,129,233,235,15,132,244,45,15,182,75,252,253,252,233,244,1,
+ 248,7,128,165,233,235,65,139,142,233,65,137,174,233,137,141,233,15,182,75,
+ 252,253,252,233,244,2,255,15,182,252,236,15,182,192,139,44,252,234,252,242,
+ 15,44,4,194,252,246,133,233,235,15,133,244,253,248,2,59,133,233,15,131,244,
+ 48,193,224,3,3,133,233,248,49,72,139,44,202,72,137,40,139,3,15,182,204,15,
+ 182,232,131,195,4,193,232,16,65,252,255,36,252,238,248,7,128,165,233,235,
+ 65,139,142,233,65,137,174,233,137,141,233,15,182,75,252,253,252,233,244,2,
+ 255,68,137,60,36,69,139,60,199,248,1,141,12,202,139,105,252,248,252,246,133,
+ 233,235,15,133,244,253,248,2,139,68,36,4,131,232,1,15,132,244,250,68,1,252,
+ 248,59,133,233,15,135,244,251,68,41,252,248,65,193,231,3,68,3,189,233,248,
+ 3,72,139,41,131,193,8,73,137,47,65,131,199,8,131,232,1,15,133,244,3,248,4,
+ 68,139,60,36,139,3,15,182,204,15,182,232,131,195,4,193,232,16,65,252,255,
+ 36,252,238,248,5,139,124,36,24,137,151,233,137,252,238,137,194,137,252,253,
+ 137,92,36,28,232,251,1,56,139,149,233,255,15,182,75,252,253,252,233,244,1,
+ 248,7,128,165,233,235,65,139,134,233,65,137,174,233,137,133,233,252,233,244,
+ 2,255,3,68,36,4,255,129,124,253,202,4,239,139,44,202,15,133,244,66,141,84,
+ 202,8,137,90,252,252,139,157,233,139,11,15,182,252,233,15,182,205,131,195,
+ 4,65,252,255,36,252,238,255,141,76,202,8,65,137,215,139,105,252,248,129,121,
+ 253,252,252,239,15,133,244,30,248,67,139,90,252,252,252,247,195,237,15,133,
+ 244,253,248,1,137,106,252,248,137,68,36,4,131,232,1,15,132,244,249,248,2,
+ 72,139,41,131,193,8,73,137,47,65,131,199,8,131,232,1,15,133,244,2,139,106,
+ 252,248,248,3,139,68,36,4,128,189,233,1,15,135,244,251,248,4,139,157,233,
+ 255,139,11,15,182,252,233,15,182,205,131,195,4,65,252,255,36,252,238,248,
+ 5,252,247,195,237,15,133,244,4,15,182,75,252,253,72,252,247,209,68,139,124,
+ 202,252,248,69,139,191,233,69,139,191,233,252,233,244,4,248,7,129,252,235,
+ 239,252,247,195,237,15,133,244,254,41,218,65,137,215,139,90,252,252,252,233,
+ 244,1,248,8,129,195,239,252,233,244,1,255,141,76,202,8,72,139,105,232,72,
+ 139,65,252,240,72,137,41,72,137,65,8,139,105,224,139,65,228,137,105,252,248,
+ 137,65,252,252,129,252,248,239,184,237,15,133,244,30,137,202,137,90,252,252,
+ 139,157,233,139,11,15,182,252,233,15,182,205,131,195,4,65,252,255,36,252,
+ 238,255,68,137,60,36,68,137,116,36,4,139,108,202,252,240,139,68,202,252,248,
+ 68,139,181,233,131,195,4,68,139,189,233,248,1,68,57,252,240,15,131,244,251,
+ 65,129,124,253,199,4,239,15,132,244,250,252,242,15,42,192,73,139,44,199,72,
+ 137,108,202,8,131,192,1,252,242,15,17,4,202,137,68,202,252,248,248,2,15,183,
+ 67,252,254,141,156,253,131,233,248,3,68,139,116,36,4,68,139,60,36,139,3,15,
+ 182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,248,4,131,192,
+ 1,252,233,244,1,248,5,68,41,252,240,248,6,59,133,233,15,135,244,3,255,68,
+ 105,252,248,239,68,3,189,233,65,129,191,233,239,15,132,244,253,70,141,116,
+ 48,1,73,139,175,233,73,139,135,233,72,137,44,202,72,137,68,202,8,68,137,116,
+ 202,252,248,252,233,244,2,248,7,131,192,1,252,233,244,6,255,129,124,253,202,
+ 252,236,239,15,133,244,251,139,108,202,232,129,124,253,202,252,244,239,15,
+ 133,244,251,129,124,253,202,252,252,239,15,133,244,251,128,189,233,235,15,
+ 133,244,251,141,156,253,131,233,199,68,202,252,248,0,0,0,0,199,68,202,252,
+ 252,252,255,127,252,254,252,255,248,1,139,3,15,182,204,15,182,232,131,195,
+ 4,193,232,16,65,252,255,36,252,238,248,5,198,67,252,252,235,141,156,253,131,
+ 233,198,3,235,255,15,182,252,236,15,182,192,68,137,60,36,68,141,188,253,194,
+ 233,141,12,202,68,43,122,252,252,133,252,237,15,132,244,251,141,108,252,233,
+ 252,248,65,57,215,15,131,244,248,248,1,73,139,71,252,248,65,131,199,8,72,
+ 137,1,131,193,8,57,252,233,15,131,244,249,65,57,215,15,130,244,1,248,2,199,
+ 65,4,237,131,193,8,57,252,233,15,130,244,2,248,3,68,139,60,36,139,3,15,182,
+ 204,15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,248,5,199,68,36,
+ 4,1,0,0,0,137,208,68,41,252,248,15,134,244,3,137,197,193,252,237,3,131,197,
+ 1,137,108,36,4,139,108,36,24,1,200,59,133,233,255,15,135,244,253,248,6,73,
+ 139,71,252,248,65,131,199,8,72,137,1,131,193,8,65,57,215,15,130,244,6,252,
+ 233,244,3,248,7,137,149,233,137,141,233,137,92,36,28,65,41,215,139,116,36,
+ 4,131,252,238,1,137,252,239,232,251,1,0,139,149,233,139,141,233,65,1,215,
+ 252,233,244,6,255,193,225,3,255,248,1,139,90,252,252,137,68,36,4,252,247,
+ 195,237,15,133,244,253,255,248,14,65,137,215,131,232,1,15,132,244,249,248,
+ 2,73,139,44,15,73,137,111,252,248,65,131,199,8,131,232,1,15,133,244,2,248,
+ 3,139,68,36,4,15,182,107,252,255,248,5,57,197,15,135,244,252,255,72,139,44,
+ 10,72,137,106,252,248,255,248,5,56,67,252,255,15,135,244,252,255,15,182,75,
+ 252,253,72,252,247,209,141,20,202,68,139,122,252,248,69,139,191,233,69,139,
+ 191,233,139,3,15,182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,252,
+ 238,248,6,255,65,199,71,252,252,237,65,131,199,8,255,199,68,194,252,244,237,
+ 255,131,192,1,252,233,244,5,248,7,141,171,233,252,247,197,237,15,133,244,
+ 15,41,252,234,255,1,252,233,255,137,221,209,252,237,129,229,239,102,65,129,
+ 172,253,46,233,238,15,130,244,150,255,141,12,202,255,129,121,253,4,239,15,
+ 133,244,255,255,129,121,253,12,239,15,133,244,68,129,121,253,20,239,15,133,
+ 244,68,139,41,131,121,16,0,15,140,244,251,255,129,121,253,12,239,15,133,244,
+ 163,129,121,253,20,239,15,133,244,163,255,139,105,16,133,252,237,15,136,244,
+ 251,3,41,15,128,244,247,137,41,255,59,105,8,199,65,28,237,137,105,24,255,
+ 15,142,244,253,248,1,248,6,141,156,253,131,233,255,141,156,253,131,233,15,
+ 183,67,252,254,15,142,245,248,1,248,6,255,15,143,244,253,248,6,141,156,253,
+ 131,233,248,1,255,248,7,139,3,15,182,204,15,182,232,131,195,4,193,232,16,
+ 65,252,255,36,252,238,248,5,255,3,41,15,128,244,1,137,41,255,15,141,244,7,
+ 255,141,156,253,131,233,15,183,67,252,254,15,141,245,255,15,140,244,7,255,
+ 252,233,244,6,248,9,255,129,121,253,4,239,255,15,131,244,68,129,121,253,12,
+ 239,15,131,244,68,255,129,121,253,12,239,15,131,244,163,129,121,253,20,239,
+ 15,131,244,163,255,139,105,20,255,129,252,253,239,15,131,244,68,255,252,242,
+ 15,16,1,252,242,15,16,73,8,255,252,242,15,88,65,16,252,242,15,17,1,133,252,
+ 237,15,136,244,249,255,15,140,244,249,255,102,15,46,200,248,1,252,242,15,
+ 17,65,24,255,15,131,244,248,141,156,253,131,233,255,141,156,253,131,233,15,
+ 183,67,252,254,15,131,245,255,15,130,244,248,141,156,253,131,233,255,248,
+ 2,139,3,15,182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,
+ 248,3,102,15,46,193,252,233,244,1,255,141,12,202,139,105,4,129,252,253,239,
+ 15,132,244,247,255,137,105,252,252,139,41,137,105,252,248,252,233,245,255,
+ 141,156,253,131,233,139,1,137,105,252,252,137,65,252,248,255,65,139,142,233,
+ 139,4,129,72,139,128,233,139,108,36,24,65,137,150,233,65,137,174,233,76,137,
+ 36,36,76,137,108,36,8,72,131,252,236,16,252,255,224,255,141,156,253,131,233,
+ 139,3,15,182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,252,238,255,
+ 137,221,209,252,237,129,229,239,102,65,129,172,253,46,233,238,15,130,244,
+ 152,255,68,139,187,233,139,108,36,24,141,12,202,59,141,233,15,135,244,25,
+ 15,182,139,233,57,200,15,134,244,249,248,2,255,15,183,67,252,254,252,233,
+ 245,255,248,3,199,68,194,252,252,237,131,192,1,57,200,15,134,244,3,252,233,
+ 244,2,255,141,44,197,237,141,4,194,68,139,122,252,248,137,104,252,252,68,
+ 137,120,252,248,139,108,36,24,141,12,200,59,141,233,15,135,244,24,137,209,
+ 137,194,15,182,171,233,133,252,237,15,132,244,248,248,1,131,193,8,57,209,
+ 15,131,244,249,68,139,121,252,248,68,137,56,68,139,121,252,252,68,137,120,
+ 4,131,192,8,199,65,252,252,237,131,252,237,1,15,133,244,1,248,2,255,68,139,
+ 187,233,139,3,15,182,204,15,182,232,131,195,4,193,232,16,65,252,255,36,252,
+ 238,255,248,3,199,64,4,237,131,192,8,131,252,237,1,15,133,244,3,252,233,244,
+ 2,255,139,106,252,248,76,139,189,233,139,108,36,24,141,68,194,252,248,137,
+ 149,233,141,136,233,59,141,233,137,133,233,255,137,252,239,255,76,137,252,
+ 254,137,252,239,255,15,135,244,23,65,199,134,233,237,255,65,252,255,215,255,
+ 65,252,255,150,233,255,139,149,233,65,137,174,233,65,199,134,233,237,141,
+ 12,194,252,247,217,3,141,233,139,90,252,252,252,233,244,12,255,254,0
+};
+
+#line 13 "vm_x86.dasc"
+//|.globals GLOB_
+enum {
+ GLOB_vm_returnp,
+ GLOB_cont_dispatch,
+ GLOB_vm_returnc,
+ GLOB_vm_unwind_yield,
+ GLOB_BC_RET_Z,
+ GLOB_vm_return,
+ GLOB_vm_leave_cp,
+ GLOB_vm_leave_unw,
+ GLOB_vm_unwind_c_eh,
+ GLOB_vm_unwind_c,
+ GLOB_vm_unwind_rethrow,
+ GLOB_vm_unwind_ff,
+ GLOB_vm_unwind_ff_eh,
+ GLOB_vm_growstack_c,
+ GLOB_vm_growstack_v,
+ GLOB_vm_growstack_f,
+ GLOB_vm_resume,
+ GLOB_vm_pcall,
+ GLOB_vm_call,
+ GLOB_vm_call_dispatch,
+ GLOB_vmeta_call,
+ GLOB_vm_call_dispatch_f,
+ GLOB_vm_cpcall,
+ GLOB_cont_ffi_callback,
+ GLOB_vm_call_tail,
+ GLOB_cont_cat,
+ GLOB_cont_ra,
+ GLOB_BC_CAT_Z,
+ GLOB_vmeta_tgets,
+ GLOB_vmeta_tgetb,
+ GLOB_vmeta_tgetv,
+ GLOB_vmeta_tgetr,
+ GLOB_BC_TGETR_Z,
+ GLOB_BC_TGETR2_Z,
+ GLOB_vmeta_tsets,
+ GLOB_vmeta_tsetb,
+ GLOB_vmeta_tsetv,
+ GLOB_cont_nop,
+ GLOB_vmeta_tsetr,
+ GLOB_BC_TSETR_Z,
+ GLOB_vmeta_comp,
+ GLOB_vmeta_binop,
+ GLOB_cont_condt,
+ GLOB_cont_condf,
+ GLOB_vmeta_equal,
+ GLOB_vmeta_equal_cd,
+ GLOB_vmeta_istype,
+ GLOB_vmeta_arith_vno,
+ GLOB_vmeta_arith_vn,
+ GLOB_vmeta_arith_nvo,
+ GLOB_vmeta_arith_nv,
+ GLOB_vmeta_unm,
+ GLOB_vmeta_arith_vvo,
+ GLOB_vmeta_arith_vv,
+ GLOB_vmeta_len,
+ GLOB_BC_LEN_Z,
+ GLOB_vmeta_call_ra,
+ GLOB_BC_CALLT_Z,
+ GLOB_vmeta_for,
+ GLOB_ff_assert,
+ GLOB_fff_fallback,
+ GLOB_fff_res_,
+ GLOB_ff_type,
+ GLOB_fff_res1,
+ GLOB_ff_getmetatable,
+ GLOB_ff_setmetatable,
+ GLOB_ff_rawget,
+ GLOB_ff_tonumber,
+ GLOB_fff_resxmm0,
+ GLOB_ff_tostring,
+ GLOB_fff_gcstep,
+ GLOB_ff_next,
+ GLOB_fff_res2,
+ GLOB_fff_res,
+ GLOB_ff_pairs,
+ GLOB_ff_ipairs_aux,
+ GLOB_fff_res0,
+ GLOB_ff_ipairs,
+ GLOB_ff_pcall,
+ GLOB_ff_xpcall,
+ GLOB_ff_coroutine_resume,
+ GLOB_ff_coroutine_wrap_aux,
+ GLOB_ff_coroutine_yield,
+ GLOB_fff_resi,
+ GLOB_fff_resn,
+ GLOB_ff_math_abs,
+ GLOB_ff_math_floor,
+ GLOB_vm_floor_sse,
+ GLOB_ff_math_ceil,
+ GLOB_vm_ceil_sse,
+ GLOB_ff_math_sqrt,
+ GLOB_ff_math_log,
+ GLOB_ff_math_log10,
+ GLOB_ff_math_exp,
+ GLOB_ff_math_sin,
+ GLOB_ff_math_cos,
+ GLOB_ff_math_tan,
+ GLOB_ff_math_asin,
+ GLOB_ff_math_acos,
+ GLOB_ff_math_atan,
+ GLOB_ff_math_sinh,
+ GLOB_ff_math_cosh,
+ GLOB_ff_math_tanh,
+ GLOB_ff_math_pow,
+ GLOB_ff_math_atan2,
+ GLOB_ff_math_fmod,
+ GLOB_ff_math_ldexp,
+ GLOB_ff_math_frexp,
+ GLOB_ff_math_modf,
+ GLOB_vm_trunc_sse,
+ GLOB_ff_math_min,
+ GLOB_ff_math_max,
+ GLOB_ff_string_byte,
+ GLOB_ff_string_char,
+ GLOB_fff_newstr,
+ GLOB_fff_resstr,
+ GLOB_ff_string_sub,
+ GLOB_fff_emptystr,
+ GLOB_ff_string_reverse,
+ GLOB_ff_string_lower,
+ GLOB_ff_string_upper,
+ GLOB_ff_bit_tobit,
+ GLOB_fff_resbit,
+ GLOB_ff_bit_band,
+ GLOB_fff_fallback_bit_op,
+ GLOB_ff_bit_bor,
+ GLOB_ff_bit_bxor,
+ GLOB_ff_bit_bswap,
+ GLOB_ff_bit_bnot,
+ GLOB_ff_bit_lshift,
+ GLOB_ff_bit_rshift,
+ GLOB_ff_bit_arshift,
+ GLOB_ff_bit_rol,
+ GLOB_ff_bit_ror,
+ GLOB_fff_fallback_2,
+ GLOB_fff_fallback_1,
+ GLOB_vm_record,
+ GLOB_vm_rethook,
+ GLOB_vm_inshook,
+ GLOB_cont_hook,
+ GLOB_vm_hotloop,
+ GLOB_vm_callhook,
+ GLOB_vm_hotcall,
+ GLOB_cont_stitch,
+ GLOB_vm_profhook,
+ GLOB_vm_exit_handler,
+ GLOB_vm_exit_interp,
+ GLOB_vm_floor,
+ GLOB_vm_ceil,
+ GLOB_vm_trunc,
+ GLOB_vm_mod,
+ GLOB_vm_powi_sse,
+ GLOB_vm_cpuid,
+ GLOB_assert_bad_for_arg_type,
+ GLOB_vm_ffi_callback,
+ GLOB_vm_ffi_call,
+ GLOB_BC_MODVN_Z,
+ GLOB_BC_TGETS_Z,
+ GLOB_BC_TSETS_Z,
+ GLOB__MAX
+};
+#line 14 "vm_x86.dasc"
+//|.globalnames globnames
+static const char *const globnames[] = {
+ "vm_returnp",
+ "cont_dispatch",
+ "vm_returnc",
+ "vm_unwind_yield",
+ "BC_RET_Z",
+ "vm_return",
+ "vm_leave_cp",
+ "vm_leave_unw",
+ "vm_unwind_c_eh",
+ "vm_unwind_c@8",
+ "vm_unwind_rethrow",
+ "vm_unwind_ff@4",
+ "vm_unwind_ff_eh",
+ "vm_growstack_c",
+ "vm_growstack_v",
+ "vm_growstack_f",
+ "vm_resume",
+ "vm_pcall",
+ "vm_call",
+ "vm_call_dispatch",
+ "vmeta_call",
+ "vm_call_dispatch_f",
+ "vm_cpcall",
+ "cont_ffi_callback",
+ "vm_call_tail",
+ "cont_cat",
+ "cont_ra",
+ "BC_CAT_Z",
+ "vmeta_tgets",
+ "vmeta_tgetb",
+ "vmeta_tgetv",
+ "vmeta_tgetr",
+ "BC_TGETR_Z",
+ "BC_TGETR2_Z",
+ "vmeta_tsets",
+ "vmeta_tsetb",
+ "vmeta_tsetv",
+ "cont_nop",
+ "vmeta_tsetr",
+ "BC_TSETR_Z",
+ "vmeta_comp",
+ "vmeta_binop",
+ "cont_condt",
+ "cont_condf",
+ "vmeta_equal",
+ "vmeta_equal_cd",
+ "vmeta_istype",
+ "vmeta_arith_vno",
+ "vmeta_arith_vn",
+ "vmeta_arith_nvo",
+ "vmeta_arith_nv",
+ "vmeta_unm",
+ "vmeta_arith_vvo",
+ "vmeta_arith_vv",
+ "vmeta_len",
+ "BC_LEN_Z",
+ "vmeta_call_ra",
+ "BC_CALLT_Z",
+ "vmeta_for",
+ "ff_assert",
+ "fff_fallback",
+ "fff_res_",
+ "ff_type",
+ "fff_res1",
+ "ff_getmetatable",
+ "ff_setmetatable",
+ "ff_rawget",
+ "ff_tonumber",
+ "fff_resxmm0",
+ "ff_tostring",
+ "fff_gcstep",
+ "ff_next",
+ "fff_res2",
+ "fff_res",
+ "ff_pairs",
+ "ff_ipairs_aux",
+ "fff_res0",
+ "ff_ipairs",
+ "ff_pcall",
+ "ff_xpcall",
+ "ff_coroutine_resume",
+ "ff_coroutine_wrap_aux",
+ "ff_coroutine_yield",
+ "fff_resi",
+ "fff_resn",
+ "ff_math_abs",
+ "ff_math_floor",
+ "vm_floor_sse",
+ "ff_math_ceil",
+ "vm_ceil_sse",
+ "ff_math_sqrt",
+ "ff_math_log",
+ "ff_math_log10",
+ "ff_math_exp",
+ "ff_math_sin",
+ "ff_math_cos",
+ "ff_math_tan",
+ "ff_math_asin",
+ "ff_math_acos",
+ "ff_math_atan",
+ "ff_math_sinh",
+ "ff_math_cosh",
+ "ff_math_tanh",
+ "ff_math_pow",
+ "ff_math_atan2",
+ "ff_math_fmod",
+ "ff_math_ldexp",
+ "ff_math_frexp",
+ "ff_math_modf",
+ "vm_trunc_sse",
+ "ff_math_min",
+ "ff_math_max",
+ "ff_string_byte",
+ "ff_string_char",
+ "fff_newstr",
+ "fff_resstr",
+ "ff_string_sub",
+ "fff_emptystr",
+ "ff_string_reverse",
+ "ff_string_lower",
+ "ff_string_upper",
+ "ff_bit_tobit",
+ "fff_resbit",
+ "ff_bit_band",
+ "fff_fallback_bit_op",
+ "ff_bit_bor",
+ "ff_bit_bxor",
+ "ff_bit_bswap",
+ "ff_bit_bnot",
+ "ff_bit_lshift",
+ "ff_bit_rshift",
+ "ff_bit_arshift",
+ "ff_bit_rol",
+ "ff_bit_ror",
+ "fff_fallback_2",
+ "fff_fallback_1",
+ "vm_record",
+ "vm_rethook",
+ "vm_inshook",
+ "cont_hook",
+ "vm_hotloop",
+ "vm_callhook",
+ "vm_hotcall",
+ "cont_stitch",
+ "vm_profhook",
+ "vm_exit_handler",
+ "vm_exit_interp",
+ "vm_floor",
+ "vm_ceil",
+ "vm_trunc",
+ "vm_mod",
+ "vm_powi_sse",
+ "vm_cpuid",
+ "assert_bad_for_arg_type",
+ "vm_ffi_callback",
+ "vm_ffi_call@4",
+ "BC_MODVN_Z",
+ "BC_TGETS_Z",
+ "BC_TSETS_Z",
+ (const char *)0
+};
+#line 15 "vm_x86.dasc"
+//|.externnames extnames
+static const char *const extnames[] = {
+ "lj_state_growstack@8",
+ "lj_err_throw@8",
+ "lj_meta_tget",
+ "lj_tab_getinth@8",
+ "lj_meta_tset",
+ "lj_tab_setinth",
+ "lj_meta_comp",
+ "lj_meta_equal",
+ "lj_meta_equal_cd@8",
+ "lj_meta_istype",
+ "lj_meta_arith",
+ "lj_meta_len@8",
+ "lj_meta_call",
+ "lj_meta_for@8",
+ "lj_tab_get",
+ "lj_strfmt_num@8",
+ "lj_tab_next",
+ "lj_ffh_coroutine_wrap_err@8",
+ "log",
+ "log10",
+ "exp",
+ "sin",
+ "cos",
+ "tan",
+ "asin",
+ "acos",
+ "atan",
+ "sinh",
+ "cosh",
+ "tanh",
+ "pow",
+ "atan2",
+ "fmod",
+ "lj_str_new",
+ "lj_buf_putstr_reverse@8",
+ "lj_buf_tostr@4",
+ "lj_buf_putstr_lower@8",
+ "lj_buf_putstr_upper@8",
+ "lj_gc_step@4",
+ "lj_dispatch_ins@8",
+ "lj_trace_hot@8",
+ "lj_dispatch_call@8",
+ "lj_dispatch_stitch@8",
+ "lj_dispatch_profile@8",
+ "lj_trace_exit@8",
+ "lj_ccallback_enter@8",
+ "lj_ccallback_leave@8",
+ "lj_tab_len@4",
+ "lj_meta_cat",
+ "lj_gc_barrieruv@8",
+ "lj_func_closeuv@8",
+ "lj_func_newL_gc",
+ "lj_tab_new",
+ "lj_gc_step_fixtop@4",
+ "lj_tab_dup@8",
+ "lj_tab_newkey",
+ "lj_tab_reasize",
+ (const char *)0
+};
+#line 16 "vm_x86.dasc"
+//|
+//|//-----------------------------------------------------------------------
+//|
+//|.if P64
+//|.define X64, 1
+//|.if WIN
+//|.define X64WIN, 1
+//|.endif
+//|.endif
+//|
+//|// Fixed register assignments for the interpreter.
+//|// This is very fragile and has many dependencies. Caveat emptor.
+//|.define BASE, edx // Not C callee-save, refetched anyway.
+//|.if not X64
+//|.define KBASE, edi // Must be C callee-save.
+//|.define KBASEa, KBASE
+//|.define PC, esi // Must be C callee-save.
+//|.define PCa, PC
+//|.define DISPATCH, ebx // Must be C callee-save.
+//|.elif X64WIN
+//|.define KBASE, edi // Must be C callee-save.
+//|.define KBASEa, rdi
+//|.define PC, esi // Must be C callee-save.
+//|.define PCa, rsi
+//|.define DISPATCH, ebx // Must be C callee-save.
+//|.else
+//|.define KBASE, r15d // Must be C callee-save.
+//|.define KBASEa, r15
+//|.define PC, ebx // Must be C callee-save.
+//|.define PCa, rbx
+//|.define DISPATCH, r14d // Must be C callee-save.
+//|.endif
+//|
+//|.define RA, ecx
+//|.define RAH, ch
+//|.define RAL, cl
+//|.define RB, ebp // Must be ebp (C callee-save).
+//|.define RC, eax // Must be eax.
+//|.define RCW, ax
+//|.define RCH, ah
+//|.define RCL, al
+//|.define OP, RB
+//|.define RD, RC
+//|.define RDW, RCW
+//|.define RDL, RCL
+//|.if X64
+//|.define RAa, rcx
+//|.define RBa, rbp
+//|.define RCa, rax
+//|.define RDa, rax
+//|.else
+//|.define RAa, RA
+//|.define RBa, RB
+//|.define RCa, RC
+//|.define RDa, RD
+//|.endif
+//|
+//|.if not X64
+//|.define FCARG1, ecx // x86 fastcall arguments.
+//|.define FCARG2, edx
+//|.elif X64WIN
+//|.define CARG1, rcx // x64/WIN64 C call arguments.
+//|.define CARG2, rdx
+//|.define CARG3, r8
+//|.define CARG4, r9
+//|.define CARG1d, ecx
+//|.define CARG2d, edx
+//|.define CARG3d, r8d
+//|.define CARG4d, r9d
+//|.define FCARG1, CARG1d // Upwards compatible to x86 fastcall.
+//|.define FCARG2, CARG2d
+//|.else
+//|.define CARG1, rdi // x64/POSIX C call arguments.
+//|.define CARG2, rsi
+//|.define CARG3, rdx
+//|.define CARG4, rcx
+//|.define CARG5, r8
+//|.define CARG6, r9
+//|.define CARG1d, edi
+//|.define CARG2d, esi
+//|.define CARG3d, edx
+//|.define CARG4d, ecx
+//|.define CARG5d, r8d
+//|.define CARG6d, r9d
+//|.define FCARG1, CARG1d // Simulate x86 fastcall.
+//|.define FCARG2, CARG2d
+//|.endif
+//|
+//|// Type definitions. Some of these are only used for documentation.
+//|.type L, lua_State
+#define Dt1(_V) (int)(ptrdiff_t)&(((lua_State *)0)_V)
+#line 106 "vm_x86.dasc"
+//|.type GL, global_State
+#define Dt2(_V) (int)(ptrdiff_t)&(((global_State *)0)_V)
+#line 107 "vm_x86.dasc"
+//|.type TVALUE, TValue
+#define Dt3(_V) (int)(ptrdiff_t)&(((TValue *)0)_V)
+#line 108 "vm_x86.dasc"
+//|.type GCOBJ, GCobj
+#define Dt4(_V) (int)(ptrdiff_t)&(((GCobj *)0)_V)
+#line 109 "vm_x86.dasc"
+//|.type STR, GCstr
+#define Dt5(_V) (int)(ptrdiff_t)&(((GCstr *)0)_V)
+#line 110 "vm_x86.dasc"
+//|.type TAB, GCtab
+#define Dt6(_V) (int)(ptrdiff_t)&(((GCtab *)0)_V)
+#line 111 "vm_x86.dasc"
+//|.type LFUNC, GCfuncL
+#define Dt7(_V) (int)(ptrdiff_t)&(((GCfuncL *)0)_V)
+#line 112 "vm_x86.dasc"
+//|.type CFUNC, GCfuncC
+#define Dt8(_V) (int)(ptrdiff_t)&(((GCfuncC *)0)_V)
+#line 113 "vm_x86.dasc"
+//|.type PROTO, GCproto
+#define Dt9(_V) (int)(ptrdiff_t)&(((GCproto *)0)_V)
+#line 114 "vm_x86.dasc"
+//|.type UPVAL, GCupval
+#define DtA(_V) (int)(ptrdiff_t)&(((GCupval *)0)_V)
+#line 115 "vm_x86.dasc"
+//|.type NODE, Node
+#define DtB(_V) (int)(ptrdiff_t)&(((Node *)0)_V)
+#line 116 "vm_x86.dasc"
+//|.type NARGS, int
+#define DtC(_V) (int)(ptrdiff_t)&(((int *)0)_V)
+#line 117 "vm_x86.dasc"
+//|.type TRACE, GCtrace
+#define DtD(_V) (int)(ptrdiff_t)&(((GCtrace *)0)_V)
+#line 118 "vm_x86.dasc"
+//|.type SBUF, SBuf
+#define DtE(_V) (int)(ptrdiff_t)&(((SBuf *)0)_V)
+#line 119 "vm_x86.dasc"
+//|
+//|// Stack layout while in interpreter. Must match with lj_frame.h.
+//|//-----------------------------------------------------------------------
+//|.if not X64 // x86 stack layout.
+//|
+//|.if WIN
+//|
+//|.define CFRAME_SPACE, aword*9 // Delta for esp (see <--).
+//|.macro saveregs_
+//| push edi; push esi; push ebx
+//| push extern lj_err_unwind_win
+//| fs; push dword [0]
+//| fs; mov [0], esp
+//| sub esp, CFRAME_SPACE
+//|.endmacro
+//|.macro restoreregs
+//| add esp, CFRAME_SPACE
+//| fs; pop dword [0]
+//| pop edi // Short for esp += 4.
+//| pop ebx; pop esi; pop edi; pop ebp
+//|.endmacro
+//|
+//|.else
+//|
+//|.define CFRAME_SPACE, aword*7 // Delta for esp (see <--).
+//|.macro saveregs_
+//| push edi; push esi; push ebx
+//| sub esp, CFRAME_SPACE
+//|.endmacro
+//|.macro restoreregs
+//| add esp, CFRAME_SPACE
+//| pop ebx; pop esi; pop edi; pop ebp
+//|.endmacro
+//|
+//|.endif
+//|
+//|.macro saveregs
+//| push ebp; saveregs_
+//|.endmacro
+//|
+//|.if WIN
+//|.define SAVE_ERRF, aword [esp+aword*19] // vm_pcall/vm_cpcall only.
+//|.define SAVE_NRES, aword [esp+aword*18]
+//|.define SAVE_CFRAME, aword [esp+aword*17]
+//|.define SAVE_L, aword [esp+aword*16]
+//|//----- 16 byte aligned, ^^^ arguments from C caller
+//|.define SAVE_RET, aword [esp+aword*15] //<-- esp entering interpreter.
+//|.define SAVE_R4, aword [esp+aword*14]
+//|.define SAVE_R3, aword [esp+aword*13]
+//|.define SAVE_R2, aword [esp+aword*12]
+//|//----- 16 byte aligned
+//|.define SAVE_R1, aword [esp+aword*11]
+//|.define SEH_FUNC, aword [esp+aword*10]
+//|.define SEH_NEXT, aword [esp+aword*9] //<-- esp after register saves.
+//|.define UNUSED2, aword [esp+aword*8]
+//|//----- 16 byte aligned
+//|.define UNUSED1, aword [esp+aword*7]
+//|.define SAVE_PC, aword [esp+aword*6]
+//|.define TMP2, aword [esp+aword*5]
+//|.define TMP1, aword [esp+aword*4]
+//|//----- 16 byte aligned
+//|.define ARG4, aword [esp+aword*3]
+//|.define ARG3, aword [esp+aword*2]
+//|.define ARG2, aword [esp+aword*1]
+//|.define ARG1, aword [esp] //<-- esp while in interpreter.
+//|//----- 16 byte aligned, ^^^ arguments for C callee
+//|.else
+//|.define SAVE_ERRF, aword [esp+aword*15] // vm_pcall/vm_cpcall only.
+//|.define SAVE_NRES, aword [esp+aword*14]
+//|.define SAVE_CFRAME, aword [esp+aword*13]
+//|.define SAVE_L, aword [esp+aword*12]
+//|//----- 16 byte aligned, ^^^ arguments from C caller
+//|.define SAVE_RET, aword [esp+aword*11] //<-- esp entering interpreter.
+//|.define SAVE_R4, aword [esp+aword*10]
+//|.define SAVE_R3, aword [esp+aword*9]
+//|.define SAVE_R2, aword [esp+aword*8]
+//|//----- 16 byte aligned
+//|.define SAVE_R1, aword [esp+aword*7] //<-- esp after register saves.
+//|.define SAVE_PC, aword [esp+aword*6]
+//|.define TMP2, aword [esp+aword*5]
+//|.define TMP1, aword [esp+aword*4]
+//|//----- 16 byte aligned
+//|.define ARG4, aword [esp+aword*3]
+//|.define ARG3, aword [esp+aword*2]
+//|.define ARG2, aword [esp+aword*1]
+//|.define ARG1, aword [esp] //<-- esp while in interpreter.
+//|//----- 16 byte aligned, ^^^ arguments for C callee
+//|.endif
+//|
+//|// FPARGx overlaps ARGx and ARG(x+1) on x86.
+//|.define FPARG3, qword [esp+qword*1]
+//|.define FPARG1, qword [esp]
+//|// TMPQ overlaps TMP1/TMP2. ARG5/MULTRES overlap TMP1/TMP2 (and TMPQ).
+//|.define TMPQ, qword [esp+aword*4]
+//|.define TMP3, ARG4
+//|.define ARG5, TMP1
+//|.define TMPa, TMP1
+//|.define MULTRES, TMP2
+//|
+//|// Arguments for vm_call and vm_pcall.
+//|.define INARG_BASE, SAVE_CFRAME // Overwritten by SAVE_CFRAME!
+//|
+//|// Arguments for vm_cpcall.
+//|.define INARG_CP_CALL, SAVE_ERRF
+//|.define INARG_CP_UD, SAVE_NRES
+//|.define INARG_CP_FUNC, SAVE_CFRAME
+//|
+//|//-----------------------------------------------------------------------
+//|.elif X64WIN // x64/Windows stack layout
+//|
+//|.define CFRAME_SPACE, aword*5 // Delta for rsp (see <--).
+//|.macro saveregs_
+//| push rdi; push rsi; push rbx
+//| sub rsp, CFRAME_SPACE
+//|.endmacro
+//|.macro saveregs
+//| push rbp; saveregs_
+//|.endmacro
+//|.macro restoreregs
+//| add rsp, CFRAME_SPACE
+//| pop rbx; pop rsi; pop rdi; pop rbp
+//|.endmacro
+//|
+//|.define SAVE_CFRAME, aword [rsp+aword*13]
+//|.define SAVE_PC, dword [rsp+dword*25]
+//|.define SAVE_L, dword [rsp+dword*24]
+//|.define SAVE_ERRF, dword [rsp+dword*23]
+//|.define SAVE_NRES, dword [rsp+dword*22]
+//|.define TMP2, dword [rsp+dword*21]
+//|.define TMP1, dword [rsp+dword*20]
+//|//----- 16 byte aligned, ^^^ 32 byte register save area, owned by interpreter
+//|.define SAVE_RET, aword [rsp+aword*9] //<-- rsp entering interpreter.
+//|.define SAVE_R4, aword [rsp+aword*8]
+//|.define SAVE_R3, aword [rsp+aword*7]
+//|.define SAVE_R2, aword [rsp+aword*6]
+//|.define SAVE_R1, aword [rsp+aword*5] //<-- rsp after register saves.
+//|.define ARG5, aword [rsp+aword*4]
+//|.define CSAVE_4, aword [rsp+aword*3]
+//|.define CSAVE_3, aword [rsp+aword*2]
+//|.define CSAVE_2, aword [rsp+aword*1]
+//|.define CSAVE_1, aword [rsp] //<-- rsp while in interpreter.
+//|//----- 16 byte aligned, ^^^ 32 byte register save area, owned by callee
+//|
+//|// TMPQ overlaps TMP1/TMP2. MULTRES overlaps TMP2 (and TMPQ).
+//|.define TMPQ, qword [rsp+aword*10]
+//|.define MULTRES, TMP2
+//|.define TMPa, ARG5
+//|.define ARG5d, dword [rsp+aword*4]
+//|.define TMP3, ARG5d
+//|
+//|//-----------------------------------------------------------------------
+//|.else // x64/POSIX stack layout
+//|
+//|.define CFRAME_SPACE, aword*5 // Delta for rsp (see <--).
+//|.macro saveregs_
+//| push rbx; push r15; push r14
+//|.if NO_UNWIND
+//| push r13; push r12
+//|.endif
+//| sub rsp, CFRAME_SPACE
+//|.endmacro
+//|.macro saveregs
+//| push rbp; saveregs_
+//|.endmacro
+//|.macro restoreregs
+//| add rsp, CFRAME_SPACE
+//|.if NO_UNWIND
+//| pop r12; pop r13
+//|.endif
+//| pop r14; pop r15; pop rbx; pop rbp
+//|.endmacro
+//|
+//|//----- 16 byte aligned,
+//|.if NO_UNWIND
+//|.define SAVE_RET, aword [rsp+aword*11] //<-- rsp entering interpreter.
+//|.define SAVE_R4, aword [rsp+aword*10]
+//|.define SAVE_R3, aword [rsp+aword*9]
+//|.define SAVE_R2, aword [rsp+aword*8]
+//|.define SAVE_R1, aword [rsp+aword*7]
+//|.define SAVE_RU2, aword [rsp+aword*6]
+//|.define SAVE_RU1, aword [rsp+aword*5] //<-- rsp after register saves.
+//|.else
+//|.define SAVE_RET, aword [rsp+aword*9] //<-- rsp entering interpreter.
+//|.define SAVE_R4, aword [rsp+aword*8]
+//|.define SAVE_R3, aword [rsp+aword*7]
+//|.define SAVE_R2, aword [rsp+aword*6]
+//|.define SAVE_R1, aword [rsp+aword*5] //<-- rsp after register saves.
+//|.endif
+//|.define SAVE_CFRAME, aword [rsp+aword*4]
+//|.define SAVE_PC, dword [rsp+dword*7]
+//|.define SAVE_L, dword [rsp+dword*6]
+//|.define SAVE_ERRF, dword [rsp+dword*5]
+//|.define SAVE_NRES, dword [rsp+dword*4]
+//|.define TMPa, aword [rsp+aword*1]
+//|.define TMP2, dword [rsp+dword*1]
+//|.define TMP1, dword [rsp] //<-- rsp while in interpreter.
+//|//----- 16 byte aligned
+//|
+//|// TMPQ overlaps TMP1/TMP2. MULTRES overlaps TMP2 (and TMPQ).
+//|.define TMPQ, qword [rsp]
+//|.define TMP3, dword [rsp+aword*1]
+//|.define MULTRES, TMP2
+//|
+//|.endif
+//|
+//|//-----------------------------------------------------------------------
+//|
+//|// Instruction headers.
+//|.macro ins_A; .endmacro
+//|.macro ins_AD; .endmacro
+//|.macro ins_AJ; .endmacro
+//|.macro ins_ABC; movzx RB, RCH; movzx RC, RCL; .endmacro
+//|.macro ins_AB_; movzx RB, RCH; .endmacro
+//|.macro ins_A_C; movzx RC, RCL; .endmacro
+//|.macro ins_AND; not RDa; .endmacro
+//|
+//|// Instruction decode+dispatch. Carefully tuned (nope, lodsd is not faster).
+//|.macro ins_NEXT
+//| mov RC, [PC]
+//| movzx RA, RCH
+//| movzx OP, RCL
+//| add PC, 4
+//| shr RC, 16
+//|.if X64
+//| jmp aword [DISPATCH+OP*8]
+//|.else
+//| jmp aword [DISPATCH+OP*4]
+//|.endif
+//|.endmacro
+//|
+//|// Instruction footer.
+//|.if 1
+//| // Replicated dispatch. Less unpredictable branches, but higher I-Cache use.
+//| .define ins_next, ins_NEXT
+//| .define ins_next_, ins_NEXT
+//|.else
+//| // Common dispatch. Lower I-Cache use, only one (very) unpredictable branch.
+//| // Affects only certain kinds of benchmarks (and only with -j off).
+//| // Around 10%-30% slower on Core2, a lot more slower on P4.
+//| .macro ins_next
+//| jmp ->ins_next
+//| .endmacro
+//| .macro ins_next_
+//| ->ins_next:
+//| ins_NEXT
+//| .endmacro
+//|.endif
+//|
+//|// Call decode and dispatch.
+//|.macro ins_callt
+//| // BASE = new base, RB = LFUNC, RD = nargs+1, [BASE-4] = PC
+//| mov PC, LFUNC:RB->pc
+//| mov RA, [PC]
+//| movzx OP, RAL
+//| movzx RA, RAH
+//| add PC, 4
+//|.if X64
+//| jmp aword [DISPATCH+OP*8]
+//|.else
+//| jmp aword [DISPATCH+OP*4]
+//|.endif
+//|.endmacro
+//|
+//|.macro ins_call
+//| // BASE = new base, RB = LFUNC, RD = nargs+1
+//| mov [BASE-4], PC
+//| ins_callt
+//|.endmacro
+//|
+//|//-----------------------------------------------------------------------
+//|
+//|// Macros to test operand types.
+//|.macro checktp, reg, tp; cmp dword [BASE+reg*8+4], tp; .endmacro
+//|.macro checknum, reg, target; checktp reg, LJ_TISNUM; jae target; .endmacro
+//|.macro checkint, reg, target; checktp reg, LJ_TISNUM; jne target; .endmacro
+//|.macro checkstr, reg, target; checktp reg, LJ_TSTR; jne target; .endmacro
+//|.macro checktab, reg, target; checktp reg, LJ_TTAB; jne target; .endmacro
+//|
+//|// These operands must be used with movzx.
+//|.define PC_OP, byte [PC-4]
+//|.define PC_RA, byte [PC-3]
+//|.define PC_RB, byte [PC-1]
+//|.define PC_RC, byte [PC-2]
+//|.define PC_RD, word [PC-2]
+//|
+//|.macro branchPC, reg
+//| lea PC, [PC+reg*4-BCBIAS_J*4]
+//|.endmacro
+//|
+//|// Assumes DISPATCH is relative to GL.
+#define DISPATCH_GL(field) (GG_DISP2G + (int)offsetof(global_State, field))
+#define DISPATCH_J(field) (GG_DISP2J + (int)offsetof(jit_State, field))
+//|
+#define PC2PROTO(field) ((int)offsetof(GCproto, field)-(int)sizeof(GCproto))
+//|
+//|// Decrement hashed hotcount and trigger trace recorder if zero.
+//|.macro hotloop, reg
+//| mov reg, PC
+//| shr reg, 1
+//| and reg, HOTCOUNT_PCMASK
+//| sub word [DISPATCH+reg+GG_DISP2HOT], HOTCOUNT_LOOP
+//| jb ->vm_hotloop
+//|.endmacro
+//|
+//|.macro hotcall, reg
+//| mov reg, PC
+//| shr reg, 1
+//| and reg, HOTCOUNT_PCMASK
+//| sub word [DISPATCH+reg+GG_DISP2HOT], HOTCOUNT_CALL
+//| jb ->vm_hotcall
+//|.endmacro
+//|
+//|// Set current VM state.
+//|.macro set_vmstate, st
+//| mov dword [DISPATCH+DISPATCH_GL(vmstate)], ~LJ_VMST_..st
+//|.endmacro
+//|
+//|// x87 compares.
+//|.macro fcomparepp // Compare and pop st0 >< st1.
+//| fucomip st1
+//| fpop
+//|.endmacro
+//|
+//|.macro fpop1; fstp st1; .endmacro
+//|
+//|// Synthesize SSE FP constants.
+//|.macro sseconst_abs, reg, tmp // Synthesize abs mask.
+//|.if X64
+//| mov64 tmp, U64x(7fffffff,ffffffff); movd reg, tmp
+//|.else
+//| pxor reg, reg; pcmpeqd reg, reg; psrlq reg, 1
+//|.endif
+//|.endmacro
+//|
+//|.macro sseconst_hi, reg, tmp, val // Synthesize hi-32 bit const.
+//|.if X64
+//| mov64 tmp, U64x(val,00000000); movd reg, tmp
+//|.else
+//| mov tmp, 0x .. val; movd reg, tmp; pshufd reg, reg, 0x51
+//|.endif
+//|.endmacro
+//|
+//|.macro sseconst_sign, reg, tmp // Synthesize sign mask.
+//| sseconst_hi reg, tmp, 80000000
+//|.endmacro
+//|.macro sseconst_1, reg, tmp // Synthesize 1.0.
+//| sseconst_hi reg, tmp, 3ff00000
+//|.endmacro
+//|.macro sseconst_m1, reg, tmp // Synthesize -1.0.
+//| sseconst_hi reg, tmp, bff00000
+//|.endmacro
+//|.macro sseconst_2p52, reg, tmp // Synthesize 2^52.
+//| sseconst_hi reg, tmp, 43300000
+//|.endmacro
+//|.macro sseconst_tobit, reg, tmp // Synthesize 2^52 + 2^51.
+//| sseconst_hi reg, tmp, 43380000
+//|.endmacro
+//|
+//|// Move table write barrier back. Overwrites reg.
+//|.macro barrierback, tab, reg
+//| and byte tab->marked, (uint8_t)~LJ_GC_BLACK // black2gray(tab)
+//| mov reg, [DISPATCH+DISPATCH_GL(gc.grayagain)]
+//| mov [DISPATCH+DISPATCH_GL(gc.grayagain)], tab
+//| mov tab->gclist, reg
+//|.endmacro
+//|
+//|//-----------------------------------------------------------------------
+
+/* Generate subroutines used by opcodes and other parts of the VM. */
+/* The .code_sub section should be last to help static branch prediction. */
+static void build_subroutines(BuildCtx *ctx)
+{
+ //|.code_sub
+ dasm_put(Dst, 0);
+#line 492 "vm_x86.dasc"
+ //|
+ //|//-----------------------------------------------------------------------
+ //|//-- Return handling ----------------------------------------------------
+ //|//-----------------------------------------------------------------------
+ //|
+ //|->vm_returnp:
+ //| test PC, FRAME_P
+ //| jz ->cont_dispatch
+ //|
+ //| // Return from pcall or xpcall fast func.
+ //| and PC, -8
+ //| sub BASE, PC // Restore caller base.
+ //| lea RAa, [RA+PC-8] // Rebase RA and prepend one result.
+ //| mov PC, [BASE-4] // Fetch PC of previous frame.
+ //| // Prepending may overwrite the pcall frame, so do it at the end.
+ //| mov dword [BASE+RA+4], LJ_TTRUE // Prepend true to results.
+ //|
+ //|->vm_returnc:
+ //| add RD, 1 // RD = nresults+1
+ //| jz ->vm_unwind_yield
+ //| mov MULTRES, RD
+ //| test PC, FRAME_TYPE
+ //| jz ->BC_RET_Z // Handle regular return to Lua.
+ //|
+ //|->vm_return:
+ //| // BASE = base, RA = resultofs, RD = nresults+1 (= MULTRES), PC = return
+ //| xor PC, FRAME_C
+ //| test PC, FRAME_TYPE
+ //| jnz ->vm_returnp
+ //|
+ //| // Return to C.
+ //| set_vmstate C
+ //| and PC, -8
+ //| sub PC, BASE
+ //| neg PC // Previous base = BASE - delta.
+ //|
+ //| sub RD, 1
+ //| jz >2
+ //|1: // Move results down.
+ //|.if X64
+ //| mov RBa, [BASE+RA]
+ dasm_put(Dst, 2, FRAME_P, LJ_TTRUE, FRAME_TYPE, FRAME_C, FRAME_TYPE, DISPATCH_GL(vmstate), ~LJ_VMST_C);
+#line 533 "vm_x86.dasc"
+ //| mov [BASE-8], RBa
+ //|.else
+ //| mov RB, [BASE+RA]
+ //| mov [BASE-8], RB
+ //| mov RB, [BASE+RA+4]
+ //| mov [BASE-4], RB
+ //|.endif
+ //| add BASE, 8
+ //| sub RD, 1
+ //| jnz <1
+ //|2:
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, PC
+ //|3:
+ //| mov RD, MULTRES
+ //| mov RA, SAVE_NRES // RA = wanted nresults+1
+ //|4:
+ //| cmp RA, RD
+ //| jne >6 // More/less results wanted?
+ //|5:
+ //| sub BASE, 8
+ //| mov L:RB->top, BASE
+ //|
+ //|->vm_leave_cp:
+ //| mov RAa, SAVE_CFRAME // Restore previous C frame.
+ //| mov L:RB->cframe, RAa
+ //| xor eax, eax // Ok return status for vm_pcall.
+ //|
+ //|->vm_leave_unw:
+ //| restoreregs
+ //| ret
+ //|
+ //|6:
+ //| jb >7 // Less results wanted?
+ //| // More results wanted. Check stack size and fill up results with nil.
+ //| cmp BASE, L:RB->maxstack
+ //| ja >8
+ //| mov dword [BASE-4], LJ_TNIL
+ dasm_put(Dst, 92, Dt1(->base), Dt1(->top), Dt1(->cframe), Dt1(->maxstack));
+#line 571 "vm_x86.dasc"
+ //| add BASE, 8
+ //| add RD, 1
+ //| jmp <4
+ //|
+ //|7: // Less results wanted.
+ //| test RA, RA
+ //| jz <5 // But check for LUA_MULTRET+1.
+ //| sub RA, RD // Negative result!
+ //| lea BASE, [BASE+RA*8] // Correct top.
+ //| jmp <5
+ //|
+ //|8: // Corner case: need to grow stack for filling up results.
+ //| // This can happen if:
+ //| // - A C function grows the stack (a lot).
+ //| // - The GC shrinks the stack in between.
+ //| // - A return back from a lua_call() with (high) nresults adjustment.
+ //| mov L:RB->top, BASE // Save current top held in BASE (yes).
+ //| mov MULTRES, RD // Need to fill only remainder with nil.
+ //| mov FCARG2, RA
+ //| mov FCARG1, L:RB
+ //| call extern lj_state_growstack@8 // (lua_State *L, int n)
+ //| mov BASE, L:RB->top // Need the (realloced) L->top in BASE.
+ //| jmp <3
+ //|
+ //|->vm_unwind_yield:
+ //| mov al, LUA_YIELD
+ //| jmp ->vm_unwind_c_eh
+ //|
+ //|->vm_unwind_c@8: // Unwind C stack, return from vm_pcall.
+ //| // (void *cframe, int errcode)
+ //|.if X64
+ //| mov eax, CARG2d // Error return status for vm_pcall.
+ //| mov rsp, CARG1
+ //|.else
+ //| mov eax, FCARG2 // Error return status for vm_pcall.
+ //| mov esp, FCARG1
+ //|.if WIN
+ //| lea FCARG1, SEH_NEXT
+ //| fs; mov [0], FCARG1
+ //|.endif
+ //|.endif
+ //|->vm_unwind_c_eh: // Landing pad for external unwinder.
+ //| mov L:RB, SAVE_L
+ dasm_put(Dst, 187, LJ_TNIL, Dt1(->top), Dt1(->top), LUA_YIELD);
+#line 614 "vm_x86.dasc"
+ //| mov GL:RB, L:RB->glref
+ //| mov dword GL:RB->vmstate, ~LJ_VMST_C
+ //| jmp ->vm_leave_unw
+ //|
+ //|->vm_unwind_rethrow:
+ //|.if X64 and not X64WIN
+ //| mov FCARG1, SAVE_L
+ //| mov FCARG2, eax
+ //| restoreregs
+ //| jmp extern lj_err_throw@8 // (lua_State *L, int errcode)
+ //|.endif
+ //|
+ //|->vm_unwind_ff@4: // Unwind C stack, return from ff pcall.
+ //| // (void *cframe)
+ //|.if X64
+ //| and CARG1, CFRAME_RAWMASK
+ //| mov rsp, CARG1
+ //|.else
+ //| and FCARG1, CFRAME_RAWMASK
+ //| mov esp, FCARG1
+ //|.if WIN
+ //| lea FCARG1, SEH_NEXT
+ //| fs; mov [0], FCARG1
+ //|.endif
+ //|.endif
+ //|->vm_unwind_ff_eh: // Landing pad for external unwinder.
+ //| mov L:RB, SAVE_L
+ //| mov RAa, -8 // Results start at BASE+RA = BASE-8.
+ //| mov RD, 1+1 // Really 1+2 results, incr. later.
+ //| mov BASE, L:RB->base
+ //| mov DISPATCH, L:RB->glref // Setup pointer to dispatch table.
+ //| add DISPATCH, GG_G2DISP
+ //| mov PC, [BASE-4] // Fetch PC of previous frame.
+ //| mov dword [BASE-4], LJ_TFALSE // Prepend false to error message.
+ //| set_vmstate INTERP
+ //| jmp ->vm_returnc // Increments RD/MULTRES and returns.
+ //|
+ //|.if WIN and not X64
+ //|->vm_rtlunwind@16: // Thin layer around RtlUnwind.
+ //| // (void *cframe, void *excptrec, void *unwinder, int errcode)
+ //| mov [esp], FCARG1 // Return value for RtlUnwind.
+ //| push FCARG2 // Exception record for RtlUnwind.
+ //| push 0 // Ignored by RtlUnwind.
+ //| push dword [FCARG1+CFRAME_OFS_SEH]
+ //| call extern RtlUnwind@16 // Violates ABI (clobbers too much).
+ //| mov FCARG1, eax
+ //| mov FCARG2, [esp+4] // errcode (for vm_unwind_c).
+ //| ret // Jump to unwinder.
+ //|.endif
+ //|
+ //|//-----------------------------------------------------------------------
+ //|//-- Grow stack for calls -----------------------------------------------
+ //|//-----------------------------------------------------------------------
+ //|
+ //|->vm_growstack_c: // Grow stack for C function.
+ //| mov FCARG2, LUA_MINSTACK
+ dasm_put(Dst, 264, Dt1(->glref), Dt2(->vmstate), ~LJ_VMST_C, CFRAME_RAWMASK, 1+1, Dt1(->base), Dt1(->glref), GG_G2DISP, LJ_TFALSE, DISPATCH_GL(vmstate), ~LJ_VMST_INTERP);
+#line 670 "vm_x86.dasc"
+ //| jmp >2
+ //|
+ //|->vm_growstack_v: // Grow stack for vararg Lua function.
+ //| sub RD, 8
+ //| jmp >1
+ //|
+ //|->vm_growstack_f: // Grow stack for fixarg Lua function.
+ //| // BASE = new base, RD = nargs+1, RB = L, PC = first PC
+ //| lea RD, [BASE+NARGS:RD*8-8]
+ //|1:
+ //| movzx RA, byte [PC-4+PC2PROTO(framesize)]
+ //| add PC, 4 // Must point after first instruction.
+ //| mov L:RB->base, BASE
+ //| mov L:RB->top, RD
+ //| mov SAVE_PC, PC
+ //| mov FCARG2, RA
+ //|2:
+ //| // RB = L, L->base = new base, L->top = top
+ //| mov FCARG1, L:RB
+ //| call extern lj_state_growstack@8 // (lua_State *L, int n)
+ //| mov BASE, L:RB->base
+ //| mov RD, L:RB->top
+ //| mov LFUNC:RB, [BASE-8]
+ //| sub RD, BASE
+ //| shr RD, 3
+ //| add NARGS:RD, 1
+ //| // BASE = new base, RB = LFUNC, RD = nargs+1
+ //| ins_callt // Just retry the call.
+ //|
+ //|//-----------------------------------------------------------------------
+ //|//-- Entry points into the assembler VM ---------------------------------
+ //|//-----------------------------------------------------------------------
+ //|
+ //|->vm_resume: // Setup C frame and resume thread.
+ //| // (lua_State *L, TValue *base, int nres1 = 0, ptrdiff_t ef = 0)
+ //| saveregs
+ //|.if X64
+ //| mov L:RB, CARG1d // Caveat: CARG1d may be RA.
+ //| mov SAVE_L, CARG1d
+ //| mov RA, CARG2d
+ //|.else
+ //| mov L:RB, SAVE_L
+ //| mov RA, INARG_BASE // Caveat: overlaps SAVE_CFRAME!
+ //|.endif
+ //| mov PC, FRAME_CP
+ //| xor RD, RD
+ //| lea KBASEa, [esp+CFRAME_RESUME]
+ //| mov DISPATCH, L:RB->glref // Setup pointer to dispatch table.
+ //| add DISPATCH, GG_G2DISP
+ dasm_put(Dst, 363, LUA_MINSTACK, -4+PC2PROTO(framesize), Dt1(->base), Dt1(->top), Dt1(->base), Dt1(->top), Dt7(->pc), FRAME_CP, CFRAME_RESUME, Dt1(->glref));
+#line 719 "vm_x86.dasc"
+ //| mov SAVE_PC, RD // Any value outside of bytecode is ok.
+ //| mov SAVE_CFRAME, RDa
+ //|.if X64
+ //| mov SAVE_NRES, RD
+ //| mov SAVE_ERRF, RD
+ //|.endif
+ //| mov L:RB->cframe, KBASEa
+ //| cmp byte L:RB->status, RDL
+ //| je >2 // Initial resume (like a call).
+ //|
+ //| // Resume after yield (like a return).
+ //| mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB
+ //| set_vmstate INTERP
+ //| mov byte L:RB->status, RDL
+ //| mov BASE, L:RB->base
+ //| mov RD, L:RB->top
+ //| sub RD, RA
+ //| shr RD, 3
+ //| add RD, 1 // RD = nresults+1
+ //| sub RA, BASE // RA = resultofs
+ //| mov PC, [BASE-4]
+ //| mov MULTRES, RD
+ //| test PC, FRAME_TYPE
+ //| jz ->BC_RET_Z
+ //| jmp ->vm_return
+ //|
+ //|->vm_pcall: // Setup protected C frame and enter VM.
+ //| // (lua_State *L, TValue *base, int nres1, ptrdiff_t ef)
+ //| saveregs
+ //| mov PC, FRAME_CP
+ //|.if X64
+ //| mov SAVE_ERRF, CARG4d
+ //|.endif
+ //| jmp >1
+ //|
+ //|->vm_call: // Setup C frame and enter VM.
+ //| // (lua_State *L, TValue *base, int nres1)
+ //| saveregs
+ dasm_put(Dst, 492, GG_G2DISP, Dt1(->cframe), Dt1(->status), DISPATCH_GL(cur_L), DISPATCH_GL(vmstate), ~LJ_VMST_INTERP, Dt1(->status), Dt1(->base), Dt1(->top), FRAME_TYPE, FRAME_CP);
+#line 757 "vm_x86.dasc"
+ //| mov PC, FRAME_C
+ //|
+ //|1: // Entry point for vm_pcall above (PC = ftype).
+ //|.if X64
+ //| mov SAVE_NRES, CARG3d
+ //| mov L:RB, CARG1d // Caveat: CARG1d may be RA.
+ //| mov SAVE_L, CARG1d
+ //| mov RA, CARG2d
+ //|.else
+ //| mov L:RB, SAVE_L
+ //| mov RA, INARG_BASE // Caveat: overlaps SAVE_CFRAME!
+ //|.endif
+ //|
+ //| mov DISPATCH, L:RB->glref // Setup pointer to dispatch table.
+ //| mov KBASEa, L:RB->cframe // Add our C frame to cframe chain.
+ //| mov SAVE_CFRAME, KBASEa
+ //| mov SAVE_PC, L:RB // Any value outside of bytecode is ok.
+ //| add DISPATCH, GG_G2DISP
+ //|.if X64
+ //| mov L:RB->cframe, rsp
+ //|.else
+ //| mov L:RB->cframe, esp
+ //|.endif
+ //|
+ //|2: // Entry point for vm_resume/vm_cpcall (RA = base, RB = L, PC = ftype).
+ //| mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB
+ //| set_vmstate INTERP
+ //| mov BASE, L:RB->base // BASE = old base (used in vmeta_call).
+ //| add PC, RA
+ //| sub PC, BASE // PC = frame delta + frame type
+ //|
+ //| mov RD, L:RB->top
+ //| sub RD, RA
+ //| shr NARGS:RD, 3
+ //| add NARGS:RD, 1 // RD = nargs+1
+ //|
+ //|->vm_call_dispatch:
+ //| mov LFUNC:RB, [RA-8]
+ //| cmp dword [RA-4], LJ_TFUNC
+ //| jne ->vmeta_call // Ensure KBASE defined and != BASE.
+ //|
+ //|->vm_call_dispatch_f:
+ //| mov BASE, RA
+ //| ins_call
+ //| // BASE = new base, RB = func, RD = nargs+1, PC = caller PC
+ //|
+ //|->vm_cpcall: // Setup protected C frame, call C.
+ //| // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp)
+ //| saveregs
+ dasm_put(Dst, 598, FRAME_C, Dt1(->glref), Dt1(->cframe), GG_G2DISP, Dt1(->cframe), DISPATCH_GL(cur_L), DISPATCH_GL(vmstate), ~LJ_VMST_INTERP, Dt1(->base), Dt1(->top), LJ_TFUNC, Dt7(->pc));
+#line 806 "vm_x86.dasc"
+ //|.if X64
+ //| mov L:RB, CARG1d // Caveat: CARG1d may be RA.
+ //| mov SAVE_L, CARG1d
+ //|.else
+ //| mov L:RB, SAVE_L
+ //| // Caveat: INARG_CP_* and SAVE_CFRAME/SAVE_NRES/SAVE_ERRF overlap!
+ //| mov RC, INARG_CP_UD // Get args before they are overwritten.
+ //| mov RA, INARG_CP_FUNC
+ //| mov BASE, INARG_CP_CALL
+ //|.endif
+ //| mov SAVE_PC, L:RB // Any value outside of bytecode is ok.
+ //|
+ //| mov KBASE, L:RB->stack // Compute -savestack(L, L->top).
+ //| sub KBASE, L:RB->top
+ //| mov DISPATCH, L:RB->glref // Setup pointer to dispatch table.
+ //| mov SAVE_ERRF, 0 // No error function.
+ //| mov SAVE_NRES, KBASE // Neg. delta means cframe w/o frame.
+ //| add DISPATCH, GG_G2DISP
+ //| // Handler may change cframe_nres(L->cframe) or cframe_errfunc(L->cframe).
+ //|
+ //|.if X64
+ //| mov KBASEa, L:RB->cframe // Add our C frame to cframe chain.
+ //| mov SAVE_CFRAME, KBASEa
+ //| mov L:RB->cframe, rsp
+ //| mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB
+ //|
+ //| call CARG4 // (lua_State *L, lua_CFunction func, void *ud)
+ //|.else
+ //| mov ARG3, RC // Have to copy args downwards.
+ //| mov ARG2, RA
+ //| mov ARG1, L:RB
+ //|
+ //| mov KBASE, L:RB->cframe // Add our C frame to cframe chain.
+ //| mov SAVE_CFRAME, KBASE
+ //| mov L:RB->cframe, esp
+ //| mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB
+ //|
+ //| call BASE // (lua_State *L, lua_CFunction func, void *ud)
+ //|.endif
+ //| // TValue * (new base) or NULL returned in eax (RC).
+ //| test RC, RC
+ //| jz ->vm_leave_cp // No base? Just remove C frame.
+ //| mov RA, RC
+ //| mov PC, FRAME_CP
+ //| jmp <2 // Else continue with the call.
+ //|
+ //|//-----------------------------------------------------------------------
+ //|//-- Metamethod handling ------------------------------------------------
+ //|//-----------------------------------------------------------------------
+ //|
+ //|//-- Continuation dispatch ----------------------------------------------
+ //|
+ //|->cont_dispatch:
+ //| // BASE = meta base, RA = resultofs, RD = nresults+1 (also in MULTRES)
+ //| add RA, BASE
+ //| and PC, -8
+ //| mov RB, BASE
+ //| sub BASE, PC // Restore caller BASE.
+ //| mov dword [RA+RD*8-4], LJ_TNIL // Ensure one valid arg.
+ //| mov RC, RA // ... in [RC]
+ //| mov PC, [RB-12] // Restore PC from [cont|PC].
+ //|.if X64
+ //| movsxd RAa, dword [RB-16] // May be negative on WIN64 with debug.
+ //|.if FFI
+ //| cmp RA, 1
+ //| jbe >1
+ //|.endif
+ //| lea KBASEa, qword [=>0]
+ //| add RAa, KBASEa
+ //|.else
+ //| mov RA, dword [RB-16]
+ //|.if FFI
+ //| cmp RA, 1
+ //| jbe >1
+ //|.endif
+ //|.endif
+ //| mov LFUNC:KBASE, [BASE-8]
+ //| mov KBASE, LFUNC:KBASE->pc
+ //| mov KBASE, [KBASE+PC2PROTO(k)]
+ dasm_put(Dst, 729, Dt1(->stack), Dt1(->top), Dt1(->glref), GG_G2DISP, Dt1(->cframe), Dt1(->cframe), DISPATCH_GL(cur_L), FRAME_CP, LJ_TNIL, 0, Dt7(->pc));
+#line 885 "vm_x86.dasc"
+ //| // BASE = base, RC = result, RB = meta base
+ //| jmp RAa // Jump to continuation.
+ //|
+ //|.if FFI
+ //|1:
+ //| je ->cont_ffi_callback // cont = 1: return from FFI callback.
+ //| // cont = 0: Tail call from C function.
+ //| sub RB, BASE
+ //| shr RB, 3
+ //| lea RD, [RB-1]
+ //| jmp ->vm_call_tail
+ //|.endif
+ //|
+ //|->cont_cat: // BASE = base, RC = result, RB = mbase
+ //| movzx RA, PC_RB
+ //| sub RB, 16
+ //| lea RA, [BASE+RA*8]
+ //| sub RA, RB
+ //| je ->cont_ra
+ //| neg RA
+ //| shr RA, 3
+ //|.if X64WIN
+ //| mov CARG3d, RA
+ //| mov L:CARG1d, SAVE_L
+ //| mov L:CARG1d->base, BASE
+ //| mov RCa, [RC]
+ //| mov [RB], RCa
+ //| mov CARG2d, RB
+ //|.elif X64
+ //| mov L:CARG1d, SAVE_L
+ //| mov L:CARG1d->base, BASE
+ //| mov CARG3d, RA
+ //| mov RAa, [RC]
+ //| mov [RB], RAa
+ //| mov CARG2d, RB
+ //|.else
+ //| mov ARG3, RA
+ //| mov RA, [RC+4]
+ //| mov RC, [RC]
+ //| mov [RB+4], RA
+ //| mov [RB], RC
+ //| mov ARG2, RB
+ //|.endif
+ //| jmp ->BC_CAT_Z
+ //|
+ //|//-- Table indexing metamethods -----------------------------------------
+ //|
+ //|->vmeta_tgets:
+ //| mov TMP1, RC // RC = GCstr *
+ //| mov TMP2, LJ_TSTR
+ //| lea RCa, TMP1 // Store temp. TValue in TMP1/TMP2.
+ //| cmp PC_OP, BC_GGET
+ //| jne >1
+ //| lea RA, [DISPATCH+DISPATCH_GL(tmptv)] // Store fn->l.env in g->tmptv.
+ //| mov [RA], TAB:RB // RB = GCtab *
+ //| mov dword [RA+4], LJ_TTAB
+ //| mov RB, RA
+ dasm_put(Dst, 869, PC2PROTO(k), Dt1(->base), LJ_TSTR, BC_GGET, DISPATCH_GL(tmptv), LJ_TTAB);
+#line 942 "vm_x86.dasc"
+ //| jmp >2
+ //|
+ //|->vmeta_tgetb:
+ //| movzx RC, PC_RC
+ //|.if DUALNUM
+ //| mov TMP2, LJ_TISNUM
+ //| mov TMP1, RC
+ //|.else
+ //| cvtsi2sd xmm0, RC
+ //| movsd TMPQ, xmm0
+ //|.endif
+ //| lea RCa, TMPQ // Store temp. TValue in TMPQ.
+ //| jmp >1
+ //|
+ //|->vmeta_tgetv:
+ //| movzx RC, PC_RC // Reload TValue *k from RC.
+ //| lea RC, [BASE+RC*8]
+ //|1:
+ //| movzx RB, PC_RB // Reload TValue *t from RB.
+ //| lea RB, [BASE+RB*8]
+ //|2:
+ //|.if X64
+ //| mov L:CARG1d, SAVE_L
+ //| mov L:CARG1d->base, BASE // Caveat: CARG2d/CARG3d may be BASE.
+ //| mov CARG2d, RB
+ //| mov CARG3, RCa // May be 64 bit ptr to stack.
+ //| mov L:RB, L:CARG1d
+ //|.else
+ //| mov ARG2, RB
+ //| mov L:RB, SAVE_L
+ //| mov ARG3, RC
+ //| mov ARG1, L:RB
+ //| mov L:RB->base, BASE
+ //|.endif
+ //| mov SAVE_PC, PC
+ //| call extern lj_meta_tget // (lua_State *L, TValue *o, TValue *k)
+ //| // TValue * (finished) or NULL (metamethod) returned in eax (RC).
+ //| mov BASE, L:RB->base
+ //| test RC, RC
+ //| jz >3
+ //|->cont_ra: // BASE = base, RC = result
+ //| movzx RA, PC_RA
+ //|.if X64
+ //| mov RBa, [RC]
+ //| mov [BASE+RA*8], RBa
+ //|.else
+ //| mov RB, [RC+4]
+ //| mov RC, [RC]
+ //| mov [BASE+RA*8+4], RB
+ //| mov [BASE+RA*8], RC
+ //|.endif
+ //| ins_next
+ //|
+ //|3: // Call __index metamethod.
+ //| // BASE = base, L->top = new base, stack = cont/func/t/k
+ //| mov RA, L:RB->top
+ //| mov [RA-12], PC // [cont|PC]
+ //| lea PC, [RA+FRAME_CONT]
+ //| sub PC, BASE
+ //| mov LFUNC:RB, [RA-8] // Guaranteed to be a function here.
+ //| mov NARGS:RD, 2+1 // 2 args for func(t, k).
+ //| jmp ->vm_call_dispatch_f
+ //|
+ //|->vmeta_tgetr:
+ //| mov FCARG1, TAB:RB
+ dasm_put(Dst, 981, Dt1(->base), Dt1(->base), Dt1(->top), FRAME_CONT, 2+1);
+#line 1007 "vm_x86.dasc"
+ //| mov RB, BASE // Save BASE.
+ //| mov FCARG2, RC // Caveat: FCARG2 == BASE
+ //| call extern lj_tab_getinth@8 // (GCtab *t, int32_t key)
+ //| // cTValue * or NULL returned in eax (RC).
+ //| movzx RA, PC_RA
+ //| mov BASE, RB // Restore BASE.
+ //| test RC, RC
+ //| jnz ->BC_TGETR_Z
+ //| mov dword [BASE+RA*8+4], LJ_TNIL
+ //| jmp ->BC_TGETR2_Z
+ //|
+ //|//-----------------------------------------------------------------------
+ //|
+ //|->vmeta_tsets:
+ //| mov TMP1, RC // RC = GCstr *
+ //| mov TMP2, LJ_TSTR
+ //| lea RCa, TMP1 // Store temp. TValue in TMP1/TMP2.
+ //| cmp PC_OP, BC_GSET
+ //| jne >1
+ //| lea RA, [DISPATCH+DISPATCH_GL(tmptv)] // Store fn->l.env in g->tmptv.
+ //| mov [RA], TAB:RB // RB = GCtab *
+ //| mov dword [RA+4], LJ_TTAB
+ //| mov RB, RA
+ //| jmp >2
+ //|
+ //|->vmeta_tsetb:
+ //| movzx RC, PC_RC
+ //|.if DUALNUM
+ //| mov TMP2, LJ_TISNUM
+ //| mov TMP1, RC
+ //|.else
+ //| cvtsi2sd xmm0, RC
+ //| movsd TMPQ, xmm0
+ //|.endif
+ //| lea RCa, TMPQ // Store temp. TValue in TMPQ.
+ //| jmp >1
+ //|
+ //|->vmeta_tsetv:
+ //| movzx RC, PC_RC // Reload TValue *k from RC.
+ //| lea RC, [BASE+RC*8]
+ //|1:
+ //| movzx RB, PC_RB // Reload TValue *t from RB.
+ dasm_put(Dst, 1130, LJ_TNIL, LJ_TSTR, BC_GSET, DISPATCH_GL(tmptv), LJ_TTAB);
+#line 1049 "vm_x86.dasc"
+ //| lea RB, [BASE+RB*8]
+ //|2:
+ //|.if X64
+ //| mov L:CARG1d, SAVE_L
+ //| mov L:CARG1d->base, BASE // Caveat: CARG2d/CARG3d may be BASE.
+ //| mov CARG2d, RB
+ //| mov CARG3, RCa // May be 64 bit ptr to stack.
+ //| mov L:RB, L:CARG1d
+ //|.else
+ //| mov ARG2, RB
+ //| mov L:RB, SAVE_L
+ //| mov ARG3, RC
+ //| mov ARG1, L:RB
+ //| mov L:RB->base, BASE
+ //|.endif
+ //| mov SAVE_PC, PC
+ //| call extern lj_meta_tset // (lua_State *L, TValue *o, TValue *k)
+ //| // TValue * (finished) or NULL (metamethod) returned in eax (RC).
+ //| mov BASE, L:RB->base
+ //| test RC, RC
+ //| jz >3
+ //| // NOBARRIER: lj_meta_tset ensures the table is not black.
+ //| movzx RA, PC_RA
+ //|.if X64
+ //| mov RBa, [BASE+RA*8]
+ //| mov [RC], RBa
+ //|.else
+ //| mov RB, [BASE+RA*8+4]
+ //| mov RA, [BASE+RA*8]
+ //| mov [RC+4], RB
+ //| mov [RC], RA
+ //|.endif
+ //|->cont_nop: // BASE = base, (RC = result)
+ //| ins_next
+ //|
+ //|3: // Call __newindex metamethod.
+ //| // BASE = base, L->top = new base, stack = cont/func/t/k/(v)
+ //| mov RA, L:RB->top
+ //| mov [RA-12], PC // [cont|PC]
+ //| movzx RC, PC_RA
+ //| // Copy value to third argument.
+ //|.if X64
+ //| mov RBa, [BASE+RC*8]
+ //| mov [RA+16], RBa
+ //|.else
+ //| mov RB, [BASE+RC*8+4]
+ //| mov RC, [BASE+RC*8]
+ //| mov [RA+20], RB
+ //| mov [RA+16], RC
+ //|.endif
+ //| lea PC, [RA+FRAME_CONT]
+ //| sub PC, BASE
+ //| mov LFUNC:RB, [RA-8] // Guaranteed to be a function here.
+ //| mov NARGS:RD, 3+1 // 3 args for func(t, k, v).
+ //| jmp ->vm_call_dispatch_f
+ //|
+ //|->vmeta_tsetr:
+ //|.if X64WIN
+ //| mov L:CARG1d, SAVE_L
+ //| mov CARG3d, RC
+ //| mov L:CARG1d->base, BASE
+ //| xchg CARG2d, TAB:RB // Caveat: CARG2d == BASE.
+ //|.elif X64
+ //| mov L:CARG1d, SAVE_L
+ //| mov CARG2d, TAB:RB
+ //| mov L:CARG1d->base, BASE
+ //| mov RB, BASE // Save BASE.
+ //| mov CARG3d, RC // Caveat: CARG3d == BASE.
+ //|.else
+ //| mov L:RA, SAVE_L
+ //| mov ARG2, TAB:RB
+ //| mov RB, BASE // Save BASE.
+ //| mov ARG3, RC
+ //| mov ARG1, L:RA
+ //| mov L:RA->base, BASE
+ //|.endif
+ //| mov SAVE_PC, PC
+ //| call extern lj_tab_setinth // (lua_State *L, GCtab *t, int32_t key)
+ //| // TValue * returned in eax (RC).
+ //| movzx RA, PC_RA
+ //| mov BASE, RB // Restore BASE.
+ //| jmp ->BC_TSETR_Z
+ //|
+ //|//-- Comparison metamethods ---------------------------------------------
+ //|
+ //|->vmeta_comp:
+ //|.if X64
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE // Caveat: CARG2d/CARG3d == BASE.
+ //|.if X64WIN
+ //| lea CARG3d, [BASE+RD*8]
+ //| lea CARG2d, [BASE+RA*8]
+ //|.else
+ //| lea CARG2d, [BASE+RA*8]
+ //| lea CARG3d, [BASE+RD*8]
+ //|.endif
+ //| mov CARG1d, L:RB // Caveat: CARG1d/CARG4d == RA.
+ //| movzx CARG4d, PC_OP
+ //|.else
+ //| movzx RB, PC_OP
+ //| lea RD, [BASE+RD*8]
+ //| lea RA, [BASE+RA*8]
+ //| mov ARG4, RB
+ //| mov L:RB, SAVE_L
+ //| mov ARG3, RD
+ //| mov ARG2, RA
+ //| mov ARG1, L:RB
+ //| mov L:RB->base, BASE
+ //|.endif
+ //| mov SAVE_PC, PC
+ //| call extern lj_meta_comp // (lua_State *L, TValue *o1, *o2, int op)
+ //| // 0/1 or TValue * (metamethod) returned in eax (RC).
+ //|3:
+ //| mov BASE, L:RB->base
+ dasm_put(Dst, 1242, Dt1(->base), Dt1(->base), Dt1(->top), FRAME_CONT, 3+1, Dt1(->base), Dt1(->base));
+#line 1163 "vm_x86.dasc"
+ //| cmp RC, 1
+ //| ja ->vmeta_binop
+ //|4:
+ //| lea PC, [PC+4]
+ //| jb >6
+ //|5:
+ //| movzx RD, PC_RD
+ //| branchPC RD
+ //|6:
+ //| ins_next
+ //|
+ //|->cont_condt: // BASE = base, RC = result
+ //| add PC, 4
+ //| cmp dword [RC+4], LJ_TISTRUECOND // Branch if result is true.
+ //| jb <5
+ //| jmp <6
+ //|
+ //|->cont_condf: // BASE = base, RC = result
+ //| cmp dword [RC+4], LJ_TISTRUECOND // Branch if result is false.
+ //| jmp <4
+ //|
+ //|->vmeta_equal:
+ //| sub PC, 4
+ dasm_put(Dst, 1427, Dt1(->base), -BCBIAS_J*4, LJ_TISTRUECOND, LJ_TISTRUECOND);
+#line 1186 "vm_x86.dasc"
+ //|.if X64WIN
+ //| mov CARG3d, RD
+ //| mov CARG4d, RB
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE // Caveat: CARG2d == BASE.
+ //| mov CARG2d, RA
+ //| mov CARG1d, L:RB // Caveat: CARG1d == RA.
+ //|.elif X64
+ //| mov CARG2d, RA
+ //| mov CARG4d, RB // Caveat: CARG4d == RA.
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE // Caveat: CARG3d == BASE.
+ //| mov CARG3d, RD
+ //| mov CARG1d, L:RB
+ //|.else
+ //| mov ARG4, RB
+ //| mov L:RB, SAVE_L
+ //| mov ARG3, RD
+ //| mov ARG2, RA
+ //| mov ARG1, L:RB
+ //| mov L:RB->base, BASE
+ //|.endif
+ //| mov SAVE_PC, PC
+ //| call extern lj_meta_equal // (lua_State *L, GCobj *o1, *o2, int ne)
+ //| // 0/1 or TValue * (metamethod) returned in eax (RC).
+ //| jmp <3
+ //|
+ //|->vmeta_equal_cd:
+ //|.if FFI
+ //| sub PC, 4
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE
+ //| mov FCARG1, L:RB
+ //| mov FCARG2, dword [PC-4]
+ //| mov SAVE_PC, PC
+ //| call extern lj_meta_equal_cd@8 // (lua_State *L, BCIns ins)
+ //| // 0/1 or TValue * (metamethod) returned in eax (RC).
+ //| jmp <3
+ //|.endif
+ //|
+ //|->vmeta_istype:
+ //|.if X64
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE // Caveat: CARG2d/CARG3d may be BASE.
+ //| mov CARG2d, RA
+ //| movzx CARG3d, PC_RD
+ //| mov L:CARG1d, L:RB
+ //|.else
+ //| movzx RD, PC_RD
+ //| mov ARG2, RA
+ //| mov L:RB, SAVE_L
+ //| mov ARG3, RD
+ //| mov ARG1, L:RB
+ //| mov L:RB->base, BASE
+ //|.endif
+ //| mov SAVE_PC, PC
+ //| call extern lj_meta_istype // (lua_State *L, BCReg ra, BCReg tp)
+ //| mov BASE, L:RB->base
+ //| jmp <6
+ //|
+ //|//-- Arithmetic metamethods ---------------------------------------------
+ //|
+ //|->vmeta_arith_vno:
+ //|.if DUALNUM
+ //| movzx RB, PC_RB
+ //|.endif
+ //|->vmeta_arith_vn:
+ //| lea RC, [KBASE+RC*8]
+ //| jmp >1
+ //|
+ //|->vmeta_arith_nvo:
+ //|.if DUALNUM
+ //| movzx RC, PC_RC
+ //|.endif
+ //|->vmeta_arith_nv:
+ //| lea RC, [KBASE+RC*8]
+ //| lea RB, [BASE+RB*8]
+ //| xchg RB, RC
+ //| jmp >2
+ //|
+ //|->vmeta_unm:
+ //| lea RC, [BASE+RD*8]
+ dasm_put(Dst, 1513, Dt1(->base), Dt1(->base), Dt1(->base), Dt1(->base));
+#line 1268 "vm_x86.dasc"
+ //| mov RB, RC
+ //| jmp >2
+ //|
+ //|->vmeta_arith_vvo:
+ //|.if DUALNUM
+ //| movzx RB, PC_RB
+ //|.endif
+ //|->vmeta_arith_vv:
+ //| lea RC, [BASE+RC*8]
+ //|1:
+ //| lea RB, [BASE+RB*8]
+ //|2:
+ //| lea RA, [BASE+RA*8]
+ //|.if X64WIN
+ //| mov CARG3d, RB
+ //| mov CARG4d, RC
+ //| movzx RC, PC_OP
+ //| mov ARG5d, RC
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE // Caveat: CARG2d == BASE.
+ //| mov CARG2d, RA
+ //| mov CARG1d, L:RB // Caveat: CARG1d == RA.
+ //|.elif X64
+ //| movzx CARG5d, PC_OP
+ //| mov CARG2d, RA
+ //| mov CARG4d, RC // Caveat: CARG4d == RA.
+ //| mov L:CARG1d, SAVE_L
+ //| mov L:CARG1d->base, BASE // Caveat: CARG3d == BASE.
+ //| mov CARG3d, RB
+ //| mov L:RB, L:CARG1d
+ //|.else
+ //| mov ARG3, RB
+ //| mov L:RB, SAVE_L
+ //| mov ARG4, RC
+ //| movzx RC, PC_OP
+ //| mov ARG2, RA
+ //| mov ARG5, RC
+ //| mov ARG1, L:RB
+ //| mov L:RB->base, BASE
+ //|.endif
+ //| mov SAVE_PC, PC
+ //| call extern lj_meta_arith // (lua_State *L, TValue *ra,*rb,*rc, BCReg op)
+ //| // NULL (finished) or TValue * (metamethod) returned in eax (RC).
+ //| mov BASE, L:RB->base
+ //| test RC, RC
+ //| jz ->cont_nop
+ //|
+ //| // Call metamethod for binary op.
+ //|->vmeta_binop:
+ //| // BASE = base, RC = new base, stack = cont/func/o1/o2
+ //| mov RA, RC
+ //| sub RC, BASE
+ //| mov [RA-12], PC // [cont|PC]
+ //| lea PC, [RC+FRAME_CONT]
+ //| mov NARGS:RD, 2+1 // 2 args for func(o1, o2).
+ //| jmp ->vm_call_dispatch
+ //|
+ //|->vmeta_len:
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE
+ //| lea FCARG2, [BASE+RD*8] // Caveat: FCARG2 == BASE
+ //| mov L:FCARG1, L:RB
+ //| mov SAVE_PC, PC
+ //| call extern lj_meta_len@8 // (lua_State *L, TValue *o)
+ //| // NULL (retry) or TValue * (metamethod) returned in eax (RC).
+ //| mov BASE, L:RB->base
+ dasm_put(Dst, 1644, Dt1(->base), Dt1(->base), FRAME_CONT, 2+1, Dt1(->base), Dt1(->base));
+#line 1334 "vm_x86.dasc"
+#if LJ_52
+ //| test RC, RC
+ //| jne ->vmeta_binop // Binop call for compatibility.
+ //| movzx RD, PC_RD
+ //| mov TAB:FCARG1, [BASE+RD*8]
+ //| jmp ->BC_LEN_Z
+ dasm_put(Dst, 1757);
+#line 1340 "vm_x86.dasc"
+#else
+ //| jmp ->vmeta_binop // Binop call for compatibility.
+ dasm_put(Dst, 1776);
+#line 1342 "vm_x86.dasc"
+#endif
+ //|
+ //|//-- Call metamethod ----------------------------------------------------
+ //|
+ //|->vmeta_call_ra:
+ //| lea RA, [BASE+RA*8+8]
+ //|->vmeta_call: // Resolve and call __call metamethod.
+ //| // BASE = old base, RA = new base, RC = nargs+1, PC = return
+ //| mov TMP2, RA // Save RA, RC for us.
+ //| mov TMP1, NARGS:RD
+ //| sub RA, 8
+ //|.if X64
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE // Caveat: CARG2d/CARG3d may be BASE.
+ //| mov CARG2d, RA
+ //| lea CARG3d, [RA+NARGS:RD*8]
+ //| mov CARG1d, L:RB // Caveat: CARG1d may be RA.
+ //|.else
+ //| lea RC, [RA+NARGS:RD*8]
+ //| mov L:RB, SAVE_L
+ //| mov ARG2, RA
+ //| mov ARG3, RC
+ //| mov ARG1, L:RB
+ //| mov L:RB->base, BASE // This is the callers base!
+ //|.endif
+ //| mov SAVE_PC, PC
+ //| call extern lj_meta_call // (lua_State *L, TValue *func, TValue *top)
+ //| mov BASE, L:RB->base
+ //| mov RA, TMP2
+ //| mov NARGS:RD, TMP1
+ //| mov LFUNC:RB, [RA-8]
+ //| add NARGS:RD, 1
+ //| // This is fragile. L->base must not move, KBASE must always be defined.
+ //| cmp KBASE, BASE // Continue with CALLT if flag set.
+ //| je ->BC_CALLT_Z
+ //| mov BASE, RA
+ //| ins_call // Otherwise call resolved metamethod.
+ //|
+ //|//-- Argument coercion for 'for' statement ------------------------------
+ //|
+ //|->vmeta_for:
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE
+ //| mov FCARG2, RA // Caveat: FCARG2 == BASE
+ //| mov L:FCARG1, L:RB // Caveat: FCARG1 == RA
+ //| mov SAVE_PC, PC
+ //| call extern lj_meta_for@8 // (lua_State *L, TValue *base)
+ //| mov BASE, L:RB->base
+ //| mov RC, [PC-4]
+ //| movzx RA, RCH
+ //| movzx OP, RCL
+ //| shr RC, 16
+ //|.if X64
+ //| jmp aword [DISPATCH+OP*8+GG_DISP2STATIC] // Retry FORI or JFORI.
+ //|.else
+ //| jmp aword [DISPATCH+OP*4+GG_DISP2STATIC] // Retry FORI or JFORI.
+ //|.endif
+ //|
+ //|//-----------------------------------------------------------------------
+ //|//-- Fast functions -----------------------------------------------------
+ //|//-----------------------------------------------------------------------
+ //|
+ //|.macro .ffunc, name
+ //|->ff_ .. name:
+ //|.endmacro
+ //|
+ //|.macro .ffunc_1, name
+ //|->ff_ .. name:
+ //| cmp NARGS:RD, 1+1; jb ->fff_fallback
+ //|.endmacro
+ //|
+ //|.macro .ffunc_2, name
+ //|->ff_ .. name:
+ //| cmp NARGS:RD, 2+1; jb ->fff_fallback
+ //|.endmacro
+ //|
+ //|.macro .ffunc_nsse, name, op
+ //| .ffunc_1 name
+ //| cmp dword [BASE+4], LJ_TISNUM; jae ->fff_fallback
+ //| op xmm0, qword [BASE]
+ //|.endmacro
+ //|
+ //|.macro .ffunc_nsse, name
+ //| .ffunc_nsse name, movsd
+ //|.endmacro
+ //|
+ //|.macro .ffunc_nnsse, name
+ //| .ffunc_2 name
+ //| cmp dword [BASE+4], LJ_TISNUM; jae ->fff_fallback
+ //| cmp dword [BASE+12], LJ_TISNUM; jae ->fff_fallback
+ //| movsd xmm0, qword [BASE]
+ //| movsd xmm1, qword [BASE+8]
+ //|.endmacro
+ //|
+ //|.macro .ffunc_nnr, name
+ //| .ffunc_2 name
+ //| cmp dword [BASE+4], LJ_TISNUM; jae ->fff_fallback
+ //| cmp dword [BASE+12], LJ_TISNUM; jae ->fff_fallback
+ //| fld qword [BASE+8]
+ //| fld qword [BASE]
+ //|.endmacro
+ //|
+ //|// Inlined GC threshold check. Caveat: uses label 1.
+ //|.macro ffgccheck
+ //| mov RB, [DISPATCH+DISPATCH_GL(gc.total)]
+ //| cmp RB, [DISPATCH+DISPATCH_GL(gc.threshold)]
+ //| jb >1
+ //| call ->fff_gcstep
+ //|1:
+ //|.endmacro
+ //|
+ //|//-- Base library: checks -----------------------------------------------
+ //|
+ //|.ffunc_1 assert
+ //| mov RB, [BASE+4]
+ //| cmp RB, LJ_TISTRUECOND; jae ->fff_fallback
+ //| mov PC, [BASE-4]
+ //| mov MULTRES, RD
+ //| mov [BASE-4], RB
+ //| mov RB, [BASE]
+ //| mov [BASE-8], RB
+ //| sub RD, 2
+ //| jz >2
+ //| mov RA, BASE
+ dasm_put(Dst, 1781, Dt1(->base), Dt1(->base), Dt7(->pc), Dt1(->base), Dt1(->base), GG_DISP2STATIC, 1+1, LJ_TISTRUECOND);
+#line 1466 "vm_x86.dasc"
+ //|1:
+ //| add RA, 8
+ //|.if X64
+ //| mov RBa, [RA]
+ //| mov [RA-8], RBa
+ //|.else
+ //| mov RB, [RA+4]
+ //| mov [RA-4], RB
+ //| mov RB, [RA]
+ //| mov [RA-8], RB
+ //|.endif
+ //| sub RD, 1
+ //| jnz <1
+ //|2:
+ //| mov RD, MULTRES
+ //| jmp ->fff_res_
+ //|
+ //|.ffunc_1 type
+ //| mov RB, [BASE+4]
+ //|.if X64
+ //| mov RA, RB
+ //| sar RA, 15
+ //| cmp RA, -2
+ //| je >3
+ //|.endif
+ //| mov RC, ~LJ_TNUMX
+ //| not RB
+ //| cmp RC, RB
+ //| cmova RC, RB
+ //|2:
+ //| mov CFUNC:RB, [BASE-8]
+ //| mov STR:RC, [CFUNC:RB+RC*8+((char *)(&((GCfuncC *)0)->upvalue))]
+ //| mov PC, [BASE-4]
+ //| mov dword [BASE-4], LJ_TSTR
+ //| mov [BASE-8], STR:RC
+ //| jmp ->fff_res1
+ //|.if X64
+ //|3:
+ //| mov RC, ~LJ_TLIGHTUD
+ dasm_put(Dst, 1967, 1+1, ~LJ_TNUMX, ((char *)(&((GCfuncC *)0)->upvalue)), LJ_TSTR);
+#line 1505 "vm_x86.dasc"
+ //| jmp <2
+ //|.endif
+ //|
+ //|//-- Base library: getters and setters ---------------------------------
+ //|
+ //|.ffunc_1 getmetatable
+ //| mov RB, [BASE+4]
+ //| mov PC, [BASE-4]
+ //| cmp RB, LJ_TTAB; jne >6
+ //|1: // Field metatable must be at same offset for GCtab and GCudata!
+ //| mov TAB:RB, [BASE]
+ //| mov TAB:RB, TAB:RB->metatable
+ //|2:
+ //| test TAB:RB, TAB:RB
+ //| mov dword [BASE-4], LJ_TNIL
+ //| jz ->fff_res1
+ //| mov STR:RC, [DISPATCH+DISPATCH_GL(gcroot)+4*(GCROOT_MMNAME+MM_metatable)]
+ //| mov dword [BASE-4], LJ_TTAB // Store metatable as default result.
+ //| mov [BASE-8], TAB:RB
+ //| mov RA, TAB:RB->hmask
+ //| and RA, STR:RC->hash
+ dasm_put(Dst, 2069, ~LJ_TLIGHTUD, 1+1, LJ_TTAB, Dt6(->metatable), LJ_TNIL, DISPATCH_GL(gcroot)+4*(GCROOT_MMNAME+MM_metatable), LJ_TTAB, Dt6(->hmask));
+#line 1526 "vm_x86.dasc"
+ //| imul RA, #NODE
+ //| add NODE:RA, TAB:RB->node
+ //|3: // Rearranged logic, because we expect _not_ to find the key.
+ //| cmp dword NODE:RA->key.it, LJ_TSTR
+ //| jne >4
+ //| cmp dword NODE:RA->key.gcr, STR:RC
+ //| je >5
+ //|4:
+ //| mov NODE:RA, NODE:RA->next
+ //| test NODE:RA, NODE:RA
+ //| jnz <3
+ //| jmp ->fff_res1 // Not found, keep default result.
+ //|5:
+ //| mov RB, [RA+4]
+ //| cmp RB, LJ_TNIL; je ->fff_res1 // Ditto for nil value.
+ dasm_put(Dst, 2138, Dt5(->hash), sizeof(Node), Dt6(->node), DtB(->key.it), LJ_TSTR, DtB(->key.gcr), DtB(->next), LJ_TNIL);
+#line 1541 "vm_x86.dasc"
+ //| mov RC, [RA]
+ //| mov [BASE-4], RB // Return value of mt.__metatable.
+ //| mov [BASE-8], RC
+ //| jmp ->fff_res1
+ //|
+ //|6:
+ //| cmp RB, LJ_TUDATA; je <1
+ //|.if X64
+ //| cmp RB, LJ_TNUMX; ja >8
+ //| cmp RB, LJ_TISNUM; jbe >7
+ //| mov RB, LJ_TLIGHTUD
+ //| jmp >8
+ //|7:
+ //|.else
+ //| cmp RB, LJ_TISNUM; ja >8
+ //|.endif
+ //| mov RB, LJ_TNUMX
+ //|8:
+ //| not RB
+ dasm_put(Dst, 2189, LJ_TUDATA, LJ_TNUMX, LJ_TISNUM, LJ_TLIGHTUD, LJ_TNUMX);
+#line 1560 "vm_x86.dasc"
+ //| mov TAB:RB, [DISPATCH+RB*4+DISPATCH_GL(gcroot[GCROOT_BASEMT])]
+ //| jmp <2
+ //|
+ //|.ffunc_2 setmetatable
+ //| cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback
+ //| // Fast path: no mt for table yet and not clearing the mt.
+ //| mov TAB:RB, [BASE]
+ //| cmp dword TAB:RB->metatable, 0; jne ->fff_fallback
+ //| cmp dword [BASE+12], LJ_TTAB; jne ->fff_fallback
+ //| mov TAB:RC, [BASE+8]
+ //| mov TAB:RB->metatable, TAB:RC
+ //| mov PC, [BASE-4]
+ //| mov dword [BASE-4], LJ_TTAB // Return original table.
+ //| mov [BASE-8], TAB:RB
+ //| test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table)
+ //| jz >1
+ dasm_put(Dst, 2246, DISPATCH_GL(gcroot[GCROOT_BASEMT]), 2+1, LJ_TTAB, Dt6(->metatable), LJ_TTAB, Dt6(->metatable), LJ_TTAB, Dt6(->marked), LJ_GC_BLACK);
+#line 1576 "vm_x86.dasc"
+ //| // Possible write barrier. Table is black, but skip iswhite(mt) check.
+ //| barrierback TAB:RB, RC
+ //|1:
+ //| jmp ->fff_res1
+ //|
+ //|.ffunc_2 rawget
+ //| cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback
+ //|.if X64WIN
+ //| mov RB, BASE // Save BASE.
+ //| lea CARG3d, [BASE+8]
+ //| mov CARG2d, [BASE] // Caveat: CARG2d == BASE.
+ //| mov CARG1d, SAVE_L
+ //|.elif X64
+ //| mov RB, BASE // Save BASE.
+ //| mov CARG2d, [BASE]
+ //| lea CARG3d, [BASE+8] // Caveat: CARG3d == BASE.
+ //| mov CARG1d, SAVE_L
+ //|.else
+ //| mov TAB:RD, [BASE]
+ //| mov L:RB, SAVE_L
+ //| mov ARG2, TAB:RD
+ //| mov ARG1, L:RB
+ //| mov RB, BASE // Save BASE.
+ //| add BASE, 8
+ //| mov ARG3, BASE
+ //|.endif
+ //| call extern lj_tab_get // (lua_State *L, GCtab *t, cTValue *key)
+ //| // cTValue * returned in eax (RD).
+ //| mov BASE, RB // Restore BASE.
+ //| // Copy table slot.
+ //|.if X64
+ //| mov RBa, [RD]
+ //| mov PC, [BASE-4]
+ //| mov [BASE-8], RBa
+ //|.else
+ //| mov RB, [RD]
+ //| mov RD, [RD+4]
+ //| mov PC, [BASE-4]
+ //| mov [BASE-8], RB
+ //| mov [BASE-4], RD
+ //|.endif
+ //| jmp ->fff_res1
+ //|
+ //|//-- Base library: conversions ------------------------------------------
+ //|
+ //|.ffunc tonumber
+ //| // Only handles the number case inline (without a base argument).
+ //| cmp NARGS:RD, 1+1; jne ->fff_fallback // Exactly one argument.
+ dasm_put(Dst, 2322, Dt6(->marked), (uint8_t)~LJ_GC_BLACK, DISPATCH_GL(gc.grayagain), DISPATCH_GL(gc.grayagain), Dt6(->gclist), 2+1, LJ_TTAB);
+#line 1624 "vm_x86.dasc"
+ //| cmp dword [BASE+4], LJ_TISNUM
+ //|.if DUALNUM
+ //| jne >1
+ //| mov RB, dword [BASE]; jmp ->fff_resi
+ //|1:
+ //| ja ->fff_fallback
+ //|.else
+ //| jae ->fff_fallback
+ //|.endif
+ //| movsd xmm0, qword [BASE]; jmp ->fff_resxmm0
+ //|
+ //|.ffunc_1 tostring
+ //| // Only handles the string or number case inline.
+ //| mov PC, [BASE-4]
+ //| cmp dword [BASE+4], LJ_TSTR; jne >3
+ //| // A __tostring method in the string base metatable is ignored.
+ //| mov STR:RD, [BASE]
+ //|2:
+ //| mov dword [BASE-4], LJ_TSTR
+ //| mov [BASE-8], STR:RD
+ //| jmp ->fff_res1
+ //|3: // Handle numbers inline, unless a number base metatable is present.
+ //| cmp dword [BASE+4], LJ_TISNUM; ja ->fff_fallback
+ dasm_put(Dst, 2403, 1+1, LJ_TISNUM, 1+1, LJ_TSTR, LJ_TSTR);
+#line 1647 "vm_x86.dasc"
+ //| cmp dword [DISPATCH+DISPATCH_GL(gcroot[GCROOT_BASEMT_NUM])], 0
+ //| jne ->fff_fallback
+ //| ffgccheck // Caveat: uses label 1.
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE // Add frame since C call can throw.
+ //| mov SAVE_PC, PC // Redundant (but a defined value).
+ //|.if X64 and not X64WIN
+ //| mov FCARG2, BASE // Otherwise: FCARG2 == BASE
+ //|.endif
+ //| mov L:FCARG1, L:RB
+ //|.if DUALNUM
+ //| call extern lj_strfmt_number@8 // (lua_State *L, cTValue *o)
+ //|.else
+ //| call extern lj_strfmt_num@8 // (lua_State *L, lua_Number *np)
+ //|.endif
+ //| // GCstr returned in eax (RD).
+ //| mov BASE, L:RB->base
+ //| jmp <2
+ //|
+ //|//-- Base library: iterators -------------------------------------------
+ //|
+ //|.ffunc_1 next
+ dasm_put(Dst, 2472, LJ_TISNUM, DISPATCH_GL(gcroot[GCROOT_BASEMT_NUM]), DISPATCH_GL(gc.total), DISPATCH_GL(gc.threshold), Dt1(->base), Dt1(->base), 1+1);
+#line 1669 "vm_x86.dasc"
+ //| je >2 // Missing 2nd arg?
+ //|1:
+ //| cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE // Add frame since C call can throw.
+ //| mov L:RB->top, BASE // Dummy frame length is ok.
+ //| mov PC, [BASE-4]
+ //|.if X64WIN
+ //| lea CARG3d, [BASE+8]
+ //| mov CARG2d, [BASE] // Caveat: CARG2d == BASE.
+ //| mov CARG1d, L:RB
+ //|.elif X64
+ //| mov CARG2d, [BASE]
+ //| lea CARG3d, [BASE+8] // Caveat: CARG3d == BASE.
+ //| mov CARG1d, L:RB
+ //|.else
+ //| mov TAB:RD, [BASE]
+ //| mov ARG2, TAB:RD
+ //| mov ARG1, L:RB
+ //| add BASE, 8
+ //| mov ARG3, BASE
+ //|.endif
+ //| mov SAVE_PC, PC // Needed for ITERN fallback.
+ //| call extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
+ //| // Flag returned in eax (RD).
+ //| mov BASE, L:RB->base
+ //| test RD, RD; jz >3 // End of traversal?
+ //| // Copy key and value to results.
+ //|.if X64
+ //| mov RBa, [BASE+8]
+ //| mov RDa, [BASE+16]
+ //| mov [BASE-8], RBa
+ //| mov [BASE], RDa
+ //|.else
+ //| mov RB, [BASE+8]
+ //| mov RD, [BASE+12]
+ //| mov [BASE-8], RB
+ //| mov [BASE-4], RD
+ //| mov RB, [BASE+16]
+ //| mov RD, [BASE+20]
+ //| mov [BASE], RB
+ //| mov [BASE+4], RD
+ //|.endif
+ //|->fff_res2:
+ //| mov RD, 1+2
+ //| jmp ->fff_res
+ //|2: // Set missing 2nd arg to nil.
+ //| mov dword [BASE+12], LJ_TNIL
+ //| jmp <1
+ dasm_put(Dst, 2541, LJ_TTAB, Dt1(->base), Dt1(->top), Dt1(->base), 1+2, LJ_TNIL);
+#line 1718 "vm_x86.dasc"
+ //|3: // End of traversal: return nil.
+ //| mov dword [BASE-4], LJ_TNIL
+ //| jmp ->fff_res1
+ //|
+ //|.ffunc_1 pairs
+ //| mov TAB:RB, [BASE]
+ //| cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback
+ dasm_put(Dst, 2630, LJ_TNIL, 1+1, LJ_TTAB);
+#line 1725 "vm_x86.dasc"
+#if LJ_52
+ //| cmp dword TAB:RB->metatable, 0; jne ->fff_fallback
+ dasm_put(Dst, 2667, Dt6(->metatable));
+#line 1727 "vm_x86.dasc"
+#endif
+ //| mov CFUNC:RB, [BASE-8]
+ //| mov CFUNC:RD, CFUNC:RB->upvalue[0]
+ //| mov PC, [BASE-4]
+ //| mov dword [BASE-4], LJ_TFUNC
+ //| mov [BASE-8], CFUNC:RD
+ //| mov dword [BASE+12], LJ_TNIL
+ //| mov RD, 1+3
+ //| jmp ->fff_res
+ //|
+ //|.ffunc_2 ipairs_aux
+ //| cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback
+ //| cmp dword [BASE+12], LJ_TISNUM
+ //|.if DUALNUM
+ //| jne ->fff_fallback
+ //|.else
+ //| jae ->fff_fallback
+ //|.endif
+ //| mov PC, [BASE-4]
+ //|.if DUALNUM
+ //| mov RD, dword [BASE+8]
+ //| add RD, 1
+ //| mov dword [BASE-4], LJ_TISNUM
+ //| mov dword [BASE-8], RD
+ //|.else
+ //| movsd xmm0, qword [BASE+8]
+ //| sseconst_1 xmm1, RBa
+ //| addsd xmm0, xmm1
+ //| cvttsd2si RD, xmm0
+ //| movsd qword [BASE-8], xmm0
+ //|.endif
+ //| mov TAB:RB, [BASE]
+ //| cmp RD, TAB:RB->asize; jae >2 // Not in array part?
+ dasm_put(Dst, 2676, Dt8(->upvalue[0]), LJ_TFUNC, LJ_TNIL, 1+3, 2+1, LJ_TTAB, LJ_TISNUM, (unsigned int)(U64x(3ff00000,00000000)), (unsigned int)((U64x(3ff00000,00000000))>>32), Dt6(->asize));
+#line 1760 "vm_x86.dasc"
+ //| shl RD, 3
+ //| add RD, TAB:RB->array
+ //|1:
+ //| cmp dword [RD+4], LJ_TNIL; je ->fff_res0
+ //| // Copy array slot.
+ //|.if X64
+ //| mov RBa, [RD]
+ //| mov [BASE], RBa
+ //|.else
+ //| mov RB, [RD]
+ //| mov RD, [RD+4]
+ //| mov [BASE], RB
+ //| mov [BASE+4], RD
+ //|.endif
+ //| jmp ->fff_res2
+ //|2: // Check for empty hash part first. Otherwise call C function.
+ //| cmp dword TAB:RB->hmask, 0; je ->fff_res0
+ //| mov FCARG1, TAB:RB
+ //| mov RB, BASE // Save BASE.
+ //| mov FCARG2, RD // Caveat: FCARG2 == BASE
+ //| call extern lj_tab_getinth@8 // (GCtab *t, int32_t key)
+ //| // cTValue * or NULL returned in eax (RD).
+ //| mov BASE, RB
+ //| test RD, RD
+ //| jnz <1
+ //|->fff_res0:
+ //| mov RD, 1+0
+ //| jmp ->fff_res
+ //|
+ //|.ffunc_1 ipairs
+ dasm_put(Dst, 2776, Dt6(->array), LJ_TNIL, Dt6(->hmask), 1+0);
+#line 1790 "vm_x86.dasc"
+ //| mov TAB:RB, [BASE]
+ //| cmp dword [BASE+4], LJ_TTAB; jne ->fff_fallback
+ dasm_put(Dst, 2647, 1+1, LJ_TTAB);
+#line 1792 "vm_x86.dasc"
+#if LJ_52
+ //| cmp dword TAB:RB->metatable, 0; jne ->fff_fallback
+ dasm_put(Dst, 2667, Dt6(->metatable));
+#line 1794 "vm_x86.dasc"
+#endif
+ //| mov CFUNC:RB, [BASE-8]
+ //| mov CFUNC:RD, CFUNC:RB->upvalue[0]
+ //| mov PC, [BASE-4]
+ //| mov dword [BASE-4], LJ_TFUNC
+ //| mov [BASE-8], CFUNC:RD
+ //|.if DUALNUM
+ //| mov dword [BASE+12], LJ_TISNUM
+ //| mov dword [BASE+8], 0
+ //|.else
+ //| xorps xmm0, xmm0
+ //| movsd qword [BASE+8], xmm0
+ //|.endif
+ //| mov RD, 1+3
+ //| jmp ->fff_res
+ //|
+ //|//-- Base library: catch errors ----------------------------------------
+ //|
+ //|.ffunc_1 pcall
+ //| lea RA, [BASE+8]
+ //| sub NARGS:RD, 1
+ //| mov PC, 8+FRAME_PCALL
+ //|1:
+ //| movzx RB, byte [DISPATCH+DISPATCH_GL(hookmask)]
+ //| shr RB, HOOK_ACTIVE_SHIFT
+ //| and RB, 1
+ //| add PC, RB // Remember active hook before pcall.
+ //| jmp ->vm_call_dispatch
+ //|
+ //|.ffunc_2 xpcall
+ //| cmp dword [BASE+12], LJ_TFUNC; jne ->fff_fallback
+ dasm_put(Dst, 2848, Dt8(->upvalue[0]), LJ_TFUNC, 1+3, 1+1, 8+FRAME_PCALL, DISPATCH_GL(hookmask), HOOK_ACTIVE_SHIFT, 2+1);
+#line 1825 "vm_x86.dasc"
+ //| mov RB, [BASE+4] // Swap function and traceback.
+ //| mov [BASE+12], RB
+ //| mov dword [BASE+4], LJ_TFUNC
+ //| mov LFUNC:RB, [BASE]
+ //| mov PC, [BASE+8]
+ //| mov [BASE+8], LFUNC:RB
+ //| mov [BASE], PC
+ //| lea RA, [BASE+16]
+ //| sub NARGS:RD, 2
+ //| mov PC, 16+FRAME_PCALL
+ //| jmp <1
+ //|
+ //|//-- Coroutine library --------------------------------------------------
+ //|
+ //|.macro coroutine_resume_wrap, resume
+ //|.if resume
+ //|.ffunc_1 coroutine_resume
+ //| mov L:RB, [BASE]
+ //|.else
+ //|.ffunc coroutine_wrap_aux
+ //| mov CFUNC:RB, [BASE-8]
+ //| mov L:RB, CFUNC:RB->upvalue[0].gcr
+ //|.endif
+ //| mov PC, [BASE-4]
+ //| mov SAVE_PC, PC
+ //|.if X64
+ //| mov TMP1, L:RB
+ //|.else
+ //| mov ARG1, L:RB
+ //|.endif
+ //|.if resume
+ //| cmp dword [BASE+4], LJ_TTHREAD; jne ->fff_fallback
+ //|.endif
+ //| cmp aword L:RB->cframe, 0; jne ->fff_fallback
+ //| cmp byte L:RB->status, LUA_YIELD; ja ->fff_fallback
+ //| mov RA, L:RB->top
+ //| je >1 // Status != LUA_YIELD (i.e. 0)?
+ //| cmp RA, L:RB->base // Check for presence of initial func.
+ //| je ->fff_fallback
+ //|1:
+ //|.if resume
+ //| lea PC, [RA+NARGS:RD*8-16] // Check stack space (-1-thread).
+ //|.else
+ //| lea PC, [RA+NARGS:RD*8-8] // Check stack space (-1).
+ //|.endif
+ //| cmp PC, L:RB->maxstack; ja ->fff_fallback
+ //| mov L:RB->top, PC
+ //|
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE
+ //|.if resume
+ //| add BASE, 8 // Keep resumed thread in stack for GC.
+ //|.endif
+ //| mov L:RB->top, BASE
+ //|.if resume
+ //| lea RB, [BASE+NARGS:RD*8-24] // RB = end of source for stack move.
+ //|.else
+ //| lea RB, [BASE+NARGS:RD*8-16] // RB = end of source for stack move.
+ //|.endif
+ //| sub RBa, PCa // Relative to PC.
+ //|
+ //| cmp PC, RA
+ //| je >3
+ //|2: // Move args to coroutine.
+ //|.if X64
+ //| mov RCa, [PC+RB]
+ //| mov [PC-8], RCa
+ //|.else
+ //| mov RC, [PC+RB+4]
+ //| mov [PC-4], RC
+ //| mov RC, [PC+RB]
+ //| mov [PC-8], RC
+ //|.endif
+ //| sub PC, 8
+ //| cmp PC, RA
+ //| jne <2
+ //|3:
+ //|.if X64
+ //| mov CARG2d, RA
+ //| mov CARG1d, TMP1
+ //|.else
+ //| mov ARG2, RA
+ //| xor RA, RA
+ //| mov ARG4, RA
+ //| mov ARG3, RA
+ //|.endif
+ //| call ->vm_resume // (lua_State *L, TValue *base, 0, 0)
+ //|
+ //| mov L:RB, SAVE_L
+ //|.if X64
+ //| mov L:PC, TMP1
+ //|.else
+ //| mov L:PC, ARG1 // The callee doesn't modify SAVE_L.
+ //|.endif
+ //| mov BASE, L:RB->base
+ //| mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB
+ //| set_vmstate INTERP
+ //|
+ //| cmp eax, LUA_YIELD
+ //| ja >8
+ //|4:
+ //| mov RA, L:PC->base
+ //| mov KBASE, L:PC->top
+ //| mov L:PC->top, RA // Clear coroutine stack.
+ //| mov PC, KBASE
+ //| sub PC, RA
+ //| je >6 // No results?
+ //| lea RD, [BASE+PC]
+ //| shr PC, 3
+ //| cmp RD, L:RB->maxstack
+ //| ja >9 // Need to grow stack?
+ //|
+ //| mov RB, BASE
+ //| sub RBa, RAa
+ //|5: // Move results from coroutine.
+ //|.if X64
+ //| mov RDa, [RA]
+ //| mov [RA+RB], RDa
+ //|.else
+ //| mov RD, [RA]
+ //| mov [RA+RB], RD
+ //| mov RD, [RA+4]
+ //| mov [RA+RB+4], RD
+ //|.endif
+ //| add RA, 8
+ //| cmp RA, KBASE
+ //| jne <5
+ //|6:
+ //|.if resume
+ //| lea RD, [PC+2] // nresults+1 = 1 + true + results.
+ //| mov dword [BASE-4], LJ_TTRUE // Prepend true to results.
+ //|.else
+ //| lea RD, [PC+1] // nresults+1 = 1 + results.
+ //|.endif
+ //|7:
+ //| mov PC, SAVE_PC
+ //| mov MULTRES, RD
+ //|.if resume
+ //| mov RAa, -8
+ //|.else
+ //| xor RA, RA
+ //|.endif
+ //| test PC, FRAME_TYPE
+ //| jz ->BC_RET_Z
+ //| jmp ->vm_return
+ //|
+ //|8: // Coroutine returned with error (at co->top-1).
+ //|.if resume
+ //| mov dword [BASE-4], LJ_TFALSE // Prepend false to results.
+ //| mov RA, L:PC->top
+ //| sub RA, 8
+ //| mov L:PC->top, RA // Clear error from coroutine stack.
+ //| // Copy error message.
+ //|.if X64
+ //| mov RDa, [RA]
+ //| mov [BASE], RDa
+ //|.else
+ //| mov RD, [RA]
+ //| mov [BASE], RD
+ //| mov RD, [RA+4]
+ //| mov [BASE+4], RD
+ //|.endif
+ //| mov RD, 1+2 // nresults+1 = 1 + false + error.
+ //| jmp <7
+ //|.else
+ //| mov FCARG2, L:PC
+ //| mov FCARG1, L:RB
+ //| call extern lj_ffh_coroutine_wrap_err@8 // (lua_State *L, lua_State *co)
+ //| // Error function does not return.
+ //|.endif
+ //|
+ //|9: // Handle stack expansion on return from yield.
+ //|.if X64
+ //| mov L:RA, TMP1
+ //|.else
+ //| mov L:RA, ARG1 // The callee doesn't modify SAVE_L.
+ //|.endif
+ //| mov L:RA->top, KBASE // Undo coroutine stack clearing.
+ //| mov FCARG2, PC
+ //| mov FCARG1, L:RB
+ //| call extern lj_state_growstack@8 // (lua_State *L, int n)
+ //|.if X64
+ //| mov L:PC, TMP1
+ //|.else
+ //| mov L:PC, ARG1
+ //|.endif
+ //| mov BASE, L:RB->base
+ //| jmp <4 // Retry the stack move.
+ //|.endmacro
+ //|
+ //| coroutine_resume_wrap 1 // coroutine.resume
+ dasm_put(Dst, 2933, LJ_TFUNC, LJ_TFUNC, 16+FRAME_PCALL, 1+1, LJ_TTHREAD, Dt1(->cframe), Dt1(->status), LUA_YIELD);
+ dasm_put(Dst, 3020, Dt1(->top), Dt1(->base), Dt1(->maxstack), Dt1(->top), Dt1(->base), Dt1(->top));
+ dasm_put(Dst, 3105, Dt1(->base), DISPATCH_GL(cur_L), DISPATCH_GL(vmstate), ~LJ_VMST_INTERP, LUA_YIELD, Dt1(->base), Dt1(->top), Dt1(->top), Dt1(->maxstack));
+ dasm_put(Dst, 3184, LJ_TTRUE, FRAME_TYPE, LJ_TFALSE, Dt1(->top), Dt1(->top), 1+2, Dt1(->top));
+#line 2016 "vm_x86.dasc"
+ //| coroutine_resume_wrap 0 // coroutine.wrap
+ dasm_put(Dst, 3284, Dt1(->base), Dt8(->upvalue[0].gcr), Dt1(->cframe), Dt1(->status), LUA_YIELD, Dt1(->top), Dt1(->base));
+ dasm_put(Dst, 3357, Dt1(->maxstack), Dt1(->top), Dt1(->base), Dt1(->top), Dt1(->base), DISPATCH_GL(cur_L), DISPATCH_GL(vmstate), ~LJ_VMST_INTERP, LUA_YIELD);
+ dasm_put(Dst, 3451, Dt1(->base), Dt1(->top), Dt1(->top), Dt1(->maxstack), FRAME_TYPE);
+#line 2017 "vm_x86.dasc"
+ //|
+ //|.ffunc coroutine_yield
+ //| mov L:RB, SAVE_L
+ //| test aword L:RB->cframe, CFRAME_RESUME
+ //| jz ->fff_fallback
+ //| mov L:RB->base, BASE
+ //| lea RD, [BASE+NARGS:RD*8-8]
+ //| mov L:RB->top, RD
+ //| xor RD, RD
+ //| mov aword L:RB->cframe, RDa
+ //| mov al, LUA_YIELD
+ //| mov byte L:RB->status, al
+ //| jmp ->vm_leave_unw
+ //|
+ //|//-- Math library -------------------------------------------------------
+ //|
+ //|.if not DUALNUM
+ //|->fff_resi: // Dummy.
+ //|.endif
+ //|
+ //|->fff_resn:
+ //| mov PC, [BASE-4]
+ dasm_put(Dst, 3542, Dt1(->top), Dt1(->base), Dt1(->cframe), CFRAME_RESUME, Dt1(->base), Dt1(->top), Dt1(->cframe), LUA_YIELD, Dt1(->status));
+#line 2039 "vm_x86.dasc"
+ //| fstp qword [BASE-8]
+ //| jmp ->fff_res1
+ //|
+ //| .ffunc_1 math_abs
+ //|.if DUALNUM
+ //| cmp dword [BASE+4], LJ_TISNUM; jne >2
+ //| mov RB, dword [BASE]
+ //| cmp RB, 0; jns ->fff_resi
+ //| neg RB; js >1
+ //|->fff_resbit:
+ //|->fff_resi:
+ //| mov PC, [BASE-4]
+ //| mov dword [BASE-4], LJ_TISNUM
+ //| mov dword [BASE-8], RB
+ //| jmp ->fff_res1
+ //|1:
+ //| mov PC, [BASE-4]
+ //| mov dword [BASE-4], 0x41e00000 // 2^31.
+ //| mov dword [BASE-8], 0
+ //| jmp ->fff_res1
+ //|2:
+ //| ja ->fff_fallback
+ //|.else
+ //| cmp dword [BASE+4], LJ_TISNUM; jae ->fff_fallback
+ //|.endif
+ //| movsd xmm0, qword [BASE]
+ //| sseconst_abs xmm1, RDa
+ //| andps xmm0, xmm1
+ //|->fff_resxmm0:
+ //| mov PC, [BASE-4]
+ //| movsd qword [BASE-8], xmm0
+ //| // fallthrough
+ //|
+ //|->fff_res1:
+ //| mov RD, 1+1
+ //|->fff_res:
+ //| mov MULTRES, RD
+ //|->fff_res_:
+ //| test PC, FRAME_TYPE
+ //| jnz >7
+ //|5:
+ //| cmp PC_RB, RDL // More results expected?
+ dasm_put(Dst, 3632, 1+1, LJ_TISNUM, (unsigned int)(U64x(7fffffff,ffffffff)), (unsigned int)((U64x(7fffffff,ffffffff))>>32), 1+1, FRAME_TYPE);
+#line 2081 "vm_x86.dasc"
+ //| ja >6
+ //| // Adjust BASE. KBASE is assumed to be set for the calling frame.
+ //| movzx RA, PC_RA
+ //| not RAa // Note: ~RA = -(RA+1)
+ //| lea BASE, [BASE+RA*8] // base = base - (RA+1)*8
+ //| ins_next
+ //|
+ //|6: // Fill up results with nil.
+ //| mov dword [BASE+RD*8-12], LJ_TNIL
+ //| add RD, 1
+ //| jmp <5
+ //|
+ //|7: // Non-standard return case.
+ //| mov RAa, -8 // Results start at BASE+RA = BASE-8.
+ //| jmp ->vm_return
+ //|
+ //|.if X64
+ //|.define fff_resfp, fff_resxmm0
+ //|.else
+ //|.define fff_resfp, fff_resn
+ //|.endif
+ //|
+ //|.macro math_round, func
+ //| .ffunc math_ .. func
+ //|.if DUALNUM
+ //| cmp dword [BASE+4], LJ_TISNUM; jne >1
+ //| mov RB, dword [BASE]; jmp ->fff_resi
+ //|1:
+ //| ja ->fff_fallback
+ //|.else
+ //| cmp dword [BASE+4], LJ_TISNUM; jae ->fff_fallback
+ //|.endif
+ //| movsd xmm0, qword [BASE]
+ //| call ->vm_ .. func .. _sse
+ //|.if DUALNUM
+ //| cvttsd2si RB, xmm0
+ //| cmp RB, 0x80000000
+ //| jne ->fff_resi
+ //| cvtsi2sd xmm1, RB
+ //| ucomisd xmm0, xmm1
+ //| jp ->fff_resxmm0
+ //| je ->fff_resi
+ //|.endif
+ //| jmp ->fff_resxmm0
+ //|.endmacro
+ //|
+ //| math_round floor
+ //| math_round ceil
+ dasm_put(Dst, 3716, LJ_TNIL, LJ_TISNUM, LJ_TISNUM);
+#line 2129 "vm_x86.dasc"
+ //|
+ //|.ffunc_nsse math_sqrt, sqrtsd; jmp ->fff_resxmm0
+ //|
+ //|.ffunc math_log
+ //| cmp NARGS:RD, 1+1; jne ->fff_fallback // Exactly one argument.
+ //| cmp dword [BASE+4], LJ_TISNUM; jae ->fff_fallback
+ dasm_put(Dst, 3819, 1+1, LJ_TISNUM, 1+1);
+#line 2135 "vm_x86.dasc"
+ //| movsd xmm0, qword [BASE]
+ //|.if not X64
+ //| movsd FPARG1, xmm0
+ //|.endif
+ //| mov RB, BASE
+ //| call extern log
+ //| mov BASE, RB
+ //| jmp ->fff_resfp
+ //|
+ //|.macro math_extern, func
+ //| .ffunc_nsse math_ .. func
+ //|.if not X64
+ //| movsd FPARG1, xmm0
+ //|.endif
+ //| mov RB, BASE
+ //| call extern func
+ //| mov BASE, RB
+ //| jmp ->fff_resfp
+ //|.endmacro
+ //|
+ //|.macro math_extern2, func
+ //| .ffunc_nnsse math_ .. func
+ //|.if not X64
+ //| movsd FPARG1, xmm0
+ //| movsd FPARG3, xmm1
+ //|.endif
+ //| mov RB, BASE
+ //| call extern func
+ //| mov BASE, RB
+ //| jmp ->fff_resfp
+ //|.endmacro
+ //|
+ //| math_extern log10
+ //| math_extern exp
+ dasm_put(Dst, 3874, LJ_TISNUM, 1+1, LJ_TISNUM, 1+1, LJ_TISNUM);
+#line 2169 "vm_x86.dasc"
+ //| math_extern sin
+ //| math_extern cos
+ dasm_put(Dst, 3954, 1+1, LJ_TISNUM, 1+1, LJ_TISNUM);
+#line 2171 "vm_x86.dasc"
+ //| math_extern tan
+ //| math_extern asin
+ //| math_extern acos
+ dasm_put(Dst, 4033, 1+1, LJ_TISNUM, 1+1, LJ_TISNUM);
+#line 2174 "vm_x86.dasc"
+ //| math_extern atan
+ //| math_extern sinh
+ dasm_put(Dst, 4128, 1+1, LJ_TISNUM, 1+1, LJ_TISNUM, 1+1);
+#line 2176 "vm_x86.dasc"
+ //| math_extern cosh
+ //| math_extern tanh
+ dasm_put(Dst, 4207, LJ_TISNUM, 1+1, LJ_TISNUM, 1+1);
+#line 2178 "vm_x86.dasc"
+ //| math_extern2 pow
+ //| math_extern2 atan2
+ dasm_put(Dst, 4286, LJ_TISNUM, 2+1, LJ_TISNUM, LJ_TISNUM, 2+1);
+#line 2180 "vm_x86.dasc"
+ //| math_extern2 fmod
+ dasm_put(Dst, 4372, LJ_TISNUM, LJ_TISNUM, 2+1, LJ_TISNUM, LJ_TISNUM);
+#line 2181 "vm_x86.dasc"
+ //|
+ //|.ffunc_nnr math_ldexp; fscale; fpop1; jmp ->fff_resn
+ //|
+ //|.ffunc_1 math_frexp
+ //| mov RB, [BASE+4]
+ //| cmp RB, LJ_TISNUM; jae ->fff_fallback
+ dasm_put(Dst, 4447, 2+1, LJ_TISNUM, LJ_TISNUM, 1+1, LJ_TISNUM);
+#line 2187 "vm_x86.dasc"
+ //| mov PC, [BASE-4]
+ //| mov RC, [BASE]
+ //| mov [BASE-4], RB; mov [BASE-8], RC
+ //| shl RB, 1; cmp RB, 0xffe00000; jae >3
+ //| or RC, RB; jz >3
+ //| mov RC, 1022
+ //| cmp RB, 0x00200000; jb >4
+ //|1:
+ //| shr RB, 21; sub RB, RC // Extract and unbias exponent.
+ //| cvtsi2sd xmm0, RB
+ //| mov RB, [BASE-4]
+ //| and RB, 0x800fffff // Mask off exponent.
+ //| or RB, 0x3fe00000 // Put mantissa in range [0.5,1) or 0.
+ //| mov [BASE-4], RB
+ //|2:
+ //| movsd qword [BASE], xmm0
+ //| mov RD, 1+2
+ //| jmp ->fff_res
+ //|3: // Return +-0, +-Inf, NaN unmodified and an exponent of 0.
+ //| xorps xmm0, xmm0; jmp <2
+ //|4: // Handle denormals by multiplying with 2^54 and adjusting the bias.
+ //| movsd xmm0, qword [BASE]
+ //| sseconst_hi xmm1, RBa, 43500000 // 2^54.
+ dasm_put(Dst, 4531, 1+2, (unsigned int)(U64x(43500000,00000000)), (unsigned int)((U64x(43500000,00000000))>>32));
+#line 2210 "vm_x86.dasc"
+ //| mulsd xmm0, xmm1
+ //| movsd qword [BASE-8], xmm0
+ //| mov RB, [BASE-4]; mov RC, 1076; shl RB, 1; jmp <1
+ //|
+ //|.ffunc_nsse math_modf
+ //| mov RB, [BASE+4]
+ //| mov PC, [BASE-4]
+ //| shl RB, 1; cmp RB, 0xffe00000; je >4 // +-Inf?
+ //| movaps xmm4, xmm0
+ //| call ->vm_trunc_sse
+ //| subsd xmm4, xmm0
+ //|1:
+ //| movsd qword [BASE-8], xmm0
+ //| movsd qword [BASE], xmm4
+ //| mov RC, [BASE-4]; mov RB, [BASE+4]
+ //| xor RC, RB; js >3 // Need to adjust sign?
+ //|2:
+ //| mov RD, 1+2
+ //| jmp ->fff_res
+ //|3:
+ //| xor RB, 0x80000000; mov [BASE+4], RB // Flip sign of fraction.
+ dasm_put(Dst, 4655, 1+1, LJ_TISNUM, 1+2);
+#line 2231 "vm_x86.dasc"
+ //| jmp <2
+ //|4:
+ //| xorps xmm4, xmm4; jmp <1 // Return +-Inf and +-0.
+ //|
+ //|.macro math_minmax, name, cmovop, sseop
+ //| .ffunc name
+ //| mov RA, 2
+ //| cmp dword [BASE+4], LJ_TISNUM
+ //|.if DUALNUM
+ //| jne >4
+ //| mov RB, dword [BASE]
+ //|1: // Handle integers.
+ //| cmp RA, RD; jae ->fff_resi
+ //| cmp dword [BASE+RA*8-4], LJ_TISNUM; jne >3
+ //| cmp RB, dword [BASE+RA*8-8]
+ //| cmovop RB, dword [BASE+RA*8-8]
+ //| add RA, 1
+ //| jmp <1
+ //|3:
+ //| ja ->fff_fallback
+ //| // Convert intermediate result to number and continue below.
+ //| cvtsi2sd xmm0, RB
+ //| jmp >6
+ //|4:
+ //| ja ->fff_fallback
+ //|.else
+ //| jae ->fff_fallback
+ //|.endif
+ //|
+ //| movsd xmm0, qword [BASE]
+ //|5: // Handle numbers or integers.
+ //| cmp RA, RD; jae ->fff_resxmm0
+ //| cmp dword [BASE+RA*8-4], LJ_TISNUM
+ //|.if DUALNUM
+ //| jb >6
+ //| ja ->fff_fallback
+ //| cvtsi2sd xmm1, dword [BASE+RA*8-8]
+ //| jmp >7
+ //|.else
+ //| jae ->fff_fallback
+ //|.endif
+ //|6:
+ //| movsd xmm1, qword [BASE+RA*8-8]
+ //|7:
+ //| sseop xmm0, xmm1
+ //| add RA, 1
+ //| jmp <5
+ //|.endmacro
+ //|
+ //| math_minmax math_min, cmovg, minsd
+ //| math_minmax math_max, cmovl, maxsd
+ dasm_put(Dst, 4781, LJ_TISNUM, LJ_TISNUM);
+#line 2282 "vm_x86.dasc"
+ //|
+ //|//-- String library -----------------------------------------------------
+ //|
+ //|.ffunc string_byte // Only handle the 1-arg case here.
+ //| cmp NARGS:RD, 1+1; jne ->fff_fallback
+ //| cmp dword [BASE+4], LJ_TSTR; jne ->fff_fallback
+ //| mov STR:RB, [BASE]
+ dasm_put(Dst, 4871, LJ_TISNUM, LJ_TISNUM, 1+1, LJ_TSTR);
+#line 2289 "vm_x86.dasc"
+ //| mov PC, [BASE-4]
+ //| cmp dword STR:RB->len, 1
+ //| jb ->fff_res0 // Return no results for empty string.
+ //| movzx RB, byte STR:RB[1]
+ //|.if DUALNUM
+ //| jmp ->fff_resi
+ //|.else
+ //| cvtsi2sd xmm0, RB; jmp ->fff_resxmm0
+ //|.endif
+ //|
+ //|.ffunc string_char // Only handle the 1-arg case here.
+ //| ffgccheck
+ //| cmp NARGS:RD, 1+1; jne ->fff_fallback // *Exactly* 1 arg.
+ //| cmp dword [BASE+4], LJ_TISNUM
+ //|.if DUALNUM
+ //| jne ->fff_fallback
+ //| mov RB, dword [BASE]
+ //| cmp RB, 255; ja ->fff_fallback
+ //| mov TMP2, RB
+ //|.else
+ //| jae ->fff_fallback
+ //| cvttsd2si RB, qword [BASE]
+ dasm_put(Dst, 4953, Dt5(->len), Dt5([1]), DISPATCH_GL(gc.total), DISPATCH_GL(gc.threshold), 1+1, LJ_TISNUM);
+#line 2311 "vm_x86.dasc"
+ //| cmp RB, 255; ja ->fff_fallback
+ //| mov TMP2, RB
+ //|.endif
+ //|.if X64
+ //| mov TMP3, 1
+ //|.else
+ //| mov ARG3, 1
+ //|.endif
+ //| lea RDa, TMP2 // Points to stack. Little-endian.
+ //|->fff_newstr:
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE
+ //|.if X64
+ //| mov CARG3d, TMP3 // Zero-extended to size_t.
+ //| mov CARG2, RDa // May be 64 bit ptr to stack.
+ //| mov CARG1d, L:RB
+ //|.else
+ //| mov ARG2, RD
+ //| mov ARG1, L:RB
+ //|.endif
+ //| mov SAVE_PC, PC
+ //| call extern lj_str_new // (lua_State *L, char *str, size_t l)
+ //|->fff_resstr:
+ //| // GCstr * returned in eax (RD).
+ //| mov BASE, L:RB->base
+ //| mov PC, [BASE-4]
+ //| mov dword [BASE-4], LJ_TSTR
+ //| mov [BASE-8], STR:RD
+ //| jmp ->fff_res1
+ //|
+ //|.ffunc string_sub
+ //| ffgccheck
+ //| mov TMP2, -1
+ //| cmp NARGS:RD, 1+2; jb ->fff_fallback
+ //| jna >1
+ dasm_put(Dst, 5017, Dt1(->base), Dt1(->base), LJ_TSTR, DISPATCH_GL(gc.total), DISPATCH_GL(gc.threshold), 1+2);
+#line 2346 "vm_x86.dasc"
+ //| cmp dword [BASE+20], LJ_TISNUM
+ //|.if DUALNUM
+ //| jne ->fff_fallback
+ //| mov RB, dword [BASE+16]
+ //| mov TMP2, RB
+ //|.else
+ //| jae ->fff_fallback
+ //| cvttsd2si RB, qword [BASE+16]
+ //| mov TMP2, RB
+ //|.endif
+ //|1:
+ //| cmp dword [BASE+4], LJ_TSTR; jne ->fff_fallback
+ //| cmp dword [BASE+12], LJ_TISNUM
+ //|.if DUALNUM
+ //| jne ->fff_fallback
+ //|.else
+ //| jae ->fff_fallback
+ //|.endif
+ //| mov STR:RB, [BASE]
+ //| mov TMP3, STR:RB
+ //| mov RB, STR:RB->len
+ //|.if DUALNUM
+ //| mov RA, dword [BASE+8]
+ //|.else
+ //| cvttsd2si RA, qword [BASE+8]
+ //|.endif
+ //| mov RC, TMP2
+ //| cmp RB, RC // len < end? (unsigned compare)
+ //| jb >5
+ //|2:
+ //| test RA, RA // start <= 0?
+ //| jle >7
+ //|3:
+ //| mov STR:RB, TMP3
+ dasm_put(Dst, 5140, LJ_TISNUM, LJ_TSTR, LJ_TISNUM, Dt5(->len));
+#line 2380 "vm_x86.dasc"
+ //| sub RC, RA // start > end?
+ //| jl ->fff_emptystr
+ //| lea RB, [STR:RB+RA+#STR-1]
+ //| add RC, 1
+ //|4:
+ //|.if X64
+ //| mov TMP3, RC
+ //|.else
+ //| mov ARG3, RC
+ //|.endif
+ //| mov RD, RB
+ //| jmp ->fff_newstr
+ //|
+ //|5: // Negative end or overflow.
+ //| jl >6
+ //| lea RC, [RC+RB+1] // end = end+(len+1)
+ //| jmp <2
+ //|6: // Overflow.
+ //| mov RC, RB // end = len
+ //| jmp <2
+ //|
+ //|7: // Negative start or underflow.
+ //| je >8
+ //| add RA, RB // start = start+(len+1)
+ //| add RA, 1
+ //| jg <3 // start > 0?
+ //|8: // Underflow.
+ //| mov RA, 1 // start = 1
+ dasm_put(Dst, 5219, sizeof(GCstr)-1);
+#line 2408 "vm_x86.dasc"
+ //| jmp <3
+ //|
+ //|->fff_emptystr: // Range underflow.
+ //| xor RC, RC // Zero length. Any ptr in RB is ok.
+ //| jmp <4
+ //|
+ //|.macro ffstring_op, name
+ //| .ffunc_1 string_ .. name
+ //| ffgccheck
+ //| cmp dword [BASE+4], LJ_TSTR; jne ->fff_fallback
+ //| mov L:RB, SAVE_L
+ //| lea SBUF:FCARG1, [DISPATCH+DISPATCH_GL(tmpbuf)]
+ //| mov L:RB->base, BASE
+ //| mov STR:FCARG2, [BASE] // Caveat: FCARG2 == BASE
+ //| mov RC, SBUF:FCARG1->b
+ //| mov SBUF:FCARG1->L, L:RB
+ //| mov SBUF:FCARG1->p, RC
+ //| mov SAVE_PC, PC
+ //| call extern lj_buf_putstr_ .. name .. @8
+ //| mov FCARG1, eax
+ //| call extern lj_buf_tostr@4
+ //| jmp ->fff_resstr
+ //|.endmacro
+ //|
+ //|ffstring_op reverse
+ dasm_put(Dst, 5290, 1+1, DISPATCH_GL(gc.total), DISPATCH_GL(gc.threshold), LJ_TSTR);
+#line 2433 "vm_x86.dasc"
+ //|ffstring_op lower
+ dasm_put(Dst, 5344, DISPATCH_GL(tmpbuf), Dt1(->base), DtE(->b), DtE(->L), DtE(->p), 1+1, DISPATCH_GL(gc.total), DISPATCH_GL(gc.threshold), LJ_TSTR);
+#line 2434 "vm_x86.dasc"
+ //|ffstring_op upper
+ dasm_put(Dst, 5417, DISPATCH_GL(tmpbuf), Dt1(->base), DtE(->b), DtE(->L), DtE(->p), 1+1, DISPATCH_GL(gc.total), DISPATCH_GL(gc.threshold));
+#line 2435 "vm_x86.dasc"
+ //|
+ //|//-- Bit library --------------------------------------------------------
+ //|
+ //|.macro .ffunc_bit, name, kind, fdef
+ //| fdef name
+ //|.if kind == 2
+ //| sseconst_tobit xmm1, RBa
+ //|.endif
+ //| cmp dword [BASE+4], LJ_TISNUM
+ //|.if DUALNUM
+ //| jne >1
+ //| mov RB, dword [BASE]
+ //|.if kind > 0
+ //| jmp >2
+ //|.else
+ //| jmp ->fff_resbit
+ //|.endif
+ //|1:
+ //| ja ->fff_fallback
+ //|.else
+ //| jae ->fff_fallback
+ //|.endif
+ //| movsd xmm0, qword [BASE]
+ //|.if kind < 2
+ //| sseconst_tobit xmm1, RBa
+ //|.endif
+ //| addsd xmm0, xmm1
+ //| movd RB, xmm0
+ //|2:
+ //|.endmacro
+ //|
+ //|.macro .ffunc_bit, name, kind
+ //| .ffunc_bit name, kind, .ffunc_1
+ //|.endmacro
+ //|
+ //|.ffunc_bit bit_tobit, 0
+ dasm_put(Dst, 5489, LJ_TSTR, DISPATCH_GL(tmpbuf), Dt1(->base), DtE(->b), DtE(->L), DtE(->p), 1+1, LJ_TISNUM, (unsigned int)(U64x(43380000,00000000)), (unsigned int)((U64x(43380000,00000000))>>32));
+#line 2471 "vm_x86.dasc"
+ //| jmp ->fff_resbit
+ //|
+ //|.macro .ffunc_bit_op, name, ins
+ //| .ffunc_bit name, 2
+ //| mov TMP2, NARGS:RD // Save for fallback.
+ //| lea RD, [BASE+NARGS:RD*8-16]
+ //|1:
+ //| cmp RD, BASE
+ //| jbe ->fff_resbit
+ //| cmp dword [RD+4], LJ_TISNUM
+ //|.if DUALNUM
+ //| jne >2
+ //| ins RB, dword [RD]
+ //| sub RD, 8
+ //| jmp <1
+ //|2:
+ //| ja ->fff_fallback_bit_op
+ //|.else
+ //| jae ->fff_fallback_bit_op
+ //|.endif
+ //| movsd xmm0, qword [RD]
+ //| addsd xmm0, xmm1
+ //| movd RA, xmm0
+ //| ins RB, RA
+ //| sub RD, 8
+ //| jmp <1
+ //|.endmacro
+ //|
+ //|.ffunc_bit_op bit_band, and
+ dasm_put(Dst, 5567, 1+1, (unsigned int)(U64x(43380000,00000000)), (unsigned int)((U64x(43380000,00000000))>>32), LJ_TISNUM, LJ_TISNUM);
+#line 2500 "vm_x86.dasc"
+ //|.ffunc_bit_op bit_bor, or
+ //|.ffunc_bit_op bit_bxor, xor
+ dasm_put(Dst, 5658, 1+1, (unsigned int)(U64x(43380000,00000000)), (unsigned int)((U64x(43380000,00000000))>>32), LJ_TISNUM, LJ_TISNUM);
+#line 2502 "vm_x86.dasc"
+ //|
+ //|.ffunc_bit bit_bswap, 1
+ dasm_put(Dst, 5777, 1+1, (unsigned int)(U64x(43380000,00000000)), (unsigned int)((U64x(43380000,00000000))>>32), LJ_TISNUM, LJ_TISNUM, 1+1);
+#line 2504 "vm_x86.dasc"
+ //| bswap RB
+ //| jmp ->fff_resbit
+ //|
+ //|.ffunc_bit bit_bnot, 1
+ dasm_put(Dst, 5875, LJ_TISNUM, (unsigned int)(U64x(43380000,00000000)), (unsigned int)((U64x(43380000,00000000))>>32), 1+1, LJ_TISNUM, (unsigned int)(U64x(43380000,00000000)), (unsigned int)((U64x(43380000,00000000))>>32));
+#line 2508 "vm_x86.dasc"
+ //| not RB
+ //|.if DUALNUM
+ //| jmp ->fff_resbit
+ //|.else
+ //|->fff_resbit:
+ //| cvtsi2sd xmm0, RB
+ //| jmp ->fff_resxmm0
+ //|.endif
+ //|
+ //|->fff_fallback_bit_op:
+ //| mov NARGS:RD, TMP2 // Restore for fallback
+ //| jmp ->fff_fallback
+ //|
+ //|.macro .ffunc_bit_sh, name, ins
+ //|.if DUALNUM
+ //| .ffunc_bit name, 1, .ffunc_2
+ //| // Note: no inline conversion from number for 2nd argument!
+ //| cmp dword [BASE+12], LJ_TISNUM; jne ->fff_fallback
+ //| mov RA, dword [BASE+8]
+ //|.else
+ //| .ffunc_nnsse name
+ //| sseconst_tobit xmm2, RBa
+ //| addsd xmm0, xmm2
+ //| addsd xmm1, xmm2
+ //| movd RB, xmm0
+ //| movd RA, xmm1
+ //|.endif
+ //| ins RB, cl // Assumes RA is ecx.
+ //| jmp ->fff_resbit
+ //|.endmacro
+ //|
+ //|.ffunc_bit_sh bit_lshift, shl
+ dasm_put(Dst, 5948, 2+1, LJ_TISNUM, LJ_TISNUM, (unsigned int)(U64x(43380000,00000000)), (unsigned int)((U64x(43380000,00000000))>>32));
+#line 2540 "vm_x86.dasc"
+ //|.ffunc_bit_sh bit_rshift, shr
+ //|.ffunc_bit_sh bit_arshift, sar
+ dasm_put(Dst, 6032, 2+1, LJ_TISNUM, LJ_TISNUM, (unsigned int)(U64x(43380000,00000000)), (unsigned int)((U64x(43380000,00000000))>>32), 2+1);
+#line 2542 "vm_x86.dasc"
+ //|.ffunc_bit_sh bit_rol, rol
+ dasm_put(Dst, 6145, LJ_TISNUM, LJ_TISNUM, (unsigned int)(U64x(43380000,00000000)), (unsigned int)((U64x(43380000,00000000))>>32), 2+1, LJ_TISNUM, LJ_TISNUM);
+#line 2543 "vm_x86.dasc"
+ //|.ffunc_bit_sh bit_ror, ror
+ //|
+ //|//-----------------------------------------------------------------------
+ //|
+ //|->fff_fallback_2:
+ //| mov NARGS:RD, 1+2 // Other args are ignored, anyway.
+ dasm_put(Dst, 6237, (unsigned int)(U64x(43380000,00000000)), (unsigned int)((U64x(43380000,00000000))>>32), 2+1, LJ_TISNUM, LJ_TISNUM, (unsigned int)(U64x(43380000,00000000)), (unsigned int)((U64x(43380000,00000000))>>32));
+#line 2549 "vm_x86.dasc"
+ //| jmp ->fff_fallback
+ //|->fff_fallback_1:
+ //| mov NARGS:RD, 1+1 // Other args are ignored, anyway.
+ //|->fff_fallback: // Call fast function fallback handler.
+ //| // BASE = new base, RD = nargs+1
+ //| mov L:RB, SAVE_L
+ //| mov PC, [BASE-4] // Fallback may overwrite PC.
+ //| mov SAVE_PC, PC // Redundant (but a defined value).
+ //| mov L:RB->base, BASE
+ //| lea RD, [BASE+NARGS:RD*8-8]
+ //| lea RA, [RD+8*LUA_MINSTACK] // Ensure enough space for handler.
+ //| mov L:RB->top, RD
+ //| mov CFUNC:RD, [BASE-8]
+ //| cmp RA, L:RB->maxstack
+ //| ja >5 // Need to grow stack.
+ //|.if X64
+ //| mov CARG1d, L:RB
+ //|.else
+ //| mov ARG1, L:RB
+ //|.endif
+ //| call aword CFUNC:RD->f // (lua_State *L)
+ //| mov BASE, L:RB->base
+ //| // Either throws an error, or recovers and returns -1, 0 or nresults+1.
+ //| test RD, RD; jg ->fff_res // Returned nresults+1?
+ //|1:
+ //| mov RA, L:RB->top
+ //| sub RA, BASE
+ //| shr RA, 3
+ //| test RD, RD
+ //| lea NARGS:RD, [RA+1]
+ //| mov LFUNC:RB, [BASE-8]
+ //| jne ->vm_call_tail // Returned -1?
+ //| ins_callt // Returned 0: retry fast path.
+ dasm_put(Dst, 6356, 1+2, 1+1, Dt1(->base), 8*LUA_MINSTACK, Dt1(->top), Dt1(->maxstack), Dt8(->f), Dt1(->base), Dt1(->top));
+#line 2582 "vm_x86.dasc"
+ //|
+ //|// Reconstruct previous base for vmeta_call during tailcall.
+ //|->vm_call_tail:
+ //| mov RA, BASE
+ //| test PC, FRAME_TYPE
+ //| jnz >3
+ //| movzx RB, PC_RA
+ //| not RBa // Note: ~RB = -(RB+1)
+ //| lea BASE, [BASE+RB*8] // base = base - (RB+1)*8
+ //| jmp ->vm_call_dispatch // Resolve again for tailcall.
+ //|3:
+ //| mov RB, PC
+ //| and RB, -8
+ //| sub BASE, RB
+ //| jmp ->vm_call_dispatch // Resolve again for tailcall.
+ //|
+ //|5: // Grow stack for fallback handler.
+ //| mov FCARG2, LUA_MINSTACK
+ //| mov FCARG1, L:RB
+ //| call extern lj_state_growstack@8 // (lua_State *L, int n)
+ //| mov BASE, L:RB->base
+ //| xor RD, RD // Simulate a return 0.
+ //| jmp <1 // Dumb retry (goes through ff first).
+ //|
+ //|->fff_gcstep: // Call GC step function.
+ //| // BASE = new base, RD = nargs+1
+ //| pop RBa // Must keep stack at same level.
+ //| mov TMPa, RBa // Save return address
+ //| mov L:RB, SAVE_L
+ //| mov SAVE_PC, PC // Redundant (but a defined value).
+ //| mov L:RB->base, BASE
+ //| lea RD, [BASE+NARGS:RD*8-8]
+ //| mov FCARG1, L:RB
+ //| mov L:RB->top, RD
+ //| call extern lj_gc_step@4 // (lua_State *L)
+ //| mov BASE, L:RB->base
+ //| mov RD, L:RB->top
+ dasm_put(Dst, 6446, Dt7(->pc), FRAME_TYPE, LUA_MINSTACK, Dt1(->base), Dt1(->base), Dt1(->top), Dt1(->base));
+#line 2619 "vm_x86.dasc"
+ //| sub RD, BASE
+ //| shr RD, 3
+ //| add NARGS:RD, 1
+ //| mov RBa, TMPa
+ //| push RBa // Restore return address.
+ //| ret
+ //|
+ //|//-----------------------------------------------------------------------
+ //|//-- Special dispatch targets -------------------------------------------
+ //|//-----------------------------------------------------------------------
+ //|
+ //|->vm_record: // Dispatch target for recording phase.
+ //|.if JIT
+ //| movzx RD, byte [DISPATCH+DISPATCH_GL(hookmask)]
+ //| test RDL, HOOK_VMEVENT // No recording while in vmevent.
+ //| jnz >5
+ //| // Decrement the hookcount for consistency, but always do the call.
+ //| test RDL, HOOK_ACTIVE
+ //| jnz >1
+ //| test RDL, LUA_MASKLINE|LUA_MASKCOUNT
+ //| jz >1
+ //| dec dword [DISPATCH+DISPATCH_GL(hookcount)]
+ //| jmp >1
+ //|.endif
+ //|
+ //|->vm_rethook: // Dispatch target for return hooks.
+ //| movzx RD, byte [DISPATCH+DISPATCH_GL(hookmask)]
+ //| test RDL, HOOK_ACTIVE // Hook already active?
+ //| jnz >5
+ //| jmp >1
+ dasm_put(Dst, 6569, Dt1(->top), DISPATCH_GL(hookmask), HOOK_VMEVENT, HOOK_ACTIVE, LUA_MASKLINE|LUA_MASKCOUNT, DISPATCH_GL(hookcount), DISPATCH_GL(hookmask), HOOK_ACTIVE);
+#line 2649 "vm_x86.dasc"
+ //|
+ //|->vm_inshook: // Dispatch target for instr/line hooks.
+ //| movzx RD, byte [DISPATCH+DISPATCH_GL(hookmask)]
+ //| test RDL, HOOK_ACTIVE // Hook already active?
+ //| jnz >5
+ //|
+ //| test RDL, LUA_MASKLINE|LUA_MASKCOUNT
+ //| jz >5
+ //| dec dword [DISPATCH+DISPATCH_GL(hookcount)]
+ //| jz >1
+ //| test RDL, LUA_MASKLINE
+ //| jz >5
+ //|1:
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE
+ //| mov FCARG2, PC // Caveat: FCARG2 == BASE
+ //| mov FCARG1, L:RB
+ //| // SAVE_PC must hold the _previous_ PC. The callee updates it with PC.
+ //| call extern lj_dispatch_ins@8 // (lua_State *L, const BCIns *pc)
+ //|3:
+ //| mov BASE, L:RB->base
+ dasm_put(Dst, 6635, DISPATCH_GL(hookmask), HOOK_ACTIVE, LUA_MASKLINE|LUA_MASKCOUNT, DISPATCH_GL(hookcount), LUA_MASKLINE, Dt1(->base));
+#line 2670 "vm_x86.dasc"
+ //|4:
+ //| movzx RA, PC_RA
+ //|5:
+ //| movzx OP, PC_OP
+ //| movzx RD, PC_RD
+ //|.if X64
+ //| jmp aword [DISPATCH+OP*8+GG_DISP2STATIC] // Re-dispatch to static ins.
+ //|.else
+ //| jmp aword [DISPATCH+OP*4+GG_DISP2STATIC] // Re-dispatch to static ins.
+ //|.endif
+ //|
+ //|->cont_hook: // Continue from hook yield.
+ //| add PC, 4
+ //| mov RA, [RB-24]
+ //| mov MULTRES, RA // Restore MULTRES for *M ins.
+ //| jmp <4
+ //|
+ //|->vm_hotloop: // Hot loop counter underflow.
+ //|.if JIT
+ //| mov LFUNC:RB, [BASE-8] // Same as curr_topL(L).
+ //| mov RB, LFUNC:RB->pc
+ //| movzx RD, byte [RB+PC2PROTO(framesize)]
+ //| lea RD, [BASE+RD*8]
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE
+ //| mov L:RB->top, RD
+ //| mov FCARG2, PC
+ //| lea FCARG1, [DISPATCH+GG_DISP2J]
+ //| mov aword [DISPATCH+DISPATCH_J(L)], L:RBa
+ //| mov SAVE_PC, PC
+ //| call extern lj_trace_hot@8 // (jit_State *J, const BCIns *pc)
+ //| jmp <3
+ //|.endif
+ //|
+ //|->vm_callhook: // Dispatch target for call hooks.
+ //| mov SAVE_PC, PC
+ //|.if JIT
+ //| jmp >1
+ //|.endif
+ //|
+ //|->vm_hotcall: // Hot call counter underflow.
+ //|.if JIT
+ //| mov SAVE_PC, PC
+ dasm_put(Dst, 6694, Dt1(->base), GG_DISP2STATIC, Dt7(->pc), PC2PROTO(framesize), Dt1(->base), Dt1(->top), GG_DISP2J, DISPATCH_J(L));
+#line 2713 "vm_x86.dasc"
+ //| or PC, 1 // Marker for hot call.
+ //|1:
+ //|.endif
+ //| lea RD, [BASE+NARGS:RD*8-8]
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE
+ //| mov L:RB->top, RD
+ //| mov FCARG2, PC
+ //| mov FCARG1, L:RB
+ //| call extern lj_dispatch_call@8 // (lua_State *L, const BCIns *pc)
+ //| // ASMFunction returned in eax/rax (RDa).
+ //| mov SAVE_PC, 0 // Invalidate for subsequent line hook.
+ //|.if JIT
+ //| and PC, -2
+ //|.endif
+ //| mov BASE, L:RB->base
+ //| mov RAa, RDa
+ //| mov RD, L:RB->top
+ //| sub RD, BASE
+ //| mov RBa, RAa
+ //| movzx RA, PC_RA
+ //| shr RD, 3
+ //| add NARGS:RD, 1
+ //| jmp RBa
+ //|
+ //|->cont_stitch: // Trace stitching.
+ //|.if JIT
+ //| // BASE = base, RC = result, RB = mbase
+ //| mov TRACE:RA, [RB-24] // Save previous trace.
+ //| mov TMP1, TRACE:RA
+ //| mov TMP3, DISPATCH // Need one more register.
+ //| mov DISPATCH, MULTRES
+ //| movzx RA, PC_RA
+ //| lea RA, [BASE+RA*8] // Call base.
+ //| sub DISPATCH, 1
+ //| jz >2
+ //|1: // Move results down.
+ //|.if X64
+ //| mov RBa, [RC]
+ //| mov [RA], RBa
+ //|.else
+ //| mov RB, [RC]
+ //| mov [RA], RB
+ //| mov RB, [RC+4]
+ //| mov [RA+4], RB
+ //|.endif
+ //| add RC, 8
+ //| add RA, 8
+ //| sub DISPATCH, 1
+ //| jnz <1
+ //|2:
+ //| movzx RC, PC_RA
+ //| movzx RB, PC_RB
+ //| add RC, RB
+ //| lea RC, [BASE+RC*8-8]
+ //|3:
+ //| cmp RC, RA
+ //| ja >9 // More results wanted?
+ //|
+ //| mov DISPATCH, TMP3
+ //| mov TRACE:RD, TMP1 // Get previous trace.
+ //| movzx RB, word TRACE:RD->traceno
+ //| movzx RD, word TRACE:RD->link
+ //| cmp RD, RB
+ //| je ->cont_nop // Blacklisted.
+ //| test RD, RD
+ dasm_put(Dst, 6801, Dt1(->base), Dt1(->top), Dt1(->base), Dt1(->top), DtD(->traceno), DtD(->link));
+#line 2779 "vm_x86.dasc"
+ //| jne =>BC_JLOOP // Jump to stitched trace.
+ //|
+ //| // Stitch a new trace to the previous trace.
+ //| mov [DISPATCH+DISPATCH_J(exitno)], RB
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE
+ //| mov FCARG2, PC
+ //| lea FCARG1, [DISPATCH+GG_DISP2J]
+ //| mov aword [DISPATCH+DISPATCH_J(L)], L:RBa
+ //| call extern lj_dispatch_stitch@8 // (jit_State *J, const BCIns *pc)
+ //| mov BASE, L:RB->base
+ //| jmp ->cont_nop
+ //|
+ //|9: // Fill up results with nil.
+ //| mov dword [RA+4], LJ_TNIL
+ //| add RA, 8
+ //| jmp <3
+ //|.endif
+ //|
+ //|->vm_profhook: // Dispatch target for profiler hook.
+ dasm_put(Dst, 6982, BC_JLOOP, DISPATCH_J(exitno), Dt1(->base), GG_DISP2J, DISPATCH_J(L), Dt1(->base), LJ_TNIL);
+#line 2799 "vm_x86.dasc"
+#if LJ_HASPROFILE
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE
+ //| mov FCARG2, PC // Caveat: FCARG2 == BASE
+ //| mov FCARG1, L:RB
+ //| call extern lj_dispatch_profile@8 // (lua_State *L, const BCIns *pc)
+ //| mov BASE, L:RB->base
+ //| // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction.
+ //| sub PC, 4
+ //| jmp ->cont_nop
+ dasm_put(Dst, 7035, Dt1(->base), Dt1(->base));
+#line 2809 "vm_x86.dasc"
+#endif
+ //|
+ //|//-----------------------------------------------------------------------
+ //|//-- Trace exit handler -------------------------------------------------
+ //|//-----------------------------------------------------------------------
+ //|
+ //|// Called from an exit stub with the exit number on the stack.
+ //|// The 16 bit exit number is stored with two (sign-extended) push imm8.
+ //|->vm_exit_handler:
+ //|.if JIT
+ //|.if X64
+ //| push r13; push r12
+ //| push r11; push r10; push r9; push r8
+ //| push rdi; push rsi; push rbp; lea rbp, [rsp+88]; push rbp
+ //| push rbx; push rdx; push rcx; push rax
+ //| movzx RC, byte [rbp-8] // Reconstruct exit number.
+ //| mov RCH, byte [rbp-16]
+ //| mov [rbp-8], r15; mov [rbp-16], r14
+ //|.else
+ //| push ebp; lea ebp, [esp+12]; push ebp
+ //| push ebx; push edx; push ecx; push eax
+ //| movzx RC, byte [ebp-4] // Reconstruct exit number.
+ //| mov RCH, byte [ebp-8]
+ //| mov [ebp-4], edi; mov [ebp-8], esi
+ //|.endif
+ //| // Caveat: DISPATCH is ebx.
+ //| mov DISPATCH, [ebp]
+ //| mov RA, [DISPATCH+DISPATCH_GL(vmstate)] // Get trace number.
+ //| set_vmstate EXIT
+ //| mov [DISPATCH+DISPATCH_J(exitno)], RC
+ //| mov [DISPATCH+DISPATCH_J(parent)], RA
+ //|.if X64
+ //|.if X64WIN
+ //| sub rsp, 16*8+4*8 // Room for SSE regs + save area.
+ //|.else
+ //| sub rsp, 16*8 // Room for SSE regs.
+ //|.endif
+ //| add rbp, -128
+ //| movsd qword [rbp-8], xmm15; movsd qword [rbp-16], xmm14
+ //| movsd qword [rbp-24], xmm13; movsd qword [rbp-32], xmm12
+ //| movsd qword [rbp-40], xmm11; movsd qword [rbp-48], xmm10
+ //| movsd qword [rbp-56], xmm9; movsd qword [rbp-64], xmm8
+ //| movsd qword [rbp-72], xmm7; movsd qword [rbp-80], xmm6
+ //| movsd qword [rbp-88], xmm5; movsd qword [rbp-96], xmm4
+ //| movsd qword [rbp-104], xmm3; movsd qword [rbp-112], xmm2
+ //| movsd qword [rbp-120], xmm1; movsd qword [rbp-128], xmm0
+ //|.else
+ //| sub esp, 8*8+16 // Room for SSE regs + args.
+ //| movsd qword [ebp-40], xmm7; movsd qword [ebp-48], xmm6
+ //| movsd qword [ebp-56], xmm5; movsd qword [ebp-64], xmm4
+ //| movsd qword [ebp-72], xmm3; movsd qword [ebp-80], xmm2
+ //| movsd qword [ebp-88], xmm1; movsd qword [ebp-96], xmm0
+ //|.endif
+ //| // Caveat: RB is ebp.
+ //| mov L:RB, [DISPATCH+DISPATCH_GL(cur_L)]
+ //| mov BASE, [DISPATCH+DISPATCH_GL(jit_base)]
+ //| mov aword [DISPATCH+DISPATCH_J(L)], L:RBa
+ //| mov L:RB->base, BASE
+ //|.if X64WIN
+ //| lea CARG2, [rsp+4*8]
+ //|.elif X64
+ //| mov CARG2, rsp
+ //|.else
+ //| lea FCARG2, [esp+16]
+ //|.endif
+ //| lea FCARG1, [DISPATCH+GG_DISP2J]
+ //| mov dword [DISPATCH+DISPATCH_GL(jit_base)], 0
+ //| call extern lj_trace_exit@8 // (jit_State *J, ExitState *ex)
+ //| // MULTRES or negated error code returned in eax (RD).
+ //| mov RAa, L:RB->cframe
+ //| and RAa, CFRAME_RAWMASK
+ //|.if X64WIN
+ //| // Reposition stack later.
+ //|.elif X64
+ //| mov rsp, RAa // Reposition stack to C frame.
+ //|.else
+ //| mov esp, RAa // Reposition stack to C frame.
+ //|.endif
+ //| mov [RAa+CFRAME_OFS_L], L:RB // Set SAVE_L (on-trace resume/yield).
+ //| mov BASE, L:RB->base
+ //| mov PC, [RAa+CFRAME_OFS_PC] // Get SAVE_PC.
+ //|.if X64
+ //| jmp >1
+ //|.endif
+ //|.endif
+ //|->vm_exit_interp:
+ //| // RD = MULTRES or negated error code, BASE, PC and DISPATCH set.
+ //|.if JIT
+ //|.if X64
+ //| // Restore additional callee-save registers only used in compiled code.
+ //|.if X64WIN
+ //| lea RAa, [rsp+9*16+4*8]
+ //|1:
+ //| movdqa xmm15, [RAa-9*16]
+ //| movdqa xmm14, [RAa-8*16]
+ //| movdqa xmm13, [RAa-7*16]
+ //| movdqa xmm12, [RAa-6*16]
+ //| movdqa xmm11, [RAa-5*16]
+ //| movdqa xmm10, [RAa-4*16]
+ //| movdqa xmm9, [RAa-3*16]
+ //| movdqa xmm8, [RAa-2*16]
+ //| movdqa xmm7, [RAa-1*16]
+ //| mov rsp, RAa // Reposition stack to C frame.
+ //| movdqa xmm6, [RAa]
+ //| mov r15, CSAVE_3
+ //| mov r14, CSAVE_4
+ //|.else
+ //| add rsp, 16 // Reposition stack to C frame.
+ dasm_put(Dst, 7063, DISPATCH_GL(vmstate), DISPATCH_GL(vmstate), ~LJ_VMST_EXIT, DISPATCH_J(exitno), DISPATCH_J(parent), 16*8, DISPATCH_GL(cur_L), DISPATCH_GL(jit_base), DISPATCH_J(L), Dt1(->base), GG_DISP2J, DISPATCH_GL(jit_base), Dt1(->cframe), CFRAME_RAWMASK, CFRAME_OFS_L, Dt1(->base), CFRAME_OFS_PC);
+#line 2917 "vm_x86.dasc"
+ //|1:
+ //|.endif
+ //| mov r13, TMPa
+ //| mov r12, TMPQ
+ //|.endif
+ //| test RD, RD; js >9 // Check for error from exit.
+ //| mov L:RB, SAVE_L
+ //| mov MULTRES, RD
+ //| mov LFUNC:KBASE, [BASE-8]
+ //| mov KBASE, LFUNC:KBASE->pc
+ //| mov KBASE, [KBASE+PC2PROTO(k)]
+ //| mov L:RB->base, BASE
+ //| mov dword [DISPATCH+DISPATCH_GL(jit_base)], 0
+ //| set_vmstate INTERP
+ //| // Modified copy of ins_next which handles function header dispatch, too.
+ //| mov RC, [PC]
+ //| movzx RA, RCH
+ //| movzx OP, RCL
+ //| add PC, 4
+ //| shr RC, 16
+ //| cmp OP, BC_FUNCF // Function header?
+ //| jb >3
+ //| cmp OP, BC_FUNCC+2 // Fast function?
+ //| jae >4
+ //|2:
+ //| mov RC, MULTRES // RC/RD holds nres+1.
+ //|3:
+ //|.if X64
+ //| jmp aword [DISPATCH+OP*8]
+ //|.else
+ //| jmp aword [DISPATCH+OP*4]
+ //|.endif
+ //|
+ //|4: // Check frame below fast function.
+ //| mov RC, [BASE-4]
+ //| test RC, FRAME_TYPE
+ //| jnz <2 // Trace stitching continuation?
+ dasm_put(Dst, 7306, Dt7(->pc), PC2PROTO(k), Dt1(->base), DISPATCH_GL(jit_base), DISPATCH_GL(vmstate), ~LJ_VMST_INTERP, BC_FUNCF, BC_FUNCC+2, FRAME_TYPE);
+#line 2954 "vm_x86.dasc"
+ //| // Otherwise set KBASE for Lua function below fast function.
+ //| movzx RC, byte [RC-3]
+ //| not RCa
+ //| mov LFUNC:KBASE, [BASE+RC*8-8]
+ //| mov KBASE, LFUNC:KBASE->pc
+ //| mov KBASE, [KBASE+PC2PROTO(k)]
+ //| jmp <2
+ //|
+ //|9: // Rethrow error from the right C frame.
+ //| neg RD
+ //| mov FCARG1, L:RB
+ //| mov FCARG2, RD
+ //| call extern lj_err_throw@8 // (lua_State *L, int errcode)
+ //|.endif
+ //|
+ //|//-----------------------------------------------------------------------
+ //|//-- Math helper functions ----------------------------------------------
+ //|//-----------------------------------------------------------------------
+ //|
+ //|// FP value rounding. Called by math.floor/math.ceil fast functions
+ //|// and from JIT code. arg/ret is xmm0. xmm0-xmm3 and RD (eax) modified.
+ //|.macro vm_round, name, mode, cond
+ //|->name:
+ //|.if not X64 and cond
+ //| movsd xmm0, qword [esp+4]
+ //| call ->name .. _sse
+ //| movsd qword [esp+4], xmm0 // Overwrite callee-owned arg.
+ //| fld qword [esp+4]
+ //| ret
+ //|.endif
+ //|
+ //|->name .. _sse:
+ //| sseconst_abs xmm2, RDa
+ //| sseconst_2p52 xmm3, RDa
+ //| movaps xmm1, xmm0
+ //| andpd xmm1, xmm2 // |x|
+ //| ucomisd xmm3, xmm1 // No truncation if 2^52 <= |x|.
+ //| jbe >1
+ //| andnpd xmm2, xmm0 // Isolate sign bit.
+ //|.if mode == 2 // trunc(x)?
+ //| movaps xmm0, xmm1
+ //| addsd xmm1, xmm3 // (|x| + 2^52) - 2^52
+ //| subsd xmm1, xmm3
+ //| sseconst_1 xmm3, RDa
+ //| cmpsd xmm0, xmm1, 1 // |x| < result?
+ //| andpd xmm0, xmm3
+ //| subsd xmm1, xmm0 // If yes, subtract -1.
+ //| orpd xmm1, xmm2 // Merge sign bit back in.
+ //|.else
+ //| addsd xmm1, xmm3 // (|x| + 2^52) - 2^52
+ //| subsd xmm1, xmm3
+ //| orpd xmm1, xmm2 // Merge sign bit back in.
+ //| .if mode == 1 // ceil(x)?
+ //| sseconst_m1 xmm2, RDa // Must subtract -1 to preserve -0.
+ //| cmpsd xmm0, xmm1, 6 // x > result?
+ //| .else // floor(x)?
+ //| sseconst_1 xmm2, RDa
+ //| cmpsd xmm0, xmm1, 1 // x < result?
+ //| .endif
+ //| andpd xmm0, xmm2
+ //| subsd xmm1, xmm0 // If yes, subtract +-1.
+ //|.endif
+ //| movaps xmm0, xmm1
+ //|1:
+ //| ret
+ //|.endmacro
+ //|
+ //| vm_round vm_floor, 0, 1
+ //| vm_round vm_ceil, 1, JIT
+ dasm_put(Dst, 7417, Dt7(->pc), PC2PROTO(k), (unsigned int)(U64x(7fffffff,ffffffff)), (unsigned int)((U64x(7fffffff,ffffffff))>>32), (unsigned int)(U64x(43300000,00000000)), (unsigned int)((U64x(43300000,00000000))>>32), (unsigned int)(U64x(3ff00000,00000000)), (unsigned int)((U64x(3ff00000,00000000))>>32), (unsigned int)(U64x(7fffffff,ffffffff)), (unsigned int)((U64x(7fffffff,ffffffff))>>32));
+#line 3023 "vm_x86.dasc"
+ //| vm_round vm_trunc, 2, JIT
+ //|
+ //|// FP modulo x%y. Called by BC_MOD* and vm_arith.
+ //|->vm_mod:
+ //|// Args in xmm0/xmm1, return value in xmm0.
+ //|// Caveat: xmm0-xmm5 and RC (eax) modified!
+ //| movaps xmm5, xmm0
+ dasm_put(Dst, 7556, (unsigned int)(U64x(43300000,00000000)), (unsigned int)((U64x(43300000,00000000))>>32), (unsigned int)(U64x(bff00000,00000000)), (unsigned int)((U64x(bff00000,00000000))>>32), (unsigned int)(U64x(7fffffff,ffffffff)), (unsigned int)((U64x(7fffffff,ffffffff))>>32), (unsigned int)(U64x(43300000,00000000)), (unsigned int)((U64x(43300000,00000000))>>32), (unsigned int)(U64x(3ff00000,00000000)), (unsigned int)((U64x(3ff00000,00000000))>>32));
+#line 3030 "vm_x86.dasc"
+ //| divsd xmm0, xmm1
+ //| sseconst_abs xmm2, RDa
+ //| sseconst_2p52 xmm3, RDa
+ //| movaps xmm4, xmm0
+ //| andpd xmm4, xmm2 // |x/y|
+ //| ucomisd xmm3, xmm4 // No truncation if 2^52 <= |x/y|.
+ //| jbe >1
+ //| andnpd xmm2, xmm0 // Isolate sign bit.
+ //| addsd xmm4, xmm3 // (|x/y| + 2^52) - 2^52
+ //| subsd xmm4, xmm3
+ //| orpd xmm4, xmm2 // Merge sign bit back in.
+ //| sseconst_1 xmm2, RDa
+ //| cmpsd xmm0, xmm4, 1 // x/y < result?
+ //| andpd xmm0, xmm2
+ //| subsd xmm4, xmm0 // If yes, subtract 1.0.
+ //| movaps xmm0, xmm5
+ //| mulsd xmm1, xmm4
+ //| subsd xmm0, xmm1
+ //| ret
+ //|1:
+ //| mulsd xmm1, xmm0
+ //| movaps xmm0, xmm5
+ //| subsd xmm0, xmm1
+ //| ret
+ //|
+ //|// Args in xmm0/eax. Ret in xmm0. xmm0-xmm1 and eax modified.
+ //|->vm_powi_sse:
+ //| cmp eax, 1; jle >6 // i<=1?
+ //| // Now 1 < (unsigned)i <= 0x80000000.
+ //|1: // Handle leading zeros.
+ //| test eax, 1; jnz >2
+ //| mulsd xmm0, xmm0
+ //| shr eax, 1
+ //| jmp <1
+ //|2:
+ //| shr eax, 1; jz >5
+ //| movaps xmm1, xmm0
+ dasm_put(Dst, 7724, (unsigned int)(U64x(7fffffff,ffffffff)), (unsigned int)((U64x(7fffffff,ffffffff))>>32), (unsigned int)(U64x(43300000,00000000)), (unsigned int)((U64x(43300000,00000000))>>32), (unsigned int)(U64x(3ff00000,00000000)), (unsigned int)((U64x(3ff00000,00000000))>>32));
+#line 3067 "vm_x86.dasc"
+ //|3: // Handle trailing bits.
+ //| mulsd xmm0, xmm0
+ //| shr eax, 1; jz >4
+ //| jnc <3
+ //| mulsd xmm1, xmm0
+ //| jmp <3
+ //|4:
+ //| mulsd xmm0, xmm1
+ //|5:
+ //| ret
+ //|6:
+ //| je <5 // x^1 ==> x
+ //| jb >7 // x^0 ==> 1
+ //| neg eax
+ //| call <1
+ //| sseconst_1 xmm1, RDa
+ //| divsd xmm1, xmm0
+ //| movaps xmm0, xmm1
+ //| ret
+ //|7:
+ //| sseconst_1 xmm0, RDa
+ dasm_put(Dst, 7878, (unsigned int)(U64x(3ff00000,00000000)), (unsigned int)((U64x(3ff00000,00000000))>>32), (unsigned int)(U64x(3ff00000,00000000)), (unsigned int)((U64x(3ff00000,00000000))>>32));
+#line 3088 "vm_x86.dasc"
+ //| ret
+ //|
+ //|//-----------------------------------------------------------------------
+ //|//-- Miscellaneous functions --------------------------------------------
+ //|//-----------------------------------------------------------------------
+ //|
+ //|// int lj_vm_cpuid(uint32_t f, uint32_t res[4])
+ //|->vm_cpuid:
+ //|.if X64
+ //| mov eax, CARG1d
+ //| .if X64WIN; push rsi; mov rsi, CARG2; .endif
+ //| push rbx
+ //| xor ecx, ecx
+ //| cpuid
+ //| mov [rsi], eax
+ //| mov [rsi+4], ebx
+ //| mov [rsi+8], ecx
+ //| mov [rsi+12], edx
+ //| pop rbx
+ //| .if X64WIN; pop rsi; .endif
+ //| ret
+ //|.else
+ //| pushfd
+ //| pop edx
+ //| mov ecx, edx
+ //| xor edx, 0x00200000 // Toggle ID bit in flags.
+ //| push edx
+ //| popfd
+ //| pushfd
+ //| pop edx
+ //| xor eax, eax // Zero means no features supported.
+ //| cmp ecx, edx
+ //| jz >1 // No ID toggle means no CPUID support.
+ //| mov eax, [esp+4] // Argument 1 is function number.
+ //| push edi
+ //| push ebx
+ //| xor ecx, ecx
+ //| cpuid
+ //| mov edi, [esp+16] // Argument 2 is result area.
+ //| mov [edi], eax
+ //| mov [edi+4], ebx
+ //| mov [edi+8], ecx
+ //| mov [edi+12], edx
+ //| pop ebx
+ //| pop edi
+ //|1:
+ //| ret
+ //|.endif
+ //|
+ //|//-----------------------------------------------------------------------
+ //|//-- Assertions ---------------------------------------------------------
+ //|//-----------------------------------------------------------------------
+ //|
+ //|->assert_bad_for_arg_type:
+ dasm_put(Dst, 7958);
+#line 3142 "vm_x86.dasc"
+#ifdef LUA_USE_ASSERT
+ //| int3
+ dasm_put(Dst, 7990);
+#line 3144 "vm_x86.dasc"
+#endif
+ //| int3
+ //|
+ //|//-----------------------------------------------------------------------
+ //|//-- FFI helper functions -----------------------------------------------
+ //|//-----------------------------------------------------------------------
+ //|
+ //|// Handler for callback functions. Callback slot number in ah/al.
+ //|->vm_ffi_callback:
+ //|.if FFI
+ //|.type CTSTATE, CTState, PC
+#define DtF(_V) (int)(ptrdiff_t)&(((CTState *)0)_V)
+#line 3155 "vm_x86.dasc"
+ //|.if not X64
+ //| sub esp, 16 // Leave room for SAVE_ERRF etc.
+ //|.endif
+ //| saveregs_ // ebp/rbp already saved. ebp now holds global_State *.
+ //| lea DISPATCH, [ebp+GG_G2DISP]
+ //| mov CTSTATE, GL:ebp->ctype_state
+ //| movzx eax, ax
+ //| mov CTSTATE->cb.slot, eax
+ //|.if X64
+ //| mov CTSTATE->cb.gpr[0], CARG1
+ //| mov CTSTATE->cb.gpr[1], CARG2
+ //| mov CTSTATE->cb.gpr[2], CARG3
+ //| mov CTSTATE->cb.gpr[3], CARG4
+ //| movsd qword CTSTATE->cb.fpr[0], xmm0
+ //| movsd qword CTSTATE->cb.fpr[1], xmm1
+ //| movsd qword CTSTATE->cb.fpr[2], xmm2
+ //| movsd qword CTSTATE->cb.fpr[3], xmm3
+ //|.if X64WIN
+ //| lea rax, [rsp+CFRAME_SIZE+4*8]
+ //|.else
+ //| lea rax, [rsp+CFRAME_SIZE]
+ //| mov CTSTATE->cb.gpr[4], CARG5
+ //| mov CTSTATE->cb.gpr[5], CARG6
+ //| movsd qword CTSTATE->cb.fpr[4], xmm4
+ //| movsd qword CTSTATE->cb.fpr[5], xmm5
+ //| movsd qword CTSTATE->cb.fpr[6], xmm6
+ //| movsd qword CTSTATE->cb.fpr[7], xmm7
+ //|.endif
+ //| mov CTSTATE->cb.stack, rax
+ dasm_put(Dst, 7992, GG_G2DISP, Dt2(->ctype_state), DtF(->cb.slot), DtF(->cb.gpr[0]), DtF(->cb.gpr[1]), DtF(->cb.gpr[2]), DtF(->cb.gpr[3]), DtF(->cb.fpr[0]), DtF(->cb.fpr[1]), DtF(->cb.fpr[2]), DtF(->cb.fpr[3]), CFRAME_SIZE, DtF(->cb.gpr[4]), DtF(->cb.gpr[5]), DtF(->cb.fpr[4]), DtF(->cb.fpr[5]), DtF(->cb.fpr[6]), DtF(->cb.fpr[7]));
+#line 3184 "vm_x86.dasc"
+ //| mov CARG2, rsp
+ //|.else
+ //| lea eax, [esp+CFRAME_SIZE+16]
+ //| mov CTSTATE->cb.gpr[0], FCARG1
+ //| mov CTSTATE->cb.gpr[1], FCARG2
+ //| mov CTSTATE->cb.stack, eax
+ //| mov FCARG1, [esp+CFRAME_SIZE+12] // Move around misplaced retaddr/ebp.
+ //| mov FCARG2, [esp+CFRAME_SIZE+8]
+ //| mov SAVE_RET, FCARG1
+ //| mov SAVE_R4, FCARG2
+ //| mov FCARG2, esp
+ //|.endif
+ //| mov SAVE_PC, CTSTATE // Any value outside of bytecode is ok.
+ //| mov FCARG1, CTSTATE
+ //| call extern lj_ccallback_enter@8 // (CTState *cts, void *cf)
+ //| // lua_State * returned in eax (RD).
+ //| set_vmstate INTERP
+ //| mov BASE, L:RD->base
+ //| mov RD, L:RD->top
+ //| sub RD, BASE
+ //| mov LFUNC:RB, [BASE-8]
+ //| shr RD, 3
+ //| add RD, 1
+ //| ins_callt
+ //|.endif
+ //|
+ //|->cont_ffi_callback: // Return from FFI callback.
+ //|.if FFI
+ //| mov L:RA, SAVE_L
+ //| mov CTSTATE, [DISPATCH+DISPATCH_GL(ctype_state)]
+ //| mov aword CTSTATE->L, L:RAa
+ //| mov L:RA->base, BASE
+ //| mov L:RA->top, RB
+ //| mov FCARG1, CTSTATE
+ //| mov FCARG2, RC
+ //| call extern lj_ccallback_leave@8 // (CTState *cts, TValue *o)
+ //|.if X64
+ //| mov rax, CTSTATE->cb.gpr[0]
+ //| movsd xmm0, qword CTSTATE->cb.fpr[0]
+ //| jmp ->vm_leave_unw
+ //|.else
+ //| mov L:RB, SAVE_L
+ //| mov eax, CTSTATE->cb.gpr[0]
+ //| mov edx, CTSTATE->cb.gpr[1]
+ //| cmp dword CTSTATE->cb.gpr[2], 1
+ //| jb >7
+ //| je >6
+ //| fld qword CTSTATE->cb.fpr[0].d
+ //| jmp >7
+ //|6:
+ //| fld dword CTSTATE->cb.fpr[0].f
+ //|7:
+ //| mov ecx, L:RB->top
+ //| movzx ecx, word [ecx+6] // Get stack adjustment and copy up.
+ //| mov SAVE_L, ecx // Must be one slot above SAVE_RET
+ //| restoreregs
+ //| pop ecx // Move return addr from SAVE_RET.
+ //| add esp, [esp] // Adjust stack.
+ //| add esp, 16
+ //| push ecx
+ //| ret
+ //|.endif
+ //|.endif
+ //|
+ //|->vm_ffi_call@4: // Call C function via FFI.
+ //| // Caveat: needs special frame unwinding, see below.
+ //|.if FFI
+ //|.if X64
+ //| .type CCSTATE, CCallState, rbx
+#define Dt10(_V) (int)(ptrdiff_t)&(((CCallState *)0)_V)
+#line 3253 "vm_x86.dasc"
+ //| push rbp; mov rbp, rsp; push rbx; mov CCSTATE, CARG1
+ //|.else
+ //| .type CCSTATE, CCallState, ebx
+ //| push ebp; mov ebp, esp; push ebx; mov CCSTATE, FCARG1
+ //|.endif
+ //|
+ //| // Readjust stack.
+ //|.if X64
+ //| mov eax, CCSTATE->spadj
+ //| sub rsp, rax
+ //|.else
+ //| sub esp, CCSTATE->spadj
+ //|.if WIN
+ //| mov CCSTATE->spadj, esp
+ //|.endif
+ //|.endif
+ //|
+ //| // Copy stack slots.
+ //| movzx ecx, byte CCSTATE->nsp
+ //| sub ecx, 1
+ //| js >2
+ //|1:
+ //|.if X64
+ //| mov rax, [CCSTATE+rcx*8+offsetof(CCallState, stack)]
+ dasm_put(Dst, 8097, DtF(->cb.stack), DISPATCH_GL(vmstate), ~LJ_VMST_INTERP, Dt1(->base), Dt1(->top), Dt7(->pc), DISPATCH_GL(ctype_state), DtF(->L), Dt1(->base), Dt1(->top), DtF(->cb.gpr[0]), DtF(->cb.fpr[0]), Dt10(->spadj), Dt10(->nsp));
+#line 3277 "vm_x86.dasc"
+ //| mov [rsp+rcx*8+CCALL_SPS_EXTRA*8], rax
+ //|.else
+ //| mov eax, [CCSTATE+ecx*4+offsetof(CCallState, stack)]
+ //| mov [esp+ecx*4], eax
+ //|.endif
+ //| sub ecx, 1
+ //| jns <1
+ //|2:
+ //|
+ //|.if X64
+ //| movzx eax, byte CCSTATE->nfpr
+ //| mov CARG1, CCSTATE->gpr[0]
+ //| mov CARG2, CCSTATE->gpr[1]
+ //| mov CARG3, CCSTATE->gpr[2]
+ //| mov CARG4, CCSTATE->gpr[3]
+ //|.if not X64WIN
+ //| mov CARG5, CCSTATE->gpr[4]
+ //| mov CARG6, CCSTATE->gpr[5]
+ //|.endif
+ //| test eax, eax; jz >5
+ //| movaps xmm0, CCSTATE->fpr[0]
+ //| movaps xmm1, CCSTATE->fpr[1]
+ //| movaps xmm2, CCSTATE->fpr[2]
+ //| movaps xmm3, CCSTATE->fpr[3]
+ //|.if not X64WIN
+ //| cmp eax, 4; jbe >5
+ //| movaps xmm4, CCSTATE->fpr[4]
+ dasm_put(Dst, 8232, offsetof(CCallState, stack), CCALL_SPS_EXTRA*8, Dt10(->nfpr), Dt10(->gpr[0]), Dt10(->gpr[1]), Dt10(->gpr[2]), Dt10(->gpr[3]), Dt10(->gpr[4]), Dt10(->gpr[5]), Dt10(->fpr[0]), Dt10(->fpr[1]), Dt10(->fpr[2]), Dt10(->fpr[3]));
+#line 3304 "vm_x86.dasc"
+ //| movaps xmm5, CCSTATE->fpr[5]
+ //| movaps xmm6, CCSTATE->fpr[6]
+ //| movaps xmm7, CCSTATE->fpr[7]
+ //|.endif
+ //|5:
+ //|.else
+ //| mov FCARG1, CCSTATE->gpr[0]
+ //| mov FCARG2, CCSTATE->gpr[1]
+ //|.endif
+ //|
+ //| call aword CCSTATE->func
+ //|
+ //|.if X64
+ //| mov CCSTATE->gpr[0], rax
+ //| movaps CCSTATE->fpr[0], xmm0
+ //|.if not X64WIN
+ //| mov CCSTATE->gpr[1], rdx
+ //| movaps CCSTATE->fpr[1], xmm1
+ //|.endif
+ //|.else
+ //| mov CCSTATE->gpr[0], eax
+ //| mov CCSTATE->gpr[1], edx
+ //| cmp byte CCSTATE->resx87, 1
+ //| jb >7
+ //| je >6
+ //| fstp qword CCSTATE->fpr[0].d[0]
+ //| jmp >7
+ //|6:
+ //| fstp dword CCSTATE->fpr[0].f[0]
+ //|7:
+ //|.if WIN
+ //| sub CCSTATE->spadj, esp
+ //|.endif
+ //|.endif
+ //|
+ //|.if X64
+ //| mov rbx, [rbp-8]; leave; ret
+ //|.else
+ //| mov ebx, [ebp-4]; leave; ret
+ //|.endif
+ //|.endif
+ //|// Note: vm_ffi_call must be the last function in this object file!
+ //|
+ //|//-----------------------------------------------------------------------
+ dasm_put(Dst, 8313, Dt10(->fpr[4]), Dt10(->fpr[5]), Dt10(->fpr[6]), Dt10(->fpr[7]), Dt10(->func), Dt10(->gpr[0]), Dt10(->fpr[0]), Dt10(->gpr[1]), Dt10(->fpr[1]));
+#line 3348 "vm_x86.dasc"
+}
+
+/* Generate the code for a single instruction. */
+static void build_ins(BuildCtx *ctx, BCOp op, int defop)
+{
+ int vk = 0;
+ //|// Note: aligning all instructions does not pay off.
+ //|=>defop:
+ dasm_put(Dst, 8359, defop);
+#line 3356 "vm_x86.dasc"
+
+ switch (op) {
+
+ /* -- Comparison ops ---------------------------------------------------- */
+
+ /* Remember: all ops branch for a true comparison, fall through otherwise. */
+
+ //|.macro jmp_comp, lt, ge, le, gt, target
+ //||switch (op) {
+ //||case BC_ISLT:
+ //| lt target
+ //||break;
+ //||case BC_ISGE:
+ //| ge target
+ //||break;
+ //||case BC_ISLE:
+ //| le target
+ //||break;
+ //||case BC_ISGT:
+ //| gt target
+ //||break;
+ //||default: break; /* Shut up GCC. */
+ //||}
+ //|.endmacro
+
+ case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT:
+ //| // RA = src1, RD = src2, JMP with RD = target
+ //| ins_AD
+ //|.if DUALNUM
+ //| checkint RA, >7
+ //| checkint RD, >8
+ //| mov RB, dword [BASE+RA*8]
+ //| add PC, 4
+ //| cmp RB, dword [BASE+RD*8]
+ //| jmp_comp jge, jl, jg, jle, >9
+ //|6:
+ //| movzx RD, PC_RD
+ //| branchPC RD
+ //|9:
+ //| ins_next
+ //|
+ //|7: // RA is not an integer.
+ //| ja ->vmeta_comp
+ //| // RA is a number.
+ //| cmp dword [BASE+RD*8+4], LJ_TISNUM; jb >1; jne ->vmeta_comp
+ //| // RA is a number, RD is an integer.
+ //| cvtsi2sd xmm0, dword [BASE+RD*8]
+ //| jmp >2
+ //|
+ //|8: // RA is an integer, RD is not an integer.
+ //| ja ->vmeta_comp
+ //| // RA is an integer, RD is a number.
+ //| cvtsi2sd xmm1, dword [BASE+RA*8]
+ //| movsd xmm0, qword [BASE+RD*8]
+ //| add PC, 4
+ //| ucomisd xmm0, xmm1
+ //| jmp_comp jbe, ja, jb, jae, <9
+ //| jmp <6
+ //|.else
+ //| checknum RA, ->vmeta_comp
+ //| checknum RD, ->vmeta_comp
+ //|.endif
+ //|1:
+ //| movsd xmm0, qword [BASE+RD*8]
+ //|2:
+ //| add PC, 4
+ //| ucomisd xmm0, qword [BASE+RA*8]
+ //|3:
+ //| // Unordered: all of ZF CF PF set, ordered: PF clear.
+ //| // To preserve NaN semantics GE/GT branch on unordered, but LT/LE don't.
+ //|.if DUALNUM
+ //| jmp_comp jbe, ja, jb, jae, <9
+ //| jmp <6
+ //|.else
+ //| jmp_comp jbe, ja, jb, jae, >1
+ dasm_put(Dst, 8361, LJ_TISNUM, LJ_TISNUM);
+ switch (op) {
+ case BC_ISLT:
+ dasm_put(Dst, 8402);
+ break;
+ case BC_ISGE:
+ dasm_put(Dst, 8407);
+ break;
+ case BC_ISLE:
+ dasm_put(Dst, 8412);
+ break;
+ case BC_ISGT:
+ dasm_put(Dst, 8417);
+ break;
+ default: break; /* Shut up GCC. */
+ }
+#line 3431 "vm_x86.dasc"
+ //| movzx RD, PC_RD
+ //| branchPC RD
+ //|1:
+ //| ins_next
+ //|.endif
+ dasm_put(Dst, 8422, -BCBIAS_J*4);
+#line 3436 "vm_x86.dasc"
+ break;
+
+ case BC_ISEQV: case BC_ISNEV:
+ vk = op == BC_ISEQV;
+ //| ins_AD // RA = src1, RD = src2, JMP with RD = target
+ //| mov RB, [BASE+RD*8+4]
+ //| add PC, 4
+ //|.if DUALNUM
+ //| cmp RB, LJ_TISNUM; jne >7
+ //| checkint RA, >8
+ //| mov RB, dword [BASE+RD*8]
+ //| cmp RB, dword [BASE+RA*8]
+ dasm_put(Dst, 8455);
+#line 3448 "vm_x86.dasc"
+ if (vk) {
+ //| jne >9
+ } else {
+ //| je >9
+ }
+ //| movzx RD, PC_RD
+ //| branchPC RD
+ //|9:
+ //| ins_next
+ //|
+ //|7: // RD is not an integer.
+ //| ja >5
+ //| // RD is a number.
+ //| cmp dword [BASE+RA*8+4], LJ_TISNUM; jb >1; jne >5
+ //| // RD is a number, RA is an integer.
+ //| cvtsi2sd xmm0, dword [BASE+RA*8]
+ //| jmp >2
+ //|
+ //|8: // RD is an integer, RA is not an integer.
+ //| ja >5
+ //| // RD is an integer, RA is a number.
+ //| cvtsi2sd xmm0, dword [BASE+RD*8]
+ //| ucomisd xmm0, qword [BASE+RA*8]
+ //| jmp >4
+ //|
+ //|.else
+ //| cmp RB, LJ_TISNUM; jae >5
+ //| checknum RA, >5
+ //|.endif
+ //|1:
+ //| movsd xmm0, qword [BASE+RA*8]
+ //|2:
+ //| ucomisd xmm0, qword [BASE+RD*8]
+ //|4:
+ dasm_put(Dst, 8463, LJ_TISNUM, LJ_TISNUM);
+#line 3482 "vm_x86.dasc"
+ iseqne_fp:
+ if (vk) {
+ //| jp >2 // Unordered means not equal.
+ //| jne >2
+ dasm_put(Dst, 8499);
+#line 3486 "vm_x86.dasc"
+ } else {
+ //| jp >2 // Unordered means not equal.
+ //| je >1
+ dasm_put(Dst, 8508);
+#line 3489 "vm_x86.dasc"
+ }
+ iseqne_end:
+ if (vk) {
+ //|1: // EQ: Branch to the target.
+ //| movzx RD, PC_RD
+ //| branchPC RD
+ //|2: // NE: Fallthrough to next instruction.
+ //|.if not FFI
+ //|3:
+ //|.endif
+ dasm_put(Dst, 8517, -BCBIAS_J*4);
+#line 3499 "vm_x86.dasc"
+ } else {
+ //|.if not FFI
+ //|3:
+ //|.endif
+ //|2: // NE: Branch to the target.
+ //| movzx RD, PC_RD
+ //| branchPC RD
+ //|1: // EQ: Fallthrough to next instruction.
+ dasm_put(Dst, 8532, -BCBIAS_J*4);
+#line 3507 "vm_x86.dasc"
+ }
+ if (LJ_DUALNUM && (op == BC_ISEQV || op == BC_ISNEV ||
+ op == BC_ISEQN || op == BC_ISNEN)) {
+ //| jmp <9
+ dasm_put(Dst, 8547);
+#line 3511 "vm_x86.dasc"
+ } else {
+ //| ins_next
+ dasm_put(Dst, 8434);
+#line 3513 "vm_x86.dasc"
+ }
+ //|
+ if (op == BC_ISEQV || op == BC_ISNEV) {
+ //|5: // Either or both types are not numbers.
+ //|.if FFI
+ //| cmp RB, LJ_TCDATA; je ->vmeta_equal_cd
+ //| checktp RA, LJ_TCDATA; je ->vmeta_equal_cd
+ //|.endif
+ //| checktp RA, RB // Compare types.
+ //| jne <2 // Not the same type?
+ //| cmp RB, LJ_TISPRI
+ //| jae <1 // Same type and primitive type?
+ //|
+ //| // Same types and not a primitive type. Compare GCobj or pvalue.
+ //| mov RA, [BASE+RA*8]
+ //| mov RD, [BASE+RD*8]
+ //| cmp RA, RD
+ //| je <1 // Same GCobjs or pvalues?
+ //| cmp RB, LJ_TISTABUD
+ //| ja <2 // Different objects and not table/ud?
+ //|.if X64
+ //| cmp RB, LJ_TUDATA // And not 64 bit lightuserdata.
+ //| jb <2
+ //|.endif
+ //|
+ //| // Different tables or userdatas. Need to check __eq metamethod.
+ //| // Field metatable must be at same offset for GCtab and GCudata!
+ //| mov TAB:RB, TAB:RA->metatable
+ dasm_put(Dst, 8552, LJ_TCDATA, LJ_TCDATA, LJ_TISPRI, LJ_TISTABUD, LJ_TUDATA);
+#line 3541 "vm_x86.dasc"
+ //| test TAB:RB, TAB:RB
+ //| jz <2 // No metatable?
+ //| test byte TAB:RB->nomm, 1<metatable), Dt6(->nomm), 1<vmeta_equal // Handle __eq metamethod.
+ dasm_put(Dst, 8647);
+#line 3551 "vm_x86.dasc"
+ } else {
+ //|.if FFI
+ //|3:
+ //| cmp RB, LJ_TCDATA
+ dasm_put(Dst, 8652, LJ_TCDATA);
+#line 3555 "vm_x86.dasc"
+ if (LJ_DUALNUM && vk) {
+ //| jne <9
+ dasm_put(Dst, 8659);
+#line 3557 "vm_x86.dasc"
+ } else {
+ //| jne <2
+ dasm_put(Dst, 8632);
+#line 3559 "vm_x86.dasc"
+ }
+ //| jmp ->vmeta_equal_cd
+ //|.endif
+ dasm_put(Dst, 8664);
+#line 3562 "vm_x86.dasc"
+ }
+ break;
+ case BC_ISEQS: case BC_ISNES:
+ vk = op == BC_ISEQS;
+ //| ins_AND // RA = src, RD = str const, JMP with RD = target
+ //| mov RB, [BASE+RA*8+4]
+ //| add PC, 4
+ //| cmp RB, LJ_TSTR; jne >3
+ //| mov RA, [BASE+RA*8]
+ //| cmp RA, [KBASE+RD*4]
+ dasm_put(Dst, 8669, LJ_TSTR);
+#line 3572 "vm_x86.dasc"
+ iseqne_test:
+ if (vk) {
+ //| jne >2
+ dasm_put(Dst, 8503);
+#line 3575 "vm_x86.dasc"
+ } else {
+ //| je >1
+ dasm_put(Dst, 8512);
+#line 3577 "vm_x86.dasc"
+ }
+ goto iseqne_end;
+ case BC_ISEQN: case BC_ISNEN:
+ vk = op == BC_ISEQN;
+ //| ins_AD // RA = src, RD = num const, JMP with RD = target
+ //| mov RB, [BASE+RA*8+4]
+ //| add PC, 4
+ //|.if DUALNUM
+ //| cmp RB, LJ_TISNUM; jne >7
+ //| cmp dword [KBASE+RD*8+4], LJ_TISNUM; jne >8
+ //| mov RB, dword [KBASE+RD*8]
+ //| cmp RB, dword [BASE+RA*8]
+ dasm_put(Dst, 8696);
+#line 3589 "vm_x86.dasc"
+ if (vk) {
+ //| jne >9
+ } else {
+ //| je >9
+ }
+ //| movzx RD, PC_RD
+ //| branchPC RD
+ //|9:
+ //| ins_next
+ //|
+ //|7: // RA is not an integer.
+ //| ja >3
+ //| // RA is a number.
+ //| cmp dword [KBASE+RD*8+4], LJ_TISNUM; jb >1
+ //| // RA is a number, RD is an integer.
+ //| cvtsi2sd xmm0, dword [KBASE+RD*8]
+ //| jmp >2
+ //|
+ //|8: // RA is an integer, RD is a number.
+ //| cvtsi2sd xmm0, dword [BASE+RA*8]
+ //| ucomisd xmm0, qword [KBASE+RD*8]
+ //| jmp >4
+ //|.else
+ //| cmp RB, LJ_TISNUM; jae >3
+ //|.endif
+ //|1:
+ //| movsd xmm0, qword [KBASE+RD*8]
+ //|2:
+ //| ucomisd xmm0, qword [BASE+RA*8]
+ //|4:
+ dasm_put(Dst, 8704, LJ_TISNUM);
+#line 3619 "vm_x86.dasc"
+ goto iseqne_fp;
+ case BC_ISEQP: case BC_ISNEP:
+ vk = op == BC_ISEQP;
+ //| ins_AND // RA = src, RD = primitive type (~), JMP with RD = target
+ //| mov RB, [BASE+RA*8+4]
+ //| add PC, 4
+ //| cmp RB, RD
+ dasm_put(Dst, 8731);
+#line 3626 "vm_x86.dasc"
+ if (!LJ_HASFFI) goto iseqne_test;
+ if (vk) {
+ //| jne >3
+ //| movzx RD, PC_RD
+ //| branchPC RD
+ //|2:
+ //| ins_next
+ //|3:
+ //| cmp RB, LJ_TCDATA; jne <2
+ //| jmp ->vmeta_equal_cd
+ dasm_put(Dst, 8745, -BCBIAS_J*4, LJ_TCDATA);
+#line 3636 "vm_x86.dasc"
+ } else {
+ //| je >2
+ //| cmp RB, LJ_TCDATA; je ->vmeta_equal_cd
+ //| movzx RD, PC_RD
+ //| branchPC RD
+ //|2:
+ //| ins_next
+ dasm_put(Dst, 8796, LJ_TCDATA, -BCBIAS_J*4);
+#line 3643 "vm_x86.dasc"
+ }
+ break;
+
+ /* -- Unary test and copy ops ------------------------------------------- */
+
+ case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF:
+ //| ins_AD // RA = dst or unused, RD = src, JMP with RD = target
+ //| mov RB, [BASE+RD*8+4]
+ //| add PC, 4
+ //| cmp RB, LJ_TISTRUECOND
+ dasm_put(Dst, 8841, LJ_TISTRUECOND);
+#line 3653 "vm_x86.dasc"
+ if (op == BC_IST || op == BC_ISTC) {
+ //| jae >1
+ dasm_put(Dst, 8417);
+#line 3655 "vm_x86.dasc"
+ } else {
+ //| jb >1
+ dasm_put(Dst, 8412);
+#line 3657 "vm_x86.dasc"
+ }
+ if (op == BC_ISTC || op == BC_ISFC) {
+ //| mov [BASE+RA*8+4], RB
+ //| mov RB, [BASE+RD*8]
+ //| mov [BASE+RA*8], RB
+ dasm_put(Dst, 8853);
+#line 3662 "vm_x86.dasc"
+ }
+ //| movzx RD, PC_RD
+ //| branchPC RD
+ //|1: // Fallthrough to the next instruction.
+ //| ins_next
+ dasm_put(Dst, 8422, -BCBIAS_J*4);
+#line 3667 "vm_x86.dasc"
+ break;
+
+ case BC_ISTYPE:
+ //| ins_AD // RA = src, RD = -type
+ //| add RD, [BASE+RA*8+4]
+ //| jne ->vmeta_istype
+ //| ins_next
+ dasm_put(Dst, 8864);
+#line 3674 "vm_x86.dasc"
+ break;
+ case BC_ISNUM:
+ //| ins_AD // RA = src, RD = -(TISNUM-1)
+ //| checknum RA, ->vmeta_istype
+ //| ins_next
+ dasm_put(Dst, 8893, LJ_TISNUM);
+#line 3679 "vm_x86.dasc"
+ break;
+
+ /* -- Unary ops --------------------------------------------------------- */
+
+ case BC_MOV:
+ //| ins_AD // RA = dst, RD = src
+ //|.if X64
+ //| mov RBa, [BASE+RD*8]
+ //| mov [BASE+RA*8], RBa
+ //|.else
+ //| mov RB, [BASE+RD*8+4]
+ //| mov RD, [BASE+RD*8]
+ //| mov [BASE+RA*8+4], RB
+ //| mov [BASE+RA*8], RD
+ //|.endif
+ //| ins_next_
+ dasm_put(Dst, 8924);
+#line 3695 "vm_x86.dasc"
+ break;
+ case BC_NOT:
+ //| ins_AD // RA = dst, RD = src
+ //| xor RB, RB
+ //| checktp RD, LJ_TISTRUECOND
+ //| adc RB, LJ_TTRUE
+ //| mov [BASE+RA*8+4], RB
+ //| ins_next
+ dasm_put(Dst, 8953, LJ_TISTRUECOND, LJ_TTRUE);
+#line 3703 "vm_x86.dasc"
+ break;
+ case BC_UNM:
+ //| ins_AD // RA = dst, RD = src
+ //|.if DUALNUM
+ //| checkint RD, >5
+ //| mov RB, [BASE+RD*8]
+ //| neg RB
+ //| jo >4
+ //| mov dword [BASE+RA*8+4], LJ_TISNUM
+ //| mov dword [BASE+RA*8], RB
+ //|9:
+ //| ins_next
+ //|4:
+ //| mov dword [BASE+RA*8+4], 0x41e00000 // 2^31.
+ //| mov dword [BASE+RA*8], 0
+ //| jmp <9
+ //|5:
+ //| ja ->vmeta_unm
+ //|.else
+ //| checknum RD, ->vmeta_unm
+ //|.endif
+ //| movsd xmm0, qword [BASE+RD*8]
+ //| sseconst_sign xmm1, RDa
+ //| xorps xmm0, xmm1
+ //| movsd qword [BASE+RA*8], xmm0
+ //|.if DUALNUM
+ //| jmp <9
+ //|.else
+ //| ins_next
+ //|.endif
+ dasm_put(Dst, 8990, LJ_TISNUM, (unsigned int)(U64x(80000000,00000000)), (unsigned int)((U64x(80000000,00000000))>>32));
+#line 3733 "vm_x86.dasc"
+ break;
+ case BC_LEN:
+ //| ins_AD // RA = dst, RD = src
+ //| checkstr RD, >2
+ //| mov STR:RD, [BASE+RD*8]
+ //|.if DUALNUM
+ //| mov RD, dword STR:RD->len
+ //|1:
+ //| mov dword [BASE+RA*8+4], LJ_TISNUM
+ //| mov dword [BASE+RA*8], RD
+ //|.else
+ //| xorps xmm0, xmm0
+ //| cvtsi2sd xmm0, dword STR:RD->len
+ //|1:
+ //| movsd qword [BASE+RA*8], xmm0
+ //|.endif
+ //| ins_next
+ //|2:
+ //| checktab RD, ->vmeta_len
+ //| mov TAB:FCARG1, [BASE+RD*8]
+ dasm_put(Dst, 9045, LJ_TSTR, Dt5(->len), LJ_TTAB);
+#line 3753 "vm_x86.dasc"
+#if LJ_52
+ //| mov TAB:RB, TAB:FCARG1->metatable
+ //| cmp TAB:RB, 0
+ //| jnz >9
+ //|3:
+ dasm_put(Dst, 9111, Dt6(->metatable));
+#line 3758 "vm_x86.dasc"
+#endif
+ //|->BC_LEN_Z:
+ //| mov RB, BASE // Save BASE.
+ //| call extern lj_tab_len@4 // (GCtab *t)
+ //| // Length of table returned in eax (RD).
+ //|.if DUALNUM
+ //| // Nothing to do.
+ //|.else
+ //| cvtsi2sd xmm0, RD
+ //|.endif
+ //| mov BASE, RB // Restore BASE.
+ //| movzx RA, PC_RA
+ //| jmp <1
+ dasm_put(Dst, 9125);
+#line 3771 "vm_x86.dasc"
+#if LJ_52
+ //|9: // Check for __len.
+ //| test byte TAB:RB->nomm, 1<vmeta_len // 'no __len' flag NOT set: check.
+ dasm_put(Dst, 9151, Dt6(->nomm), 1<vmeta_arith_vn
+ //| .if DUALNUM
+ //| cmp dword [KBASE+RC*8+4], LJ_TISNUM; jae ->vmeta_arith_vn
+ //| .endif
+ //| movsd xmm0, qword [BASE+RB*8]
+ //| sseins ssereg, qword [KBASE+RC*8]
+ //|| break;
+ //||case 1:
+ //| checknum RB, ->vmeta_arith_nv
+ //| .if DUALNUM
+ //| cmp dword [KBASE+RC*8+4], LJ_TISNUM; jae ->vmeta_arith_nv
+ //| .endif
+ //| movsd xmm0, qword [KBASE+RC*8]
+ //| sseins ssereg, qword [BASE+RB*8]
+ //|| break;
+ //||default:
+ //| checknum RB, ->vmeta_arith_vv
+ //| checknum RC, ->vmeta_arith_vv
+ //| movsd xmm0, qword [BASE+RB*8]
+ //| sseins ssereg, qword [BASE+RC*8]
+ //|| break;
+ //||}
+ //|.endmacro
+ //|
+ //|.macro ins_arithdn, intins
+ //| ins_ABC
+ //||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN);
+ //||switch (vk) {
+ //||case 0:
+ //| checkint RB, ->vmeta_arith_vn
+ //| cmp dword [KBASE+RC*8+4], LJ_TISNUM; jne ->vmeta_arith_vn
+ //| mov RB, [BASE+RB*8]
+ //| intins RB, [KBASE+RC*8]; jo ->vmeta_arith_vno
+ //|| break;
+ //||case 1:
+ //| checkint RB, ->vmeta_arith_nv
+ //| cmp dword [KBASE+RC*8+4], LJ_TISNUM; jne ->vmeta_arith_nv
+ //| mov RC, [KBASE+RC*8]
+ //| intins RC, [BASE+RB*8]; jo ->vmeta_arith_nvo
+ //|| break;
+ //||default:
+ //| checkint RB, ->vmeta_arith_vv
+ //| checkint RC, ->vmeta_arith_vv
+ //| mov RB, [BASE+RB*8]
+ //| intins RB, [BASE+RC*8]; jo ->vmeta_arith_vvo
+ //|| break;
+ //||}
+ //| mov dword [BASE+RA*8+4], LJ_TISNUM
+ //||if (vk == 1) {
+ //| mov dword [BASE+RA*8], RC
+ //||} else {
+ //| mov dword [BASE+RA*8], RB
+ //||}
+ //| ins_next
+ //|.endmacro
+ //|
+ //|.macro ins_arithpost
+ //| movsd qword [BASE+RA*8], xmm0
+ //|.endmacro
+ //|
+ //|.macro ins_arith, sseins
+ //| ins_arithpre sseins, xmm0
+ //| ins_arithpost
+ //| ins_next
+ //|.endmacro
+ //|
+ //|.macro ins_arith, intins, sseins
+ //|.if DUALNUM
+ //| ins_arithdn intins
+ //|.else
+ //| ins_arith, sseins
+ //|.endif
+ //|.endmacro
+
+ //| // RA = dst, RB = src1 or num const, RC = src2 or num const
+ case BC_ADDVN: case BC_ADDNV: case BC_ADDVV:
+ //| ins_arith add, addsd
+ dasm_put(Dst, 9167);
+ vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN);
+ switch (vk) {
+ case 0:
+ dasm_put(Dst, 9175, LJ_TISNUM);
+ break;
+ case 1:
+ dasm_put(Dst, 9201, LJ_TISNUM);
+ break;
+ default:
+ dasm_put(Dst, 9227, LJ_TISNUM, LJ_TISNUM);
+ break;
+ }
+ dasm_put(Dst, 9018);
+#line 3863 "vm_x86.dasc"
+ break;
+ case BC_SUBVN: case BC_SUBNV: case BC_SUBVV:
+ //| ins_arith sub, subsd
+ dasm_put(Dst, 9167);
+ vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN);
+ switch (vk) {
+ case 0:
+ dasm_put(Dst, 9262, LJ_TISNUM);
+ break;
+ case 1:
+ dasm_put(Dst, 9288, LJ_TISNUM);
+ break;
+ default:
+ dasm_put(Dst, 9314, LJ_TISNUM, LJ_TISNUM);
+ break;
+ }
+ dasm_put(Dst, 9018);
+#line 3866 "vm_x86.dasc"
+ break;
+ case BC_MULVN: case BC_MULNV: case BC_MULVV:
+ //| ins_arith imul, mulsd
+ dasm_put(Dst, 9167);
+ vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN);
+ switch (vk) {
+ case 0:
+ dasm_put(Dst, 9349, LJ_TISNUM);
+ break;
+ case 1:
+ dasm_put(Dst, 9375, LJ_TISNUM);
+ break;
+ default:
+ dasm_put(Dst, 9401, LJ_TISNUM, LJ_TISNUM);
+ break;
+ }
+ dasm_put(Dst, 9018);
+#line 3869 "vm_x86.dasc"
+ break;
+ case BC_DIVVN: case BC_DIVNV: case BC_DIVVV:
+ //| ins_arith divsd
+ dasm_put(Dst, 9167);
+ vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN);
+ switch (vk) {
+ case 0:
+ dasm_put(Dst, 9436, LJ_TISNUM);
+ break;
+ case 1:
+ dasm_put(Dst, 9462, LJ_TISNUM);
+ break;
+ default:
+ dasm_put(Dst, 9488, LJ_TISNUM, LJ_TISNUM);
+ break;
+ }
+ dasm_put(Dst, 9018);
+#line 3872 "vm_x86.dasc"
+ break;
+ case BC_MODVN:
+ //| ins_arithpre movsd, xmm1
+ dasm_put(Dst, 9167);
+ vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN);
+ switch (vk) {
+ case 0:
+ dasm_put(Dst, 9523, LJ_TISNUM);
+ break;
+ case 1:
+ dasm_put(Dst, 9549, LJ_TISNUM);
+ break;
+ default:
+ dasm_put(Dst, 9575, LJ_TISNUM, LJ_TISNUM);
+ break;
+ }
+#line 3875 "vm_x86.dasc"
+ //|->BC_MODVN_Z:
+ //| call ->vm_mod
+ //| ins_arithpost
+ //| ins_next
+ dasm_put(Dst, 9610);
+#line 3879 "vm_x86.dasc"
+ break;
+ case BC_MODNV: case BC_MODVV:
+ //| ins_arithpre movsd, xmm1
+ dasm_put(Dst, 9167);
+ vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN);
+ switch (vk) {
+ case 0:
+ dasm_put(Dst, 9523, LJ_TISNUM);
+ break;
+ case 1:
+ dasm_put(Dst, 9549, LJ_TISNUM);
+ break;
+ default:
+ dasm_put(Dst, 9575, LJ_TISNUM, LJ_TISNUM);
+ break;
+ }
+#line 3882 "vm_x86.dasc"
+ //| jmp ->BC_MODVN_Z // Avoid 3 copies. It's slow anyway.
+ dasm_put(Dst, 9642);
+#line 3883 "vm_x86.dasc"
+ break;
+ case BC_POW:
+ //| ins_arithpre movsd, xmm1
+ dasm_put(Dst, 9167);
+ vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN);
+ switch (vk) {
+ case 0:
+ dasm_put(Dst, 9523, LJ_TISNUM);
+ break;
+ case 1:
+ dasm_put(Dst, 9549, LJ_TISNUM);
+ break;
+ default:
+ dasm_put(Dst, 9575, LJ_TISNUM, LJ_TISNUM);
+ break;
+ }
+#line 3886 "vm_x86.dasc"
+ //| mov RB, BASE
+ //|.if not X64
+ //| movsd FPARG1, xmm0
+ //| movsd FPARG3, xmm1
+ //|.endif
+ //| call extern pow
+ //| movzx RA, PC_RA
+ //| mov BASE, RB
+ //|.if X64
+ //| ins_arithpost
+ //|.else
+ //| fstp qword [BASE+RA*8]
+ //|.endif
+ //| ins_next
+ dasm_put(Dst, 9647);
+#line 3900 "vm_x86.dasc"
+ break;
+
+ case BC_CAT:
+ //| ins_ABC // RA = dst, RB = src_start, RC = src_end
+ //|.if X64
+ //| mov L:CARG1d, SAVE_L
+ //| mov L:CARG1d->base, BASE
+ //| lea CARG2d, [BASE+RC*8]
+ //| mov CARG3d, RC
+ //| sub CARG3d, RB
+ //|->BC_CAT_Z:
+ //| mov L:RB, L:CARG1d
+ //|.else
+ //| lea RA, [BASE+RC*8]
+ //| sub RC, RB
+ //| mov ARG2, RA
+ //| mov ARG3, RC
+ //|->BC_CAT_Z:
+ //| mov L:RB, SAVE_L
+ //| mov ARG1, L:RB
+ //| mov L:RB->base, BASE
+ //|.endif
+ //| mov SAVE_PC, PC
+ //| call extern lj_meta_cat // (lua_State *L, TValue *top, int left)
+ //| // NULL (finished) or TValue * (metamethod) returned in eax (RC).
+ //| mov BASE, L:RB->base
+ //| test RC, RC
+ //| jnz ->vmeta_binop
+ //| movzx RB, PC_RB // Copy result to Stk[RA] from Stk[RB].
+ //| movzx RA, PC_RA
+ //|.if X64
+ //| mov RCa, [BASE+RB*8]
+ //| mov [BASE+RA*8], RCa
+ //|.else
+ //| mov RC, [BASE+RB*8+4]
+ //| mov RB, [BASE+RB*8]
+ //| mov [BASE+RA*8+4], RC
+ //| mov [BASE+RA*8], RB
+ //|.endif
+ //| ins_next
+ dasm_put(Dst, 9688, Dt1(->base), Dt1(->base));
+#line 3940 "vm_x86.dasc"
+ break;
+
+ /* -- Constant ops ------------------------------------------------------ */
+
+ case BC_KSTR:
+ //| ins_AND // RA = dst, RD = str const (~)
+ //| mov RD, [KBASE+RD*4]
+ //| mov dword [BASE+RA*8+4], LJ_TSTR
+ //| mov [BASE+RA*8], RD
+ //| ins_next
+ dasm_put(Dst, 9772, LJ_TSTR);
+#line 3950 "vm_x86.dasc"
+ break;
+ case BC_KCDATA:
+ //|.if FFI
+ //| ins_AND // RA = dst, RD = cdata const (~)
+ //| mov RD, [KBASE+RD*4]
+ //| mov dword [BASE+RA*8+4], LJ_TCDATA
+ //| mov [BASE+RA*8], RD
+ //| ins_next
+ //|.endif
+ dasm_put(Dst, 9772, LJ_TCDATA);
+#line 3959 "vm_x86.dasc"
+ break;
+ case BC_KSHORT:
+ //| ins_AD // RA = dst, RD = signed int16 literal
+ //|.if DUALNUM
+ //| movsx RD, RDW
+ //| mov dword [BASE+RA*8+4], LJ_TISNUM
+ //| mov dword [BASE+RA*8], RD
+ //|.else
+ //| movsx RD, RDW // Sign-extend literal.
+ //| cvtsi2sd xmm0, RD
+ //| movsd qword [BASE+RA*8], xmm0
+ //|.endif
+ //| ins_next
+ dasm_put(Dst, 9809);
+#line 3972 "vm_x86.dasc"
+ break;
+ case BC_KNUM:
+ //| ins_AD // RA = dst, RD = num const
+ //| movsd xmm0, qword [KBASE+RD*8]
+ //| movsd qword [BASE+RA*8], xmm0
+ //| ins_next
+ dasm_put(Dst, 9844);
+#line 3978 "vm_x86.dasc"
+ break;
+ case BC_KPRI:
+ //| ins_AND // RA = dst, RD = primitive type (~)
+ //| mov [BASE+RA*8+4], RD
+ //| ins_next
+ dasm_put(Dst, 9878);
+#line 3983 "vm_x86.dasc"
+ break;
+ case BC_KNIL:
+ //| ins_AD // RA = dst_start, RD = dst_end
+ //| lea RA, [BASE+RA*8+12]
+ //| lea RD, [BASE+RD*8+4]
+ //| mov RB, LJ_TNIL
+ //| mov [RA-8], RB // Sets minimum 2 slots.
+ //|1:
+ //| mov [RA], RB
+ //| add RA, 8
+ //| cmp RA, RD
+ //| jbe <1
+ //| ins_next
+ dasm_put(Dst, 9907, LJ_TNIL);
+#line 3996 "vm_x86.dasc"
+ break;
+
+ /* -- Upvalue and function ops ------------------------------------------ */
+
+ case BC_UGET:
+ //| ins_AD // RA = dst, RD = upvalue #
+ //| mov LFUNC:RB, [BASE-8]
+ //| mov UPVAL:RB, [LFUNC:RB+RD*4+offsetof(GCfuncL, uvptr)]
+ //| mov RB, UPVAL:RB->v
+ //|.if X64
+ //| mov RDa, [RB]
+ //| mov [BASE+RA*8], RDa
+ //|.else
+ //| mov RD, [RB+4]
+ //| mov RB, [RB]
+ //| mov [BASE+RA*8+4], RD
+ //| mov [BASE+RA*8], RB
+ //|.endif
+ //| ins_next
+ dasm_put(Dst, 9955, offsetof(GCfuncL, uvptr), DtA(->v));
+#line 4015 "vm_x86.dasc"
+ break;
+ case BC_USETV:
+#define TV2MARKOFS \
+ ((int32_t)offsetof(GCupval, marked)-(int32_t)offsetof(GCupval, tv))
+ //| ins_AD // RA = upvalue #, RD = src
+ //| mov LFUNC:RB, [BASE-8]
+ //| mov UPVAL:RB, [LFUNC:RB+RA*4+offsetof(GCfuncL, uvptr)]
+ //| cmp byte UPVAL:RB->closed, 0
+ //| mov RB, UPVAL:RB->v
+ //| mov RA, [BASE+RD*8]
+ //| mov RD, [BASE+RD*8+4]
+ //| mov [RB], RA
+ //| mov [RB+4], RD
+ //| jz >1
+ //| // Check barrier for closed upvalue.
+ //| test byte [RB+TV2MARKOFS], LJ_GC_BLACK // isblack(uv)
+ //| jnz >2
+ //|1:
+ //| ins_next
+ //|
+ //|2: // Upvalue is black. Check if new value is collectable and white.
+ //| sub RD, LJ_TISGCV
+ //| cmp RD, LJ_TNUMX - LJ_TISGCV // tvisgcv(v)
+ //| jbe <1
+ //| test byte GCOBJ:RA->gch.marked, LJ_GC_WHITES // iswhite(v)
+ //| jz <1
+ //| // Crossed a write barrier. Move the barrier forward.
+ //|.if X64 and not X64WIN
+ //| mov FCARG2, RB
+ dasm_put(Dst, 9996, offsetof(GCfuncL, uvptr), DtA(->closed), DtA(->v), TV2MARKOFS, LJ_GC_BLACK, LJ_TISGCV, LJ_TNUMX - LJ_TISGCV, Dt4(->gch.marked), LJ_GC_WHITES);
+#line 4044 "vm_x86.dasc"
+ //| mov RB, BASE // Save BASE.
+ //|.else
+ //| xchg FCARG2, RB // Save BASE (FCARG2 == BASE).
+ //|.endif
+ //| lea GL:FCARG1, [DISPATCH+GG_DISP2G]
+ //| call extern lj_gc_barrieruv@8 // (global_State *g, TValue *tv)
+ //| mov BASE, RB // Restore BASE.
+ //| jmp <1
+ dasm_put(Dst, 10083, GG_DISP2G);
+#line 4052 "vm_x86.dasc"
+ break;
+#undef TV2MARKOFS
+ case BC_USETS:
+ //| ins_AND // RA = upvalue #, RD = str const (~)
+ //| mov LFUNC:RB, [BASE-8]
+ //| mov UPVAL:RB, [LFUNC:RB+RA*4+offsetof(GCfuncL, uvptr)]
+ //| mov GCOBJ:RA, [KBASE+RD*4]
+ //| mov RD, UPVAL:RB->v
+ //| mov [RD], GCOBJ:RA
+ //| mov dword [RD+4], LJ_TSTR
+ //| test byte UPVAL:RB->marked, LJ_GC_BLACK // isblack(uv)
+ //| jnz >2
+ //|1:
+ //| ins_next
+ //|
+ //|2: // Check if string is white and ensure upvalue is closed.
+ //| test byte GCOBJ:RA->gch.marked, LJ_GC_WHITES // iswhite(str)
+ //| jz <1
+ //| cmp byte UPVAL:RB->closed, 0
+ //| jz <1
+ //| // Crossed a write barrier. Move the barrier forward.
+ //| mov RB, BASE // Save BASE (FCARG2 == BASE).
+ //| mov FCARG2, RD
+ //| lea GL:FCARG1, [DISPATCH+GG_DISP2G]
+ //| call extern lj_gc_barrieruv@8 // (global_State *g, TValue *tv)
+ //| mov BASE, RB // Restore BASE.
+ //| jmp <1
+ dasm_put(Dst, 10104, offsetof(GCfuncL, uvptr), DtA(->v), LJ_TSTR, DtA(->marked), LJ_GC_BLACK, Dt4(->gch.marked), LJ_GC_WHITES, DtA(->closed), GG_DISP2G);
+#line 4079 "vm_x86.dasc"
+ break;
+ case BC_USETN:
+ //| ins_AD // RA = upvalue #, RD = num const
+ //| mov LFUNC:RB, [BASE-8]
+ //| movsd xmm0, qword [KBASE+RD*8]
+ //| mov UPVAL:RB, [LFUNC:RB+RA*4+offsetof(GCfuncL, uvptr)]
+ //| mov RA, UPVAL:RB->v
+ //| movsd qword [RA], xmm0
+ //| ins_next
+ dasm_put(Dst, 10200, offsetof(GCfuncL, uvptr), DtA(->v));
+#line 4088 "vm_x86.dasc"
+ break;
+ case BC_USETP:
+ //| ins_AND // RA = upvalue #, RD = primitive type (~)
+ //| mov LFUNC:RB, [BASE-8]
+ //| mov UPVAL:RB, [LFUNC:RB+RA*4+offsetof(GCfuncL, uvptr)]
+ //| mov RA, UPVAL:RB->v
+ //| mov [RA+4], RD
+ //| ins_next
+ dasm_put(Dst, 10245, offsetof(GCfuncL, uvptr), DtA(->v));
+#line 4096 "vm_x86.dasc"
+ break;
+ case BC_UCLO:
+ //| ins_AD // RA = level, RD = target
+ //| branchPC RD // Do this first to free RD.
+ //| mov L:RB, SAVE_L
+ //| cmp dword L:RB->openupval, 0
+ //| je >1
+ //| mov L:RB->base, BASE
+ //| lea FCARG2, [BASE+RA*8] // Caveat: FCARG2 == BASE
+ //| mov L:FCARG1, L:RB // Caveat: FCARG1 == RA
+ //| call extern lj_func_closeuv@8 // (lua_State *L, TValue *level)
+ //| mov BASE, L:RB->base
+ //|1:
+ //| ins_next
+ dasm_put(Dst, 10285, -BCBIAS_J*4, Dt1(->openupval), Dt1(->base), Dt1(->base));
+#line 4110 "vm_x86.dasc"
+ break;
+
+ case BC_FNEW:
+ //| ins_AND // RA = dst, RD = proto const (~) (holding function prototype)
+ //|.if X64
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE // Caveat: CARG2d/CARG3d may be BASE.
+ //| mov CARG3d, [BASE-8]
+ //| mov CARG2d, [KBASE+RD*4] // Fetch GCproto *.
+ //| mov CARG1d, L:RB
+ //|.else
+ //| mov LFUNC:RA, [BASE-8]
+ //| mov PROTO:RD, [KBASE+RD*4] // Fetch GCproto *.
+ //| mov L:RB, SAVE_L
+ //| mov ARG3, LFUNC:RA
+ //| mov ARG2, PROTO:RD
+ //| mov ARG1, L:RB
+ //| mov L:RB->base, BASE
+ //|.endif
+ //| mov SAVE_PC, PC
+ //| // (lua_State *L, GCproto *pt, GCfuncL *parent)
+ //| call extern lj_func_newL_gc
+ //| // GCfuncL * returned in eax (RC).
+ //| mov BASE, L:RB->base
+ //| movzx RA, PC_RA
+ //| mov [BASE+RA*8], LFUNC:RC
+ //| mov dword [BASE+RA*8+4], LJ_TFUNC
+ //| ins_next
+ dasm_put(Dst, 10341, Dt1(->base), Dt1(->base), LJ_TFUNC);
+#line 4138 "vm_x86.dasc"
+ break;
+
+ /* -- Table ops --------------------------------------------------------- */
+
+ case BC_TNEW:
+ //| ins_AD // RA = dst, RD = hbits|asize
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE
+ //| mov RA, [DISPATCH+DISPATCH_GL(gc.total)]
+ //| cmp RA, [DISPATCH+DISPATCH_GL(gc.threshold)]
+ //| mov SAVE_PC, PC
+ //| jae >5
+ //|1:
+ //|.if X64
+ //| mov CARG3d, RD
+ //| and RD, 0x7ff
+ //| shr CARG3d, 11
+ //|.else
+ //| mov RA, RD
+ //| and RD, 0x7ff
+ //| shr RA, 11
+ //| mov ARG3, RA
+ //|.endif
+ //| cmp RD, 0x7ff
+ //| je >3
+ //|2:
+ //|.if X64
+ //| mov L:CARG1d, L:RB
+ //| mov CARG2d, RD
+ //|.else
+ //| mov ARG1, L:RB
+ //| mov ARG2, RD
+ //|.endif
+ //| call extern lj_tab_new // (lua_State *L, int32_t asize, uint32_t hbits)
+ //| // Table * returned in eax (RC).
+ //| mov BASE, L:RB->base
+ //| movzx RA, PC_RA
+ //| mov [BASE+RA*8], TAB:RC
+ //| mov dword [BASE+RA*8+4], LJ_TTAB
+ //| ins_next
+ //|3: // Turn 0x7ff into 0x801.
+ //| mov RD, 0x801
+ //| jmp <2
+ //|5:
+ //| mov L:FCARG1, L:RB
+ //| call extern lj_gc_step_fixtop@4 // (lua_State *L)
+ //| movzx RD, PC_RD
+ //| jmp <1
+ dasm_put(Dst, 10408, Dt1(->base), DISPATCH_GL(gc.total), DISPATCH_GL(gc.threshold), Dt1(->base), LJ_TTAB);
+#line 4186 "vm_x86.dasc"
+ break;
+ case BC_TDUP:
+ //| ins_AND // RA = dst, RD = table const (~) (holding template table)
+ //| mov L:RB, SAVE_L
+ //| mov RA, [DISPATCH+DISPATCH_GL(gc.total)]
+ //| mov SAVE_PC, PC
+ //| cmp RA, [DISPATCH+DISPATCH_GL(gc.threshold)]
+ //| mov L:RB->base, BASE
+ //| jae >3
+ //|2:
+ //| mov TAB:FCARG2, [KBASE+RD*4] // Caveat: FCARG2 == BASE
+ //| mov L:FCARG1, L:RB // Caveat: FCARG1 == RA
+ //| call extern lj_tab_dup@8 // (lua_State *L, Table *kt)
+ //| // Table * returned in eax (RC).
+ //| mov BASE, L:RB->base
+ //| movzx RA, PC_RA
+ //| mov [BASE+RA*8], TAB:RC
+ //| mov dword [BASE+RA*8+4], LJ_TTAB
+ //| ins_next
+ //|3:
+ //| mov L:FCARG1, L:RB
+ //| call extern lj_gc_step_fixtop@4 // (lua_State *L)
+ //| movzx RD, PC_RD // Need to reload RD.
+ //| not RDa
+ //| jmp <2
+ dasm_put(Dst, 10532, DISPATCH_GL(gc.total), DISPATCH_GL(gc.threshold), Dt1(->base), Dt1(->base), LJ_TTAB);
+#line 4211 "vm_x86.dasc"
+ break;
+
+ case BC_GGET:
+ //| ins_AND // RA = dst, RD = str const (~)
+ //| mov LFUNC:RB, [BASE-8]
+ //| mov TAB:RB, LFUNC:RB->env
+ //| mov STR:RC, [KBASE+RD*4]
+ //| jmp ->BC_TGETS_Z
+ dasm_put(Dst, 10631, Dt7(->env));
+#line 4219 "vm_x86.dasc"
+ break;
+ case BC_GSET:
+ //| ins_AND // RA = src, RD = str const (~)
+ //| mov LFUNC:RB, [BASE-8]
+ //| mov TAB:RB, LFUNC:RB->env
+ //| mov STR:RC, [KBASE+RD*4]
+ //| jmp ->BC_TSETS_Z
+ dasm_put(Dst, 10651, Dt7(->env));
+#line 4226 "vm_x86.dasc"
+ break;
+
+ case BC_TGETV:
+ //| ins_ABC // RA = dst, RB = table, RC = key
+ //| checktab RB, ->vmeta_tgetv
+ //| mov TAB:RB, [BASE+RB*8]
+ //|
+ //| // Integer key?
+ //|.if DUALNUM
+ //| checkint RC, >5
+ //| mov RC, dword [BASE+RC*8]
+ //|.else
+ //| // Convert number to int and back and compare.
+ //| checknum RC, >5
+ //| movsd xmm0, qword [BASE+RC*8]
+ //| cvttsd2si RC, xmm0
+ //| cvtsi2sd xmm1, RC
+ //| ucomisd xmm0, xmm1
+ //| jne ->vmeta_tgetv // Generic numeric key? Use fallback.
+ //|.endif
+ //| cmp RC, TAB:RB->asize // Takes care of unordered, too.
+ //| jae ->vmeta_tgetv // Not in array part? Use fallback.
+ //| shl RC, 3
+ //| add RC, TAB:RB->array
+ //| cmp dword [RC+4], LJ_TNIL // Avoid overwriting RB in fastpath.
+ //| je >2
+ //| // Get array slot.
+ //|.if X64
+ //| mov RBa, [RC]
+ //| mov [BASE+RA*8], RBa
+ //|.else
+ //| mov RB, [RC]
+ //| mov RC, [RC+4]
+ //| mov [BASE+RA*8], RB
+ //| mov [BASE+RA*8+4], RC
+ //|.endif
+ //|1:
+ //| ins_next
+ //|
+ //|2: // Check for __index if table value is nil.
+ //| cmp dword TAB:RB->metatable, 0 // Shouldn't overwrite RA for fastpath.
+ //| jz >3
+ //| mov TAB:RA, TAB:RB->metatable
+ dasm_put(Dst, 10671, LJ_TTAB, LJ_TISNUM, Dt6(->asize), Dt6(->array), LJ_TNIL, Dt6(->metatable));
+#line 4269 "vm_x86.dasc"
+ //| test byte TAB:RA->nomm, 1<vmeta_tgetv // 'no __index' flag NOT set: check.
+ //| movzx RA, PC_RA // Restore RA.
+ //|3:
+ //| mov dword [BASE+RA*8+4], LJ_TNIL
+ //| jmp <1
+ //|
+ //|5: // String key?
+ //| checkstr RC, ->vmeta_tgetv
+ //| mov STR:RC, [BASE+RC*8]
+ //| jmp ->BC_TGETS_Z
+ dasm_put(Dst, 10789, Dt6(->metatable), Dt6(->nomm), 1<vmeta_tgets
+ //| mov TAB:RB, [BASE+RB*8]
+ //|->BC_TGETS_Z: // RB = GCtab *, RC = GCstr *, refetches PC_RA.
+ //| mov RA, TAB:RB->hmask
+ //| and RA, STR:RC->hash
+ //| imul RA, #NODE
+ //| add NODE:RA, TAB:RB->node
+ //|1:
+ //| cmp dword NODE:RA->key.it, LJ_TSTR
+ //| jne >4
+ //| cmp dword NODE:RA->key.gcr, STR:RC
+ //| jne >4
+ //| // Ok, key found. Assumes: offsetof(Node, val) == 0
+ //| cmp dword [RA+4], LJ_TNIL // Avoid overwriting RB in fastpath.
+ //| je >5 // Key found, but nil value?
+ //| movzx RC, PC_RA
+ dasm_put(Dst, 10837, LJ_TTAB, Dt6(->hmask), Dt5(->hash), sizeof(Node), Dt6(->node), DtB(->key.it), LJ_TSTR, DtB(->key.gcr), LJ_TNIL);
+#line 4301 "vm_x86.dasc"
+ //| // Get node value.
+ //|.if X64
+ //| mov RBa, [RA]
+ //| mov [BASE+RC*8], RBa
+ //|.else
+ //| mov RB, [RA]
+ //| mov RA, [RA+4]
+ //| mov [BASE+RC*8], RB
+ //| mov [BASE+RC*8+4], RA
+ //|.endif
+ //|2:
+ //| ins_next
+ //|
+ //|3:
+ //| movzx RC, PC_RA
+ //| mov dword [BASE+RC*8+4], LJ_TNIL
+ //| jmp <2
+ //|
+ //|4: // Follow hash chain.
+ //| mov NODE:RA, NODE:RA->next
+ //| test NODE:RA, NODE:RA
+ //| jnz <1
+ //| // End of hash chain: key not found, nil result.
+ //|
+ //|5: // Check for __index if table value is nil.
+ //| mov TAB:RA, TAB:RB->metatable
+ //| test TAB:RA, TAB:RA
+ //| jz <3 // No metatable: done.
+ //| test byte TAB:RA->nomm, 1<vmeta_tgets // Caveat: preserve STR:RC.
+ dasm_put(Dst, 10908, LJ_TNIL, DtB(->next), Dt6(->metatable), Dt6(->nomm), 1<vmeta_tgetb
+ //| mov TAB:RB, [BASE+RB*8]
+ //| cmp RC, TAB:RB->asize
+ //| jae ->vmeta_tgetb
+ //| shl RC, 3
+ //| add RC, TAB:RB->array
+ //| cmp dword [RC+4], LJ_TNIL // Avoid overwriting RB in fastpath.
+ //| je >2
+ //| // Get array slot.
+ //|.if X64
+ //| mov RBa, [RC]
+ //| mov [BASE+RA*8], RBa
+ //|.else
+ //| mov RB, [RC]
+ //| mov RC, [RC+4]
+ //| mov [BASE+RA*8], RB
+ //| mov [BASE+RA*8+4], RC
+ //|.endif
+ //|1:
+ //| ins_next
+ //|
+ //|2: // Check for __index if table value is nil.
+ //| cmp dword TAB:RB->metatable, 0 // Shouldn't overwrite RA for fastpath.
+ //| jz >3
+ //| mov TAB:RA, TAB:RB->metatable
+ //| test byte TAB:RA->nomm, 1<vmeta_tgetb // 'no __index' flag NOT set: check.
+ //| movzx RA, PC_RA // Restore RA.
+ dasm_put(Dst, 10994, LJ_TTAB, Dt6(->asize), Dt6(->array), LJ_TNIL, Dt6(->metatable), Dt6(->metatable), Dt6(->nomm), 1<asize
+ //| jae ->vmeta_tgetr // Not in array part? Use fallback.
+ //| shl RC, 3
+ //| add RC, TAB:RB->array
+ //| // Get array slot.
+ //|->BC_TGETR_Z:
+ //|.if X64
+ //| mov RBa, [RC]
+ //| mov [BASE+RA*8], RBa
+ //|.else
+ //| mov RB, [RC]
+ //| mov RC, [RC+4]
+ //| mov [BASE+RA*8], RB
+ //| mov [BASE+RA*8+4], RC
+ //|.endif
+ //|->BC_TGETR2_Z:
+ //| ins_next
+ dasm_put(Dst, 11107, Dt6(->asize), Dt6(->array));
+#line 4392 "vm_x86.dasc"
+ break;
+
+ case BC_TSETV:
+ //| ins_ABC // RA = src, RB = table, RC = key
+ //| checktab RB, ->vmeta_tsetv
+ //| mov TAB:RB, [BASE+RB*8]
+ //|
+ //| // Integer key?
+ //|.if DUALNUM
+ //| checkint RC, >5
+ //| mov RC, dword [BASE+RC*8]
+ //|.else
+ //| // Convert number to int and back and compare.
+ //| checknum RC, >5
+ //| movsd xmm0, qword [BASE+RC*8]
+ //| cvttsd2si RC, xmm0
+ //| cvtsi2sd xmm1, RC
+ //| ucomisd xmm0, xmm1
+ //| jne ->vmeta_tsetv // Generic numeric key? Use fallback.
+ //|.endif
+ //| cmp RC, TAB:RB->asize // Takes care of unordered, too.
+ //| jae ->vmeta_tsetv
+ //| shl RC, 3
+ //| add RC, TAB:RB->array
+ //| cmp dword [RC+4], LJ_TNIL
+ //| je >3 // Previous value is nil?
+ //|1:
+ //| test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table)
+ //| jnz >7
+ //|2: // Set array slot.
+ //|.if X64
+ //| mov RBa, [BASE+RA*8]
+ dasm_put(Dst, 11169, LJ_TTAB, LJ_TISNUM, Dt6(->asize), Dt6(->array), LJ_TNIL, Dt6(->marked), LJ_GC_BLACK);
+#line 4424 "vm_x86.dasc"
+ //| mov [RC], RBa
+ //|.else
+ //| mov RB, [BASE+RA*8+4]
+ //| mov RA, [BASE+RA*8]
+ //| mov [RC+4], RB
+ //| mov [RC], RA
+ //|.endif
+ //| ins_next
+ //|
+ //|3: // Check for __newindex if previous value is nil.
+ //| cmp dword TAB:RB->metatable, 0 // Shouldn't overwrite RA for fastpath.
+ //| jz <1
+ //| mov TAB:RA, TAB:RB->metatable
+ //| test byte TAB:RA->nomm, 1<vmeta_tsetv // 'no __newindex' flag NOT set: check.
+ //| movzx RA, PC_RA // Restore RA.
+ //| jmp <1
+ //|
+ //|5: // String key?
+ //| checkstr RC, ->vmeta_tsetv
+ //| mov STR:RC, [BASE+RC*8]
+ //| jmp ->BC_TSETS_Z
+ //|
+ //|7: // Possible table write barrier for the value. Skip valiswhite check.
+ //| barrierback TAB:RB, RA
+ dasm_put(Dst, 11261, Dt6(->metatable), Dt6(->metatable), Dt6(->nomm), 1<marked), (uint8_t)~LJ_GC_BLACK);
+#line 4449 "vm_x86.dasc"
+ //| movzx RA, PC_RA // Restore RA.
+ //| jmp <2
+ dasm_put(Dst, 11345, DISPATCH_GL(gc.grayagain), DISPATCH_GL(gc.grayagain), Dt6(->gclist));
+#line 4451 "vm_x86.dasc"
+ break;
+ case BC_TSETS:
+ //| ins_ABC // RA = src, RB = table, RC = str const (~)
+ //| not RCa
+ //| mov STR:RC, [KBASE+RC*4]
+ //| checktab RB, ->vmeta_tsets
+ //| mov TAB:RB, [BASE+RB*8]
+ //|->BC_TSETS_Z: // RB = GCtab *, RC = GCstr *, refetches PC_RA.
+ //| mov RA, TAB:RB->hmask
+ //| and RA, STR:RC->hash
+ //| imul RA, #NODE
+ //| mov byte TAB:RB->nomm, 0 // Clear metamethod cache.
+ //| add NODE:RA, TAB:RB->node
+ //|1:
+ //| cmp dword NODE:RA->key.it, LJ_TSTR
+ //| jne >5
+ //| cmp dword NODE:RA->key.gcr, STR:RC
+ //| jne >5
+ //| // Ok, key found. Assumes: offsetof(Node, val) == 0
+ //| cmp dword [RA+4], LJ_TNIL
+ //| je >4 // Previous value is nil?
+ //|2:
+ //| test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table)
+ dasm_put(Dst, 11366, LJ_TTAB, Dt6(->hmask), Dt5(->hash), sizeof(Node), Dt6(->nomm), Dt6(->node), DtB(->key.it), LJ_TSTR, DtB(->key.gcr), LJ_TNIL);
+#line 4474 "vm_x86.dasc"
+ //| jnz >7
+ //|3: // Set node value.
+ //| movzx RC, PC_RA
+ //|.if X64
+ //| mov RBa, [BASE+RC*8]
+ //| mov [RA], RBa
+ //|.else
+ //| mov RB, [BASE+RC*8+4]
+ //| mov RC, [BASE+RC*8]
+ //| mov [RA+4], RB
+ //| mov [RA], RC
+ //|.endif
+ //| ins_next
+ //|
+ //|4: // Check for __newindex if previous value is nil.
+ //| cmp dword TAB:RB->metatable, 0 // Shouldn't overwrite RA for fastpath.
+ //| jz <2
+ //| mov TMP1, RA // Save RA.
+ //| mov TAB:RA, TAB:RB->metatable
+ //| test byte TAB:RA->nomm, 1<vmeta_tsets // 'no __newindex' flag NOT set: check.
+ //| mov RA, TMP1 // Restore RA.
+ //| jmp <2
+ //|
+ //|5: // Follow hash chain.
+ //| mov NODE:RA, NODE:RA->next
+ //| test NODE:RA, NODE:RA
+ //| jnz <1
+ //| // End of hash chain: key not found, add a new one.
+ //|
+ //| // But check for __newindex first.
+ //| mov TAB:RA, TAB:RB->metatable
+ dasm_put(Dst, 11443, Dt6(->marked), LJ_GC_BLACK, Dt6(->metatable), Dt6(->metatable), Dt6(->nomm), 1<next));
+#line 4506 "vm_x86.dasc"
+ //| test TAB:RA, TAB:RA
+ //| jz >6 // No metatable: continue.
+ //| test byte TAB:RA->nomm, 1<vmeta_tsets // 'no __newindex' flag NOT set: check.
+ //|6:
+ //| mov TMP1, STR:RC
+ //| mov TMP2, LJ_TSTR
+ //| mov TMP3, TAB:RB // Save TAB:RB for us.
+ //|.if X64
+ //| mov L:CARG1d, SAVE_L
+ //| mov L:CARG1d->base, BASE
+ //| lea CARG3, TMP1
+ //| mov CARG2d, TAB:RB
+ //| mov L:RB, L:CARG1d
+ //|.else
+ //| lea RC, TMP1 // Store temp. TValue in TMP1/TMP2.
+ //| mov ARG2, TAB:RB
+ //| mov L:RB, SAVE_L
+ //| mov ARG3, RC
+ //| mov ARG1, L:RB
+ //| mov L:RB->base, BASE
+ //|.endif
+ //| mov SAVE_PC, PC
+ //| call extern lj_tab_newkey // (lua_State *L, GCtab *t, TValue *k)
+ //| // Handles write barrier for the new key. TValue * returned in eax (RC).
+ //| mov BASE, L:RB->base
+ //| mov TAB:RB, TMP3 // Need TAB:RB for barrier.
+ //| mov RA, eax
+ //| jmp <2 // Must check write barrier for value.
+ //|
+ //|7: // Possible table write barrier for the value. Skip valiswhite check.
+ //| barrierback TAB:RB, RC // Destroys STR:RC.
+ //| jmp <3
+ dasm_put(Dst, 11530, Dt6(->metatable), Dt6(->nomm), 1<base), Dt1(->base), Dt6(->marked), (uint8_t)~LJ_GC_BLACK, DISPATCH_GL(gc.grayagain), DISPATCH_GL(gc.grayagain), Dt6(->gclist));
+ dasm_put(Dst, 11618);
+#line 4539 "vm_x86.dasc"
+ break;
+ case BC_TSETB:
+ //| ins_ABC // RA = src, RB = table, RC = byte literal
+ //| checktab RB, ->vmeta_tsetb
+ //| mov TAB:RB, [BASE+RB*8]
+ //| cmp RC, TAB:RB->asize
+ //| jae ->vmeta_tsetb
+ //| shl RC, 3
+ //| add RC, TAB:RB->array
+ //| cmp dword [RC+4], LJ_TNIL
+ //| je >3 // Previous value is nil?
+ //|1:
+ //| test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table)
+ //| jnz >7
+ //|2: // Set array slot.
+ //|.if X64
+ //| mov RAa, [BASE+RA*8]
+ //| mov [RC], RAa
+ //|.else
+ //| mov RB, [BASE+RA*8+4]
+ //| mov RA, [BASE+RA*8]
+ //| mov [RC+4], RB
+ //| mov [RC], RA
+ //|.endif
+ //| ins_next
+ //|
+ //|3: // Check for __newindex if previous value is nil.
+ //| cmp dword TAB:RB->metatable, 0 // Shouldn't overwrite RA for fastpath.
+ //| jz <1
+ //| mov TAB:RA, TAB:RB->metatable
+ dasm_put(Dst, 11623, LJ_TTAB, Dt6(->asize), Dt6(->array), LJ_TNIL, Dt6(->marked), LJ_GC_BLACK, Dt6(->metatable));
+#line 4569 "vm_x86.dasc"
+ //| test byte TAB:RA->nomm, 1<vmeta_tsetb // 'no __newindex' flag NOT set: check.
+ //| movzx RA, PC_RA // Restore RA.
+ //| jmp <1
+ //|
+ //|7: // Possible table write barrier for the value. Skip valiswhite check.
+ //| barrierback TAB:RB, RA
+ //| movzx RA, PC_RA // Restore RA.
+ //| jmp <2
+ dasm_put(Dst, 11718, Dt6(->metatable), Dt6(->nomm), 1<marked), (uint8_t)~LJ_GC_BLACK, DISPATCH_GL(gc.grayagain), DISPATCH_GL(gc.grayagain), Dt6(->gclist));
+#line 4578 "vm_x86.dasc"
+ break;
+ case BC_TSETR:
+ //| ins_ABC // RA = src, RB = table, RC = key
+ //| mov TAB:RB, [BASE+RB*8]
+ //|.if DUALNUM
+ //| mov RC, dword [BASE+RC*8]
+ //|.else
+ //| cvttsd2si RC, qword [BASE+RC*8]
+ //|.endif
+ //| test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table)
+ //| jnz >7
+ //|2:
+ //| cmp RC, TAB:RB->asize
+ //| jae ->vmeta_tsetr
+ //| shl RC, 3
+ //| add RC, TAB:RB->array
+ //| // Set array slot.
+ //|->BC_TSETR_Z:
+ //|.if X64
+ //| mov RBa, [BASE+RA*8]
+ //| mov [RC], RBa
+ //|.else
+ //| mov RB, [BASE+RA*8+4]
+ //| mov RA, [BASE+RA*8]
+ //| mov [RC+4], RB
+ //| mov [RC], RA
+ //|.endif
+ //| ins_next
+ //|
+ //|7: // Possible table write barrier for the value. Skip valiswhite check.
+ //| barrierback TAB:RB, RA
+ //| movzx RA, PC_RA // Restore RA.
+ //| jmp <2
+ dasm_put(Dst, 11766, Dt6(->marked), LJ_GC_BLACK, Dt6(->asize), Dt6(->array), Dt6(->marked), (uint8_t)~LJ_GC_BLACK, DISPATCH_GL(gc.grayagain), DISPATCH_GL(gc.grayagain), Dt6(->gclist));
+#line 4611 "vm_x86.dasc"
+ break;
+
+ case BC_TSETM:
+ //| ins_AD // RA = base (table at base-1), RD = num const (start index)
+ //| mov TMP1, KBASE // Need one more free register.
+ //| mov KBASE, dword [KBASE+RD*8] // Integer constant is in lo-word.
+ //|1:
+ //| lea RA, [BASE+RA*8]
+ //| mov TAB:RB, [RA-8] // Guaranteed to be a table.
+ //| test byte TAB:RB->marked, LJ_GC_BLACK // isblack(table)
+ //| jnz >7
+ //|2:
+ //| mov RD, MULTRES
+ //| sub RD, 1
+ //| jz >4 // Nothing to copy?
+ //| add RD, KBASE // Compute needed size.
+ //| cmp RD, TAB:RB->asize
+ //| ja >5 // Doesn't fit into array part?
+ //| sub RD, KBASE
+ //| shl KBASE, 3
+ //| add KBASE, TAB:RB->array
+ //|3: // Copy result slots to table.
+ //|.if X64
+ //| mov RBa, [RA]
+ //| add RA, 8
+ //| mov [KBASE], RBa
+ //|.else
+ //| mov RB, [RA]
+ //| mov [KBASE], RB
+ //| mov RB, [RA+4]
+ //| add RA, 8
+ //| mov [KBASE+4], RB
+ //|.endif
+ //| add KBASE, 8
+ //| sub RD, 1
+ //| jnz <3
+ //|4:
+ //| mov KBASE, TMP1
+ //| ins_next
+ //|
+ //|5: // Need to resize array part.
+ //|.if X64
+ //| mov L:CARG1d, SAVE_L
+ //| mov L:CARG1d->base, BASE // Caveat: CARG2d/CARG3d may be BASE.
+ //| mov CARG2d, TAB:RB
+ //| mov CARG3d, RD
+ //| mov L:RB, L:CARG1d
+ //|.else
+ //| mov ARG2, TAB:RB
+ //| mov L:RB, SAVE_L
+ //| mov L:RB->base, BASE
+ //| mov ARG3, RD
+ //| mov ARG1, L:RB
+ //|.endif
+ //| mov SAVE_PC, PC
+ //| call extern lj_tab_reasize // (lua_State *L, GCtab *t, int nasize)
+ //| mov BASE, L:RB->base
+ //| movzx RA, PC_RA // Restore RA.
+ dasm_put(Dst, 11863, Dt6(->marked), LJ_GC_BLACK, Dt6(->asize), Dt6(->array), Dt1(->base), Dt1(->base));
+#line 4669 "vm_x86.dasc"
+ //| jmp <1 // Retry.
+ //|
+ //|7: // Possible table write barrier for any value. Skip valiswhite check.
+ //| barrierback TAB:RB, RD
+ //| jmp <2
+ dasm_put(Dst, 12002, Dt6(->marked), (uint8_t)~LJ_GC_BLACK, DISPATCH_GL(gc.grayagain), DISPATCH_GL(gc.grayagain), Dt6(->gclist));
+#line 4674 "vm_x86.dasc"
+ break;
+
+ /* -- Calls and vararg handling ----------------------------------------- */
+
+ case BC_CALL: case BC_CALLM:
+ //| ins_A_C // RA = base, (RB = nresults+1,) RC = nargs+1 | extra_nargs
+ dasm_put(Dst, 9171);
+#line 4680 "vm_x86.dasc"
+ if (op == BC_CALLM) {
+ //| add NARGS:RD, MULTRES
+ dasm_put(Dst, 12033);
+#line 4682 "vm_x86.dasc"
+ }
+ //| cmp dword [BASE+RA*8+4], LJ_TFUNC
+ //| mov LFUNC:RB, [BASE+RA*8]
+ //| jne ->vmeta_call_ra
+ //| lea BASE, [BASE+RA*8+8]
+ //| ins_call
+ dasm_put(Dst, 12038, LJ_TFUNC, Dt7(->pc));
+#line 4688 "vm_x86.dasc"
+ break;
+
+ case BC_CALLMT:
+ //| ins_AD // RA = base, RD = extra_nargs
+ //| add NARGS:RD, MULTRES
+ //| // Fall through. Assumes BC_CALLT follows and ins_AD is a no-op.
+ dasm_put(Dst, 12033);
+#line 4694 "vm_x86.dasc"
+ break;
+ case BC_CALLT:
+ //| ins_AD // RA = base, RD = nargs+1
+ //| lea RA, [BASE+RA*8+8]
+ //| mov KBASE, BASE // Use KBASE for move + vmeta_call hint.
+ //| mov LFUNC:RB, [RA-8]
+ //| cmp dword [RA-4], LJ_TFUNC
+ //| jne ->vmeta_call
+ //|->BC_CALLT_Z:
+ //| mov PC, [BASE-4]
+ //| test PC, FRAME_TYPE
+ //| jnz >7
+ //|1:
+ //| mov [BASE-8], LFUNC:RB // Copy function down, reloaded below.
+ //| mov MULTRES, NARGS:RD
+ //| sub NARGS:RD, 1
+ //| jz >3
+ //|2: // Move args down.
+ //|.if X64
+ //| mov RBa, [RA]
+ //| add RA, 8
+ //| mov [KBASE], RBa
+ //|.else
+ //| mov RB, [RA]
+ //| mov [KBASE], RB
+ //| mov RB, [RA+4]
+ //| add RA, 8
+ //| mov [KBASE+4], RB
+ //|.endif
+ //| add KBASE, 8
+ //| sub NARGS:RD, 1
+ //| jnz <2
+ //|
+ //| mov LFUNC:RB, [BASE-8]
+ //|3:
+ //| mov NARGS:RD, MULTRES
+ //| cmp byte LFUNC:RB->ffid, 1 // (> FF_C) Calling a fast function?
+ //| ja >5
+ //|4:
+ //| ins_callt
+ dasm_put(Dst, 12081, LJ_TFUNC, FRAME_TYPE, Dt7(->ffid), Dt7(->pc));
+#line 4734 "vm_x86.dasc"
+ //|
+ //|5: // Tailcall to a fast function.
+ //| test PC, FRAME_TYPE // Lua frame below?
+ //| jnz <4
+ //| movzx RA, PC_RA
+ //| not RAa
+ //| mov LFUNC:KBASE, [BASE+RA*8-8] // Need to prepare KBASE.
+ //| mov KBASE, LFUNC:KBASE->pc
+ //| mov KBASE, [KBASE+PC2PROTO(k)]
+ //| jmp <4
+ //|
+ //|7: // Tailcall from a vararg function.
+ //| sub PC, FRAME_VARG
+ //| test PC, FRAME_TYPEP
+ //| jnz >8 // Vararg frame below?
+ //| sub BASE, PC // Need to relocate BASE/KBASE down.
+ //| mov KBASE, BASE
+ //| mov PC, [BASE-4]
+ //| jmp <1
+ //|8:
+ //| add PC, FRAME_VARG
+ //| jmp <1
+ dasm_put(Dst, 12179, FRAME_TYPE, Dt7(->pc), PC2PROTO(k), FRAME_VARG, FRAME_TYPEP, FRAME_VARG);
+#line 4756 "vm_x86.dasc"
+ break;
+
+ case BC_ITERC:
+ //| ins_A // RA = base, (RB = nresults+1,) RC = nargs+1 (2+1)
+ //| lea RA, [BASE+RA*8+8] // fb = base+1
+ //|.if X64
+ //| mov RBa, [RA-24] // Copy state. fb[0] = fb[-3].
+ //| mov RCa, [RA-16] // Copy control var. fb[1] = fb[-2].
+ //| mov [RA], RBa
+ //| mov [RA+8], RCa
+ //|.else
+ //| mov RB, [RA-24] // Copy state. fb[0] = fb[-3].
+ //| mov RC, [RA-20]
+ //| mov [RA], RB
+ //| mov [RA+4], RC
+ //| mov RB, [RA-16] // Copy control var. fb[1] = fb[-2].
+ //| mov RC, [RA-12]
+ //| mov [RA+8], RB
+ //| mov [RA+12], RC
+ //|.endif
+ //| mov LFUNC:RB, [RA-32] // Copy callable. fb[-1] = fb[-4]
+ //| mov RC, [RA-28]
+ //| mov [RA-8], LFUNC:RB
+ //| mov [RA-4], RC
+ //| cmp RC, LJ_TFUNC // Handle like a regular 2-arg call.
+ //| mov NARGS:RD, 2+1
+ //| jne ->vmeta_call
+ //| mov BASE, RA
+ //| ins_call
+ dasm_put(Dst, 12271, LJ_TFUNC, 2+1, Dt7(->pc));
+#line 4785 "vm_x86.dasc"
+ break;
+
+ case BC_ITERN:
+ //| ins_A // RA = base, (RB = nresults+1, RC = nargs+1 (2+1))
+ //|.if JIT
+ //| // NYI: add hotloop, record BC_ITERN.
+ //|.endif
+ //| mov TMP1, KBASE // Need two more free registers.
+ //| mov TMP2, DISPATCH
+ //| mov TAB:RB, [BASE+RA*8-16]
+ //| mov RC, [BASE+RA*8-8] // Get index from control var.
+ //| mov DISPATCH, TAB:RB->asize
+ //| add PC, 4
+ //| mov KBASE, TAB:RB->array
+ //|1: // Traverse array part.
+ //| cmp RC, DISPATCH; jae >5 // Index points after array part?
+ //| cmp dword [KBASE+RC*8+4], LJ_TNIL; je >4
+ //|.if DUALNUM
+ //| mov dword [BASE+RA*8+4], LJ_TISNUM
+ //| mov dword [BASE+RA*8], RC
+ //|.else
+ //| cvtsi2sd xmm0, RC
+ //|.endif
+ //| // Copy array slot to returned value.
+ //|.if X64
+ //| mov RBa, [KBASE+RC*8]
+ //| mov [BASE+RA*8+8], RBa
+ //|.else
+ //| mov RB, [KBASE+RC*8+4]
+ //| mov [BASE+RA*8+12], RB
+ //| mov RB, [KBASE+RC*8]
+ //| mov [BASE+RA*8+8], RB
+ //|.endif
+ //| add RC, 1
+ //| // Return array index as a numeric key.
+ //|.if DUALNUM
+ //| // See above.
+ //|.else
+ //| movsd qword [BASE+RA*8], xmm0
+ //|.endif
+ //| mov [BASE+RA*8-8], RC // Update control var.
+ //|2:
+ //| movzx RD, PC_RD // Get target from ITERL.
+ //| branchPC RD
+ //|3:
+ //| mov DISPATCH, TMP2
+ //| mov KBASE, TMP1
+ //| ins_next
+ //|
+ //|4: // Skip holes in array part.
+ //| add RC, 1
+ //| jmp <1
+ //|
+ //|5: // Traverse hash part.
+ //| sub RC, DISPATCH
+ //|6:
+ //| cmp RC, TAB:RB->hmask; ja <3 // End of iteration? Branch to ITERL+1.
+ //| imul KBASE, RC, #NODE
+ dasm_put(Dst, 12343, Dt6(->asize), Dt6(->array), LJ_TNIL, -BCBIAS_J*4, Dt6(->hmask));
+#line 4843 "vm_x86.dasc"
+ //| add NODE:KBASE, TAB:RB->node
+ //| cmp dword NODE:KBASE->val.it, LJ_TNIL; je >7
+ //| lea DISPATCH, [RC+DISPATCH+1]
+ //| // Copy key and value from hash slot.
+ //|.if X64
+ //| mov RBa, NODE:KBASE->key
+ //| mov RCa, NODE:KBASE->val
+ //| mov [BASE+RA*8], RBa
+ //| mov [BASE+RA*8+8], RCa
+ //|.else
+ //| mov RB, NODE:KBASE->key.gcr
+ //| mov RC, NODE:KBASE->key.it
+ //| mov [BASE+RA*8], RB
+ //| mov [BASE+RA*8+4], RC
+ //| mov RB, NODE:KBASE->val.gcr
+ //| mov RC, NODE:KBASE->val.it
+ //| mov [BASE+RA*8+8], RB
+ //| mov [BASE+RA*8+12], RC
+ //|.endif
+ //| mov [BASE+RA*8-8], DISPATCH
+ //| jmp <2
+ //|
+ //|7: // Skip holes in hash part.
+ //| add RC, 1
+ //| jmp <6
+ dasm_put(Dst, 12490, sizeof(Node), Dt6(->node), DtB(->val.it), LJ_TNIL, DtB(->key), DtB(->val));
+#line 4868 "vm_x86.dasc"
+ break;
+
+ case BC_ISNEXT:
+ //| ins_AD // RA = base, RD = target (points to ITERN)
+ //| cmp dword [BASE+RA*8-20], LJ_TFUNC; jne >5
+ //| mov CFUNC:RB, [BASE+RA*8-24]
+ //| cmp dword [BASE+RA*8-12], LJ_TTAB; jne >5
+ //| cmp dword [BASE+RA*8-4], LJ_TNIL; jne >5
+ //| cmp byte CFUNC:RB->ffid, FF_next_N; jne >5
+ //| branchPC RD
+ //| mov dword [BASE+RA*8-8], 0 // Initialize control var.
+ //| mov dword [BASE+RA*8-4], 0xfffe7fff
+ //|1:
+ //| ins_next
+ //|5: // Despecialize bytecode if any of the checks fail.
+ //| mov PC_OP, BC_JMP
+ //| branchPC RD
+ //| mov byte [PC], BC_ITERC
+ //| jmp <1
+ dasm_put(Dst, 12550, LJ_TFUNC, LJ_TTAB, LJ_TNIL, Dt8(->ffid), FF_next_N, -BCBIAS_J*4, BC_JMP, -BCBIAS_J*4, BC_ITERC);
+ dasm_put(Dst, 9146);
+#line 4887 "vm_x86.dasc"
+ break;
+
+ case BC_VARG:
+ //| ins_ABC // RA = base, RB = nresults+1, RC = numparams
+ //| mov TMP1, KBASE // Need one more free register.
+ //| lea KBASE, [BASE+RC*8+(8+FRAME_VARG)]
+ //| lea RA, [BASE+RA*8]
+ //| sub KBASE, [BASE-4]
+ //| // Note: KBASE may now be even _above_ BASE if nargs was < numparams.
+ //| test RB, RB
+ //| jz >5 // Copy all varargs?
+ //| lea RB, [RA+RB*8-8]
+ //| cmp KBASE, BASE // No vararg slots?
+ //| jnb >2
+ //|1: // Copy vararg slots to destination slots.
+ //|.if X64
+ //| mov RCa, [KBASE-8]
+ //| add KBASE, 8
+ //| mov [RA], RCa
+ //|.else
+ //| mov RC, [KBASE-8]
+ //| mov [RA], RC
+ //| mov RC, [KBASE-4]
+ //| add KBASE, 8
+ //| mov [RA+4], RC
+ //|.endif
+ //| add RA, 8
+ //| cmp RA, RB // All destination slots filled?
+ //| jnb >3
+ //| cmp KBASE, BASE // No more vararg slots?
+ //| jb <1
+ //|2: // Fill up remainder with nil.
+ //| mov dword [RA+4], LJ_TNIL
+ //| add RA, 8
+ //| cmp RA, RB
+ //| jb <2
+ //|3:
+ //| mov KBASE, TMP1
+ //| ins_next
+ //|
+ //|5: // Copy all varargs.
+ //| mov MULTRES, 1 // MULTRES = 0+1
+ //| mov RC, BASE
+ //| sub RC, KBASE
+ //| jbe <3 // No vararg slots?
+ //| mov RB, RC
+ //| shr RB, 3
+ //| add RB, 1
+ //| mov MULTRES, RB // MULTRES = #varargs+1
+ //| mov L:RB, SAVE_L
+ //| add RC, RA
+ //| cmp RC, L:RB->maxstack
+ //| ja >7 // Need to grow stack?
+ dasm_put(Dst, 12659, (8+FRAME_VARG), LJ_TNIL, Dt1(->maxstack));
+#line 4940 "vm_x86.dasc"
+ //|6: // Copy all vararg slots.
+ //|.if X64
+ //| mov RCa, [KBASE-8]
+ //| add KBASE, 8
+ //| mov [RA], RCa
+ //|.else
+ //| mov RC, [KBASE-8]
+ //| mov [RA], RC
+ //| mov RC, [KBASE-4]
+ //| add KBASE, 8
+ //| mov [RA+4], RC
+ //|.endif
+ //| add RA, 8
+ //| cmp KBASE, BASE // No more vararg slots?
+ //| jb <6
+ //| jmp <3
+ //|
+ //|7: // Grow stack for varargs.
+ //| mov L:RB->base, BASE
+ //| mov L:RB->top, RA
+ //| mov SAVE_PC, PC
+ //| sub KBASE, BASE // Need delta, because BASE may change.
+ //| mov FCARG2, MULTRES
+ //| sub FCARG2, 1
+ //| mov FCARG1, L:RB
+ //| call extern lj_state_growstack@8 // (lua_State *L, int n)
+ //| mov BASE, L:RB->base
+ //| mov RA, L:RB->top
+ //| add KBASE, BASE
+ //| jmp <6
+ dasm_put(Dst, 12820, Dt1(->base), Dt1(->top), Dt1(->base), Dt1(->top));
+#line 4970 "vm_x86.dasc"
+ break;
+
+ /* -- Returns ----------------------------------------------------------- */
+
+ case BC_RETM:
+ //| ins_AD // RA = results, RD = extra_nresults
+ //| add RD, MULTRES // MULTRES >=1, so RD >=1.
+ //| // Fall through. Assumes BC_RET follows and ins_AD is a no-op.
+ dasm_put(Dst, 12033);
+#line 4978 "vm_x86.dasc"
+ break;
+
+ case BC_RET: case BC_RET0: case BC_RET1:
+ //| ins_AD // RA = results, RD = nresults+1
+ if (op != BC_RET0) {
+ //| shl RA, 3
+ dasm_put(Dst, 12896);
+#line 4984 "vm_x86.dasc"
+ }
+ //|1:
+ //| mov PC, [BASE-4]
+ //| mov MULTRES, RD // Save nresults+1.
+ //| test PC, FRAME_TYPE // Check frame type marker.
+ //| jnz >7 // Not returning to a fixarg Lua func?
+ dasm_put(Dst, 12900, FRAME_TYPE);
+#line 4990 "vm_x86.dasc"
+ switch (op) {
+ case BC_RET:
+ //|->BC_RET_Z:
+ //| mov KBASE, BASE // Use KBASE for result move.
+ //| sub RD, 1
+ //| jz >3
+ //|2: // Move results down.
+ //|.if X64
+ //| mov RBa, [KBASE+RA]
+ //| mov [KBASE-8], RBa
+ //|.else
+ //| mov RB, [KBASE+RA]
+ //| mov [KBASE-8], RB
+ //| mov RB, [KBASE+RA+4]
+ //| mov [KBASE-4], RB
+ //|.endif
+ //| add KBASE, 8
+ //| sub RD, 1
+ //| jnz <2
+ //|3:
+ //| mov RD, MULTRES // Note: MULTRES may be >255.
+ //| movzx RB, PC_RB // So cannot compare with RDL!
+ //|5:
+ //| cmp RB, RD // More results expected?
+ //| ja >6
+ dasm_put(Dst, 12919);
+#line 5015 "vm_x86.dasc"
+ break;
+ case BC_RET1:
+ //|.if X64
+ //| mov RBa, [BASE+RA]
+ //| mov [BASE-8], RBa
+ //|.else
+ //| mov RB, [BASE+RA+4]
+ //| mov [BASE-4], RB
+ //| mov RB, [BASE+RA]
+ //| mov [BASE-8], RB
+ //|.endif
+ dasm_put(Dst, 12973);
+#line 5026 "vm_x86.dasc"
+ /* fallthrough */
+ case BC_RET0:
+ //|5:
+ //| cmp PC_RB, RDL // More results expected?
+ //| ja >6
+ dasm_put(Dst, 12983);
+#line 5031 "vm_x86.dasc"
+ default:
+ break;
+ }
+ //| movzx RA, PC_RA
+ //| not RAa // Note: ~RA = -(RA+1)
+ //| lea BASE, [BASE+RA*8] // base = base - (RA+1)*8
+ //| mov LFUNC:KBASE, [BASE-8]
+ //| mov KBASE, LFUNC:KBASE->pc
+ //| mov KBASE, [KBASE+PC2PROTO(k)]
+ //| ins_next
+ //|
+ //|6: // Fill up results with nil.
+ dasm_put(Dst, 12994, Dt7(->pc), PC2PROTO(k));
+#line 5043 "vm_x86.dasc"
+ if (op == BC_RET) {
+ //| mov dword [KBASE-4], LJ_TNIL // Note: relies on shifted base.
+ //| add KBASE, 8
+ dasm_put(Dst, 13042, LJ_TNIL);
+#line 5046 "vm_x86.dasc"
+ } else {
+ //| mov dword [BASE+RD*8-12], LJ_TNIL
+ dasm_put(Dst, 13053, LJ_TNIL);
+#line 5048 "vm_x86.dasc"
+ }
+ //| add RD, 1
+ //| jmp <5
+ //|
+ //|7: // Non-standard return case.
+ //| lea RB, [PC-FRAME_VARG]
+ //| test RB, FRAME_TYPEP
+ //| jnz ->vm_return
+ //| // Return from vararg function: relocate BASE down and RA up.
+ //| sub BASE, RB
+ dasm_put(Dst, 13060, -FRAME_VARG, FRAME_TYPEP);
+#line 5058 "vm_x86.dasc"
+ if (op != BC_RET0) {
+ //| add RA, RB
+ dasm_put(Dst, 13084);
+#line 5060 "vm_x86.dasc"
+ }
+ //| jmp <1
+ dasm_put(Dst, 9146);
+#line 5062 "vm_x86.dasc"
+ break;
+
+ /* -- Loops and branches ------------------------------------------------ */
+
+ //|.define FOR_IDX, [RA]; .define FOR_TIDX, dword [RA+4]
+ //|.define FOR_STOP, [RA+8]; .define FOR_TSTOP, dword [RA+12]
+ //|.define FOR_STEP, [RA+16]; .define FOR_TSTEP, dword [RA+20]
+ //|.define FOR_EXT, [RA+24]; .define FOR_TEXT, dword [RA+28]
+
+ case BC_FORL:
+ //|.if JIT
+ //| hotloop RB
+ //|.endif
+ //| // Fall through. Assumes BC_IFORL follows and ins_AJ is a no-op.
+ dasm_put(Dst, 13088, HOTCOUNT_PCMASK, GG_DISP2HOT, HOTCOUNT_LOOP);
+#line 5076 "vm_x86.dasc"
+ break;
+
+ case BC_JFORI:
+ case BC_JFORL:
+#if !LJ_HASJIT
+ break;
+#endif
+ case BC_FORI:
+ case BC_IFORL:
+ vk = (op == BC_IFORL || op == BC_JFORL);
+ //| ins_AJ // RA = base, RD = target (after end of loop or start of loop)
+ //| lea RA, [BASE+RA*8]
+ dasm_put(Dst, 13109);
+#line 5088 "vm_x86.dasc"
+ if (LJ_DUALNUM) {
+ //| cmp FOR_TIDX, LJ_TISNUM; jne >9
+ dasm_put(Dst, 13113, LJ_TISNUM);
+#line 5090 "vm_x86.dasc"
+ if (!vk) {
+ //| cmp FOR_TSTOP, LJ_TISNUM; jne ->vmeta_for
+ //| cmp FOR_TSTEP, LJ_TISNUM; jne ->vmeta_for
+ //| mov RB, dword FOR_IDX
+ //| cmp dword FOR_STEP, 0; jl >5
+ dasm_put(Dst, 13123, LJ_TISNUM, LJ_TISNUM);
+#line 5095 "vm_x86.dasc"
+ } else {
+#ifdef LUA_USE_ASSERT
+ //| cmp FOR_TSTOP, LJ_TISNUM; jne ->assert_bad_for_arg_type
+ //| cmp FOR_TSTEP, LJ_TISNUM; jne ->assert_bad_for_arg_type
+ dasm_put(Dst, 13152, LJ_TISNUM, LJ_TISNUM);
+#line 5099 "vm_x86.dasc"
+#endif
+ //| mov RB, dword FOR_STEP
+ //| test RB, RB; js >5
+ //| add RB, dword FOR_IDX; jo >1
+ //| mov dword FOR_IDX, RB
+ dasm_put(Dst, 13171);
+#line 5104 "vm_x86.dasc"
+ }
+ //| cmp RB, dword FOR_STOP
+ //| mov FOR_TEXT, LJ_TISNUM
+ //| mov dword FOR_EXT, RB
+ dasm_put(Dst, 13190, LJ_TISNUM);
+#line 5108 "vm_x86.dasc"
+ if (op == BC_FORI) {
+ //| jle >7
+ //|1:
+ //|6:
+ //| branchPC RD
+ dasm_put(Dst, 13201, -BCBIAS_J*4);
+#line 5113 "vm_x86.dasc"
+ } else if (op == BC_JFORI) {
+ //| branchPC RD
+ //| movzx RD, PC_RD
+ //| jle =>BC_JLOOP
+ //|1:
+ //|6:
+ dasm_put(Dst, 13215, -BCBIAS_J*4, BC_JLOOP);
+#line 5119 "vm_x86.dasc"
+ } else if (op == BC_IFORL) {
+ //| jg >7
+ //|6:
+ //| branchPC RD
+ //|1:
+ dasm_put(Dst, 13233, -BCBIAS_J*4);
+#line 5124 "vm_x86.dasc"
+ } else {
+ //| jle =>BC_JLOOP
+ //|1:
+ //|6:
+ dasm_put(Dst, 13225, BC_JLOOP);
+#line 5128 "vm_x86.dasc"
+ }
+ //|7:
+ //| ins_next
+ //|
+ //|5: // Invert check for negative step.
+ dasm_put(Dst, 13247);
+#line 5133 "vm_x86.dasc"
+ if (vk) {
+ //| add RB, dword FOR_IDX; jo <1
+ //| mov dword FOR_IDX, RB
+ dasm_put(Dst, 13272);
+#line 5136 "vm_x86.dasc"
+ }
+ //| cmp RB, dword FOR_STOP
+ //| mov FOR_TEXT, LJ_TISNUM
+ //| mov dword FOR_EXT, RB
+ dasm_put(Dst, 13190, LJ_TISNUM);
+#line 5140 "vm_x86.dasc"
+ if (op == BC_FORI) {
+ //| jge <7
+ dasm_put(Dst, 13281);
+#line 5142 "vm_x86.dasc"
+ } else if (op == BC_JFORI) {
+ //| branchPC RD
+ //| movzx RD, PC_RD
+ //| jge =>BC_JLOOP
+ dasm_put(Dst, 13286, -BCBIAS_J*4, BC_JLOOP);
+#line 5146 "vm_x86.dasc"
+ } else if (op == BC_IFORL) {
+ //| jl <7
+ dasm_put(Dst, 13300);
+#line 5148 "vm_x86.dasc"
+ } else {
+ //| jge =>BC_JLOOP
+ dasm_put(Dst, 13296, BC_JLOOP);
+#line 5150 "vm_x86.dasc"
+ }
+ //| jmp <6
+ //|9: // Fallback to FP variant.
+ dasm_put(Dst, 13305);
+#line 5153 "vm_x86.dasc"
+ } else if (!vk) {
+ //| cmp FOR_TIDX, LJ_TISNUM
+ dasm_put(Dst, 13312, LJ_TISNUM);
+#line 5155 "vm_x86.dasc"
+ }
+ if (!vk) {
+ //| jae ->vmeta_for
+ //| cmp FOR_TSTOP, LJ_TISNUM; jae ->vmeta_for
+ dasm_put(Dst, 13318, LJ_TISNUM);
+#line 5159 "vm_x86.dasc"
+ } else {
+#ifdef LUA_USE_ASSERT
+ //| cmp FOR_TSTOP, LJ_TISNUM; jae ->assert_bad_for_arg_type
+ //| cmp FOR_TSTEP, LJ_TISNUM; jae ->assert_bad_for_arg_type
+ dasm_put(Dst, 13332, LJ_TISNUM, LJ_TISNUM);
+#line 5163 "vm_x86.dasc"
+#endif
+ }
+ //| mov RB, FOR_TSTEP // Load type/hiword of for step.
+ dasm_put(Dst, 13351);
+#line 5166 "vm_x86.dasc"
+ if (!vk) {
+ //| cmp RB, LJ_TISNUM; jae ->vmeta_for
+ dasm_put(Dst, 13355, LJ_TISNUM);
+#line 5168 "vm_x86.dasc"
+ }
+ //| movsd xmm0, qword FOR_IDX
+ //| movsd xmm1, qword FOR_STOP
+ dasm_put(Dst, 13364);
+#line 5171 "vm_x86.dasc"
+ if (vk) {
+ //| addsd xmm0, qword FOR_STEP
+ //| movsd qword FOR_IDX, xmm0
+ //| test RB, RB; js >3
+ dasm_put(Dst, 13376);
+#line 5175 "vm_x86.dasc"
+ } else {
+ //| jl >3
+ dasm_put(Dst, 13395);
+#line 5177 "vm_x86.dasc"
+ }
+ //| ucomisd xmm1, xmm0
+ //|1:
+ //| movsd qword FOR_EXT, xmm0
+ dasm_put(Dst, 13400);
+#line 5181 "vm_x86.dasc"
+ if (op == BC_FORI) {
+ //|.if DUALNUM
+ //| jnb <7
+ //|.else
+ //| jnb >2
+ //| branchPC RD
+ //|.endif
+ dasm_put(Dst, 13413, -BCBIAS_J*4);
+#line 5188 "vm_x86.dasc"
+ } else if (op == BC_JFORI) {
+ //| branchPC RD
+ //| movzx RD, PC_RD
+ //| jnb =>BC_JLOOP
+ dasm_put(Dst, 13423, -BCBIAS_J*4, BC_JLOOP);
+#line 5192 "vm_x86.dasc"
+ } else if (op == BC_IFORL) {
+ //|.if DUALNUM
+ //| jb <7
+ //|.else
+ //| jb >2
+ //| branchPC RD
+ //|.endif
+ dasm_put(Dst, 13437, -BCBIAS_J*4);
+#line 5199 "vm_x86.dasc"
+ } else {
+ //| jnb =>BC_JLOOP
+ dasm_put(Dst, 13433, BC_JLOOP);
+#line 5201 "vm_x86.dasc"
+ }
+ //|.if DUALNUM
+ //| jmp <6
+ //|.else
+ //|2:
+ //| ins_next
+ //|.endif
+ //|
+ //|3: // Invert comparison if step is negative.
+ //| ucomisd xmm0, xmm1
+ //| jmp <1
+ dasm_put(Dst, 13447);
+#line 5212 "vm_x86.dasc"
+ break;
+
+ case BC_ITERL:
+ //|.if JIT
+ //| hotloop RB
+ //|.endif
+ //| // Fall through. Assumes BC_IITERL follows and ins_AJ is a no-op.
+ dasm_put(Dst, 13088, HOTCOUNT_PCMASK, GG_DISP2HOT, HOTCOUNT_LOOP);
+#line 5219 "vm_x86.dasc"
+ break;
+
+ case BC_JITERL:
+#if !LJ_HASJIT
+ break;
+#endif
+ case BC_IITERL:
+ //| ins_AJ // RA = base, RD = target
+ //| lea RA, [BASE+RA*8]
+ //| mov RB, [RA+4]
+ //| cmp RB, LJ_TNIL; je >1 // Stop if iterator returned nil.
+ dasm_put(Dst, 13480, LJ_TNIL);
+#line 5230 "vm_x86.dasc"
+ if (op == BC_JITERL) {
+ //| mov [RA-4], RB
+ //| mov RB, [RA]
+ //| mov [RA-8], RB
+ //| jmp =>BC_JLOOP
+ dasm_put(Dst, 13495, BC_JLOOP);
+#line 5235 "vm_x86.dasc"
+ } else {
+ //| branchPC RD // Otherwise save control var + branch.
+ //| mov RD, [RA]
+ //| mov [RA-4], RB
+ //| mov [RA-8], RD
+ dasm_put(Dst, 13509, -BCBIAS_J*4);
+#line 5240 "vm_x86.dasc"
+ }
+ //|1:
+ //| ins_next
+ dasm_put(Dst, 8432);
+#line 5243 "vm_x86.dasc"
+ break;
+
+ case BC_LOOP:
+ //| ins_A // RA = base, RD = target (loop extent)
+ //| // Note: RA/RD is only used by trace recorder to determine scope/extent
+ //| // This opcode does NOT jump, it's only purpose is to detect a hot loop.
+ //|.if JIT
+ //| hotloop RB
+ //|.endif
+ //| // Fall through. Assumes BC_ILOOP follows and ins_A is a no-op.
+ dasm_put(Dst, 13088, HOTCOUNT_PCMASK, GG_DISP2HOT, HOTCOUNT_LOOP);
+#line 5253 "vm_x86.dasc"
+ break;
+
+ case BC_ILOOP:
+ //| ins_A // RA = base, RD = target (loop extent)
+ //| ins_next
+ dasm_put(Dst, 8434);
+#line 5258 "vm_x86.dasc"
+ break;
+
+ case BC_JLOOP:
+ //|.if JIT
+ //| ins_AD // RA = base (ignored), RD = traceno
+ //| mov RA, [DISPATCH+DISPATCH_J(trace)]
+ //| mov TRACE:RD, [RA+RD*4]
+ //| mov RDa, TRACE:RD->mcode
+ //| mov L:RB, SAVE_L
+ //| mov [DISPATCH+DISPATCH_GL(jit_base)], BASE
+ //| mov [DISPATCH+DISPATCH_GL(tmpbuf.L)], L:RB
+ //| // Save additional callee-save registers only used in compiled code.
+ //|.if X64WIN
+ //| mov TMPQ, r12
+ //| mov TMPa, r13
+ //| mov CSAVE_4, r14
+ //| mov CSAVE_3, r15
+ //| mov RAa, rsp
+ //| sub rsp, 9*16+4*8
+ //| movdqa [RAa], xmm6
+ //| movdqa [RAa-1*16], xmm7
+ //| movdqa [RAa-2*16], xmm8
+ //| movdqa [RAa-3*16], xmm9
+ //| movdqa [RAa-4*16], xmm10
+ //| movdqa [RAa-5*16], xmm11
+ //| movdqa [RAa-6*16], xmm12
+ //| movdqa [RAa-7*16], xmm13
+ //| movdqa [RAa-8*16], xmm14
+ //| movdqa [RAa-9*16], xmm15
+ //|.elif X64
+ //| mov TMPQ, r12
+ //| mov TMPa, r13
+ //| sub rsp, 16
+ //|.endif
+ //| jmp RDa
+ //|.endif
+ dasm_put(Dst, 13525, DISPATCH_J(trace), DtD(->mcode), DISPATCH_GL(jit_base), DISPATCH_GL(tmpbuf.L));
+#line 5294 "vm_x86.dasc"
+ break;
+
+ case BC_JMP:
+ //| ins_AJ // RA = unused, RD = target
+ //| branchPC RD
+ //| ins_next
+ dasm_put(Dst, 13566, -BCBIAS_J*4);
+#line 5300 "vm_x86.dasc"
+ break;
+
+ /* -- Function headers -------------------------------------------------- */
+
+ /*
+ ** Reminder: A function may be called with func/args above L->maxstack,
+ ** i.e. occupying EXTRA_STACK slots. And vmeta_call may add one extra slot,
+ ** too. This means all FUNC* ops (including fast functions) must check
+ ** for stack overflow _before_ adding more slots!
+ */
+
+ case BC_FUNCF:
+ //|.if JIT
+ //| hotcall RB
+ //|.endif
+ dasm_put(Dst, 13592, HOTCOUNT_PCMASK, GG_DISP2HOT, HOTCOUNT_CALL);
+#line 5315 "vm_x86.dasc"
+ case BC_FUNCV: /* NYI: compiled vararg functions. */
+ //| // Fall through. Assumes BC_IFUNCF/BC_IFUNCV follow and ins_AD is a no-op.
+ break;
+
+ case BC_JFUNCF:
+#if !LJ_HASJIT
+ break;
+#endif
+ case BC_IFUNCF:
+ //| ins_AD // BASE = new base, RA = framesize, RD = nargs+1
+ //| mov KBASE, [PC-4+PC2PROTO(k)]
+ //| mov L:RB, SAVE_L
+ //| lea RA, [BASE+RA*8] // Top of frame.
+ //| cmp RA, L:RB->maxstack
+ //| ja ->vm_growstack_f
+ //| movzx RA, byte [PC-4+PC2PROTO(numparams)]
+ //| cmp NARGS:RD, RA // Check for missing parameters.
+ //| jbe >3
+ //|2:
+ dasm_put(Dst, 13613, -4+PC2PROTO(k), Dt1(->maxstack), -4+PC2PROTO(numparams));
+#line 5334 "vm_x86.dasc"
+ if (op == BC_JFUNCF) {
+ //| movzx RD, PC_RD
+ //| jmp =>BC_JLOOP
+ dasm_put(Dst, 13644, BC_JLOOP);
+#line 5337 "vm_x86.dasc"
+ } else {
+ //| ins_next
+ dasm_put(Dst, 8434);
+#line 5339 "vm_x86.dasc"
+ }
+ //|
+ //|3: // Clear missing parameters.
+ //| mov dword [BASE+NARGS:RD*8-4], LJ_TNIL
+ //| add NARGS:RD, 1
+ //| cmp NARGS:RD, RA
+ //| jbe <3
+ //| jmp <2
+ dasm_put(Dst, 13653, LJ_TNIL);
+#line 5347 "vm_x86.dasc"
+ break;
+
+ case BC_JFUNCV:
+#if !LJ_HASJIT
+ break;
+#endif
+ //| int3 // NYI: compiled vararg functions
+ dasm_put(Dst, 7990);
+#line 5354 "vm_x86.dasc"
+ break; /* NYI: compiled vararg functions. */
+
+ case BC_IFUNCV:
+ //| ins_AD // BASE = new base, RA = framesize, RD = nargs+1
+ //| lea RB, [NARGS:RD*8+FRAME_VARG]
+ //| lea RD, [BASE+NARGS:RD*8]
+ //| mov LFUNC:KBASE, [BASE-8]
+ //| mov [RD-4], RB // Store delta + FRAME_VARG.
+ //| mov [RD-8], LFUNC:KBASE // Store copy of LFUNC.
+ //| mov L:RB, SAVE_L
+ //| lea RA, [RD+RA*8]
+ //| cmp RA, L:RB->maxstack
+ //| ja ->vm_growstack_v // Need to grow stack.
+ //| mov RA, BASE
+ //| mov BASE, RD
+ //| movzx RB, byte [PC-4+PC2PROTO(numparams)]
+ //| test RB, RB
+ //| jz >2
+ //|1: // Copy fixarg slots up to new frame.
+ //| add RA, 8
+ //| cmp RA, BASE
+ //| jnb >3 // Less args than parameters?
+ //| mov KBASE, [RA-8]
+ //| mov [RD], KBASE
+ //| mov KBASE, [RA-4]
+ //| mov [RD+4], KBASE
+ //| add RD, 8
+ //| mov dword [RA-4], LJ_TNIL // Clear old fixarg slot (help the GC).
+ //| sub RB, 1
+ //| jnz <1
+ //|2:
+ dasm_put(Dst, 13675, FRAME_VARG, Dt1(->maxstack), -4+PC2PROTO(numparams), LJ_TNIL);
+#line 5385 "vm_x86.dasc"
+ if (op == BC_JFUNCV) {
+ //| movzx RD, PC_RD
+ //| jmp =>BC_JLOOP
+ dasm_put(Dst, 13644, BC_JLOOP);
+#line 5388 "vm_x86.dasc"
+ } else {
+ //| mov KBASE, [PC-4+PC2PROTO(k)]
+ //| ins_next
+ dasm_put(Dst, 13772, -4+PC2PROTO(k));
+#line 5391 "vm_x86.dasc"
+ }
+ //|
+ //|3: // Clear missing parameters.
+ //| mov dword [RD+4], LJ_TNIL
+ //| add RD, 8
+ //| sub RB, 1
+ //| jnz <3
+ //| jmp <2
+ dasm_put(Dst, 13797, LJ_TNIL);
+#line 5399 "vm_x86.dasc"
+ break;
+
+ case BC_FUNCC:
+ case BC_FUNCCW:
+ //| ins_AD // BASE = new base, RA = ins RA|RD (unused), RD = nargs+1
+ //| mov CFUNC:RB, [BASE-8]
+ //| mov KBASEa, CFUNC:RB->f
+ //| mov L:RB, SAVE_L
+ //| lea RD, [BASE+NARGS:RD*8-8]
+ //| mov L:RB->base, BASE
+ //| lea RA, [RD+8*LUA_MINSTACK]
+ //| cmp RA, L:RB->maxstack
+ //| mov L:RB->top, RD
+ dasm_put(Dst, 13819, Dt8(->f), Dt1(->base), 8*LUA_MINSTACK, Dt1(->maxstack), Dt1(->top));
+#line 5412 "vm_x86.dasc"
+ if (op == BC_FUNCC) {
+ //|.if X64
+ //| mov CARG1d, L:RB // Caveat: CARG1d may be RA.
+ //|.else
+ //| mov ARG1, L:RB
+ //|.endif
+ dasm_put(Dst, 13849);
+#line 5418 "vm_x86.dasc"
+ } else {
+ //|.if X64
+ //| mov CARG2, KBASEa
+ //| mov CARG1d, L:RB // Caveat: CARG1d may be RA.
+ //|.else
+ //| mov ARG2, KBASEa
+ //| mov ARG1, L:RB
+ //|.endif
+ dasm_put(Dst, 13853);
+#line 5426 "vm_x86.dasc"
+ }
+ //| ja ->vm_growstack_c // Need to grow stack.
+ //| set_vmstate C
+ dasm_put(Dst, 13861, DISPATCH_GL(vmstate), ~LJ_VMST_C);
+#line 5429 "vm_x86.dasc"
+ if (op == BC_FUNCC) {
+ //| call KBASEa // (lua_State *L)
+ dasm_put(Dst, 13871);
+#line 5431 "vm_x86.dasc"
+ } else {
+ //| // (lua_State *L, lua_CFunction f)
+ //| call aword [DISPATCH+DISPATCH_GL(wrapf)]
+ dasm_put(Dst, 13876, DISPATCH_GL(wrapf));
+#line 5434 "vm_x86.dasc"
+ }
+ //| // nresults returned in eax (RD).
+ //| mov BASE, L:RB->base
+ //| mov [DISPATCH+DISPATCH_GL(cur_L)], L:RB
+ //| set_vmstate INTERP
+ //| lea RA, [BASE+RD*8]
+ //| neg RA
+ //| add RA, L:RB->top // RA = (L->top-(L->base+nresults))*8
+ //| mov PC, [BASE-4] // Fetch PC of caller.
+ //| jmp ->vm_returnc
+ dasm_put(Dst, 13882, Dt1(->base), DISPATCH_GL(cur_L), DISPATCH_GL(vmstate), ~LJ_VMST_INTERP, Dt1(->top));
+#line 5444 "vm_x86.dasc"
+ break;
+
+ /* ---------------------------------------------------------------------- */
+
+ default:
+ fprintf(stderr, "Error: undefined opcode BC_%s\n", bc_names[op]);
+ exit(2);
+ break;
+ }
+}
+
+static int build_backend(BuildCtx *ctx)
+{
+ int op;
+ dasm_growpc(Dst, BC__MAX);
+ build_subroutines(ctx);
+ //|.code_op
+ dasm_put(Dst, 13912);
+#line 5461 "vm_x86.dasc"
+ for (op = 0; op < BC__MAX; op++)
+ build_ins(ctx, (BCOp)op, op);
+ return BC__MAX;
+}
+
+/* Emit pseudo frame-info for all assembler functions. */
+static void emit_asm_debug(BuildCtx *ctx)
+{
+ int fcofs = (int)((uint8_t *)ctx->glob[GLOB_vm_ffi_call] - ctx->code);
+#if LJ_64
+#define SZPTR "8"
+#define BSZPTR "3"
+#define REG_SP "0x7"
+#define REG_RA "0x10"
+#else
+#define SZPTR "4"
+#define BSZPTR "2"
+#define REG_SP "0x4"
+#define REG_RA "0x8"
+#endif
+ switch (ctx->mode) {
+ case BUILD_elfasm:
+ fprintf(ctx->fp, "\t.section .debug_frame,\"\",@progbits\n");
+ fprintf(ctx->fp,
+ ".Lframe0:\n"
+ "\t.long .LECIE0-.LSCIE0\n"
+ ".LSCIE0:\n"
+ "\t.long 0xffffffff\n"
+ "\t.byte 0x1\n"
+ "\t.string \"\"\n"
+ "\t.uleb128 0x1\n"
+ "\t.sleb128 -" SZPTR "\n"
+ "\t.byte " REG_RA "\n"
+ "\t.byte 0xc\n\t.uleb128 " REG_SP "\n\t.uleb128 " SZPTR "\n"
+ "\t.byte 0x80+" REG_RA "\n\t.uleb128 0x1\n"
+ "\t.align " SZPTR "\n"
+ ".LECIE0:\n\n");
+ fprintf(ctx->fp,
+ ".LSFDE0:\n"
+ "\t.long .LEFDE0-.LASFDE0\n"
+ ".LASFDE0:\n"
+ "\t.long .Lframe0\n"
+#if LJ_64
+ "\t.quad .Lbegin\n"
+ "\t.quad %d\n"
+ "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */
+ "\t.byte 0x86\n\t.uleb128 0x2\n" /* offset rbp */
+ "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset rbx */
+ "\t.byte 0x8f\n\t.uleb128 0x4\n" /* offset r15 */
+ "\t.byte 0x8e\n\t.uleb128 0x5\n" /* offset r14 */
+#if LJ_NO_UNWIND
+ "\t.byte 0x8d\n\t.uleb128 0x6\n" /* offset r13 */
+ "\t.byte 0x8c\n\t.uleb128 0x7\n" /* offset r12 */
+#endif
+#else
+ "\t.long .Lbegin\n"
+ "\t.long %d\n"
+ "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */
+ "\t.byte 0x85\n\t.uleb128 0x2\n" /* offset ebp */
+ "\t.byte 0x87\n\t.uleb128 0x3\n" /* offset edi */
+ "\t.byte 0x86\n\t.uleb128 0x4\n" /* offset esi */
+ "\t.byte 0x83\n\t.uleb128 0x5\n" /* offset ebx */
+#endif
+ "\t.align " SZPTR "\n"
+ ".LEFDE0:\n\n", fcofs, CFRAME_SIZE);
+#if LJ_HASFFI
+ fprintf(ctx->fp,
+ ".LSFDE1:\n"
+ "\t.long .LEFDE1-.LASFDE1\n"
+ ".LASFDE1:\n"
+ "\t.long .Lframe0\n"
+#if LJ_64
+ "\t.quad lj_vm_ffi_call\n"
+ "\t.quad %d\n"
+ "\t.byte 0xe\n\t.uleb128 16\n" /* def_cfa_offset */
+ "\t.byte 0x86\n\t.uleb128 0x2\n" /* offset rbp */
+ "\t.byte 0xd\n\t.uleb128 0x6\n" /* def_cfa_register rbp */
+ "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset rbx */
+#else
+ "\t.long lj_vm_ffi_call\n"
+ "\t.long %d\n"
+ "\t.byte 0xe\n\t.uleb128 8\n" /* def_cfa_offset */
+ "\t.byte 0x85\n\t.uleb128 0x2\n" /* offset ebp */
+ "\t.byte 0xd\n\t.uleb128 0x5\n" /* def_cfa_register ebp */
+ "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset ebx */
+#endif
+ "\t.align " SZPTR "\n"
+ ".LEFDE1:\n\n", (int)ctx->codesz - fcofs);
+#endif
+#if !LJ_NO_UNWIND
+#if (defined(__sun__) && defined(__svr4__))
+#if LJ_64
+ fprintf(ctx->fp, "\t.section .eh_frame,\"a\",@unwind\n");
+#else
+ fprintf(ctx->fp, "\t.section .eh_frame,\"aw\",@progbits\n");
+#endif
+#else
+ fprintf(ctx->fp, "\t.section .eh_frame,\"a\",@progbits\n");
+#endif
+ fprintf(ctx->fp,
+ ".Lframe1:\n"
+ "\t.long .LECIE1-.LSCIE1\n"
+ ".LSCIE1:\n"
+ "\t.long 0\n"
+ "\t.byte 0x1\n"
+ "\t.string \"zPR\"\n"
+ "\t.uleb128 0x1\n"
+ "\t.sleb128 -" SZPTR "\n"
+ "\t.byte " REG_RA "\n"
+ "\t.uleb128 6\n" /* augmentation length */
+ "\t.byte 0x1b\n" /* pcrel|sdata4 */
+ "\t.long lj_err_unwind_dwarf-.\n"
+ "\t.byte 0x1b\n" /* pcrel|sdata4 */
+ "\t.byte 0xc\n\t.uleb128 " REG_SP "\n\t.uleb128 " SZPTR "\n"
+ "\t.byte 0x80+" REG_RA "\n\t.uleb128 0x1\n"
+ "\t.align " SZPTR "\n"
+ ".LECIE1:\n\n");
+ fprintf(ctx->fp,
+ ".LSFDE2:\n"
+ "\t.long .LEFDE2-.LASFDE2\n"
+ ".LASFDE2:\n"
+ "\t.long .LASFDE2-.Lframe1\n"
+ "\t.long .Lbegin-.\n"
+ "\t.long %d\n"
+ "\t.uleb128 0\n" /* augmentation length */
+ "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */
+#if LJ_64
+ "\t.byte 0x86\n\t.uleb128 0x2\n" /* offset rbp */
+ "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset rbx */
+ "\t.byte 0x8f\n\t.uleb128 0x4\n" /* offset r15 */
+ "\t.byte 0x8e\n\t.uleb128 0x5\n" /* offset r14 */
+#else
+ "\t.byte 0x85\n\t.uleb128 0x2\n" /* offset ebp */
+ "\t.byte 0x87\n\t.uleb128 0x3\n" /* offset edi */
+ "\t.byte 0x86\n\t.uleb128 0x4\n" /* offset esi */
+ "\t.byte 0x83\n\t.uleb128 0x5\n" /* offset ebx */
+#endif
+ "\t.align " SZPTR "\n"
+ ".LEFDE2:\n\n", fcofs, CFRAME_SIZE);
+#if LJ_HASFFI
+ fprintf(ctx->fp,
+ ".Lframe2:\n"
+ "\t.long .LECIE2-.LSCIE2\n"
+ ".LSCIE2:\n"
+ "\t.long 0\n"
+ "\t.byte 0x1\n"
+ "\t.string \"zR\"\n"
+ "\t.uleb128 0x1\n"
+ "\t.sleb128 -" SZPTR "\n"
+ "\t.byte " REG_RA "\n"
+ "\t.uleb128 1\n" /* augmentation length */
+ "\t.byte 0x1b\n" /* pcrel|sdata4 */
+ "\t.byte 0xc\n\t.uleb128 " REG_SP "\n\t.uleb128 " SZPTR "\n"
+ "\t.byte 0x80+" REG_RA "\n\t.uleb128 0x1\n"
+ "\t.align " SZPTR "\n"
+ ".LECIE2:\n\n");
+ fprintf(ctx->fp,
+ ".LSFDE3:\n"
+ "\t.long .LEFDE3-.LASFDE3\n"
+ ".LASFDE3:\n"
+ "\t.long .LASFDE3-.Lframe2\n"
+ "\t.long lj_vm_ffi_call-.\n"
+ "\t.long %d\n"
+ "\t.uleb128 0\n" /* augmentation length */
+#if LJ_64
+ "\t.byte 0xe\n\t.uleb128 16\n" /* def_cfa_offset */
+ "\t.byte 0x86\n\t.uleb128 0x2\n" /* offset rbp */
+ "\t.byte 0xd\n\t.uleb128 0x6\n" /* def_cfa_register rbp */
+ "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset rbx */
+#else
+ "\t.byte 0xe\n\t.uleb128 8\n" /* def_cfa_offset */
+ "\t.byte 0x85\n\t.uleb128 0x2\n" /* offset ebp */
+ "\t.byte 0xd\n\t.uleb128 0x5\n" /* def_cfa_register ebp */
+ "\t.byte 0x83\n\t.uleb128 0x3\n" /* offset ebx */
+#endif
+ "\t.align " SZPTR "\n"
+ ".LEFDE3:\n\n", (int)ctx->codesz - fcofs);
+#endif
+#endif
+ break;
+#if !LJ_NO_UNWIND
+ /* Mental note: never let Apple design an assembler.
+ ** Or a linker. Or a plastic case. But I digress.
+ */
+ case BUILD_machasm: {
+#if LJ_HASFFI
+ int fcsize = 0;
+#endif
+ int i;
+ fprintf(ctx->fp, "\t.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support\n");
+ fprintf(ctx->fp,
+ "EH_frame1:\n"
+ "\t.set L$set$x,LECIEX-LSCIEX\n"
+ "\t.long L$set$x\n"
+ "LSCIEX:\n"
+ "\t.long 0\n"
+ "\t.byte 0x1\n"
+ "\t.ascii \"zPR\\0\"\n"
+ "\t.byte 0x1\n"
+ "\t.byte 128-" SZPTR "\n"
+ "\t.byte " REG_RA "\n"
+ "\t.byte 6\n" /* augmentation length */
+ "\t.byte 0x9b\n" /* indirect|pcrel|sdata4 */
+#if LJ_64
+ "\t.long _lj_err_unwind_dwarf+4@GOTPCREL\n"
+ "\t.byte 0x1b\n" /* pcrel|sdata4 */
+ "\t.byte 0xc\n\t.byte " REG_SP "\n\t.byte " SZPTR "\n"
+#else
+ "\t.long L_lj_err_unwind_dwarf$non_lazy_ptr-.\n"
+ "\t.byte 0x1b\n" /* pcrel|sdata4 */
+ "\t.byte 0xc\n\t.byte 0x5\n\t.byte 0x4\n" /* esp=5 on 32 bit MACH-O. */
+#endif
+ "\t.byte 0x80+" REG_RA "\n\t.byte 0x1\n"
+ "\t.align " BSZPTR "\n"
+ "LECIEX:\n\n");
+ for (i = 0; i < ctx->nsym; i++) {
+ const char *name = ctx->sym[i].name;
+ int32_t size = ctx->sym[i+1].ofs - ctx->sym[i].ofs;
+ if (size == 0) continue;
+#if LJ_HASFFI
+ if (!strcmp(name, "_lj_vm_ffi_call")) { fcsize = size; continue; }
+#endif
+ fprintf(ctx->fp,
+ "%s.eh:\n"
+ "LSFDE%d:\n"
+ "\t.set L$set$%d,LEFDE%d-LASFDE%d\n"
+ "\t.long L$set$%d\n"
+ "LASFDE%d:\n"
+ "\t.long LASFDE%d-EH_frame1\n"
+ "\t.long %s-.\n"
+ "\t.long %d\n"
+ "\t.byte 0\n" /* augmentation length */
+ "\t.byte 0xe\n\t.byte %d\n" /* def_cfa_offset */
+#if LJ_64
+ "\t.byte 0x86\n\t.byte 0x2\n" /* offset rbp */
+ "\t.byte 0x83\n\t.byte 0x3\n" /* offset rbx */
+ "\t.byte 0x8f\n\t.byte 0x4\n" /* offset r15 */
+ "\t.byte 0x8e\n\t.byte 0x5\n" /* offset r14 */
+#else
+ "\t.byte 0x84\n\t.byte 0x2\n" /* offset ebp (4 for MACH-O)*/
+ "\t.byte 0x87\n\t.byte 0x3\n" /* offset edi */
+ "\t.byte 0x86\n\t.byte 0x4\n" /* offset esi */
+ "\t.byte 0x83\n\t.byte 0x5\n" /* offset ebx */
+#endif
+ "\t.align " BSZPTR "\n"
+ "LEFDE%d:\n\n",
+ name, i, i, i, i, i, i, i, name, size, CFRAME_SIZE, i);
+ }
+#if LJ_HASFFI
+ if (fcsize) {
+ fprintf(ctx->fp,
+ "EH_frame2:\n"
+ "\t.set L$set$y,LECIEY-LSCIEY\n"
+ "\t.long L$set$y\n"
+ "LSCIEY:\n"
+ "\t.long 0\n"
+ "\t.byte 0x1\n"
+ "\t.ascii \"zR\\0\"\n"
+ "\t.byte 0x1\n"
+ "\t.byte 128-" SZPTR "\n"
+ "\t.byte " REG_RA "\n"
+ "\t.byte 1\n" /* augmentation length */
+#if LJ_64
+ "\t.byte 0x1b\n" /* pcrel|sdata4 */
+ "\t.byte 0xc\n\t.byte " REG_SP "\n\t.byte " SZPTR "\n"
+#else
+ "\t.byte 0x1b\n" /* pcrel|sdata4 */
+ "\t.byte 0xc\n\t.byte 0x5\n\t.byte 0x4\n" /* esp=5 on 32 bit MACH. */
+#endif
+ "\t.byte 0x80+" REG_RA "\n\t.byte 0x1\n"
+ "\t.align " BSZPTR "\n"
+ "LECIEY:\n\n");
+ fprintf(ctx->fp,
+ "_lj_vm_ffi_call.eh:\n"
+ "LSFDEY:\n"
+ "\t.set L$set$yy,LEFDEY-LASFDEY\n"
+ "\t.long L$set$yy\n"
+ "LASFDEY:\n"
+ "\t.long LASFDEY-EH_frame2\n"
+ "\t.long _lj_vm_ffi_call-.\n"
+ "\t.long %d\n"
+ "\t.byte 0\n" /* augmentation length */
+#if LJ_64
+ "\t.byte 0xe\n\t.byte 16\n" /* def_cfa_offset */
+ "\t.byte 0x86\n\t.byte 0x2\n" /* offset rbp */
+ "\t.byte 0xd\n\t.byte 0x6\n" /* def_cfa_register rbp */
+ "\t.byte 0x83\n\t.byte 0x3\n" /* offset rbx */
+#else
+ "\t.byte 0xe\n\t.byte 8\n" /* def_cfa_offset */
+ "\t.byte 0x84\n\t.byte 0x2\n" /* offset ebp (4 for MACH-O)*/
+ "\t.byte 0xd\n\t.byte 0x4\n" /* def_cfa_register ebp */
+ "\t.byte 0x83\n\t.byte 0x3\n" /* offset ebx */
+#endif
+ "\t.align " BSZPTR "\n"
+ "LEFDEY:\n\n", fcsize);
+ }
+#endif
+#if !LJ_64
+ fprintf(ctx->fp,
+ "\t.non_lazy_symbol_pointer\n"
+ "L_lj_err_unwind_dwarf$non_lazy_ptr:\n"
+ ".indirect_symbol _lj_err_unwind_dwarf\n"
+ ".long 0\n\n");
+ fprintf(ctx->fp, "\t.section __IMPORT,__jump_table,symbol_stubs,pure_instructions+self_modifying_code,5\n");
+ {
+ const char *const *xn;
+ for (xn = ctx->extnames; *xn; xn++)
+ if (strncmp(*xn, LABEL_PREFIX, sizeof(LABEL_PREFIX)-1))
+ fprintf(ctx->fp, "L_%s$stub:\n\t.indirect_symbol _%s\n\t.ascii \"\\364\\364\\364\\364\\364\"\n", *xn, *xn);
+ }
+#endif
+ fprintf(ctx->fp, ".subsections_via_symbols\n");
+ }
+ break;
+#endif
+ default: /* Difficult for other modes. */
+ break;
+ }
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/host/buildvm_asm.c b/src/host/luajit-2.1.0-beta3/src/host/buildvm_asm.c
new file mode 100644
index 00000000..ffd14903
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/host/buildvm_asm.c
@@ -0,0 +1,359 @@
+/*
+** LuaJIT VM builder: Assembler source code emitter.
+** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#include "buildvm.h"
+#include "lj_bc.h"
+
+/* ------------------------------------------------------------------------ */
+
+#if LJ_TARGET_X86ORX64
+/* Emit bytes piecewise as assembler text. */
+static void emit_asm_bytes(BuildCtx *ctx, uint8_t *p, int n)
+{
+ int i;
+ for (i = 0; i < n; i++) {
+ if ((i & 15) == 0)
+ fprintf(ctx->fp, "\t.byte %d", p[i]);
+ else
+ fprintf(ctx->fp, ",%d", p[i]);
+ if ((i & 15) == 15) putc('\n', ctx->fp);
+ }
+ if ((n & 15) != 0) putc('\n', ctx->fp);
+}
+
+/* Emit relocation */
+static void emit_asm_reloc(BuildCtx *ctx, int type, const char *sym)
+{
+ switch (ctx->mode) {
+ case BUILD_elfasm:
+ if (type)
+ fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
+ else
+ fprintf(ctx->fp, "\t.long %s\n", sym);
+ break;
+ case BUILD_coffasm:
+ fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", sym);
+ if (type)
+ fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
+ else
+ fprintf(ctx->fp, "\t.long %s\n", sym);
+ break;
+ default: /* BUILD_machasm for relative relocations handled below. */
+ fprintf(ctx->fp, "\t.long %s\n", sym);
+ break;
+ }
+}
+
+static const char *const jccnames[] = {
+ "jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "ja",
+ "js", "jns", "jpe", "jpo", "jl", "jge", "jle", "jg"
+};
+
+/* Emit x86/x64 text relocations. */
+static void emit_asm_reloc_text(BuildCtx *ctx, uint8_t *cp, int n,
+ const char *sym)
+{
+ const char *opname = NULL;
+ if (--n < 0) goto err;
+ if (cp[n] == 0xe8) {
+ opname = "call";
+ } else if (cp[n] == 0xe9) {
+ opname = "jmp";
+ } else if (cp[n] >= 0x80 && cp[n] <= 0x8f && n > 0 && cp[n-1] == 0x0f) {
+ opname = jccnames[cp[n]-0x80];
+ n--;
+ } else {
+err:
+ fprintf(stderr, "Error: unsupported opcode for %s symbol relocation.\n",
+ sym);
+ exit(1);
+ }
+ emit_asm_bytes(ctx, cp, n);
+ if (strncmp(sym+(*sym == '_'), LABEL_PREFIX, sizeof(LABEL_PREFIX)-1)) {
+ /* Various fixups for external symbols outside of our binary. */
+ if (ctx->mode == BUILD_elfasm) {
+ if (LJ_32)
+ fprintf(ctx->fp, "#if __PIC__\n\t%s lj_wrap_%s\n#else\n", opname, sym);
+ fprintf(ctx->fp, "\t%s %s@PLT\n", opname, sym);
+ if (LJ_32)
+ fprintf(ctx->fp, "#endif\n");
+ return;
+ } else if (LJ_32 && ctx->mode == BUILD_machasm) {
+ fprintf(ctx->fp, "\t%s L%s$stub\n", opname, sym);
+ return;
+ }
+ }
+ fprintf(ctx->fp, "\t%s %s\n", opname, sym);
+}
+#else
+/* Emit words piecewise as assembler text. */
+static void emit_asm_words(BuildCtx *ctx, uint8_t *p, int n)
+{
+ int i;
+ for (i = 0; i < n; i += 4) {
+ uint32_t ins = *(uint32_t *)(p+i);
+#if LJ_TARGET_ARM64 && LJ_BE
+ ins = lj_bswap(ins); /* ARM64 instructions are always little-endian. */
+#endif
+ if ((i & 15) == 0)
+ fprintf(ctx->fp, "\t.long 0x%08x", ins);
+ else
+ fprintf(ctx->fp, ",0x%08x", ins);
+ if ((i & 15) == 12) putc('\n', ctx->fp);
+ }
+ if ((n & 15) != 0) putc('\n', ctx->fp);
+}
+
+/* Emit relocation as part of an instruction. */
+static void emit_asm_wordreloc(BuildCtx *ctx, uint8_t *p, int n,
+ const char *sym)
+{
+ uint32_t ins;
+ emit_asm_words(ctx, p, n-4);
+ ins = *(uint32_t *)(p+n-4);
+#if LJ_TARGET_ARM
+ if ((ins & 0xff000000u) == 0xfa000000u) {
+ fprintf(ctx->fp, "\tblx %s\n", sym);
+ } else if ((ins & 0x0e000000u) == 0x0a000000u) {
+ fprintf(ctx->fp, "\t%s%.2s %s\n", (ins & 0x01000000u) ? "bl" : "b",
+ &"eqnecsccmiplvsvchilsgeltgtle"[2*(ins >> 28)], sym);
+ } else {
+ fprintf(stderr,
+ "Error: unsupported opcode %08x for %s symbol relocation.\n",
+ ins, sym);
+ exit(1);
+ }
+#elif LJ_TARGET_ARM64
+ if ((ins >> 26) == 0x25u) {
+ fprintf(ctx->fp, "\tbl %s\n", sym);
+ } else {
+ fprintf(stderr,
+ "Error: unsupported opcode %08x for %s symbol relocation.\n",
+ ins, sym);
+ exit(1);
+ }
+#elif LJ_TARGET_PPC
+#if LJ_TARGET_PS3
+#define TOCPREFIX "."
+#else
+#define TOCPREFIX ""
+#endif
+ if ((ins >> 26) == 16) {
+ fprintf(ctx->fp, "\t%s %d, %d, " TOCPREFIX "%s\n",
+ (ins & 1) ? "bcl" : "bc", (ins >> 21) & 31, (ins >> 16) & 31, sym);
+ } else if ((ins >> 26) == 18) {
+#if LJ_ARCH_PPC64
+ const char *suffix = strchr(sym, '@');
+ if (suffix && suffix[1] == 'h') {
+ fprintf(ctx->fp, "\taddis 11, 2, %s\n", sym);
+ } else if (suffix && suffix[1] == 'l') {
+ fprintf(ctx->fp, "\tld 12, %s\n", sym);
+ } else
+#endif
+ fprintf(ctx->fp, "\t%s " TOCPREFIX "%s\n", (ins & 1) ? "bl" : "b", sym);
+ } else {
+ fprintf(stderr,
+ "Error: unsupported opcode %08x for %s symbol relocation.\n",
+ ins, sym);
+ exit(1);
+ }
+#elif LJ_TARGET_MIPS
+ fprintf(stderr,
+ "Error: unsupported opcode %08x for %s symbol relocation.\n",
+ ins, sym);
+ exit(1);
+#else
+#error "missing relocation support for this architecture"
+#endif
+}
+#endif
+
+#if LJ_TARGET_ARM
+#define ELFASM_PX "%%"
+#else
+#define ELFASM_PX "@"
+#endif
+
+/* Emit an assembler label. */
+static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc)
+{
+ switch (ctx->mode) {
+ case BUILD_elfasm:
+#if LJ_TARGET_PS3
+ if (!strncmp(name, "lj_vm_", 6) &&
+ strcmp(name, ctx->beginsym) &&
+ !strstr(name, "hook")) {
+ fprintf(ctx->fp,
+ "\n\t.globl %s\n"
+ "\t.section \".opd\",\"aw\"\n"
+ "%s:\n"
+ "\t.long .%s,.TOC.@tocbase32\n"
+ "\t.size %s,8\n"
+ "\t.previous\n"
+ "\t.globl .%s\n"
+ "\t.hidden .%s\n"
+ "\t.type .%s, " ELFASM_PX "function\n"
+ "\t.size .%s, %d\n"
+ ".%s:\n",
+ name, name, name, name, name, name, name, name, size, name);
+ break;
+ }
+#endif
+ fprintf(ctx->fp,
+ "\n\t.globl %s\n"
+ "\t.hidden %s\n"
+ "\t.type %s, " ELFASM_PX "%s\n"
+ "\t.size %s, %d\n"
+ "%s:\n",
+ name, name, name, isfunc ? "function" : "object", name, size, name);
+ break;
+ case BUILD_coffasm:
+ fprintf(ctx->fp, "\n\t.globl %s\n", name);
+ if (isfunc)
+ fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", name);
+ fprintf(ctx->fp, "%s:\n", name);
+ break;
+ case BUILD_machasm:
+ fprintf(ctx->fp,
+ "\n\t.private_extern %s\n"
+ "\t.no_dead_strip %s\n"
+ "%s:\n", name, name, name);
+ break;
+ default:
+ break;
+ }
+}
+
+/* Emit alignment. */
+static void emit_asm_align(BuildCtx *ctx, int bits)
+{
+ switch (ctx->mode) {
+ case BUILD_elfasm:
+ case BUILD_coffasm:
+ fprintf(ctx->fp, "\t.p2align %d\n", bits);
+ break;
+ case BUILD_machasm:
+ fprintf(ctx->fp, "\t.align %d\n", bits);
+ break;
+ default:
+ break;
+ }
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* Emit assembler source code. */
+void emit_asm(BuildCtx *ctx)
+{
+ int i, rel;
+
+ fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch);
+#if LJ_ARCH_PPC64
+ fprintf(ctx->fp, "\t.abiversion 2\n");
+#endif
+ fprintf(ctx->fp, "\t.text\n");
+ emit_asm_align(ctx, 4);
+
+#if LJ_TARGET_PS3
+ emit_asm_label(ctx, ctx->beginsym, ctx->codesz, 0);
+#else
+ emit_asm_label(ctx, ctx->beginsym, 0, 0);
+#endif
+ if (ctx->mode != BUILD_machasm)
+ fprintf(ctx->fp, ".Lbegin:\n");
+
+#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
+ /* This should really be moved into buildvm_arm.dasc. */
+#if LJ_ARCH_HASFPU
+ fprintf(ctx->fp,
+ ".fnstart\n"
+ ".save {r5, r6, r7, r8, r9, r10, r11, lr}\n"
+ ".vsave {d8-d15}\n"
+ ".save {r4}\n"
+ ".pad #28\n");
+#else
+ fprintf(ctx->fp,
+ ".fnstart\n"
+ ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
+ ".pad #28\n");
+#endif
+#endif
+#if LJ_TARGET_MIPS
+ fprintf(ctx->fp, ".set nomips16\n.abicalls\n.set noreorder\n.set nomacro\n");
+#endif
+
+ for (i = rel = 0; i < ctx->nsym; i++) {
+ int32_t ofs = ctx->sym[i].ofs;
+ int32_t next = ctx->sym[i+1].ofs;
+#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND && LJ_HASFFI
+ if (!strcmp(ctx->sym[i].name, "lj_vm_ffi_call"))
+ fprintf(ctx->fp,
+ ".globl lj_err_unwind_arm\n"
+ ".personality lj_err_unwind_arm\n"
+ ".fnend\n"
+ ".fnstart\n"
+ ".save {r4, r5, r11, lr}\n"
+ ".setfp r11, sp\n");
+#endif
+ emit_asm_label(ctx, ctx->sym[i].name, next - ofs, 1);
+ while (rel < ctx->nreloc && ctx->reloc[rel].ofs <= next) {
+ BuildReloc *r = &ctx->reloc[rel];
+ int n = r->ofs - ofs;
+#if LJ_TARGET_X86ORX64
+ if (r->type != 0 &&
+ (ctx->mode == BUILD_elfasm || ctx->mode == BUILD_machasm)) {
+ emit_asm_reloc_text(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
+ } else {
+ emit_asm_bytes(ctx, ctx->code+ofs, n);
+ emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]);
+ }
+ ofs += n+4;
+#else
+ emit_asm_wordreloc(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
+ ofs += n;
+#endif
+ rel++;
+ }
+#if LJ_TARGET_X86ORX64
+ emit_asm_bytes(ctx, ctx->code+ofs, next-ofs);
+#else
+ emit_asm_words(ctx, ctx->code+ofs, next-ofs);
+#endif
+ }
+
+#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
+ fprintf(ctx->fp,
+#if !LJ_HASFFI
+ ".globl lj_err_unwind_arm\n"
+ ".personality lj_err_unwind_arm\n"
+#endif
+ ".fnend\n");
+#endif
+
+ fprintf(ctx->fp, "\n");
+ switch (ctx->mode) {
+ case BUILD_elfasm:
+#if !(LJ_TARGET_PS3 || LJ_TARGET_PSVITA)
+ fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n");
+#endif
+#if LJ_TARGET_PPC && !LJ_TARGET_PS3
+ /* Hard-float ABI. */
+ fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n");
+#endif
+ /* fallthrough */
+ case BUILD_coffasm:
+ fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident);
+ break;
+ case BUILD_machasm:
+ fprintf(ctx->fp,
+ "\t.cstring\n"
+ "\t.ascii \"%s\\0\"\n", ctx->dasm_ident);
+ break;
+ default:
+ break;
+ }
+ fprintf(ctx->fp, "\n");
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/host/buildvm_asm.o b/src/host/luajit-2.1.0-beta3/src/host/buildvm_asm.o
new file mode 100644
index 00000000..486419f7
Binary files /dev/null and b/src/host/luajit-2.1.0-beta3/src/host/buildvm_asm.o differ
diff --git a/src/host/luajit-2.1.0-beta3/src/host/buildvm_fold.c b/src/host/luajit-2.1.0-beta3/src/host/buildvm_fold.c
new file mode 100644
index 00000000..d579f4d4
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/host/buildvm_fold.c
@@ -0,0 +1,229 @@
+/*
+** LuaJIT VM builder: IR folding hash table generator.
+** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#include "buildvm.h"
+#include "lj_obj.h"
+#include "lj_ir.h"
+
+/* Context for the folding hash table generator. */
+static int lineno;
+static uint32_t funcidx;
+static uint32_t foldkeys[BUILD_MAX_FOLD];
+static uint32_t nkeys;
+
+/* Try to fill the hash table with keys using the hash parameters. */
+static int tryhash(uint32_t *htab, uint32_t sz, uint32_t r, int dorol)
+{
+ uint32_t i;
+ if (dorol && ((r & 31) == 0 || (r>>5) == 0))
+ return 0; /* Avoid zero rotates. */
+ memset(htab, 0xff, (sz+1)*sizeof(uint32_t));
+ for (i = 0; i < nkeys; i++) {
+ uint32_t key = foldkeys[i];
+ uint32_t k = key & 0xffffff;
+ uint32_t h = (dorol ? lj_rol(lj_rol(k, r>>5) - k, r&31) :
+ (((k << (r>>5)) - k) << (r&31))) % sz;
+ if (htab[h] != 0xffffffff) { /* Collision on primary slot. */
+ if (htab[h+1] != 0xffffffff) { /* Collision on secondary slot. */
+ /* Try to move the colliding key, if possible. */
+ if (h < sz-1 && htab[h+2] == 0xffffffff) {
+ uint32_t k2 = htab[h+1] & 0xffffff;
+ uint32_t h2 = (dorol ? lj_rol(lj_rol(k2, r>>5) - k2, r&31) :
+ (((k2 << (r>>5)) - k2) << (r&31))) % sz;
+ if (h2 != h+1) return 0; /* Cannot resolve collision. */
+ htab[h+2] = htab[h+1]; /* Move colliding key to secondary slot. */
+ } else {
+ return 0; /* Collision. */
+ }
+ }
+ htab[h+1] = key;
+ } else {
+ htab[h] = key;
+ }
+ }
+ return 1; /* Success, all keys could be stored. */
+}
+
+/* Print the generated hash table. */
+static void printhash(BuildCtx *ctx, uint32_t *htab, uint32_t sz)
+{
+ uint32_t i;
+ fprintf(ctx->fp, "static const uint32_t fold_hash[%d] = {\n0x%08x",
+ sz+1, htab[0]);
+ for (i = 1; i < sz+1; i++)
+ fprintf(ctx->fp, ",\n0x%08x", htab[i]);
+ fprintf(ctx->fp, "\n};\n\n");
+}
+
+/* Exhaustive search for the shortest semi-perfect hash table. */
+static void makehash(BuildCtx *ctx)
+{
+ uint32_t htab[BUILD_MAX_FOLD*2+1];
+ uint32_t sz, r;
+ /* Search for the smallest hash table with an odd size. */
+ for (sz = (nkeys|1); sz < BUILD_MAX_FOLD*2; sz += 2) {
+ /* First try all shift hash combinations. */
+ for (r = 0; r < 32*32; r++) {
+ if (tryhash(htab, sz, r, 0)) {
+ printhash(ctx, htab, sz);
+ fprintf(ctx->fp,
+ "#define fold_hashkey(k)\t(((((k)<<%u)-(k))<<%u)%%%u)\n\n",
+ r>>5, r&31, sz);
+ return;
+ }
+ }
+ /* Then try all rotate hash combinations. */
+ for (r = 0; r < 32*32; r++) {
+ if (tryhash(htab, sz, r, 1)) {
+ printhash(ctx, htab, sz);
+ fprintf(ctx->fp,
+ "#define fold_hashkey(k)\t(lj_rol(lj_rol((k),%u)-(k),%u)%%%u)\n\n",
+ r>>5, r&31, sz);
+ return;
+ }
+ }
+ }
+ fprintf(stderr, "Error: search for perfect hash failed\n");
+ exit(1);
+}
+
+/* Parse one token of a fold rule. */
+static uint32_t nexttoken(char **pp, int allowlit, int allowany)
+{
+ char *p = *pp;
+ if (p) {
+ uint32_t i;
+ char *q = strchr(p, ' ');
+ if (q) *q++ = '\0';
+ *pp = q;
+ if (allowlit && !strncmp(p, "IRFPM_", 6)) {
+ for (i = 0; irfpm_names[i]; i++)
+ if (!strcmp(irfpm_names[i], p+6))
+ return i;
+ } else if (allowlit && !strncmp(p, "IRFL_", 5)) {
+ for (i = 0; irfield_names[i]; i++)
+ if (!strcmp(irfield_names[i], p+5))
+ return i;
+ } else if (allowlit && !strncmp(p, "IRCALL_", 7)) {
+ for (i = 0; ircall_names[i]; i++)
+ if (!strcmp(ircall_names[i], p+7))
+ return i;
+ } else if (allowlit && !strncmp(p, "IRCONV_", 7)) {
+ for (i = 0; irt_names[i]; i++) {
+ const char *r = strchr(p+7, '_');
+ if (r && !strncmp(irt_names[i], p+7, r-(p+7))) {
+ uint32_t j;
+ for (j = 0; irt_names[j]; j++)
+ if (!strcmp(irt_names[j], r+1))
+ return (i << 5) + j;
+ }
+ }
+ } else if (allowlit && *p >= '0' && *p <= '9') {
+ for (i = 0; *p >= '0' && *p <= '9'; p++)
+ i = i*10 + (*p - '0');
+ if (*p == '\0')
+ return i;
+ } else if (allowany && !strcmp("any", p)) {
+ return allowany;
+ } else {
+ for (i = 0; ir_names[i]; i++)
+ if (!strcmp(ir_names[i], p))
+ return i;
+ }
+ fprintf(stderr, "Error: bad fold definition token \"%s\" at line %d\n", p, lineno);
+ exit(1);
+ }
+ return 0;
+}
+
+/* Parse a fold rule. */
+static void foldrule(char *p)
+{
+ uint32_t op = nexttoken(&p, 0, 0);
+ uint32_t left = nexttoken(&p, 0, 0x7f);
+ uint32_t right = nexttoken(&p, 1, 0x3ff);
+ uint32_t key = (funcidx << 24) | (op << 17) | (left << 10) | right;
+ uint32_t i;
+ if (nkeys >= BUILD_MAX_FOLD) {
+ fprintf(stderr, "Error: too many fold rules, increase BUILD_MAX_FOLD.\n");
+ exit(1);
+ }
+ /* Simple insertion sort to detect duplicates. */
+ for (i = nkeys; i > 0; i--) {
+ if ((foldkeys[i-1]&0xffffff) < (key & 0xffffff))
+ break;
+ if ((foldkeys[i-1]&0xffffff) == (key & 0xffffff)) {
+ fprintf(stderr, "Error: duplicate fold definition at line %d\n", lineno);
+ exit(1);
+ }
+ foldkeys[i] = foldkeys[i-1];
+ }
+ foldkeys[i] = key;
+ nkeys++;
+}
+
+/* Emit C source code for IR folding hash table. */
+void emit_fold(BuildCtx *ctx)
+{
+ char buf[256]; /* We don't care about analyzing lines longer than that. */
+ const char *fname = ctx->args[0];
+ FILE *fp;
+
+ if (fname == NULL) {
+ fprintf(stderr, "Error: missing input filename\n");
+ exit(1);
+ }
+
+ if (fname[0] == '-' && fname[1] == '\0') {
+ fp = stdin;
+ } else {
+ fp = fopen(fname, "r");
+ if (!fp) {
+ fprintf(stderr, "Error: cannot open input file '%s': %s\n",
+ fname, strerror(errno));
+ exit(1);
+ }
+ }
+
+ fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
+ fprintf(ctx->fp, "static const FoldFunc fold_func[] = {\n");
+
+ lineno = 0;
+ funcidx = 0;
+ nkeys = 0;
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ lineno++;
+ /* The prefix must be at the start of a line, otherwise it's ignored. */
+ if (!strncmp(buf, FOLDDEF_PREFIX, sizeof(FOLDDEF_PREFIX)-1)) {
+ char *p = buf+sizeof(FOLDDEF_PREFIX)-1;
+ char *q = strchr(p, ')');
+ if (p[0] == '(' && q) {
+ p++;
+ *q = '\0';
+ foldrule(p);
+ } else if ((p[0] == 'F' || p[0] == 'X') && p[1] == '(' && q) {
+ p += 2;
+ *q = '\0';
+ if (funcidx)
+ fprintf(ctx->fp, ",\n");
+ if (p[-2] == 'X')
+ fprintf(ctx->fp, " %s", p);
+ else
+ fprintf(ctx->fp, " fold_%s", p);
+ funcidx++;
+ } else {
+ buf[strlen(buf)-1] = '\0';
+ fprintf(stderr, "Error: unknown fold definition tag %s%s at line %d\n",
+ FOLDDEF_PREFIX, p, lineno);
+ exit(1);
+ }
+ }
+ }
+ fclose(fp);
+ fprintf(ctx->fp, "\n};\n\n");
+
+ makehash(ctx);
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/host/buildvm_fold.o b/src/host/luajit-2.1.0-beta3/src/host/buildvm_fold.o
new file mode 100644
index 00000000..154d5c0d
Binary files /dev/null and b/src/host/luajit-2.1.0-beta3/src/host/buildvm_fold.o differ
diff --git a/src/host/luajit-2.1.0-beta3/src/host/buildvm_lib.c b/src/host/luajit-2.1.0-beta3/src/host/buildvm_lib.c
new file mode 100644
index 00000000..2956fdb6
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/host/buildvm_lib.c
@@ -0,0 +1,457 @@
+/*
+** LuaJIT VM builder: library definition compiler.
+** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#include "buildvm.h"
+#include "lj_obj.h"
+#include "lj_bc.h"
+#include "lj_lib.h"
+#include "buildvm_libbc.h"
+
+/* Context for library definitions. */
+static uint8_t obuf[8192];
+static uint8_t *optr;
+static char modname[80];
+static size_t modnamelen;
+static char funcname[80];
+static int modstate, regfunc;
+static int ffid, recffid, ffasmfunc;
+
+enum {
+ REGFUNC_OK,
+ REGFUNC_NOREG,
+ REGFUNC_NOREGUV
+};
+
+static void libdef_name(const char *p, int kind)
+{
+ size_t n = strlen(p);
+ if (kind != LIBINIT_STRING) {
+ if (n > modnamelen && p[modnamelen] == '_' &&
+ !strncmp(p, modname, modnamelen)) {
+ p += modnamelen+1;
+ n -= modnamelen+1;
+ }
+ }
+ if (n > LIBINIT_MAXSTR) {
+ fprintf(stderr, "Error: string too long: '%s'\n", p);
+ exit(1);
+ }
+ if (optr+1+n+2 > obuf+sizeof(obuf)) { /* +2 for caller. */
+ fprintf(stderr, "Error: output buffer overflow\n");
+ exit(1);
+ }
+ *optr++ = (uint8_t)(n | kind);
+ memcpy(optr, p, n);
+ optr += n;
+}
+
+static void libdef_endmodule(BuildCtx *ctx)
+{
+ if (modstate != 0) {
+ char line[80];
+ const uint8_t *p;
+ int n;
+ if (modstate == 1)
+ fprintf(ctx->fp, " (lua_CFunction)0");
+ fprintf(ctx->fp, "\n};\n");
+ fprintf(ctx->fp, "static const uint8_t %s%s[] = {\n",
+ LABEL_PREFIX_LIBINIT, modname);
+ line[0] = '\0';
+ for (n = 0, p = obuf; p < optr; p++) {
+ n += sprintf(line+n, "%d,", *p);
+ if (n >= 75) {
+ fprintf(ctx->fp, "%s\n", line);
+ n = 0;
+ line[0] = '\0';
+ }
+ }
+ fprintf(ctx->fp, "%s%d\n};\n#endif\n\n", line, LIBINIT_END);
+ }
+}
+
+static void libdef_module(BuildCtx *ctx, char *p, int arg)
+{
+ UNUSED(arg);
+ if (ctx->mode == BUILD_libdef) {
+ libdef_endmodule(ctx);
+ optr = obuf;
+ *optr++ = (uint8_t)ffid;
+ *optr++ = (uint8_t)ffasmfunc;
+ *optr++ = 0; /* Hash table size. */
+ modstate = 1;
+ fprintf(ctx->fp, "#ifdef %sMODULE_%s\n", LIBDEF_PREFIX, p);
+ fprintf(ctx->fp, "#undef %sMODULE_%s\n", LIBDEF_PREFIX, p);
+ fprintf(ctx->fp, "static const lua_CFunction %s%s[] = {\n",
+ LABEL_PREFIX_LIBCF, p);
+ }
+ modnamelen = strlen(p);
+ if (modnamelen > sizeof(modname)-1) {
+ fprintf(stderr, "Error: module name too long: '%s'\n", p);
+ exit(1);
+ }
+ strcpy(modname, p);
+}
+
+static int find_ffofs(BuildCtx *ctx, const char *name)
+{
+ int i;
+ for (i = 0; i < ctx->nglob; i++) {
+ const char *gl = ctx->globnames[i];
+ if (gl[0] == 'f' && gl[1] == 'f' && gl[2] == '_' && !strcmp(gl+3, name)) {
+ return (int)((uint8_t *)ctx->glob[i] - ctx->code);
+ }
+ }
+ fprintf(stderr, "Error: undefined fast function %s%s\n",
+ LABEL_PREFIX_FF, name);
+ exit(1);
+}
+
+static void libdef_func(BuildCtx *ctx, char *p, int arg)
+{
+ if (arg != LIBINIT_CF)
+ ffasmfunc++;
+ if (ctx->mode == BUILD_libdef) {
+ if (modstate == 0) {
+ fprintf(stderr, "Error: no module for function definition %s\n", p);
+ exit(1);
+ }
+ if (regfunc == REGFUNC_NOREG) {
+ if (optr+1 > obuf+sizeof(obuf)) {
+ fprintf(stderr, "Error: output buffer overflow\n");
+ exit(1);
+ }
+ *optr++ = LIBINIT_FFID;
+ } else {
+ if (arg != LIBINIT_ASM_) {
+ if (modstate != 1) fprintf(ctx->fp, ",\n");
+ modstate = 2;
+ fprintf(ctx->fp, " %s%s", arg ? LABEL_PREFIX_FFH : LABEL_PREFIX_CF, p);
+ }
+ if (regfunc != REGFUNC_NOREGUV) obuf[2]++; /* Bump hash table size. */
+ libdef_name(regfunc == REGFUNC_NOREGUV ? "" : p, arg);
+ }
+ } else if (ctx->mode == BUILD_ffdef) {
+ fprintf(ctx->fp, "FFDEF(%s)\n", p);
+ } else if (ctx->mode == BUILD_recdef) {
+ if (strlen(p) > sizeof(funcname)-1) {
+ fprintf(stderr, "Error: function name too long: '%s'\n", p);
+ exit(1);
+ }
+ strcpy(funcname, p);
+ } else if (ctx->mode == BUILD_vmdef) {
+ int i;
+ for (i = 1; p[i] && modname[i-1]; i++)
+ if (p[i] == '_') p[i] = '.';
+ fprintf(ctx->fp, "\"%s\",\n", p);
+ } else if (ctx->mode == BUILD_bcdef) {
+ if (arg != LIBINIT_CF)
+ fprintf(ctx->fp, ",\n%d", find_ffofs(ctx, p));
+ }
+ ffid++;
+ regfunc = REGFUNC_OK;
+}
+
+static uint8_t *libdef_uleb128(uint8_t *p, uint32_t *vv)
+{
+ uint32_t v = *p++;
+ if (v >= 0x80) {
+ int sh = 0; v &= 0x7f;
+ do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80);
+ }
+ *vv = v;
+ return p;
+}
+
+static void libdef_fixupbc(uint8_t *p)
+{
+ uint32_t i, sizebc;
+ p += 4;
+ p = libdef_uleb128(p, &sizebc);
+ p = libdef_uleb128(p, &sizebc);
+ p = libdef_uleb128(p, &sizebc);
+ for (i = 0; i < sizebc; i++, p += 4) {
+ uint8_t op = p[libbc_endian ? 3 : 0];
+ uint8_t ra = p[libbc_endian ? 2 : 1];
+ uint8_t rc = p[libbc_endian ? 1 : 2];
+ uint8_t rb = p[libbc_endian ? 0 : 3];
+ if (!LJ_DUALNUM && op == BC_ISTYPE && rc == ~LJ_TNUMX+1) {
+ op = BC_ISNUM; rc++;
+ }
+ p[LJ_ENDIAN_SELECT(0, 3)] = op;
+ p[LJ_ENDIAN_SELECT(1, 2)] = ra;
+ p[LJ_ENDIAN_SELECT(2, 1)] = rc;
+ p[LJ_ENDIAN_SELECT(3, 0)] = rb;
+ }
+}
+
+static void libdef_lua(BuildCtx *ctx, char *p, int arg)
+{
+ UNUSED(arg);
+ if (ctx->mode == BUILD_libdef) {
+ int i;
+ for (i = 0; libbc_map[i].name != NULL; i++) {
+ if (!strcmp(libbc_map[i].name, p)) {
+ int ofs = libbc_map[i].ofs;
+ int len = libbc_map[i+1].ofs - ofs;
+ obuf[2]++; /* Bump hash table size. */
+ *optr++ = LIBINIT_LUA;
+ libdef_name(p, 0);
+ memcpy(optr, libbc_code + ofs, len);
+ libdef_fixupbc(optr);
+ optr += len;
+ return;
+ }
+ }
+ fprintf(stderr, "Error: missing libbc definition for %s\n", p);
+ exit(1);
+ }
+}
+
+static uint32_t find_rec(char *name)
+{
+ char *p = (char *)obuf;
+ uint32_t n;
+ for (n = 2; *p; n++) {
+ if (strcmp(p, name) == 0)
+ return n;
+ p += strlen(p)+1;
+ }
+ if (p+strlen(name)+1 >= (char *)obuf+sizeof(obuf)) {
+ fprintf(stderr, "Error: output buffer overflow\n");
+ exit(1);
+ }
+ strcpy(p, name);
+ return n;
+}
+
+static void libdef_rec(BuildCtx *ctx, char *p, int arg)
+{
+ UNUSED(arg);
+ if (ctx->mode == BUILD_recdef) {
+ char *q;
+ uint32_t n;
+ for (; recffid+1 < ffid; recffid++)
+ fprintf(ctx->fp, ",\n0");
+ recffid = ffid;
+ if (*p == '.') p = funcname;
+ q = strchr(p, ' ');
+ if (q) *q++ = '\0';
+ n = find_rec(p);
+ if (q)
+ fprintf(ctx->fp, ",\n0x%02x00+(%s)", n, q);
+ else
+ fprintf(ctx->fp, ",\n0x%02x00", n);
+ }
+}
+
+static void memcpy_endian(void *dst, void *src, size_t n)
+{
+ union { uint8_t b; uint32_t u; } host_endian;
+ host_endian.u = 1;
+ if (host_endian.b == LJ_ENDIAN_SELECT(1, 0)) {
+ memcpy(dst, src, n);
+ } else {
+ size_t i;
+ for (i = 0; i < n; i++)
+ ((uint8_t *)dst)[i] = ((uint8_t *)src)[n-i-1];
+ }
+}
+
+static void libdef_push(BuildCtx *ctx, char *p, int arg)
+{
+ UNUSED(arg);
+ if (ctx->mode == BUILD_libdef) {
+ int len = (int)strlen(p);
+ if (*p == '"') {
+ if (len > 1 && p[len-1] == '"') {
+ p[len-1] = '\0';
+ libdef_name(p+1, LIBINIT_STRING);
+ return;
+ }
+ } else if (*p >= '0' && *p <= '9') {
+ char *ep;
+ double d = strtod(p, &ep);
+ if (*ep == '\0') {
+ if (optr+1+sizeof(double) > obuf+sizeof(obuf)) {
+ fprintf(stderr, "Error: output buffer overflow\n");
+ exit(1);
+ }
+ *optr++ = LIBINIT_NUMBER;
+ memcpy_endian(optr, &d, sizeof(double));
+ optr += sizeof(double);
+ return;
+ }
+ } else if (!strcmp(p, "lastcl")) {
+ if (optr+1 > obuf+sizeof(obuf)) {
+ fprintf(stderr, "Error: output buffer overflow\n");
+ exit(1);
+ }
+ *optr++ = LIBINIT_LASTCL;
+ return;
+ } else if (len > 4 && !strncmp(p, "top-", 4)) {
+ if (optr+2 > obuf+sizeof(obuf)) {
+ fprintf(stderr, "Error: output buffer overflow\n");
+ exit(1);
+ }
+ *optr++ = LIBINIT_COPY;
+ *optr++ = (uint8_t)atoi(p+4);
+ return;
+ }
+ fprintf(stderr, "Error: bad value for %sPUSH(%s)\n", LIBDEF_PREFIX, p);
+ exit(1);
+ }
+}
+
+static void libdef_set(BuildCtx *ctx, char *p, int arg)
+{
+ UNUSED(arg);
+ if (ctx->mode == BUILD_libdef) {
+ if (p[0] == '!' && p[1] == '\0') p[0] = '\0'; /* Set env. */
+ libdef_name(p, LIBINIT_STRING);
+ *optr++ = LIBINIT_SET;
+ obuf[2]++; /* Bump hash table size. */
+ }
+}
+
+static void libdef_regfunc(BuildCtx *ctx, char *p, int arg)
+{
+ UNUSED(ctx); UNUSED(p);
+ regfunc = arg;
+}
+
+typedef void (*LibDefFunc)(BuildCtx *ctx, char *p, int arg);
+
+typedef struct LibDefHandler {
+ const char *suffix;
+ const char *stop;
+ const LibDefFunc func;
+ const int arg;
+} LibDefHandler;
+
+static const LibDefHandler libdef_handlers[] = {
+ { "MODULE_", " \t\r\n", libdef_module, 0 },
+ { "CF(", ")", libdef_func, LIBINIT_CF },
+ { "ASM(", ")", libdef_func, LIBINIT_ASM },
+ { "ASM_(", ")", libdef_func, LIBINIT_ASM_ },
+ { "LUA(", ")", libdef_lua, 0 },
+ { "REC(", ")", libdef_rec, 0 },
+ { "PUSH(", ")", libdef_push, 0 },
+ { "SET(", ")", libdef_set, 0 },
+ { "NOREGUV", NULL, libdef_regfunc, REGFUNC_NOREGUV },
+ { "NOREG", NULL, libdef_regfunc, REGFUNC_NOREG },
+ { NULL, NULL, (LibDefFunc)0, 0 }
+};
+
+/* Emit C source code for library function definitions. */
+void emit_lib(BuildCtx *ctx)
+{
+ const char *fname;
+
+ if (ctx->mode == BUILD_ffdef || ctx->mode == BUILD_libdef ||
+ ctx->mode == BUILD_recdef)
+ fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
+ else if (ctx->mode == BUILD_vmdef)
+ fprintf(ctx->fp, "ffnames = {\n[0]=\"Lua\",\n\"C\",\n");
+ if (ctx->mode == BUILD_recdef)
+ fprintf(ctx->fp, "static const uint16_t recff_idmap[] = {\n0,\n0x0100");
+ recffid = ffid = FF_C+1;
+ ffasmfunc = 0;
+
+ while ((fname = *ctx->args++)) {
+ char buf[256]; /* We don't care about analyzing lines longer than that. */
+ FILE *fp;
+ if (fname[0] == '-' && fname[1] == '\0') {
+ fp = stdin;
+ } else {
+ fp = fopen(fname, "r");
+ if (!fp) {
+ fprintf(stderr, "Error: cannot open input file '%s': %s\n",
+ fname, strerror(errno));
+ exit(1);
+ }
+ }
+ modstate = 0;
+ regfunc = REGFUNC_OK;
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ char *p;
+ /* Simplistic pre-processor. Only handles top-level #if/#endif. */
+ if (buf[0] == '#' && buf[1] == 'i' && buf[2] == 'f') {
+ int ok = 1;
+ if (!strcmp(buf, "#if LJ_52\n"))
+ ok = LJ_52;
+ else if (!strcmp(buf, "#if LJ_HASJIT\n"))
+ ok = LJ_HASJIT;
+ else if (!strcmp(buf, "#if LJ_HASFFI\n"))
+ ok = LJ_HASFFI;
+ if (!ok) {
+ int lvl = 1;
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ if (buf[0] == '#' && buf[1] == 'e' && buf[2] == 'n') {
+ if (--lvl == 0) break;
+ } else if (buf[0] == '#' && buf[1] == 'i' && buf[2] == 'f') {
+ lvl++;
+ }
+ }
+ continue;
+ }
+ }
+ for (p = buf; (p = strstr(p, LIBDEF_PREFIX)) != NULL; ) {
+ const LibDefHandler *ldh;
+ p += sizeof(LIBDEF_PREFIX)-1;
+ for (ldh = libdef_handlers; ldh->suffix != NULL; ldh++) {
+ size_t n, len = strlen(ldh->suffix);
+ if (!strncmp(p, ldh->suffix, len)) {
+ p += len;
+ n = ldh->stop ? strcspn(p, ldh->stop) : 0;
+ if (!p[n]) break;
+ p[n] = '\0';
+ ldh->func(ctx, p, ldh->arg);
+ p += n+1;
+ break;
+ }
+ }
+ if (ldh->suffix == NULL) {
+ buf[strlen(buf)-1] = '\0';
+ fprintf(stderr, "Error: unknown library definition tag %s%s\n",
+ LIBDEF_PREFIX, p);
+ exit(1);
+ }
+ }
+ }
+ fclose(fp);
+ if (ctx->mode == BUILD_libdef) {
+ libdef_endmodule(ctx);
+ }
+ }
+
+ if (ctx->mode == BUILD_ffdef) {
+ fprintf(ctx->fp, "\n#undef FFDEF\n\n");
+ fprintf(ctx->fp,
+ "#ifndef FF_NUM_ASMFUNC\n#define FF_NUM_ASMFUNC %d\n#endif\n\n",
+ ffasmfunc);
+ } else if (ctx->mode == BUILD_vmdef) {
+ fprintf(ctx->fp, "},\n\n");
+ } else if (ctx->mode == BUILD_bcdef) {
+ int i;
+ fprintf(ctx->fp, "\n};\n\n");
+ fprintf(ctx->fp, "LJ_DATADEF const uint16_t lj_bc_mode[] = {\n");
+ fprintf(ctx->fp, "BCDEF(BCMODE)\n");
+ for (i = ffasmfunc-1; i > 0; i--)
+ fprintf(ctx->fp, "BCMODE_FF,\n");
+ fprintf(ctx->fp, "BCMODE_FF\n};\n\n");
+ } else if (ctx->mode == BUILD_recdef) {
+ char *p = (char *)obuf;
+ fprintf(ctx->fp, "\n};\n\n");
+ fprintf(ctx->fp, "static const RecordFunc recff_func[] = {\n"
+ "recff_nyi,\n"
+ "recff_c");
+ while (*p) {
+ fprintf(ctx->fp, ",\nrecff_%s", p);
+ p += strlen(p)+1;
+ }
+ fprintf(ctx->fp, "\n};\n\n");
+ }
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/host/buildvm_lib.o b/src/host/luajit-2.1.0-beta3/src/host/buildvm_lib.o
new file mode 100644
index 00000000..2c1092a5
Binary files /dev/null and b/src/host/luajit-2.1.0-beta3/src/host/buildvm_lib.o differ
diff --git a/src/host/luajit-2.1.0-beta3/src/host/buildvm_libbc.h b/src/host/luajit-2.1.0-beta3/src/host/buildvm_libbc.h
new file mode 100644
index 00000000..b2600bd5
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/host/buildvm_libbc.h
@@ -0,0 +1,56 @@
+/* This is a generated file. DO NOT EDIT! */
+
+static const int libbc_endian = 0;
+
+static const uint8_t libbc_code[] = {
+#if LJ_FR2
+0,1,2,0,0,1,2,24,1,0,0,76,1,2,0,241,135,158,166,3,220,203,178,130,4,0,1,2,0,
+0,1,2,24,1,0,0,76,1,2,0,243,244,148,165,20,198,190,199,252,3,0,1,2,0,0,0,3,
+16,0,5,0,21,1,0,0,76,1,2,0,0,2,10,0,0,0,15,16,0,12,0,16,1,9,0,41,2,1,0,21,3,
+0,0,41,4,1,0,77,2,8,128,18,6,1,0,18,8,5,0,59,9,5,0,66,6,3,2,10,6,0,0,88,7,1,
+128,76,6,2,0,79,2,248,127,75,0,1,0,0,2,11,0,0,0,16,16,0,12,0,16,1,9,0,43,2,
+0,0,18,3,0,0,41,4,0,0,88,5,7,128,18,7,1,0,18,9,5,0,18,10,6,0,66,7,3,2,10,7,
+0,0,88,8,1,128,76,7,2,0,70,5,3,3,82,5,247,127,75,0,1,0,0,1,2,0,0,0,3,16,0,12,
+0,21,1,0,0,76,1,2,0,0,2,10,0,0,2,30,16,0,12,0,21,2,0,0,11,1,0,0,88,3,7,128,
+8,2,0,0,88,3,23,128,59,3,2,0,43,4,0,0,64,4,2,0,76,3,2,0,88,3,18,128,16,1,14,
+0,41,3,1,0,3,3,1,0,88,3,14,128,3,1,2,0,88,3,12,128,59,3,1,0,22,4,1,1,18,5,2,
+0,41,6,1,0,77,4,4,128,23,8,1,7,59,9,7,0,64,9,8,0,79,4,252,127,43,4,0,0,64,4,
+2,0,76,3,2,0,75,0,1,0,0,2,0,5,12,0,0,0,35,16,0,12,0,16,1,14,0,16,2,14,0,16,
+3,14,0,11,4,0,0,88,5,1,128,18,4,0,0,16,4,12,0,3,1,2,0,88,5,24,128,33,5,1,3,
+0,2,3,0,88,6,4,128,2,3,1,0,88,6,2,128,4,4,0,0,88,6,9,128,18,6,1,0,18,7,2,0,
+41,8,1,0,77,6,4,128,32,10,5,9,59,11,9,0,64,11,10,4,79,6,252,127,88,6,8,128,
+18,6,2,0,18,7,1,0,41,8,255,255,77,6,4,128,32,10,5,9,59,11,9,0,64,11,10,4,79,
+6,252,127,76,4,2,0,0
+#else
+0,1,2,0,0,1,2,24,1,0,0,76,1,2,0,241,135,158,166,3,220,203,178,130,4,0,1,2,0,
+0,1,2,24,1,0,0,76,1,2,0,243,244,148,165,20,198,190,199,252,3,0,1,2,0,0,0,3,
+16,0,5,0,21,1,0,0,76,1,2,0,0,2,9,0,0,0,15,16,0,12,0,16,1,9,0,41,2,1,0,21,3,
+0,0,41,4,1,0,77,2,8,128,18,6,1,0,18,7,5,0,59,8,5,0,66,6,3,2,10,6,0,0,88,7,1,
+128,76,6,2,0,79,2,248,127,75,0,1,0,0,2,10,0,0,0,16,16,0,12,0,16,1,9,0,43,2,
+0,0,18,3,0,0,41,4,0,0,88,5,7,128,18,7,1,0,18,8,5,0,18,9,6,0,66,7,3,2,10,7,0,
+0,88,8,1,128,76,7,2,0,70,5,3,3,82,5,247,127,75,0,1,0,0,1,2,0,0,0,3,16,0,12,
+0,21,1,0,0,76,1,2,0,0,2,10,0,0,2,30,16,0,12,0,21,2,0,0,11,1,0,0,88,3,7,128,
+8,2,0,0,88,3,23,128,59,3,2,0,43,4,0,0,64,4,2,0,76,3,2,0,88,3,18,128,16,1,14,
+0,41,3,1,0,3,3,1,0,88,3,14,128,3,1,2,0,88,3,12,128,59,3,1,0,22,4,1,1,18,5,2,
+0,41,6,1,0,77,4,4,128,23,8,1,7,59,9,7,0,64,9,8,0,79,4,252,127,43,4,0,0,64,4,
+2,0,76,3,2,0,75,0,1,0,0,2,0,5,12,0,0,0,35,16,0,12,0,16,1,14,0,16,2,14,0,16,
+3,14,0,11,4,0,0,88,5,1,128,18,4,0,0,16,4,12,0,3,1,2,0,88,5,24,128,33,5,1,3,
+0,2,3,0,88,6,4,128,2,3,1,0,88,6,2,128,4,4,0,0,88,6,9,128,18,6,1,0,18,7,2,0,
+41,8,1,0,77,6,4,128,32,10,5,9,59,11,9,0,64,11,10,4,79,6,252,127,88,6,8,128,
+18,6,2,0,18,7,1,0,41,8,255,255,77,6,4,128,32,10,5,9,59,11,9,0,64,11,10,4,79,
+6,252,127,76,4,2,0,0
+#endif
+};
+
+static const struct { const char *name; int ofs; } libbc_map[] = {
+{"math_deg",0},
+{"math_rad",25},
+{"string_len",50},
+{"table_foreachi",69},
+{"table_foreach",136},
+{"table_getn",207},
+{"table_remove",226},
+{"table_move",355},
+{NULL,502}
+};
+
diff --git a/src/host/luajit-2.1.0-beta3/src/host/buildvm_peobj.c b/src/host/luajit-2.1.0-beta3/src/host/buildvm_peobj.c
new file mode 100644
index 00000000..2eb2bb7b
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/host/buildvm_peobj.c
@@ -0,0 +1,392 @@
+/*
+** LuaJIT VM builder: PE object emitter.
+** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
+**
+** Only used for building on Windows, since we cannot assume the presence
+** of a suitable assembler. The host and target byte order must match.
+*/
+
+#include "buildvm.h"
+#include "lj_bc.h"
+
+#if LJ_TARGET_X86ORX64 || LJ_TARGET_PPC
+
+/* Context for PE object emitter. */
+static char *strtab;
+static size_t strtabofs;
+
+/* -- PE object definitions ----------------------------------------------- */
+
+/* PE header. */
+typedef struct PEheader {
+ uint16_t arch;
+ uint16_t nsects;
+ uint32_t time;
+ uint32_t symtabofs;
+ uint32_t nsyms;
+ uint16_t opthdrsz;
+ uint16_t flags;
+} PEheader;
+
+/* PE section. */
+typedef struct PEsection {
+ char name[8];
+ uint32_t vsize;
+ uint32_t vaddr;
+ uint32_t size;
+ uint32_t ofs;
+ uint32_t relocofs;
+ uint32_t lineofs;
+ uint16_t nreloc;
+ uint16_t nline;
+ uint32_t flags;
+} PEsection;
+
+/* PE relocation. */
+typedef struct PEreloc {
+ uint32_t vaddr;
+ uint32_t symidx;
+ uint16_t type;
+} PEreloc;
+
+/* Cannot use sizeof, because it pads up to the max. alignment. */
+#define PEOBJ_RELOC_SIZE (4+4+2)
+
+/* PE symbol table entry. */
+typedef struct PEsym {
+ union {
+ char name[8];
+ uint32_t nameref[2];
+ } n;
+ uint32_t value;
+ int16_t sect;
+ uint16_t type;
+ uint8_t scl;
+ uint8_t naux;
+} PEsym;
+
+/* PE symbol table auxiliary entry for a section. */
+typedef struct PEsymaux {
+ uint32_t size;
+ uint16_t nreloc;
+ uint16_t nline;
+ uint32_t cksum;
+ uint16_t assoc;
+ uint8_t comdatsel;
+ uint8_t unused[3];
+} PEsymaux;
+
+/* Cannot use sizeof, because it pads up to the max. alignment. */
+#define PEOBJ_SYM_SIZE (8+4+2+2+1+1)
+
+/* PE object CPU specific defines. */
+#if LJ_TARGET_X86
+#define PEOBJ_ARCH_TARGET 0x014c
+#define PEOBJ_RELOC_REL32 0x14 /* MS: REL32, GNU: DISP32. */
+#define PEOBJ_RELOC_DIR32 0x06
+#define PEOBJ_RELOC_OFS 0
+#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */
+#elif LJ_TARGET_X64
+#define PEOBJ_ARCH_TARGET 0x8664
+#define PEOBJ_RELOC_REL32 0x04 /* MS: REL32, GNU: DISP32. */
+#define PEOBJ_RELOC_DIR32 0x02
+#define PEOBJ_RELOC_ADDR32NB 0x03
+#define PEOBJ_RELOC_OFS 0
+#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */
+#elif LJ_TARGET_PPC
+#define PEOBJ_ARCH_TARGET 0x01f2
+#define PEOBJ_RELOC_REL32 0x06
+#define PEOBJ_RELOC_DIR32 0x02
+#define PEOBJ_RELOC_OFS (-4)
+#define PEOBJ_TEXT_FLAGS 0x60400020 /* 60=r+x, 40=align8, 20=code. */
+#endif
+
+/* Section numbers (0-based). */
+enum {
+ PEOBJ_SECT_ABS = -2,
+ PEOBJ_SECT_UNDEF = -1,
+ PEOBJ_SECT_TEXT,
+#if LJ_TARGET_X64
+ PEOBJ_SECT_PDATA,
+ PEOBJ_SECT_XDATA,
+#elif LJ_TARGET_X86
+ PEOBJ_SECT_SXDATA,
+#endif
+ PEOBJ_SECT_RDATA_Z,
+ PEOBJ_NSECTIONS
+};
+
+/* Symbol types. */
+#define PEOBJ_TYPE_NULL 0
+#define PEOBJ_TYPE_FUNC 0x20
+
+/* Symbol storage class. */
+#define PEOBJ_SCL_EXTERN 2
+#define PEOBJ_SCL_STATIC 3
+
+/* -- PE object emitter --------------------------------------------------- */
+
+/* Emit PE object symbol. */
+static void emit_peobj_sym(BuildCtx *ctx, const char *name, uint32_t value,
+ int sect, int type, int scl)
+{
+ PEsym sym;
+ size_t len = strlen(name);
+ if (!strtab) { /* Pass 1: only calculate string table length. */
+ if (len > 8) strtabofs += len+1;
+ return;
+ }
+ if (len <= 8) {
+ memcpy(sym.n.name, name, len);
+ memset(sym.n.name+len, 0, 8-len);
+ } else {
+ sym.n.nameref[0] = 0;
+ sym.n.nameref[1] = (uint32_t)strtabofs;
+ memcpy(strtab + strtabofs, name, len);
+ strtab[strtabofs+len] = 0;
+ strtabofs += len+1;
+ }
+ sym.value = value;
+ sym.sect = (int16_t)(sect+1); /* 1-based section number. */
+ sym.type = (uint16_t)type;
+ sym.scl = (uint8_t)scl;
+ sym.naux = 0;
+ owrite(ctx, &sym, PEOBJ_SYM_SIZE);
+}
+
+/* Emit PE object section symbol. */
+static void emit_peobj_sym_sect(BuildCtx *ctx, PEsection *pesect, int sect)
+{
+ PEsym sym;
+ PEsymaux aux;
+ if (!strtab) return; /* Pass 1: no output. */
+ memcpy(sym.n.name, pesect[sect].name, 8);
+ sym.value = 0;
+ sym.sect = (int16_t)(sect+1); /* 1-based section number. */
+ sym.type = PEOBJ_TYPE_NULL;
+ sym.scl = PEOBJ_SCL_STATIC;
+ sym.naux = 1;
+ owrite(ctx, &sym, PEOBJ_SYM_SIZE);
+ memset(&aux, 0, sizeof(PEsymaux));
+ aux.size = pesect[sect].size;
+ aux.nreloc = pesect[sect].nreloc;
+ owrite(ctx, &aux, PEOBJ_SYM_SIZE);
+}
+
+/* Emit Windows PE object file. */
+void emit_peobj(BuildCtx *ctx)
+{
+ PEheader pehdr;
+ PEsection pesect[PEOBJ_NSECTIONS];
+ uint32_t sofs;
+ int i, nrsym;
+ union { uint8_t b; uint32_t u; } host_endian;
+
+ sofs = sizeof(PEheader) + PEOBJ_NSECTIONS*sizeof(PEsection);
+
+ /* Fill in PE sections. */
+ memset(&pesect, 0, PEOBJ_NSECTIONS*sizeof(PEsection));
+ memcpy(pesect[PEOBJ_SECT_TEXT].name, ".text", sizeof(".text")-1);
+ pesect[PEOBJ_SECT_TEXT].ofs = sofs;
+ sofs += (pesect[PEOBJ_SECT_TEXT].size = (uint32_t)ctx->codesz);
+ pesect[PEOBJ_SECT_TEXT].relocofs = sofs;
+ sofs += (pesect[PEOBJ_SECT_TEXT].nreloc = (uint16_t)ctx->nreloc) * PEOBJ_RELOC_SIZE;
+ /* Flags: 60 = read+execute, 50 = align16, 20 = code. */
+ pesect[PEOBJ_SECT_TEXT].flags = PEOBJ_TEXT_FLAGS;
+
+#if LJ_TARGET_X64
+ memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1);
+ pesect[PEOBJ_SECT_PDATA].ofs = sofs;
+ sofs += (pesect[PEOBJ_SECT_PDATA].size = 6*4);
+ pesect[PEOBJ_SECT_PDATA].relocofs = sofs;
+ sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = 6) * PEOBJ_RELOC_SIZE;
+ /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
+ pesect[PEOBJ_SECT_PDATA].flags = 0x40300040;
+
+ memcpy(pesect[PEOBJ_SECT_XDATA].name, ".xdata", sizeof(".xdata")-1);
+ pesect[PEOBJ_SECT_XDATA].ofs = sofs;
+ sofs += (pesect[PEOBJ_SECT_XDATA].size = 8*2+4+6*2); /* See below. */
+ pesect[PEOBJ_SECT_XDATA].relocofs = sofs;
+ sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE;
+ /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
+ pesect[PEOBJ_SECT_XDATA].flags = 0x40300040;
+#elif LJ_TARGET_X86
+ memcpy(pesect[PEOBJ_SECT_SXDATA].name, ".sxdata", sizeof(".sxdata")-1);
+ pesect[PEOBJ_SECT_SXDATA].ofs = sofs;
+ sofs += (pesect[PEOBJ_SECT_SXDATA].size = 4);
+ pesect[PEOBJ_SECT_SXDATA].relocofs = sofs;
+ /* Flags: 40 = read, 30 = align4, 02 = lnk_info, 40 = initialized data. */
+ pesect[PEOBJ_SECT_SXDATA].flags = 0x40300240;
+#endif
+
+ memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1);
+ pesect[PEOBJ_SECT_RDATA_Z].ofs = sofs;
+ sofs += (pesect[PEOBJ_SECT_RDATA_Z].size = (uint32_t)strlen(ctx->dasm_ident)+1);
+ /* Flags: 40 = read, 30 = align4, 40 = initialized data. */
+ pesect[PEOBJ_SECT_RDATA_Z].flags = 0x40300040;
+
+ /* Fill in PE header. */
+ pehdr.arch = PEOBJ_ARCH_TARGET;
+ pehdr.nsects = PEOBJ_NSECTIONS;
+ pehdr.time = 0; /* Timestamp is optional. */
+ pehdr.symtabofs = sofs;
+ pehdr.opthdrsz = 0;
+ pehdr.flags = 0;
+
+ /* Compute the size of the symbol table:
+ ** @feat.00 + nsections*2
+ ** + asm_start + nsym
+ ** + nrsym
+ */
+ nrsym = ctx->nrelocsym;
+ pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym;
+#if LJ_TARGET_X64
+ pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win. */
+#endif
+
+ /* Write PE object header and all sections. */
+ owrite(ctx, &pehdr, sizeof(PEheader));
+ owrite(ctx, &pesect, sizeof(PEsection)*PEOBJ_NSECTIONS);
+
+ /* Write .text section. */
+ host_endian.u = 1;
+ if (host_endian.b != LJ_ENDIAN_SELECT(1, 0)) {
+#if LJ_TARGET_PPC
+ uint32_t *p = (uint32_t *)ctx->code;
+ int n = (int)(ctx->codesz >> 2);
+ for (i = 0; i < n; i++, p++)
+ *p = lj_bswap(*p); /* Byteswap .text section. */
+#else
+ fprintf(stderr, "Error: different byte order for host and target\n");
+ exit(1);
+#endif
+ }
+ owrite(ctx, ctx->code, ctx->codesz);
+ for (i = 0; i < ctx->nreloc; i++) {
+ PEreloc reloc;
+ reloc.vaddr = (uint32_t)ctx->reloc[i].ofs + PEOBJ_RELOC_OFS;
+ reloc.symidx = 1+2+ctx->reloc[i].sym; /* Reloc syms are after .text sym. */
+ reloc.type = ctx->reloc[i].type ? PEOBJ_RELOC_REL32 : PEOBJ_RELOC_DIR32;
+ owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
+ }
+
+#if LJ_TARGET_X64
+ { /* Write .pdata section. */
+ uint32_t fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs;
+ uint32_t pdata[3]; /* Start of .text, end of .text and .xdata. */
+ PEreloc reloc;
+ pdata[0] = 0; pdata[1] = fcofs; pdata[2] = 0;
+ owrite(ctx, &pdata, sizeof(pdata));
+ pdata[0] = fcofs; pdata[1] = (uint32_t)ctx->codesz; pdata[2] = 20;
+ owrite(ctx, &pdata, sizeof(pdata));
+ reloc.vaddr = 0; reloc.symidx = 1+2+nrsym+2+2+1;
+ reloc.type = PEOBJ_RELOC_ADDR32NB;
+ owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
+ reloc.vaddr = 4; reloc.symidx = 1+2+nrsym+2+2+1;
+ reloc.type = PEOBJ_RELOC_ADDR32NB;
+ owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
+ reloc.vaddr = 8; reloc.symidx = 1+2+nrsym+2;
+ reloc.type = PEOBJ_RELOC_ADDR32NB;
+ owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
+ reloc.vaddr = 12; reloc.symidx = 1+2+nrsym+2+2+1;
+ reloc.type = PEOBJ_RELOC_ADDR32NB;
+ owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
+ reloc.vaddr = 16; reloc.symidx = 1+2+nrsym+2+2+1;
+ reloc.type = PEOBJ_RELOC_ADDR32NB;
+ owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
+ reloc.vaddr = 20; reloc.symidx = 1+2+nrsym+2;
+ reloc.type = PEOBJ_RELOC_ADDR32NB;
+ owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
+ }
+ { /* Write .xdata section. */
+ uint16_t xdata[8+2+6];
+ PEreloc reloc;
+ xdata[0] = 0x01|0x08|0x10; /* Ver. 1, uhandler/ehandler, prolog size 0. */
+ xdata[1] = 0x0005; /* Number of unwind codes, no frame pointer. */
+ xdata[2] = 0x4200; /* Stack offset 4*8+8 = aword*5. */
+ xdata[3] = 0x3000; /* Push rbx. */
+ xdata[4] = 0x6000; /* Push rsi. */
+ xdata[5] = 0x7000; /* Push rdi. */
+ xdata[6] = 0x5000; /* Push rbp. */
+ xdata[7] = 0; /* Alignment. */
+ xdata[8] = xdata[9] = 0; /* Relocated address of exception handler. */
+ xdata[10] = 0x01; /* Ver. 1, no handler, prolog size 0. */
+ xdata[11] = 0x1504; /* Number of unwind codes, fp = rbp, fpofs = 16. */
+ xdata[12] = 0x0300; /* set_fpreg. */
+ xdata[13] = 0x0200; /* stack offset 0*8+8 = aword*1. */
+ xdata[14] = 0x3000; /* Push rbx. */
+ xdata[15] = 0x5000; /* Push rbp. */
+ owrite(ctx, &xdata, sizeof(xdata));
+ reloc.vaddr = 2*8; reloc.symidx = 1+2+nrsym+2+2;
+ reloc.type = PEOBJ_RELOC_ADDR32NB;
+ owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
+ }
+#elif LJ_TARGET_X86
+ /* Write .sxdata section. */
+ for (i = 0; i < nrsym; i++) {
+ if (!strcmp(ctx->relocsym[i], "_lj_err_unwind_win")) {
+ uint32_t symidx = 1+2+i;
+ owrite(ctx, &symidx, 4);
+ break;
+ }
+ }
+ if (i == nrsym) {
+ fprintf(stderr, "Error: extern lj_err_unwind_win not used\n");
+ exit(1);
+ }
+#endif
+
+ /* Write .rdata$Z section. */
+ owrite(ctx, ctx->dasm_ident, strlen(ctx->dasm_ident)+1);
+
+ /* Write symbol table. */
+ strtab = NULL; /* 1st pass: collect string sizes. */
+ for (;;) {
+ strtabofs = 4;
+ /* Mark as SafeSEH compliant. */
+ emit_peobj_sym(ctx, "@feat.00", 1,
+ PEOBJ_SECT_ABS, PEOBJ_TYPE_NULL, PEOBJ_SCL_STATIC);
+
+ emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_TEXT);
+ for (i = 0; i < nrsym; i++)
+ emit_peobj_sym(ctx, ctx->relocsym[i], 0,
+ PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
+
+#if LJ_TARGET_X64
+ emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA);
+ emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA);
+ emit_peobj_sym(ctx, "lj_err_unwind_win", 0,
+ PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
+#elif LJ_TARGET_X86
+ emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_SXDATA);
+#endif
+
+ emit_peobj_sym(ctx, ctx->beginsym, 0,
+ PEOBJ_SECT_TEXT, PEOBJ_TYPE_NULL, PEOBJ_SCL_EXTERN);
+ for (i = 0; i < ctx->nsym; i++)
+ emit_peobj_sym(ctx, ctx->sym[i].name, (uint32_t)ctx->sym[i].ofs,
+ PEOBJ_SECT_TEXT, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
+
+ emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_RDATA_Z);
+
+ if (strtab)
+ break;
+ /* 2nd pass: alloc strtab, write syms and copy strings. */
+ strtab = (char *)malloc(strtabofs);
+ *(uint32_t *)strtab = (uint32_t)strtabofs;
+ }
+
+ /* Write string table. */
+ owrite(ctx, strtab, strtabofs);
+}
+
+#else
+
+void emit_peobj(BuildCtx *ctx)
+{
+ UNUSED(ctx);
+ fprintf(stderr, "Error: no PE object support for this target\n");
+ exit(1);
+}
+
+#endif
diff --git a/src/host/luajit-2.1.0-beta3/src/host/buildvm_peobj.o b/src/host/luajit-2.1.0-beta3/src/host/buildvm_peobj.o
new file mode 100644
index 00000000..69662822
Binary files /dev/null and b/src/host/luajit-2.1.0-beta3/src/host/buildvm_peobj.o differ
diff --git a/src/host/luajit-2.1.0-beta3/src/host/genlibbc.lua b/src/host/luajit-2.1.0-beta3/src/host/genlibbc.lua
new file mode 100644
index 00000000..6f5a05cc
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/host/genlibbc.lua
@@ -0,0 +1,197 @@
+----------------------------------------------------------------------------
+-- Lua script to dump the bytecode of the library functions written in Lua.
+-- The resulting 'buildvm_libbc.h' is used for the build process of LuaJIT.
+----------------------------------------------------------------------------
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+
+local ffi = require("ffi")
+local bit = require("bit")
+local vmdef = require("jit.vmdef")
+local bcnames = vmdef.bcnames
+
+local format = string.format
+
+local isbe = (string.byte(string.dump(function() end), 5) % 2 == 1)
+
+local function usage(arg)
+ io.stderr:write("Usage: ", arg and arg[0] or "genlibbc",
+ " [-o buildvm_libbc.h] lib_*.c\n")
+ os.exit(1)
+end
+
+local function parse_arg(arg)
+ local outfile = "-"
+ if not (arg and arg[1]) then
+ usage(arg)
+ end
+ if arg[1] == "-o" then
+ outfile = arg[2]
+ if not outfile then usage(arg) end
+ table.remove(arg, 1)
+ table.remove(arg, 1)
+ end
+ return outfile
+end
+
+local function read_files(names)
+ local src = ""
+ for _,name in ipairs(names) do
+ local fp = assert(io.open(name))
+ src = src .. fp:read("*a")
+ fp:close()
+ end
+ return src
+end
+
+local function transform_lua(code)
+ local fixup = {}
+ local n = -30000
+ code = string.gsub(code, "CHECK_(%w*)%((.-)%)", function(tp, var)
+ n = n + 1
+ fixup[n] = { "CHECK", tp }
+ return format("%s=%d", var, n)
+ end)
+ code = string.gsub(code, "PAIRS%((.-)%)", function(var)
+ fixup.PAIRS = true
+ return format("nil, %s, 0", var)
+ end)
+ return "return "..code, fixup
+end
+
+local function read_uleb128(p)
+ local v = p[0]; p = p + 1
+ if v >= 128 then
+ local sh = 7; v = v - 128
+ repeat
+ local r = p[0]
+ v = v + bit.lshift(bit.band(r, 127), sh)
+ sh = sh + 7
+ p = p + 1
+ until r < 128
+ end
+ return p, v
+end
+
+-- ORDER LJ_T
+local name2itype = {
+ str = 5, func = 9, tab = 12, int = 14, num = 15
+}
+
+local BC = {}
+for i=0,#bcnames/6-1 do
+ BC[string.gsub(string.sub(bcnames, i*6+1, i*6+6), " ", "")] = i
+end
+local xop, xra = isbe and 3 or 0, isbe and 2 or 1
+local xrc, xrb = isbe and 1 or 2, isbe and 0 or 3
+
+local function fixup_dump(dump, fixup)
+ local buf = ffi.new("uint8_t[?]", #dump+1, dump)
+ local p = buf+5
+ local n, sizebc
+ p, n = read_uleb128(p)
+ local start = p
+ p = p + 4
+ p = read_uleb128(p)
+ p = read_uleb128(p)
+ p, sizebc = read_uleb128(p)
+ local rawtab = {}
+ for i=0,sizebc-1 do
+ local op = p[xop]
+ if op == BC.KSHORT then
+ local rd = p[xrc] + 256*p[xrb]
+ rd = bit.arshift(bit.lshift(rd, 16), 16)
+ local f = fixup[rd]
+ if f then
+ if f[1] == "CHECK" then
+ local tp = f[2]
+ if tp == "tab" then rawtab[p[xra]] = true end
+ p[xop] = tp == "num" and BC.ISNUM or BC.ISTYPE
+ p[xrb] = 0
+ p[xrc] = name2itype[tp]
+ else
+ error("unhandled fixup type: "..f[1])
+ end
+ end
+ elseif op == BC.TGETV then
+ if rawtab[p[xrb]] then
+ p[xop] = BC.TGETR
+ end
+ elseif op == BC.TSETV then
+ if rawtab[p[xrb]] then
+ p[xop] = BC.TSETR
+ end
+ elseif op == BC.ITERC then
+ if fixup.PAIRS then
+ p[xop] = BC.ITERN
+ end
+ end
+ p = p + 4
+ end
+ return ffi.string(start, n)
+end
+
+local function find_defs(src)
+ 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)
+ defs[#defs+1] = name
+ end
+ return defs
+end
+
+local function gen_header(defs)
+ 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 = ""
+ for _,name in ipairs(defs) do
+ s = s .. defs[name]
+ end
+ w("static const uint8_t libbc_code[] = {\n")
+ local n = 0
+ for i=1,#s do
+ local x = string.byte(s, i)
+ w(x); w(",")
+ n = n + (x < 10 and 2 or (x < 100 and 3 or 4))
+ if n >= 75 then n = 0; w("\n") end
+ end
+ w("0\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]
+ end
+ w("{NULL,"); w(m); w("}\n};\n\n")
+ return table.concat(t)
+end
+
+local function write_file(name, data)
+ if name == "-" then
+ assert(io.write(data))
+ assert(io.flush())
+ else
+ local fp = io.open(name)
+ if fp then
+ local old = fp:read("*a")
+ fp:close()
+ if data == old then return end
+ end
+ fp = assert(io.open(name, "w"))
+ assert(fp:write(data))
+ assert(fp:close())
+ end
+end
+
+local outfile = parse_arg(arg)
+local src = read_files(arg)
+local defs = find_defs(src)
+local hdr = gen_header(defs)
+write_file(outfile, hdr)
+
diff --git a/src/host/luajit-2.1.0-beta3/src/host/genminilua.lua b/src/host/luajit-2.1.0-beta3/src/host/genminilua.lua
new file mode 100644
index 00000000..50feff01
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/host/genminilua.lua
@@ -0,0 +1,429 @@
+----------------------------------------------------------------------------
+-- Lua script to generate a customized, minified version of Lua.
+-- The resulting 'minilua' is used for the build process of LuaJIT.
+----------------------------------------------------------------------------
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+
+local sub, match, gsub = string.sub, string.match, string.gsub
+
+local LUA_VERSION = "5.1.5"
+local LUA_SOURCE
+
+local function usage()
+ io.stderr:write("Usage: ", arg and arg[0] or "genminilua",
+ " lua-", LUA_VERSION, "-source-dir\n")
+ os.exit(1)
+end
+
+local function find_sources()
+ LUA_SOURCE = arg and arg[1]
+ if not LUA_SOURCE then usage() end
+ if sub(LUA_SOURCE, -1) ~= "/" then LUA_SOURCE = LUA_SOURCE.."/" end
+ local fp = io.open(LUA_SOURCE .. "lua.h")
+ if not fp then
+ LUA_SOURCE = LUA_SOURCE.."src/"
+ fp = io.open(LUA_SOURCE .. "lua.h")
+ if not fp then usage() end
+ end
+ local all = fp:read("*a")
+ fp:close()
+ if not match(all, 'LUA_RELEASE%s*"Lua '..LUA_VERSION..'"') then
+ io.stderr:write("Error: version mismatch\n")
+ usage()
+ end
+end
+
+local LUA_FILES = {
+"lmem.c", "lobject.c", "ltm.c", "lfunc.c", "ldo.c", "lstring.c", "ltable.c",
+"lgc.c", "lstate.c", "ldebug.c", "lzio.c", "lopcodes.c",
+"llex.c", "lcode.c", "lparser.c", "lvm.c", "lapi.c", "lauxlib.c",
+"lbaselib.c", "ltablib.c", "liolib.c", "loslib.c", "lstrlib.c", "linit.c",
+}
+
+local REMOVE_LIB = {}
+gsub([[
+collectgarbage dofile gcinfo getfenv getmetatable load print rawequal rawset
+select tostring xpcall
+foreach foreachi getn maxn setn
+popen tmpfile seek setvbuf __tostring
+clock date difftime execute getenv rename setlocale time tmpname
+dump gfind len reverse
+LUA_LOADLIBNAME LUA_MATHLIBNAME LUA_DBLIBNAME
+]], "%S+", function(name)
+ REMOVE_LIB[name] = true
+end)
+
+local REMOVE_EXTINC = { [""] = true, [""] = true, }
+
+local CUSTOM_MAIN = [[
+typedef unsigned int UB;
+static UB barg(lua_State *L,int idx){
+union{lua_Number n;U64 b;}bn;
+bn.n=lua_tonumber(L,idx)+6755399441055744.0;
+if (bn.n==0.0&&!lua_isnumber(L,idx))luaL_typerror(L,idx,"number");
+return(UB)bn.b;
+}
+#define BRET(b) lua_pushnumber(L,(lua_Number)(int)(b));return 1;
+static int tobit(lua_State *L){
+BRET(barg(L,1))}
+static int bnot(lua_State *L){
+BRET(~barg(L,1))}
+static int band(lua_State *L){
+int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b&=barg(L,i);BRET(b)}
+static int bor(lua_State *L){
+int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b|=barg(L,i);BRET(b)}
+static int bxor(lua_State *L){
+int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b^=barg(L,i);BRET(b)}
+static int lshift(lua_State *L){
+UB b=barg(L,1),n=barg(L,2)&31;BRET(b<>n)}
+static int arshift(lua_State *L){
+UB b=barg(L,1),n=barg(L,2)&31;BRET((int)b>>n)}
+static int rol(lua_State *L){
+UB b=barg(L,1),n=barg(L,2)&31;BRET((b<>(32-n)))}
+static int ror(lua_State *L){
+UB b=barg(L,1),n=barg(L,2)&31;BRET((b>>n)|(b<<(32-n)))}
+static int bswap(lua_State *L){
+UB b=barg(L,1);b=(b>>24)|((b>>8)&0xff00)|((b&0xff00)<<8)|(b<<24);BRET(b)}
+static int tohex(lua_State *L){
+UB b=barg(L,1);
+int n=lua_isnone(L,2)?8:(int)barg(L,2);
+const char *hexdigits="0123456789abcdef";
+char buf[8];
+int i;
+if(n<0){n=-n;hexdigits="0123456789ABCDEF";}
+if(n>8)n=8;
+for(i=(int)n;--i>=0;){buf[i]=hexdigits[b&15];b>>=4;}
+lua_pushlstring(L,buf,(size_t)n);
+return 1;
+}
+static const struct luaL_Reg bitlib[] = {
+{"tobit",tobit},
+{"bnot",bnot},
+{"band",band},
+{"bor",bor},
+{"bxor",bxor},
+{"lshift",lshift},
+{"rshift",rshift},
+{"arshift",arshift},
+{"rol",rol},
+{"ror",ror},
+{"bswap",bswap},
+{"tohex",tohex},
+{NULL,NULL}
+};
+int main(int argc, char **argv){
+ lua_State *L = luaL_newstate();
+ int i;
+ luaL_openlibs(L);
+ luaL_register(L, "bit", bitlib);
+ if (argc < 2) return sizeof(void *);
+ lua_createtable(L, 0, 1);
+ lua_pushstring(L, argv[1]);
+ lua_rawseti(L, -2, 0);
+ lua_setglobal(L, "arg");
+ if (luaL_loadfile(L, argv[1]))
+ goto err;
+ for (i = 2; i < argc; i++)
+ lua_pushstring(L, argv[i]);
+ if (lua_pcall(L, argc - 2, 0, 0)) {
+ err:
+ fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
+ return 1;
+ }
+ lua_close(L);
+ return 0;
+}
+]]
+
+local function read_sources()
+ local t = {}
+ for i, name in ipairs(LUA_FILES) do
+ local fp = assert(io.open(LUA_SOURCE..name, "r"))
+ t[i] = fp:read("*a")
+ assert(fp:close())
+ end
+ t[#t+1] = CUSTOM_MAIN
+ return table.concat(t)
+end
+
+local includes = {}
+
+local function merge_includes(src)
+ return gsub(src, '#include%s*"([^"]*)"%s*\n', function(name)
+ if includes[name] then return "" end
+ includes[name] = true
+ local fp = assert(io.open(LUA_SOURCE..name, "r"))
+ local inc = fp:read("*a")
+ assert(fp:close())
+ inc = gsub(inc, "#ifndef%s+%w+_h\n#define%s+%w+_h\n", "")
+ inc = gsub(inc, "#endif%s*$", "")
+ return merge_includes(inc)
+ end)
+end
+
+local function get_license(src)
+ return match(src, "/%*+\n%* Copyright %(.-%*/\n")
+end
+
+local function fold_lines(src)
+ return gsub(src, "\\\n", " ")
+end
+
+local strings = {}
+
+local function save_str(str)
+ local n = #strings+1
+ strings[n] = str
+ return "\1"..n.."\2"
+end
+
+local function save_strings(src)
+ src = gsub(src, '"[^"\n]*"', save_str)
+ return gsub(src, "'[^'\n]*'", save_str)
+end
+
+local function restore_strings(src)
+ return gsub(src, "\1(%d+)\2", function(numstr)
+ return strings[tonumber(numstr)]
+ end)
+end
+
+local function def_istrue(def)
+ return def == "INT_MAX > 2147483640L" or
+ def == "LUAI_BITSINT >= 32" or
+ def == "SIZE_Bx < LUAI_BITSINT-1" or
+ def == "cast" or
+ def == "defined(LUA_CORE)" or
+ def == "MINSTRTABSIZE" or
+ def == "LUA_MINBUFFER" or
+ def == "HARDSTACKTESTS" or
+ def == "UNUSED"
+end
+
+local head, defs = {[[
+#ifdef _MSC_VER
+typedef unsigned __int64 U64;
+#else
+typedef unsigned long long U64;
+#endif
+int _CRT_glob = 0;
+]]}, {}
+
+local function preprocess(src)
+ local t = { match(src, "^(.-)#") }
+ local lvl, on, oldon = 0, true, {}
+ for pp, def, txt in string.gmatch(src, "#(%w+) *([^\n]*)\n([^#]*)") do
+ if pp == "if" or pp == "ifdef" or pp == "ifndef" then
+ lvl = lvl + 1
+ oldon[lvl] = on
+ on = def_istrue(def)
+ elseif pp == "else" then
+ if oldon[lvl] then
+ if on == false then on = true else on = false end
+ end
+ elseif pp == "elif" then
+ if oldon[lvl] then
+ on = def_istrue(def)
+ end
+ elseif pp == "endif" then
+ on = oldon[lvl]
+ lvl = lvl - 1
+ elseif on then
+ if pp == "include" then
+ if not head[def] and not REMOVE_EXTINC[def] then
+ head[def] = true
+ head[#head+1] = "#include "..def.."\n"
+ end
+ elseif pp == "define" then
+ local k, sp, v = match(def, "([%w_]+)(%s*)(.*)")
+ if k and not (sp == "" and sub(v, 1, 1) == "(") then
+ defs[k] = gsub(v, "%a[%w_]*", function(tok)
+ return defs[tok] or tok
+ end)
+ else
+ t[#t+1] = "#define "..def.."\n"
+ end
+ elseif pp ~= "undef" then
+ error("unexpected directive: "..pp.." "..def)
+ end
+ end
+ if on then t[#t+1] = txt end
+ end
+ return gsub(table.concat(t), "%a[%w_]*", function(tok)
+ return defs[tok] or tok
+ end)
+end
+
+local function merge_header(src, license)
+ local hdr = string.format([[
+/* This is a heavily customized and minimized copy of Lua %s. */
+/* It's only used to build LuaJIT. It does NOT have all standard functions! */
+]], LUA_VERSION)
+ return hdr..license..table.concat(head)..src
+end
+
+local function strip_unused1(src)
+ return gsub(src, '( {"?([%w_]+)"?,%s+%a[%w_]*},\n)', function(line, func)
+ return REMOVE_LIB[func] and "" or line
+ end)
+end
+
+local function strip_unused2(src)
+ return gsub(src, "Symbolic Execution.-}=", "")
+end
+
+local function strip_unused3(src)
+ src = gsub(src, "extern", "static")
+ src = gsub(src, "\nstatic([^\n]-)%(([^)]*)%)%(", "\nstatic%1 %2(")
+ src = gsub(src, "#define lua_assert[^\n]*\n", "")
+ src = gsub(src, "lua_assert%b();?", "")
+ src = gsub(src, "default:\n}", "default:;\n}")
+ src = gsub(src, "lua_lock%b();", "")
+ src = gsub(src, "lua_unlock%b();", "")
+ src = gsub(src, "luai_threadyield%b();", "")
+ src = gsub(src, "luai_userstateopen%b();", "{}")
+ src = gsub(src, "luai_userstate%w+%b();", "")
+ src = gsub(src, "%(%(c==.*luaY_parser%)", "luaY_parser")
+ src = gsub(src, "trydecpoint%(ls,seminfo%)",
+ "luaX_lexerror(ls,\"malformed number\",TK_NUMBER)")
+ src = gsub(src, "int c=luaZ_lookahead%b();", "")
+ src = gsub(src, "luaL_register%(L,[^,]*,co_funcs%);\nreturn 2;",
+ "return 1;")
+ src = gsub(src, "getfuncname%b():", "NULL:")
+ src = gsub(src, "getobjname%b():", "NULL:")
+ src = gsub(src, "if%([^\n]*hookmask[^\n]*%)\n[^\n]*\n", "")
+ src = gsub(src, "if%([^\n]*hookmask[^\n]*%)%b{}\n", "")
+ src = gsub(src, "if%([^\n]*hookmask[^\n]*&&\n[^\n]*%b{}\n", "")
+ src = gsub(src, "(twoto%b()%()", "%1(size_t)")
+ src = gsub(src, "i
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+typedef enum{
+TM_INDEX,
+TM_NEWINDEX,
+TM_GC,
+TM_MODE,
+TM_EQ,
+TM_ADD,
+TM_SUB,
+TM_MUL,
+TM_DIV,
+TM_MOD,
+TM_POW,
+TM_UNM,
+TM_LEN,
+TM_LT,
+TM_LE,
+TM_CONCAT,
+TM_CALL,
+TM_N
+}TMS;
+enum OpMode{iABC,iABx,iAsBx};
+typedef enum{
+OP_MOVE,
+OP_LOADK,
+OP_LOADBOOL,
+OP_LOADNIL,
+OP_GETUPVAL,
+OP_GETGLOBAL,
+OP_GETTABLE,
+OP_SETGLOBAL,
+OP_SETUPVAL,
+OP_SETTABLE,
+OP_NEWTABLE,
+OP_SELF,
+OP_ADD,
+OP_SUB,
+OP_MUL,
+OP_DIV,
+OP_MOD,
+OP_POW,
+OP_UNM,
+OP_NOT,
+OP_LEN,
+OP_CONCAT,
+OP_JMP,
+OP_EQ,
+OP_LT,
+OP_LE,
+OP_TEST,
+OP_TESTSET,
+OP_CALL,
+OP_TAILCALL,
+OP_RETURN,
+OP_FORLOOP,
+OP_FORPREP,
+OP_TFORLOOP,
+OP_SETLIST,
+OP_CLOSE,
+OP_CLOSURE,
+OP_VARARG
+}OpCode;
+enum OpArgMask{
+OpArgN,
+OpArgU,
+OpArgR,
+OpArgK
+};
+typedef enum{
+VVOID,
+VNIL,
+VTRUE,
+VFALSE,
+VK,
+VKNUM,
+VLOCAL,
+VUPVAL,
+VGLOBAL,
+VINDEXED,
+VJMP,
+VRELOCABLE,
+VNONRELOC,
+VCALL,
+VVARARG
+}expkind;
+enum RESERVED{
+TK_AND=257,TK_BREAK,
+TK_DO,TK_ELSE,TK_ELSEIF,TK_END,TK_FALSE,TK_FOR,TK_FUNCTION,
+TK_IF,TK_IN,TK_LOCAL,TK_NIL,TK_NOT,TK_OR,TK_REPEAT,
+TK_RETURN,TK_THEN,TK_TRUE,TK_UNTIL,TK_WHILE,
+TK_CONCAT,TK_DOTS,TK_EQ,TK_GE,TK_LE,TK_NE,TK_NUMBER,
+TK_NAME,TK_STRING,TK_EOS
+};
+typedef enum BinOpr{
+OPR_ADD,OPR_SUB,OPR_MUL,OPR_DIV,OPR_MOD,OPR_POW,
+OPR_CONCAT,
+OPR_NE,OPR_EQ,
+OPR_LT,OPR_LE,OPR_GT,OPR_GE,
+OPR_AND,OPR_OR,
+OPR_NOBINOPR
+}BinOpr;
+typedef enum UnOpr{OPR_MINUS,OPR_NOT,OPR_LEN,OPR_NOUNOPR}UnOpr;
+#define LUA_QL(x)"'"x"'"
+#define luai_apicheck(L,o){(void)L;}
+#define lua_number2str(s,n)sprintf((s),"%.14g",(n))
+#define lua_str2number(s,p)strtod((s),(p))
+#define luai_numadd(a,b)((a)+(b))
+#define luai_numsub(a,b)((a)-(b))
+#define luai_nummul(a,b)((a)*(b))
+#define luai_numdiv(a,b)((a)/(b))
+#define luai_nummod(a,b)((a)-floor((a)/(b))*(b))
+#define luai_numpow(a,b)(pow(a,b))
+#define luai_numunm(a)(-(a))
+#define luai_numeq(a,b)((a)==(b))
+#define luai_numlt(a,b)((a)<(b))
+#define luai_numle(a,b)((a)<=(b))
+#define luai_numisnan(a)(!luai_numeq((a),(a)))
+#define lua_number2int(i,d)((i)=(int)(d))
+#define lua_number2integer(i,d)((i)=(lua_Integer)(d))
+#define LUAI_THROW(L,c)longjmp((c)->b,1)
+#define LUAI_TRY(L,c,a)if(setjmp((c)->b)==0){a}
+#define lua_pclose(L,file)((void)((void)L,file),0)
+#define lua_upvalueindex(i)((-10002)-(i))
+typedef struct lua_State lua_State;
+typedef int(*lua_CFunction)(lua_State*L);
+typedef const char*(*lua_Reader)(lua_State*L,void*ud,size_t*sz);
+typedef void*(*lua_Alloc)(void*ud,void*ptr,size_t osize,size_t nsize);
+typedef double lua_Number;
+typedef ptrdiff_t lua_Integer;
+static void lua_settop(lua_State*L,int idx);
+static int lua_type(lua_State*L,int idx);
+static const char* lua_tolstring(lua_State*L,int idx,size_t*len);
+static size_t lua_objlen(lua_State*L,int idx);
+static void lua_pushlstring(lua_State*L,const char*s,size_t l);
+static void lua_pushcclosure(lua_State*L,lua_CFunction fn,int n);
+static void lua_createtable(lua_State*L,int narr,int nrec);
+static void lua_setfield(lua_State*L,int idx,const char*k);
+#define lua_pop(L,n)lua_settop(L,-(n)-1)
+#define lua_newtable(L)lua_createtable(L,0,0)
+#define lua_pushcfunction(L,f)lua_pushcclosure(L,(f),0)
+#define lua_strlen(L,i)lua_objlen(L,(i))
+#define lua_isfunction(L,n)(lua_type(L,(n))==6)
+#define lua_istable(L,n)(lua_type(L,(n))==5)
+#define lua_isnil(L,n)(lua_type(L,(n))==0)
+#define lua_isboolean(L,n)(lua_type(L,(n))==1)
+#define lua_isnone(L,n)(lua_type(L,(n))==(-1))
+#define lua_isnoneornil(L,n)(lua_type(L,(n))<=0)
+#define lua_pushliteral(L,s)lua_pushlstring(L,""s,(sizeof(s)/sizeof(char))-1)
+#define lua_setglobal(L,s)lua_setfield(L,(-10002),(s))
+#define lua_tostring(L,i)lua_tolstring(L,(i),NULL)
+typedef struct lua_Debug lua_Debug;
+typedef void(*lua_Hook)(lua_State*L,lua_Debug*ar);
+struct lua_Debug{
+int event;
+const char*name;
+const char*namewhat;
+const char*what;
+const char*source;
+int currentline;
+int nups;
+int linedefined;
+int lastlinedefined;
+char short_src[60];
+int i_ci;
+};
+typedef unsigned int lu_int32;
+typedef size_t lu_mem;
+typedef ptrdiff_t l_mem;
+typedef unsigned char lu_byte;
+#define IntPoint(p)((unsigned int)(lu_mem)(p))
+typedef union{double u;void*s;long l;}L_Umaxalign;
+typedef double l_uacNumber;
+#define check_exp(c,e)(e)
+#define UNUSED(x)((void)(x))
+#define cast(t,exp)((t)(exp))
+#define cast_byte(i)cast(lu_byte,(i))
+#define cast_num(i)cast(lua_Number,(i))
+#define cast_int(i)cast(int,(i))
+typedef lu_int32 Instruction;
+#define condhardstacktests(x)((void)0)
+typedef union GCObject GCObject;
+typedef struct GCheader{
+GCObject*next;lu_byte tt;lu_byte marked;
+}GCheader;
+typedef union{
+GCObject*gc;
+void*p;
+lua_Number n;
+int b;
+}Value;
+typedef struct lua_TValue{
+Value value;int tt;
+}TValue;
+#define ttisnil(o)(ttype(o)==0)
+#define ttisnumber(o)(ttype(o)==3)
+#define ttisstring(o)(ttype(o)==4)
+#define ttistable(o)(ttype(o)==5)
+#define ttisfunction(o)(ttype(o)==6)
+#define ttisboolean(o)(ttype(o)==1)
+#define ttisuserdata(o)(ttype(o)==7)
+#define ttisthread(o)(ttype(o)==8)
+#define ttislightuserdata(o)(ttype(o)==2)
+#define ttype(o)((o)->tt)
+#define gcvalue(o)check_exp(iscollectable(o),(o)->value.gc)
+#define pvalue(o)check_exp(ttislightuserdata(o),(o)->value.p)
+#define nvalue(o)check_exp(ttisnumber(o),(o)->value.n)
+#define rawtsvalue(o)check_exp(ttisstring(o),&(o)->value.gc->ts)
+#define tsvalue(o)(&rawtsvalue(o)->tsv)
+#define rawuvalue(o)check_exp(ttisuserdata(o),&(o)->value.gc->u)
+#define uvalue(o)(&rawuvalue(o)->uv)
+#define clvalue(o)check_exp(ttisfunction(o),&(o)->value.gc->cl)
+#define hvalue(o)check_exp(ttistable(o),&(o)->value.gc->h)
+#define bvalue(o)check_exp(ttisboolean(o),(o)->value.b)
+#define thvalue(o)check_exp(ttisthread(o),&(o)->value.gc->th)
+#define l_isfalse(o)(ttisnil(o)||(ttisboolean(o)&&bvalue(o)==0))
+#define checkconsistency(obj)
+#define checkliveness(g,obj)
+#define setnilvalue(obj)((obj)->tt=0)
+#define setnvalue(obj,x){TValue*i_o=(obj);i_o->value.n=(x);i_o->tt=3;}
+#define setbvalue(obj,x){TValue*i_o=(obj);i_o->value.b=(x);i_o->tt=1;}
+#define setsvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=4;checkliveness(G(L),i_o);}
+#define setuvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=7;checkliveness(G(L),i_o);}
+#define setthvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=8;checkliveness(G(L),i_o);}
+#define setclvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=6;checkliveness(G(L),i_o);}
+#define sethvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=5;checkliveness(G(L),i_o);}
+#define setptvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=(8+1);checkliveness(G(L),i_o);}
+#define setobj(L,obj1,obj2){const TValue*o2=(obj2);TValue*o1=(obj1);o1->value=o2->value;o1->tt=o2->tt;checkliveness(G(L),o1);}
+#define setttype(obj,tt)(ttype(obj)=(tt))
+#define iscollectable(o)(ttype(o)>=4)
+typedef TValue*StkId;
+typedef union TString{
+L_Umaxalign dummy;
+struct{
+GCObject*next;lu_byte tt;lu_byte marked;
+lu_byte reserved;
+unsigned int hash;
+size_t len;
+}tsv;
+}TString;
+#define getstr(ts)cast(const char*,(ts)+1)
+#define svalue(o)getstr(rawtsvalue(o))
+typedef union Udata{
+L_Umaxalign dummy;
+struct{
+GCObject*next;lu_byte tt;lu_byte marked;
+struct Table*metatable;
+struct Table*env;
+size_t len;
+}uv;
+}Udata;
+typedef struct Proto{
+GCObject*next;lu_byte tt;lu_byte marked;
+TValue*k;
+Instruction*code;
+struct Proto**p;
+int*lineinfo;
+struct LocVar*locvars;
+TString**upvalues;
+TString*source;
+int sizeupvalues;
+int sizek;
+int sizecode;
+int sizelineinfo;
+int sizep;
+int sizelocvars;
+int linedefined;
+int lastlinedefined;
+GCObject*gclist;
+lu_byte nups;
+lu_byte numparams;
+lu_byte is_vararg;
+lu_byte maxstacksize;
+}Proto;
+typedef struct LocVar{
+TString*varname;
+int startpc;
+int endpc;
+}LocVar;
+typedef struct UpVal{
+GCObject*next;lu_byte tt;lu_byte marked;
+TValue*v;
+union{
+TValue value;
+struct{
+struct UpVal*prev;
+struct UpVal*next;
+}l;
+}u;
+}UpVal;
+typedef struct CClosure{
+GCObject*next;lu_byte tt;lu_byte marked;lu_byte isC;lu_byte nupvalues;GCObject*gclist;struct Table*env;
+lua_CFunction f;
+TValue upvalue[1];
+}CClosure;
+typedef struct LClosure{
+GCObject*next;lu_byte tt;lu_byte marked;lu_byte isC;lu_byte nupvalues;GCObject*gclist;struct Table*env;
+struct Proto*p;
+UpVal*upvals[1];
+}LClosure;
+typedef union Closure{
+CClosure c;
+LClosure l;
+}Closure;
+#define iscfunction(o)(ttype(o)==6&&clvalue(o)->c.isC)
+typedef union TKey{
+struct{
+Value value;int tt;
+struct Node*next;
+}nk;
+TValue tvk;
+}TKey;
+typedef struct Node{
+TValue i_val;
+TKey i_key;
+}Node;
+typedef struct Table{
+GCObject*next;lu_byte tt;lu_byte marked;
+lu_byte flags;
+lu_byte lsizenode;
+struct Table*metatable;
+TValue*array;
+Node*node;
+Node*lastfree;
+GCObject*gclist;
+int sizearray;
+}Table;
+#define lmod(s,size)(check_exp((size&(size-1))==0,(cast(int,(s)&((size)-1)))))
+#define twoto(x)((size_t)1<<(x))
+#define sizenode(t)(twoto((t)->lsizenode))
+static const TValue luaO_nilobject_;
+#define ceillog2(x)(luaO_log2((x)-1)+1)
+static int luaO_log2(unsigned int x);
+#define gfasttm(g,et,e)((et)==NULL?NULL:((et)->flags&(1u<<(e)))?NULL:luaT_gettm(et,e,(g)->tmname[e]))
+#define fasttm(l,et,e)gfasttm(G(l),et,e)
+static const TValue*luaT_gettm(Table*events,TMS event,TString*ename);
+#define luaM_reallocv(L,b,on,n,e)((cast(size_t,(n)+1)<=((size_t)(~(size_t)0)-2)/(e))?luaM_realloc_(L,(b),(on)*(e),(n)*(e)):luaM_toobig(L))
+#define luaM_freemem(L,b,s)luaM_realloc_(L,(b),(s),0)
+#define luaM_free(L,b)luaM_realloc_(L,(b),sizeof(*(b)),0)
+#define luaM_freearray(L,b,n,t)luaM_reallocv(L,(b),n,0,sizeof(t))
+#define luaM_malloc(L,t)luaM_realloc_(L,NULL,0,(t))
+#define luaM_new(L,t)cast(t*,luaM_malloc(L,sizeof(t)))
+#define luaM_newvector(L,n,t)cast(t*,luaM_reallocv(L,NULL,0,n,sizeof(t)))
+#define luaM_growvector(L,v,nelems,size,t,limit,e)if((nelems)+1>(size))((v)=cast(t*,luaM_growaux_(L,v,&(size),sizeof(t),limit,e)))
+#define luaM_reallocvector(L,v,oldn,n,t)((v)=cast(t*,luaM_reallocv(L,v,oldn,n,sizeof(t))))
+static void*luaM_realloc_(lua_State*L,void*block,size_t oldsize,
+size_t size);
+static void*luaM_toobig(lua_State*L);
+static void*luaM_growaux_(lua_State*L,void*block,int*size,
+size_t size_elem,int limit,
+const char*errormsg);
+typedef struct Zio ZIO;
+#define char2int(c)cast(int,cast(unsigned char,(c)))
+#define zgetc(z)(((z)->n--)>0?char2int(*(z)->p++):luaZ_fill(z))
+typedef struct Mbuffer{
+char*buffer;
+size_t n;
+size_t buffsize;
+}Mbuffer;
+#define luaZ_initbuffer(L,buff)((buff)->buffer=NULL,(buff)->buffsize=0)
+#define luaZ_buffer(buff)((buff)->buffer)
+#define luaZ_sizebuffer(buff)((buff)->buffsize)
+#define luaZ_bufflen(buff)((buff)->n)
+#define luaZ_resetbuffer(buff)((buff)->n=0)
+#define luaZ_resizebuffer(L,buff,size)(luaM_reallocvector(L,(buff)->buffer,(buff)->buffsize,size,char),(buff)->buffsize=size)
+#define luaZ_freebuffer(L,buff)luaZ_resizebuffer(L,buff,0)
+struct Zio{
+size_t n;
+const char*p;
+lua_Reader reader;
+void*data;
+lua_State*L;
+};
+static int luaZ_fill(ZIO*z);
+struct lua_longjmp;
+#define gt(L)(&L->l_gt)
+#define registry(L)(&G(L)->l_registry)
+typedef struct stringtable{
+GCObject**hash;
+lu_int32 nuse;
+int size;
+}stringtable;
+typedef struct CallInfo{
+StkId base;
+StkId func;
+StkId top;
+const Instruction*savedpc;
+int nresults;
+int tailcalls;
+}CallInfo;
+#define curr_func(L)(clvalue(L->ci->func))
+#define ci_func(ci)(clvalue((ci)->func))
+#define f_isLua(ci)(!ci_func(ci)->c.isC)
+#define isLua(ci)(ttisfunction((ci)->func)&&f_isLua(ci))
+typedef struct global_State{
+stringtable strt;
+lua_Alloc frealloc;
+void*ud;
+lu_byte currentwhite;
+lu_byte gcstate;
+int sweepstrgc;
+GCObject*rootgc;
+GCObject**sweepgc;
+GCObject*gray;
+GCObject*grayagain;
+GCObject*weak;
+GCObject*tmudata;
+Mbuffer buff;
+lu_mem GCthreshold;
+lu_mem totalbytes;
+lu_mem estimate;
+lu_mem gcdept;
+int gcpause;
+int gcstepmul;
+lua_CFunction panic;
+TValue l_registry;
+struct lua_State*mainthread;
+UpVal uvhead;
+struct Table*mt[(8+1)];
+TString*tmname[TM_N];
+}global_State;
+struct lua_State{
+GCObject*next;lu_byte tt;lu_byte marked;
+lu_byte status;
+StkId top;
+StkId base;
+global_State*l_G;
+CallInfo*ci;
+const Instruction*savedpc;
+StkId stack_last;
+StkId stack;
+CallInfo*end_ci;
+CallInfo*base_ci;
+int stacksize;
+int size_ci;
+unsigned short nCcalls;
+unsigned short baseCcalls;
+lu_byte hookmask;
+lu_byte allowhook;
+int basehookcount;
+int hookcount;
+lua_Hook hook;
+TValue l_gt;
+TValue env;
+GCObject*openupval;
+GCObject*gclist;
+struct lua_longjmp*errorJmp;
+ptrdiff_t errfunc;
+};
+#define G(L)(L->l_G)
+union GCObject{
+GCheader gch;
+union TString ts;
+union Udata u;
+union Closure cl;
+struct Table h;
+struct Proto p;
+struct UpVal uv;
+struct lua_State th;
+};
+#define rawgco2ts(o)check_exp((o)->gch.tt==4,&((o)->ts))
+#define gco2ts(o)(&rawgco2ts(o)->tsv)
+#define rawgco2u(o)check_exp((o)->gch.tt==7,&((o)->u))
+#define gco2u(o)(&rawgco2u(o)->uv)
+#define gco2cl(o)check_exp((o)->gch.tt==6,&((o)->cl))
+#define gco2h(o)check_exp((o)->gch.tt==5,&((o)->h))
+#define gco2p(o)check_exp((o)->gch.tt==(8+1),&((o)->p))
+#define gco2uv(o)check_exp((o)->gch.tt==(8+2),&((o)->uv))
+#define ngcotouv(o)check_exp((o)==NULL||(o)->gch.tt==(8+2),&((o)->uv))
+#define gco2th(o)check_exp((o)->gch.tt==8,&((o)->th))
+#define obj2gco(v)(cast(GCObject*,(v)))
+static void luaE_freethread(lua_State*L,lua_State*L1);
+#define pcRel(pc,p)(cast(int,(pc)-(p)->code)-1)
+#define getline_(f,pc)(((f)->lineinfo)?(f)->lineinfo[pc]:0)
+#define resethookcount(L)(L->hookcount=L->basehookcount)
+static void luaG_typeerror(lua_State*L,const TValue*o,
+const char*opname);
+static void luaG_runerror(lua_State*L,const char*fmt,...);
+#define luaD_checkstack(L,n)if((char*)L->stack_last-(char*)L->top<=(n)*(int)sizeof(TValue))luaD_growstack(L,n);else condhardstacktests(luaD_reallocstack(L,L->stacksize-5-1));
+#define incr_top(L){luaD_checkstack(L,1);L->top++;}
+#define savestack(L,p)((char*)(p)-(char*)L->stack)
+#define restorestack(L,n)((TValue*)((char*)L->stack+(n)))
+#define saveci(L,p)((char*)(p)-(char*)L->base_ci)
+#define restoreci(L,n)((CallInfo*)((char*)L->base_ci+(n)))
+typedef void(*Pfunc)(lua_State*L,void*ud);
+static int luaD_poscall(lua_State*L,StkId firstResult);
+static void luaD_reallocCI(lua_State*L,int newsize);
+static void luaD_reallocstack(lua_State*L,int newsize);
+static void luaD_growstack(lua_State*L,int n);
+static void luaD_throw(lua_State*L,int errcode);
+static void*luaM_growaux_(lua_State*L,void*block,int*size,size_t size_elems,
+int limit,const char*errormsg){
+void*newblock;
+int newsize;
+if(*size>=limit/2){
+if(*size>=limit)
+luaG_runerror(L,errormsg);
+newsize=limit;
+}
+else{
+newsize=(*size)*2;
+if(newsize<4)
+newsize=4;
+}
+newblock=luaM_reallocv(L,block,*size,newsize,size_elems);
+*size=newsize;
+return newblock;
+}
+static void*luaM_toobig(lua_State*L){
+luaG_runerror(L,"memory allocation error: block too big");
+return NULL;
+}
+static void*luaM_realloc_(lua_State*L,void*block,size_t osize,size_t nsize){
+global_State*g=G(L);
+block=(*g->frealloc)(g->ud,block,osize,nsize);
+if(block==NULL&&nsize>0)
+luaD_throw(L,4);
+g->totalbytes=(g->totalbytes-osize)+nsize;
+return block;
+}
+#define resetbits(x,m)((x)&=cast(lu_byte,~(m)))
+#define setbits(x,m)((x)|=(m))
+#define testbits(x,m)((x)&(m))
+#define bitmask(b)(1<<(b))
+#define bit2mask(b1,b2)(bitmask(b1)|bitmask(b2))
+#define l_setbit(x,b)setbits(x,bitmask(b))
+#define resetbit(x,b)resetbits(x,bitmask(b))
+#define testbit(x,b)testbits(x,bitmask(b))
+#define set2bits(x,b1,b2)setbits(x,(bit2mask(b1,b2)))
+#define reset2bits(x,b1,b2)resetbits(x,(bit2mask(b1,b2)))
+#define test2bits(x,b1,b2)testbits(x,(bit2mask(b1,b2)))
+#define iswhite(x)test2bits((x)->gch.marked,0,1)
+#define isblack(x)testbit((x)->gch.marked,2)
+#define isgray(x)(!isblack(x)&&!iswhite(x))
+#define otherwhite(g)(g->currentwhite^bit2mask(0,1))
+#define isdead(g,v)((v)->gch.marked&otherwhite(g)&bit2mask(0,1))
+#define changewhite(x)((x)->gch.marked^=bit2mask(0,1))
+#define gray2black(x)l_setbit((x)->gch.marked,2)
+#define valiswhite(x)(iscollectable(x)&&iswhite(gcvalue(x)))
+#define luaC_white(g)cast(lu_byte,(g)->currentwhite&bit2mask(0,1))
+#define luaC_checkGC(L){condhardstacktests(luaD_reallocstack(L,L->stacksize-5-1));if(G(L)->totalbytes>=G(L)->GCthreshold)luaC_step(L);}
+#define luaC_barrier(L,p,v){if(valiswhite(v)&&isblack(obj2gco(p)))luaC_barrierf(L,obj2gco(p),gcvalue(v));}
+#define luaC_barriert(L,t,v){if(valiswhite(v)&&isblack(obj2gco(t)))luaC_barrierback(L,t);}
+#define luaC_objbarrier(L,p,o){if(iswhite(obj2gco(o))&&isblack(obj2gco(p)))luaC_barrierf(L,obj2gco(p),obj2gco(o));}
+#define luaC_objbarriert(L,t,o){if(iswhite(obj2gco(o))&&isblack(obj2gco(t)))luaC_barrierback(L,t);}
+static void luaC_step(lua_State*L);
+static void luaC_link(lua_State*L,GCObject*o,lu_byte tt);
+static void luaC_linkupval(lua_State*L,UpVal*uv);
+static void luaC_barrierf(lua_State*L,GCObject*o,GCObject*v);
+static void luaC_barrierback(lua_State*L,Table*t);
+#define sizestring(s)(sizeof(union TString)+((s)->len+1)*sizeof(char))
+#define sizeudata(u)(sizeof(union Udata)+(u)->len)
+#define luaS_new(L,s)(luaS_newlstr(L,s,strlen(s)))
+#define luaS_newliteral(L,s)(luaS_newlstr(L,""s,(sizeof(s)/sizeof(char))-1))
+#define luaS_fix(s)l_setbit((s)->tsv.marked,5)
+static TString*luaS_newlstr(lua_State*L,const char*str,size_t l);
+#define tostring(L,o)((ttype(o)==4)||(luaV_tostring(L,o)))
+#define tonumber(o,n)(ttype(o)==3||(((o)=luaV_tonumber(o,n))!=NULL))
+#define equalobj(L,o1,o2)(ttype(o1)==ttype(o2)&&luaV_equalval(L,o1,o2))
+static int luaV_equalval(lua_State*L,const TValue*t1,const TValue*t2);
+static const TValue*luaV_tonumber(const TValue*obj,TValue*n);
+static int luaV_tostring(lua_State*L,StkId obj);
+static void luaV_execute(lua_State*L,int nexeccalls);
+static void luaV_concat(lua_State*L,int total,int last);
+static const TValue luaO_nilobject_={{NULL},0};
+static int luaO_int2fb(unsigned int x){
+int e=0;
+while(x>=16){
+x=(x+1)>>1;
+e++;
+}
+if(x<8)return x;
+else return((e+1)<<3)|(cast_int(x)-8);
+}
+static int luaO_fb2int(int x){
+int e=(x>>3)&31;
+if(e==0)return x;
+else return((x&7)+8)<<(e-1);
+}
+static int luaO_log2(unsigned int x){
+static const lu_byte log_2[256]={
+0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
+};
+int l=-1;
+while(x>=256){l+=8;x>>=8;}
+return l+log_2[x];
+}
+static int luaO_rawequalObj(const TValue*t1,const TValue*t2){
+if(ttype(t1)!=ttype(t2))return 0;
+else switch(ttype(t1)){
+case 0:
+return 1;
+case 3:
+return luai_numeq(nvalue(t1),nvalue(t2));
+case 1:
+return bvalue(t1)==bvalue(t2);
+case 2:
+return pvalue(t1)==pvalue(t2);
+default:
+return gcvalue(t1)==gcvalue(t2);
+}
+}
+static int luaO_str2d(const char*s,lua_Number*result){
+char*endptr;
+*result=lua_str2number(s,&endptr);
+if(endptr==s)return 0;
+if(*endptr=='x'||*endptr=='X')
+*result=cast_num(strtoul(s,&endptr,16));
+if(*endptr=='\0')return 1;
+while(isspace(cast(unsigned char,*endptr)))endptr++;
+if(*endptr!='\0')return 0;
+return 1;
+}
+static void pushstr(lua_State*L,const char*str){
+setsvalue(L,L->top,luaS_new(L,str));
+incr_top(L);
+}
+static const char*luaO_pushvfstring(lua_State*L,const char*fmt,va_list argp){
+int n=1;
+pushstr(L,"");
+for(;;){
+const char*e=strchr(fmt,'%');
+if(e==NULL)break;
+setsvalue(L,L->top,luaS_newlstr(L,fmt,e-fmt));
+incr_top(L);
+switch(*(e+1)){
+case's':{
+const char*s=va_arg(argp,char*);
+if(s==NULL)s="(null)";
+pushstr(L,s);
+break;
+}
+case'c':{
+char buff[2];
+buff[0]=cast(char,va_arg(argp,int));
+buff[1]='\0';
+pushstr(L,buff);
+break;
+}
+case'd':{
+setnvalue(L->top,cast_num(va_arg(argp,int)));
+incr_top(L);
+break;
+}
+case'f':{
+setnvalue(L->top,cast_num(va_arg(argp,l_uacNumber)));
+incr_top(L);
+break;
+}
+case'p':{
+char buff[4*sizeof(void*)+8];
+sprintf(buff,"%p",va_arg(argp,void*));
+pushstr(L,buff);
+break;
+}
+case'%':{
+pushstr(L,"%");
+break;
+}
+default:{
+char buff[3];
+buff[0]='%';
+buff[1]=*(e+1);
+buff[2]='\0';
+pushstr(L,buff);
+break;
+}
+}
+n+=2;
+fmt=e+2;
+}
+pushstr(L,fmt);
+luaV_concat(L,n+1,cast_int(L->top-L->base)-1);
+L->top-=n;
+return svalue(L->top-1);
+}
+static const char*luaO_pushfstring(lua_State*L,const char*fmt,...){
+const char*msg;
+va_list argp;
+va_start(argp,fmt);
+msg=luaO_pushvfstring(L,fmt,argp);
+va_end(argp);
+return msg;
+}
+static void luaO_chunkid(char*out,const char*source,size_t bufflen){
+if(*source=='='){
+strncpy(out,source+1,bufflen);
+out[bufflen-1]='\0';
+}
+else{
+if(*source=='@'){
+size_t l;
+source++;
+bufflen-=sizeof(" '...' ");
+l=strlen(source);
+strcpy(out,"");
+if(l>bufflen){
+source+=(l-bufflen);
+strcat(out,"...");
+}
+strcat(out,source);
+}
+else{
+size_t len=strcspn(source,"\n\r");
+bufflen-=sizeof(" [string \"...\"] ");
+if(len>bufflen)len=bufflen;
+strcpy(out,"[string \"");
+if(source[len]!='\0'){
+strncat(out,source,len);
+strcat(out,"...");
+}
+else
+strcat(out,source);
+strcat(out,"\"]");
+}
+}
+}
+#define gnode(t,i)(&(t)->node[i])
+#define gkey(n)(&(n)->i_key.nk)
+#define gval(n)(&(n)->i_val)
+#define gnext(n)((n)->i_key.nk.next)
+#define key2tval(n)(&(n)->i_key.tvk)
+static TValue*luaH_setnum(lua_State*L,Table*t,int key);
+static const TValue*luaH_getstr(Table*t,TString*key);
+static TValue*luaH_set(lua_State*L,Table*t,const TValue*key);
+static const char*const luaT_typenames[]={
+"nil","boolean","userdata","number",
+"string","table","function","userdata","thread",
+"proto","upval"
+};
+static void luaT_init(lua_State*L){
+static const char*const luaT_eventname[]={
+"__index","__newindex",
+"__gc","__mode","__eq",
+"__add","__sub","__mul","__div","__mod",
+"__pow","__unm","__len","__lt","__le",
+"__concat","__call"
+};
+int i;
+for(i=0;itmname[i]=luaS_new(L,luaT_eventname[i]);
+luaS_fix(G(L)->tmname[i]);
+}
+}
+static const TValue*luaT_gettm(Table*events,TMS event,TString*ename){
+const TValue*tm=luaH_getstr(events,ename);
+if(ttisnil(tm)){
+events->flags|=cast_byte(1u<metatable;
+break;
+case 7:
+mt=uvalue(o)->metatable;
+break;
+default:
+mt=G(L)->mt[ttype(o)];
+}
+return(mt?luaH_getstr(mt,G(L)->tmname[event]):(&luaO_nilobject_));
+}
+#define sizeCclosure(n)(cast(int,sizeof(CClosure))+cast(int,sizeof(TValue)*((n)-1)))
+#define sizeLclosure(n)(cast(int,sizeof(LClosure))+cast(int,sizeof(TValue*)*((n)-1)))
+static Closure*luaF_newCclosure(lua_State*L,int nelems,Table*e){
+Closure*c=cast(Closure*,luaM_malloc(L,sizeCclosure(nelems)));
+luaC_link(L,obj2gco(c),6);
+c->c.isC=1;
+c->c.env=e;
+c->c.nupvalues=cast_byte(nelems);
+return c;
+}
+static Closure*luaF_newLclosure(lua_State*L,int nelems,Table*e){
+Closure*c=cast(Closure*,luaM_malloc(L,sizeLclosure(nelems)));
+luaC_link(L,obj2gco(c),6);
+c->l.isC=0;
+c->l.env=e;
+c->l.nupvalues=cast_byte(nelems);
+while(nelems--)c->l.upvals[nelems]=NULL;
+return c;
+}
+static UpVal*luaF_newupval(lua_State*L){
+UpVal*uv=luaM_new(L,UpVal);
+luaC_link(L,obj2gco(uv),(8+2));
+uv->v=&uv->u.value;
+setnilvalue(uv->v);
+return uv;
+}
+static UpVal*luaF_findupval(lua_State*L,StkId level){
+global_State*g=G(L);
+GCObject**pp=&L->openupval;
+UpVal*p;
+UpVal*uv;
+while(*pp!=NULL&&(p=ngcotouv(*pp))->v>=level){
+if(p->v==level){
+if(isdead(g,obj2gco(p)))
+changewhite(obj2gco(p));
+return p;
+}
+pp=&p->next;
+}
+uv=luaM_new(L,UpVal);
+uv->tt=(8+2);
+uv->marked=luaC_white(g);
+uv->v=level;
+uv->next=*pp;
+*pp=obj2gco(uv);
+uv->u.l.prev=&g->uvhead;
+uv->u.l.next=g->uvhead.u.l.next;
+uv->u.l.next->u.l.prev=uv;
+g->uvhead.u.l.next=uv;
+return uv;
+}
+static void unlinkupval(UpVal*uv){
+uv->u.l.next->u.l.prev=uv->u.l.prev;
+uv->u.l.prev->u.l.next=uv->u.l.next;
+}
+static void luaF_freeupval(lua_State*L,UpVal*uv){
+if(uv->v!=&uv->u.value)
+unlinkupval(uv);
+luaM_free(L,uv);
+}
+static void luaF_close(lua_State*L,StkId level){
+UpVal*uv;
+global_State*g=G(L);
+while(L->openupval!=NULL&&(uv=ngcotouv(L->openupval))->v>=level){
+GCObject*o=obj2gco(uv);
+L->openupval=uv->next;
+if(isdead(g,o))
+luaF_freeupval(L,uv);
+else{
+unlinkupval(uv);
+setobj(L,&uv->u.value,uv->v);
+uv->v=&uv->u.value;
+luaC_linkupval(L,uv);
+}
+}
+}
+static Proto*luaF_newproto(lua_State*L){
+Proto*f=luaM_new(L,Proto);
+luaC_link(L,obj2gco(f),(8+1));
+f->k=NULL;
+f->sizek=0;
+f->p=NULL;
+f->sizep=0;
+f->code=NULL;
+f->sizecode=0;
+f->sizelineinfo=0;
+f->sizeupvalues=0;
+f->nups=0;
+f->upvalues=NULL;
+f->numparams=0;
+f->is_vararg=0;
+f->maxstacksize=0;
+f->lineinfo=NULL;
+f->sizelocvars=0;
+f->locvars=NULL;
+f->linedefined=0;
+f->lastlinedefined=0;
+f->source=NULL;
+return f;
+}
+static void luaF_freeproto(lua_State*L,Proto*f){
+luaM_freearray(L,f->code,f->sizecode,Instruction);
+luaM_freearray(L,f->p,f->sizep,Proto*);
+luaM_freearray(L,f->k,f->sizek,TValue);
+luaM_freearray(L,f->lineinfo,f->sizelineinfo,int);
+luaM_freearray(L,f->locvars,f->sizelocvars,struct LocVar);
+luaM_freearray(L,f->upvalues,f->sizeupvalues,TString*);
+luaM_free(L,f);
+}
+static void luaF_freeclosure(lua_State*L,Closure*c){
+int size=(c->c.isC)?sizeCclosure(c->c.nupvalues):
+sizeLclosure(c->l.nupvalues);
+luaM_freemem(L,c,size);
+}
+#define MASK1(n,p)((~((~(Instruction)0)<>0)&MASK1(6,0)))
+#define SET_OPCODE(i,o)((i)=(((i)&MASK0(6,0))|((cast(Instruction,o)<<0)&MASK1(6,0))))
+#define GETARG_A(i)(cast(int,((i)>>(0+6))&MASK1(8,0)))
+#define SETARG_A(i,u)((i)=(((i)&MASK0(8,(0+6)))|((cast(Instruction,u)<<(0+6))&MASK1(8,(0+6)))))
+#define GETARG_B(i)(cast(int,((i)>>(((0+6)+8)+9))&MASK1(9,0)))
+#define SETARG_B(i,b)((i)=(((i)&MASK0(9,(((0+6)+8)+9)))|((cast(Instruction,b)<<(((0+6)+8)+9))&MASK1(9,(((0+6)+8)+9)))))
+#define GETARG_C(i)(cast(int,((i)>>((0+6)+8))&MASK1(9,0)))
+#define SETARG_C(i,b)((i)=(((i)&MASK0(9,((0+6)+8)))|((cast(Instruction,b)<<((0+6)+8))&MASK1(9,((0+6)+8)))))
+#define GETARG_Bx(i)(cast(int,((i)>>((0+6)+8))&MASK1((9+9),0)))
+#define SETARG_Bx(i,b)((i)=(((i)&MASK0((9+9),((0+6)+8)))|((cast(Instruction,b)<<((0+6)+8))&MASK1((9+9),((0+6)+8)))))
+#define GETARG_sBx(i)(GETARG_Bx(i)-(((1<<(9+9))-1)>>1))
+#define SETARG_sBx(i,b)SETARG_Bx((i),cast(unsigned int,(b)+(((1<<(9+9))-1)>>1)))
+#define CREATE_ABC(o,a,b,c)((cast(Instruction,o)<<0)|(cast(Instruction,a)<<(0+6))|(cast(Instruction,b)<<(((0+6)+8)+9))|(cast(Instruction,c)<<((0+6)+8)))
+#define CREATE_ABx(o,a,bc)((cast(Instruction,o)<<0)|(cast(Instruction,a)<<(0+6))|(cast(Instruction,bc)<<((0+6)+8)))
+#define ISK(x)((x)&(1<<(9-1)))
+#define INDEXK(r)((int)(r)&~(1<<(9-1)))
+#define RKASK(x)((x)|(1<<(9-1)))
+static const lu_byte luaP_opmodes[(cast(int,OP_VARARG)+1)];
+#define getBMode(m)(cast(enum OpArgMask,(luaP_opmodes[m]>>4)&3))
+#define getCMode(m)(cast(enum OpArgMask,(luaP_opmodes[m]>>2)&3))
+#define testTMode(m)(luaP_opmodes[m]&(1<<7))
+typedef struct expdesc{
+expkind k;
+union{
+struct{int info,aux;}s;
+lua_Number nval;
+}u;
+int t;
+int f;
+}expdesc;
+typedef struct upvaldesc{
+lu_byte k;
+lu_byte info;
+}upvaldesc;
+struct BlockCnt;
+typedef struct FuncState{
+Proto*f;
+Table*h;
+struct FuncState*prev;
+struct LexState*ls;
+struct lua_State*L;
+struct BlockCnt*bl;
+int pc;
+int lasttarget;
+int jpc;
+int freereg;
+int nk;
+int np;
+short nlocvars;
+lu_byte nactvar;
+upvaldesc upvalues[60];
+unsigned short actvar[200];
+}FuncState;
+static Proto*luaY_parser(lua_State*L,ZIO*z,Mbuffer*buff,
+const char*name);
+struct lua_longjmp{
+struct lua_longjmp*previous;
+jmp_buf b;
+volatile int status;
+};
+static void luaD_seterrorobj(lua_State*L,int errcode,StkId oldtop){
+switch(errcode){
+case 4:{
+setsvalue(L,oldtop,luaS_newliteral(L,"not enough memory"));
+break;
+}
+case 5:{
+setsvalue(L,oldtop,luaS_newliteral(L,"error in error handling"));
+break;
+}
+case 3:
+case 2:{
+setobj(L,oldtop,L->top-1);
+break;
+}
+}
+L->top=oldtop+1;
+}
+static void restore_stack_limit(lua_State*L){
+if(L->size_ci>20000){
+int inuse=cast_int(L->ci-L->base_ci);
+if(inuse+1<20000)
+luaD_reallocCI(L,20000);
+}
+}
+static void resetstack(lua_State*L,int status){
+L->ci=L->base_ci;
+L->base=L->ci->base;
+luaF_close(L,L->base);
+luaD_seterrorobj(L,status,L->base);
+L->nCcalls=L->baseCcalls;
+L->allowhook=1;
+restore_stack_limit(L);
+L->errfunc=0;
+L->errorJmp=NULL;
+}
+static void luaD_throw(lua_State*L,int errcode){
+if(L->errorJmp){
+L->errorJmp->status=errcode;
+LUAI_THROW(L,L->errorJmp);
+}
+else{
+L->status=cast_byte(errcode);
+if(G(L)->panic){
+resetstack(L,errcode);
+G(L)->panic(L);
+}
+exit(EXIT_FAILURE);
+}
+}
+static int luaD_rawrunprotected(lua_State*L,Pfunc f,void*ud){
+struct lua_longjmp lj;
+lj.status=0;
+lj.previous=L->errorJmp;
+L->errorJmp=&lj;
+LUAI_TRY(L,&lj,
+(*f)(L,ud);
+);
+L->errorJmp=lj.previous;
+return lj.status;
+}
+static void correctstack(lua_State*L,TValue*oldstack){
+CallInfo*ci;
+GCObject*up;
+L->top=(L->top-oldstack)+L->stack;
+for(up=L->openupval;up!=NULL;up=up->gch.next)
+gco2uv(up)->v=(gco2uv(up)->v-oldstack)+L->stack;
+for(ci=L->base_ci;ci<=L->ci;ci++){
+ci->top=(ci->top-oldstack)+L->stack;
+ci->base=(ci->base-oldstack)+L->stack;
+ci->func=(ci->func-oldstack)+L->stack;
+}
+L->base=(L->base-oldstack)+L->stack;
+}
+static void luaD_reallocstack(lua_State*L,int newsize){
+TValue*oldstack=L->stack;
+int realsize=newsize+1+5;
+luaM_reallocvector(L,L->stack,L->stacksize,realsize,TValue);
+L->stacksize=realsize;
+L->stack_last=L->stack+newsize;
+correctstack(L,oldstack);
+}
+static void luaD_reallocCI(lua_State*L,int newsize){
+CallInfo*oldci=L->base_ci;
+luaM_reallocvector(L,L->base_ci,L->size_ci,newsize,CallInfo);
+L->size_ci=newsize;
+L->ci=(L->ci-oldci)+L->base_ci;
+L->end_ci=L->base_ci+L->size_ci-1;
+}
+static void luaD_growstack(lua_State*L,int n){
+if(n<=L->stacksize)
+luaD_reallocstack(L,2*L->stacksize);
+else
+luaD_reallocstack(L,L->stacksize+n);
+}
+static CallInfo*growCI(lua_State*L){
+if(L->size_ci>20000)
+luaD_throw(L,5);
+else{
+luaD_reallocCI(L,2*L->size_ci);
+if(L->size_ci>20000)
+luaG_runerror(L,"stack overflow");
+}
+return++L->ci;
+}
+static StkId adjust_varargs(lua_State*L,Proto*p,int actual){
+int i;
+int nfixargs=p->numparams;
+Table*htab=NULL;
+StkId base,fixed;
+for(;actualtop++);
+fixed=L->top-actual;
+base=L->top;
+for(i=0;itop++,fixed+i);
+setnilvalue(fixed+i);
+}
+if(htab){
+sethvalue(L,L->top++,htab);
+}
+return base;
+}
+static StkId tryfuncTM(lua_State*L,StkId func){
+const TValue*tm=luaT_gettmbyobj(L,func,TM_CALL);
+StkId p;
+ptrdiff_t funcr=savestack(L,func);
+if(!ttisfunction(tm))
+luaG_typeerror(L,func,"call");
+for(p=L->top;p>func;p--)setobj(L,p,p-1);
+incr_top(L);
+func=restorestack(L,funcr);
+setobj(L,func,tm);
+return func;
+}
+#define inc_ci(L)((L->ci==L->end_ci)?growCI(L):(condhardstacktests(luaD_reallocCI(L,L->size_ci)),++L->ci))
+static int luaD_precall(lua_State*L,StkId func,int nresults){
+LClosure*cl;
+ptrdiff_t funcr;
+if(!ttisfunction(func))
+func=tryfuncTM(L,func);
+funcr=savestack(L,func);
+cl=&clvalue(func)->l;
+L->ci->savedpc=L->savedpc;
+if(!cl->isC){
+CallInfo*ci;
+StkId st,base;
+Proto*p=cl->p;
+luaD_checkstack(L,p->maxstacksize);
+func=restorestack(L,funcr);
+if(!p->is_vararg){
+base=func+1;
+if(L->top>base+p->numparams)
+L->top=base+p->numparams;
+}
+else{
+int nargs=cast_int(L->top-func)-1;
+base=adjust_varargs(L,p,nargs);
+func=restorestack(L,funcr);
+}
+ci=inc_ci(L);
+ci->func=func;
+L->base=ci->base=base;
+ci->top=L->base+p->maxstacksize;
+L->savedpc=p->code;
+ci->tailcalls=0;
+ci->nresults=nresults;
+for(st=L->top;sttop;st++)
+setnilvalue(st);
+L->top=ci->top;
+return 0;
+}
+else{
+CallInfo*ci;
+int n;
+luaD_checkstack(L,20);
+ci=inc_ci(L);
+ci->func=restorestack(L,funcr);
+L->base=ci->base=ci->func+1;
+ci->top=L->top+20;
+ci->nresults=nresults;
+n=(*curr_func(L)->c.f)(L);
+if(n<0)
+return 2;
+else{
+luaD_poscall(L,L->top-n);
+return 1;
+}
+}
+}
+static int luaD_poscall(lua_State*L,StkId firstResult){
+StkId res;
+int wanted,i;
+CallInfo*ci;
+ci=L->ci--;
+res=ci->func;
+wanted=ci->nresults;
+L->base=(ci-1)->base;
+L->savedpc=(ci-1)->savedpc;
+for(i=wanted;i!=0&&firstResulttop;i--)
+setobj(L,res++,firstResult++);
+while(i-->0)
+setnilvalue(res++);
+L->top=res;
+return(wanted-(-1));
+}
+static void luaD_call(lua_State*L,StkId func,int nResults){
+if(++L->nCcalls>=200){
+if(L->nCcalls==200)
+luaG_runerror(L,"C stack overflow");
+else if(L->nCcalls>=(200+(200>>3)))
+luaD_throw(L,5);
+}
+if(luaD_precall(L,func,nResults)==0)
+luaV_execute(L,1);
+L->nCcalls--;
+luaC_checkGC(L);
+}
+static int luaD_pcall(lua_State*L,Pfunc func,void*u,
+ptrdiff_t old_top,ptrdiff_t ef){
+int status;
+unsigned short oldnCcalls=L->nCcalls;
+ptrdiff_t old_ci=saveci(L,L->ci);
+lu_byte old_allowhooks=L->allowhook;
+ptrdiff_t old_errfunc=L->errfunc;
+L->errfunc=ef;
+status=luaD_rawrunprotected(L,func,u);
+if(status!=0){
+StkId oldtop=restorestack(L,old_top);
+luaF_close(L,oldtop);
+luaD_seterrorobj(L,status,oldtop);
+L->nCcalls=oldnCcalls;
+L->ci=restoreci(L,old_ci);
+L->base=L->ci->base;
+L->savedpc=L->ci->savedpc;
+L->allowhook=old_allowhooks;
+restore_stack_limit(L);
+}
+L->errfunc=old_errfunc;
+return status;
+}
+struct SParser{
+ZIO*z;
+Mbuffer buff;
+const char*name;
+};
+static void f_parser(lua_State*L,void*ud){
+int i;
+Proto*tf;
+Closure*cl;
+struct SParser*p=cast(struct SParser*,ud);
+luaC_checkGC(L);
+tf=luaY_parser(L,p->z,
+&p->buff,p->name);
+cl=luaF_newLclosure(L,tf->nups,hvalue(gt(L)));
+cl->l.p=tf;
+for(i=0;inups;i++)
+cl->l.upvals[i]=luaF_newupval(L);
+setclvalue(L,L->top,cl);
+incr_top(L);
+}
+static int luaD_protectedparser(lua_State*L,ZIO*z,const char*name){
+struct SParser p;
+int status;
+p.z=z;p.name=name;
+luaZ_initbuffer(L,&p.buff);
+status=luaD_pcall(L,f_parser,&p,savestack(L,L->top),L->errfunc);
+luaZ_freebuffer(L,&p.buff);
+return status;
+}
+static void luaS_resize(lua_State*L,int newsize){
+GCObject**newhash;
+stringtable*tb;
+int i;
+if(G(L)->gcstate==2)
+return;
+newhash=luaM_newvector(L,newsize,GCObject*);
+tb=&G(L)->strt;
+for(i=0;isize;i++){
+GCObject*p=tb->hash[i];
+while(p){
+GCObject*next=p->gch.next;
+unsigned int h=gco2ts(p)->hash;
+int h1=lmod(h,newsize);
+p->gch.next=newhash[h1];
+newhash[h1]=p;
+p=next;
+}
+}
+luaM_freearray(L,tb->hash,tb->size,TString*);
+tb->size=newsize;
+tb->hash=newhash;
+}
+static TString*newlstr(lua_State*L,const char*str,size_t l,
+unsigned int h){
+TString*ts;
+stringtable*tb;
+if(l+1>(((size_t)(~(size_t)0)-2)-sizeof(TString))/sizeof(char))
+luaM_toobig(L);
+ts=cast(TString*,luaM_malloc(L,(l+1)*sizeof(char)+sizeof(TString)));
+ts->tsv.len=l;
+ts->tsv.hash=h;
+ts->tsv.marked=luaC_white(G(L));
+ts->tsv.tt=4;
+ts->tsv.reserved=0;
+memcpy(ts+1,str,l*sizeof(char));
+((char*)(ts+1))[l]='\0';
+tb=&G(L)->strt;
+h=lmod(h,tb->size);
+ts->tsv.next=tb->hash[h];
+tb->hash[h]=obj2gco(ts);
+tb->nuse++;
+if(tb->nuse>cast(lu_int32,tb->size)&&tb->size<=(INT_MAX-2)/2)
+luaS_resize(L,tb->size*2);
+return ts;
+}
+static TString*luaS_newlstr(lua_State*L,const char*str,size_t l){
+GCObject*o;
+unsigned int h=cast(unsigned int,l);
+size_t step=(l>>5)+1;
+size_t l1;
+for(l1=l;l1>=step;l1-=step)
+h=h^((h<<5)+(h>>2)+cast(unsigned char,str[l1-1]));
+for(o=G(L)->strt.hash[lmod(h,G(L)->strt.size)];
+o!=NULL;
+o=o->gch.next){
+TString*ts=rawgco2ts(o);
+if(ts->tsv.len==l&&(memcmp(str,getstr(ts),l)==0)){
+if(isdead(G(L),o))changewhite(o);
+return ts;
+}
+}
+return newlstr(L,str,l,h);
+}
+static Udata*luaS_newudata(lua_State*L,size_t s,Table*e){
+Udata*u;
+if(s>((size_t)(~(size_t)0)-2)-sizeof(Udata))
+luaM_toobig(L);
+u=cast(Udata*,luaM_malloc(L,s+sizeof(Udata)));
+u->uv.marked=luaC_white(G(L));
+u->uv.tt=7;
+u->uv.len=s;
+u->uv.metatable=NULL;
+u->uv.env=e;
+u->uv.next=G(L)->mainthread->next;
+G(L)->mainthread->next=obj2gco(u);
+return u;
+}
+#define hashpow2(t,n)(gnode(t,lmod((n),sizenode(t))))
+#define hashstr(t,str)hashpow2(t,(str)->tsv.hash)
+#define hashboolean(t,p)hashpow2(t,p)
+#define hashmod(t,n)(gnode(t,((n)%((sizenode(t)-1)|1))))
+#define hashpointer(t,p)hashmod(t,IntPoint(p))
+static const Node dummynode_={
+{{NULL},0},
+{{{NULL},0,NULL}}
+};
+static Node*hashnum(const Table*t,lua_Number n){
+unsigned int a[cast_int(sizeof(lua_Number)/sizeof(int))];
+int i;
+if(luai_numeq(n,0))
+return gnode(t,0);
+memcpy(a,&n,sizeof(a));
+for(i=1;isizearray)
+return i-1;
+else{
+Node*n=mainposition(t,key);
+do{
+if(luaO_rawequalObj(key2tval(n),key)||
+(ttype(gkey(n))==(8+3)&&iscollectable(key)&&
+gcvalue(gkey(n))==gcvalue(key))){
+i=cast_int(n-gnode(t,0));
+return i+t->sizearray;
+}
+else n=gnext(n);
+}while(n);
+luaG_runerror(L,"invalid key to "LUA_QL("next"));
+return 0;
+}
+}
+static int luaH_next(lua_State*L,Table*t,StkId key){
+int i=findindex(L,t,key);
+for(i++;isizearray;i++){
+if(!ttisnil(&t->array[i])){
+setnvalue(key,cast_num(i+1));
+setobj(L,key+1,&t->array[i]);
+return 1;
+}
+}
+for(i-=t->sizearray;i<(int)sizenode(t);i++){
+if(!ttisnil(gval(gnode(t,i)))){
+setobj(L,key,key2tval(gnode(t,i)));
+setobj(L,key+1,gval(gnode(t,i)));
+return 1;
+}
+}
+return 0;
+}
+static int computesizes(int nums[],int*narray){
+int i;
+int twotoi;
+int a=0;
+int na=0;
+int n=0;
+for(i=0,twotoi=1;twotoi/2<*narray;i++,twotoi*=2){
+if(nums[i]>0){
+a+=nums[i];
+if(a>twotoi/2){
+n=twotoi;
+na=a;
+}
+}
+if(a==*narray)break;
+}
+*narray=n;
+return na;
+}
+static int countint(const TValue*key,int*nums){
+int k=arrayindex(key);
+if(0t->sizearray){
+lim=t->sizearray;
+if(i>lim)
+break;
+}
+for(;i<=lim;i++){
+if(!ttisnil(&t->array[i-1]))
+lc++;
+}
+nums[lg]+=lc;
+ause+=lc;
+}
+return ause;
+}
+static int numusehash(const Table*t,int*nums,int*pnasize){
+int totaluse=0;
+int ause=0;
+int i=sizenode(t);
+while(i--){
+Node*n=&t->node[i];
+if(!ttisnil(gval(n))){
+ause+=countint(key2tval(n),nums);
+totaluse++;
+}
+}
+*pnasize+=ause;
+return totaluse;
+}
+static void setarrayvector(lua_State*L,Table*t,int size){
+int i;
+luaM_reallocvector(L,t->array,t->sizearray,size,TValue);
+for(i=t->sizearray;iarray[i]);
+t->sizearray=size;
+}
+static void setnodevector(lua_State*L,Table*t,int size){
+int lsize;
+if(size==0){
+t->node=cast(Node*,(&dummynode_));
+lsize=0;
+}
+else{
+int i;
+lsize=ceillog2(size);
+if(lsize>(32-2))
+luaG_runerror(L,"table overflow");
+size=twoto(lsize);
+t->node=luaM_newvector(L,size,Node);
+for(i=0;ilsizenode=cast_byte(lsize);
+t->lastfree=gnode(t,size);
+}
+static void resize(lua_State*L,Table*t,int nasize,int nhsize){
+int i;
+int oldasize=t->sizearray;
+int oldhsize=t->lsizenode;
+Node*nold=t->node;
+if(nasize>oldasize)
+setarrayvector(L,t,nasize);
+setnodevector(L,t,nhsize);
+if(nasizesizearray=nasize;
+for(i=nasize;iarray[i]))
+setobj(L,luaH_setnum(L,t,i+1),&t->array[i]);
+}
+luaM_reallocvector(L,t->array,oldasize,nasize,TValue);
+}
+for(i=twoto(oldhsize)-1;i>=0;i--){
+Node*old=nold+i;
+if(!ttisnil(gval(old)))
+setobj(L,luaH_set(L,t,key2tval(old)),gval(old));
+}
+if(nold!=(&dummynode_))
+luaM_freearray(L,nold,twoto(oldhsize),Node);
+}
+static void luaH_resizearray(lua_State*L,Table*t,int nasize){
+int nsize=(t->node==(&dummynode_))?0:sizenode(t);
+resize(L,t,nasize,nsize);
+}
+static void rehash(lua_State*L,Table*t,const TValue*ek){
+int nasize,na;
+int nums[(32-2)+1];
+int i;
+int totaluse;
+for(i=0;i<=(32-2);i++)nums[i]=0;
+nasize=numusearray(t,nums);
+totaluse=nasize;
+totaluse+=numusehash(t,nums,&nasize);
+nasize+=countint(ek,nums);
+totaluse++;
+na=computesizes(nums,&nasize);
+resize(L,t,nasize,totaluse-na);
+}
+static Table*luaH_new(lua_State*L,int narray,int nhash){
+Table*t=luaM_new(L,Table);
+luaC_link(L,obj2gco(t),5);
+t->metatable=NULL;
+t->flags=cast_byte(~0);
+t->array=NULL;
+t->sizearray=0;
+t->lsizenode=0;
+t->node=cast(Node*,(&dummynode_));
+setarrayvector(L,t,narray);
+setnodevector(L,t,nhash);
+return t;
+}
+static void luaH_free(lua_State*L,Table*t){
+if(t->node!=(&dummynode_))
+luaM_freearray(L,t->node,sizenode(t),Node);
+luaM_freearray(L,t->array,t->sizearray,TValue);
+luaM_free(L,t);
+}
+static Node*getfreepos(Table*t){
+while(t->lastfree-->t->node){
+if(ttisnil(gkey(t->lastfree)))
+return t->lastfree;
+}
+return NULL;
+}
+static TValue*newkey(lua_State*L,Table*t,const TValue*key){
+Node*mp=mainposition(t,key);
+if(!ttisnil(gval(mp))||mp==(&dummynode_)){
+Node*othern;
+Node*n=getfreepos(t);
+if(n==NULL){
+rehash(L,t,key);
+return luaH_set(L,t,key);
+}
+othern=mainposition(t,key2tval(mp));
+if(othern!=mp){
+while(gnext(othern)!=mp)othern=gnext(othern);
+gnext(othern)=n;
+*n=*mp;
+gnext(mp)=NULL;
+setnilvalue(gval(mp));
+}
+else{
+gnext(n)=gnext(mp);
+gnext(mp)=n;
+mp=n;
+}
+}
+gkey(mp)->value=key->value;gkey(mp)->tt=key->tt;
+luaC_barriert(L,t,key);
+return gval(mp);
+}
+static const TValue*luaH_getnum(Table*t,int key){
+if(cast(unsigned int,key)-1sizearray))
+return&t->array[key-1];
+else{
+lua_Number nk=cast_num(key);
+Node*n=hashnum(t,nk);
+do{
+if(ttisnumber(gkey(n))&&luai_numeq(nvalue(gkey(n)),nk))
+return gval(n);
+else n=gnext(n);
+}while(n);
+return(&luaO_nilobject_);
+}
+}
+static const TValue*luaH_getstr(Table*t,TString*key){
+Node*n=hashstr(t,key);
+do{
+if(ttisstring(gkey(n))&&rawtsvalue(gkey(n))==key)
+return gval(n);
+else n=gnext(n);
+}while(n);
+return(&luaO_nilobject_);
+}
+static const TValue*luaH_get(Table*t,const TValue*key){
+switch(ttype(key)){
+case 0:return(&luaO_nilobject_);
+case 4:return luaH_getstr(t,rawtsvalue(key));
+case 3:{
+int k;
+lua_Number n=nvalue(key);
+lua_number2int(k,n);
+if(luai_numeq(cast_num(k),nvalue(key)))
+return luaH_getnum(t,k);
+}
+default:{
+Node*n=mainposition(t,key);
+do{
+if(luaO_rawequalObj(key2tval(n),key))
+return gval(n);
+else n=gnext(n);
+}while(n);
+return(&luaO_nilobject_);
+}
+}
+}
+static TValue*luaH_set(lua_State*L,Table*t,const TValue*key){
+const TValue*p=luaH_get(t,key);
+t->flags=0;
+if(p!=(&luaO_nilobject_))
+return cast(TValue*,p);
+else{
+if(ttisnil(key))luaG_runerror(L,"table index is nil");
+else if(ttisnumber(key)&&luai_numisnan(nvalue(key)))
+luaG_runerror(L,"table index is NaN");
+return newkey(L,t,key);
+}
+}
+static TValue*luaH_setnum(lua_State*L,Table*t,int key){
+const TValue*p=luaH_getnum(t,key);
+if(p!=(&luaO_nilobject_))
+return cast(TValue*,p);
+else{
+TValue k;
+setnvalue(&k,cast_num(key));
+return newkey(L,t,&k);
+}
+}
+static TValue*luaH_setstr(lua_State*L,Table*t,TString*key){
+const TValue*p=luaH_getstr(t,key);
+if(p!=(&luaO_nilobject_))
+return cast(TValue*,p);
+else{
+TValue k;
+setsvalue(L,&k,key);
+return newkey(L,t,&k);
+}
+}
+static int unbound_search(Table*t,unsigned int j){
+unsigned int i=j;
+j++;
+while(!ttisnil(luaH_getnum(t,j))){
+i=j;
+j*=2;
+if(j>cast(unsigned int,(INT_MAX-2))){
+i=1;
+while(!ttisnil(luaH_getnum(t,i)))i++;
+return i-1;
+}
+}
+while(j-i>1){
+unsigned int m=(i+j)/2;
+if(ttisnil(luaH_getnum(t,m)))j=m;
+else i=m;
+}
+return i;
+}
+static int luaH_getn(Table*t){
+unsigned int j=t->sizearray;
+if(j>0&&ttisnil(&t->array[j-1])){
+unsigned int i=0;
+while(j-i>1){
+unsigned int m=(i+j)/2;
+if(ttisnil(&t->array[m-1]))j=m;
+else i=m;
+}
+return i;
+}
+else if(t->node==(&dummynode_))
+return j;
+else return unbound_search(t,j);
+}
+#define makewhite(g,x)((x)->gch.marked=cast_byte(((x)->gch.marked&cast_byte(~(bitmask(2)|bit2mask(0,1))))|luaC_white(g)))
+#define white2gray(x)reset2bits((x)->gch.marked,0,1)
+#define black2gray(x)resetbit((x)->gch.marked,2)
+#define stringmark(s)reset2bits((s)->tsv.marked,0,1)
+#define isfinalized(u)testbit((u)->marked,3)
+#define markfinalized(u)l_setbit((u)->marked,3)
+#define markvalue(g,o){checkconsistency(o);if(iscollectable(o)&&iswhite(gcvalue(o)))reallymarkobject(g,gcvalue(o));}
+#define markobject(g,t){if(iswhite(obj2gco(t)))reallymarkobject(g,obj2gco(t));}
+#define setthreshold(g)(g->GCthreshold=(g->estimate/100)*g->gcpause)
+static void removeentry(Node*n){
+if(iscollectable(gkey(n)))
+setttype(gkey(n),(8+3));
+}
+static void reallymarkobject(global_State*g,GCObject*o){
+white2gray(o);
+switch(o->gch.tt){
+case 4:{
+return;
+}
+case 7:{
+Table*mt=gco2u(o)->metatable;
+gray2black(o);
+if(mt)markobject(g,mt);
+markobject(g,gco2u(o)->env);
+return;
+}
+case(8+2):{
+UpVal*uv=gco2uv(o);
+markvalue(g,uv->v);
+if(uv->v==&uv->u.value)
+gray2black(o);
+return;
+}
+case 6:{
+gco2cl(o)->c.gclist=g->gray;
+g->gray=o;
+break;
+}
+case 5:{
+gco2h(o)->gclist=g->gray;
+g->gray=o;
+break;
+}
+case 8:{
+gco2th(o)->gclist=g->gray;
+g->gray=o;
+break;
+}
+case(8+1):{
+gco2p(o)->gclist=g->gray;
+g->gray=o;
+break;
+}
+default:;
+}
+}
+static void marktmu(global_State*g){
+GCObject*u=g->tmudata;
+if(u){
+do{
+u=u->gch.next;
+makewhite(g,u);
+reallymarkobject(g,u);
+}while(u!=g->tmudata);
+}
+}
+static size_t luaC_separateudata(lua_State*L,int all){
+global_State*g=G(L);
+size_t deadmem=0;
+GCObject**p=&g->mainthread->next;
+GCObject*curr;
+while((curr=*p)!=NULL){
+if(!(iswhite(curr)||all)||isfinalized(gco2u(curr)))
+p=&curr->gch.next;
+else if(fasttm(L,gco2u(curr)->metatable,TM_GC)==NULL){
+markfinalized(gco2u(curr));
+p=&curr->gch.next;
+}
+else{
+deadmem+=sizeudata(gco2u(curr));
+markfinalized(gco2u(curr));
+*p=curr->gch.next;
+if(g->tmudata==NULL)
+g->tmudata=curr->gch.next=curr;
+else{
+curr->gch.next=g->tmudata->gch.next;
+g->tmudata->gch.next=curr;
+g->tmudata=curr;
+}
+}
+}
+return deadmem;
+}
+static int traversetable(global_State*g,Table*h){
+int i;
+int weakkey=0;
+int weakvalue=0;
+const TValue*mode;
+if(h->metatable)
+markobject(g,h->metatable);
+mode=gfasttm(g,h->metatable,TM_MODE);
+if(mode&&ttisstring(mode)){
+weakkey=(strchr(svalue(mode),'k')!=NULL);
+weakvalue=(strchr(svalue(mode),'v')!=NULL);
+if(weakkey||weakvalue){
+h->marked&=~(bitmask(3)|bitmask(4));
+h->marked|=cast_byte((weakkey<<3)|
+(weakvalue<<4));
+h->gclist=g->weak;
+g->weak=obj2gco(h);
+}
+}
+if(weakkey&&weakvalue)return 1;
+if(!weakvalue){
+i=h->sizearray;
+while(i--)
+markvalue(g,&h->array[i]);
+}
+i=sizenode(h);
+while(i--){
+Node*n=gnode(h,i);
+if(ttisnil(gval(n)))
+removeentry(n);
+else{
+if(!weakkey)markvalue(g,gkey(n));
+if(!weakvalue)markvalue(g,gval(n));
+}
+}
+return weakkey||weakvalue;
+}
+static void traverseproto(global_State*g,Proto*f){
+int i;
+if(f->source)stringmark(f->source);
+for(i=0;isizek;i++)
+markvalue(g,&f->k[i]);
+for(i=0;isizeupvalues;i++){
+if(f->upvalues[i])
+stringmark(f->upvalues[i]);
+}
+for(i=0;isizep;i++){
+if(f->p[i])
+markobject(g,f->p[i]);
+}
+for(i=0;isizelocvars;i++){
+if(f->locvars[i].varname)
+stringmark(f->locvars[i].varname);
+}
+}
+static void traverseclosure(global_State*g,Closure*cl){
+markobject(g,cl->c.env);
+if(cl->c.isC){
+int i;
+for(i=0;ic.nupvalues;i++)
+markvalue(g,&cl->c.upvalue[i]);
+}
+else{
+int i;
+markobject(g,cl->l.p);
+for(i=0;il.nupvalues;i++)
+markobject(g,cl->l.upvals[i]);
+}
+}
+static void checkstacksizes(lua_State*L,StkId max){
+int ci_used=cast_int(L->ci-L->base_ci);
+int s_used=cast_int(max-L->stack);
+if(L->size_ci>20000)
+return;
+if(4*ci_usedsize_ci&&2*8size_ci)
+luaD_reallocCI(L,L->size_ci/2);
+condhardstacktests(luaD_reallocCI(L,ci_used+1));
+if(4*s_usedstacksize&&
+2*((2*20)+5)stacksize)
+luaD_reallocstack(L,L->stacksize/2);
+condhardstacktests(luaD_reallocstack(L,s_used));
+}
+static void traversestack(global_State*g,lua_State*l){
+StkId o,lim;
+CallInfo*ci;
+markvalue(g,gt(l));
+lim=l->top;
+for(ci=l->base_ci;ci<=l->ci;ci++){
+if(limtop)lim=ci->top;
+}
+for(o=l->stack;otop;o++)
+markvalue(g,o);
+for(;o<=lim;o++)
+setnilvalue(o);
+checkstacksizes(l,lim);
+}
+static l_mem propagatemark(global_State*g){
+GCObject*o=g->gray;
+gray2black(o);
+switch(o->gch.tt){
+case 5:{
+Table*h=gco2h(o);
+g->gray=h->gclist;
+if(traversetable(g,h))
+black2gray(o);
+return sizeof(Table)+sizeof(TValue)*h->sizearray+
+sizeof(Node)*sizenode(h);
+}
+case 6:{
+Closure*cl=gco2cl(o);
+g->gray=cl->c.gclist;
+traverseclosure(g,cl);
+return(cl->c.isC)?sizeCclosure(cl->c.nupvalues):
+sizeLclosure(cl->l.nupvalues);
+}
+case 8:{
+lua_State*th=gco2th(o);
+g->gray=th->gclist;
+th->gclist=g->grayagain;
+g->grayagain=o;
+black2gray(o);
+traversestack(g,th);
+return sizeof(lua_State)+sizeof(TValue)*th->stacksize+
+sizeof(CallInfo)*th->size_ci;
+}
+case(8+1):{
+Proto*p=gco2p(o);
+g->gray=p->gclist;
+traverseproto(g,p);
+return sizeof(Proto)+sizeof(Instruction)*p->sizecode+
+sizeof(Proto*)*p->sizep+
+sizeof(TValue)*p->sizek+
+sizeof(int)*p->sizelineinfo+
+sizeof(LocVar)*p->sizelocvars+
+sizeof(TString*)*p->sizeupvalues;
+}
+default:return 0;
+}
+}
+static size_t propagateall(global_State*g){
+size_t m=0;
+while(g->gray)m+=propagatemark(g);
+return m;
+}
+static int iscleared(const TValue*o,int iskey){
+if(!iscollectable(o))return 0;
+if(ttisstring(o)){
+stringmark(rawtsvalue(o));
+return 0;
+}
+return iswhite(gcvalue(o))||
+(ttisuserdata(o)&&(!iskey&&isfinalized(uvalue(o))));
+}
+static void cleartable(GCObject*l){
+while(l){
+Table*h=gco2h(l);
+int i=h->sizearray;
+if(testbit(h->marked,4)){
+while(i--){
+TValue*o=&h->array[i];
+if(iscleared(o,0))
+setnilvalue(o);
+}
+}
+i=sizenode(h);
+while(i--){
+Node*n=gnode(h,i);
+if(!ttisnil(gval(n))&&
+(iscleared(key2tval(n),1)||iscleared(gval(n),0))){
+setnilvalue(gval(n));
+removeentry(n);
+}
+}
+l=h->gclist;
+}
+}
+static void freeobj(lua_State*L,GCObject*o){
+switch(o->gch.tt){
+case(8+1):luaF_freeproto(L,gco2p(o));break;
+case 6:luaF_freeclosure(L,gco2cl(o));break;
+case(8+2):luaF_freeupval(L,gco2uv(o));break;
+case 5:luaH_free(L,gco2h(o));break;
+case 8:{
+luaE_freethread(L,gco2th(o));
+break;
+}
+case 4:{
+G(L)->strt.nuse--;
+luaM_freemem(L,o,sizestring(gco2ts(o)));
+break;
+}
+case 7:{
+luaM_freemem(L,o,sizeudata(gco2u(o)));
+break;
+}
+default:;
+}
+}
+#define sweepwholelist(L,p)sweeplist(L,p,((lu_mem)(~(lu_mem)0)-2))
+static GCObject**sweeplist(lua_State*L,GCObject**p,lu_mem count){
+GCObject*curr;
+global_State*g=G(L);
+int deadmask=otherwhite(g);
+while((curr=*p)!=NULL&&count-->0){
+if(curr->gch.tt==8)
+sweepwholelist(L,&gco2th(curr)->openupval);
+if((curr->gch.marked^bit2mask(0,1))&deadmask){
+makewhite(g,curr);
+p=&curr->gch.next;
+}
+else{
+*p=curr->gch.next;
+if(curr==g->rootgc)
+g->rootgc=curr->gch.next;
+freeobj(L,curr);
+}
+}
+return p;
+}
+static void checkSizes(lua_State*L){
+global_State*g=G(L);
+if(g->strt.nusestrt.size/4)&&
+g->strt.size>32*2)
+luaS_resize(L,g->strt.size/2);
+if(luaZ_sizebuffer(&g->buff)>32*2){
+size_t newsize=luaZ_sizebuffer(&g->buff)/2;
+luaZ_resizebuffer(L,&g->buff,newsize);
+}
+}
+static void GCTM(lua_State*L){
+global_State*g=G(L);
+GCObject*o=g->tmudata->gch.next;
+Udata*udata=rawgco2u(o);
+const TValue*tm;
+if(o==g->tmudata)
+g->tmudata=NULL;
+else
+g->tmudata->gch.next=udata->uv.next;
+udata->uv.next=g->mainthread->next;
+g->mainthread->next=o;
+makewhite(g,o);
+tm=fasttm(L,udata->uv.metatable,TM_GC);
+if(tm!=NULL){
+lu_byte oldah=L->allowhook;
+lu_mem oldt=g->GCthreshold;
+L->allowhook=0;
+g->GCthreshold=2*g->totalbytes;
+setobj(L,L->top,tm);
+setuvalue(L,L->top+1,udata);
+L->top+=2;
+luaD_call(L,L->top-2,0);
+L->allowhook=oldah;
+g->GCthreshold=oldt;
+}
+}
+static void luaC_callGCTM(lua_State*L){
+while(G(L)->tmudata)
+GCTM(L);
+}
+static void luaC_freeall(lua_State*L){
+global_State*g=G(L);
+int i;
+g->currentwhite=bit2mask(0,1)|bitmask(6);
+sweepwholelist(L,&g->rootgc);
+for(i=0;istrt.size;i++)
+sweepwholelist(L,&g->strt.hash[i]);
+}
+static void markmt(global_State*g){
+int i;
+for(i=0;i<(8+1);i++)
+if(g->mt[i])markobject(g,g->mt[i]);
+}
+static void markroot(lua_State*L){
+global_State*g=G(L);
+g->gray=NULL;
+g->grayagain=NULL;
+g->weak=NULL;
+markobject(g,g->mainthread);
+markvalue(g,gt(g->mainthread));
+markvalue(g,registry(L));
+markmt(g);
+g->gcstate=1;
+}
+static void remarkupvals(global_State*g){
+UpVal*uv;
+for(uv=g->uvhead.u.l.next;uv!=&g->uvhead;uv=uv->u.l.next){
+if(isgray(obj2gco(uv)))
+markvalue(g,uv->v);
+}
+}
+static void atomic(lua_State*L){
+global_State*g=G(L);
+size_t udsize;
+remarkupvals(g);
+propagateall(g);
+g->gray=g->weak;
+g->weak=NULL;
+markobject(g,L);
+markmt(g);
+propagateall(g);
+g->gray=g->grayagain;
+g->grayagain=NULL;
+propagateall(g);
+udsize=luaC_separateudata(L,0);
+marktmu(g);
+udsize+=propagateall(g);
+cleartable(g->weak);
+g->currentwhite=cast_byte(otherwhite(g));
+g->sweepstrgc=0;
+g->sweepgc=&g->rootgc;
+g->gcstate=2;
+g->estimate=g->totalbytes-udsize;
+}
+static l_mem singlestep(lua_State*L){
+global_State*g=G(L);
+switch(g->gcstate){
+case 0:{
+markroot(L);
+return 0;
+}
+case 1:{
+if(g->gray)
+return propagatemark(g);
+else{
+atomic(L);
+return 0;
+}
+}
+case 2:{
+lu_mem old=g->totalbytes;
+sweepwholelist(L,&g->strt.hash[g->sweepstrgc++]);
+if(g->sweepstrgc>=g->strt.size)
+g->gcstate=3;
+g->estimate-=old-g->totalbytes;
+return 10;
+}
+case 3:{
+lu_mem old=g->totalbytes;
+g->sweepgc=sweeplist(L,g->sweepgc,40);
+if(*g->sweepgc==NULL){
+checkSizes(L);
+g->gcstate=4;
+}
+g->estimate-=old-g->totalbytes;
+return 40*10;
+}
+case 4:{
+if(g->tmudata){
+GCTM(L);
+if(g->estimate>100)
+g->estimate-=100;
+return 100;
+}
+else{
+g->gcstate=0;
+g->gcdept=0;
+return 0;
+}
+}
+default:return 0;
+}
+}
+static void luaC_step(lua_State*L){
+global_State*g=G(L);
+l_mem lim=(1024u/100)*g->gcstepmul;
+if(lim==0)
+lim=(((lu_mem)(~(lu_mem)0)-2)-1)/2;
+g->gcdept+=g->totalbytes-g->GCthreshold;
+do{
+lim-=singlestep(L);
+if(g->gcstate==0)
+break;
+}while(lim>0);
+if(g->gcstate!=0){
+if(g->gcdept<1024u)
+g->GCthreshold=g->totalbytes+1024u;
+else{
+g->gcdept-=1024u;
+g->GCthreshold=g->totalbytes;
+}
+}
+else{
+setthreshold(g);
+}
+}
+static void luaC_barrierf(lua_State*L,GCObject*o,GCObject*v){
+global_State*g=G(L);
+if(g->gcstate==1)
+reallymarkobject(g,v);
+else
+makewhite(g,o);
+}
+static void luaC_barrierback(lua_State*L,Table*t){
+global_State*g=G(L);
+GCObject*o=obj2gco(t);
+black2gray(o);
+t->gclist=g->grayagain;
+g->grayagain=o;
+}
+static void luaC_link(lua_State*L,GCObject*o,lu_byte tt){
+global_State*g=G(L);
+o->gch.next=g->rootgc;
+g->rootgc=o;
+o->gch.marked=luaC_white(g);
+o->gch.tt=tt;
+}
+static void luaC_linkupval(lua_State*L,UpVal*uv){
+global_State*g=G(L);
+GCObject*o=obj2gco(uv);
+o->gch.next=g->rootgc;
+g->rootgc=o;
+if(isgray(o)){
+if(g->gcstate==1){
+gray2black(o);
+luaC_barrier(L,uv,uv->v);
+}
+else{
+makewhite(g,o);
+}
+}
+}
+typedef union{
+lua_Number r;
+TString*ts;
+}SemInfo;
+typedef struct Token{
+int token;
+SemInfo seminfo;
+}Token;
+typedef struct LexState{
+int current;
+int linenumber;
+int lastline;
+Token t;
+Token lookahead;
+struct FuncState*fs;
+struct lua_State*L;
+ZIO*z;
+Mbuffer*buff;
+TString*source;
+char decpoint;
+}LexState;
+static void luaX_init(lua_State*L);
+static void luaX_lexerror(LexState*ls,const char*msg,int token);
+#define state_size(x)(sizeof(x)+0)
+#define fromstate(l)(cast(lu_byte*,(l))-0)
+#define tostate(l)(cast(lua_State*,cast(lu_byte*,l)+0))
+typedef struct LG{
+lua_State l;
+global_State g;
+}LG;
+static void stack_init(lua_State*L1,lua_State*L){
+L1->base_ci=luaM_newvector(L,8,CallInfo);
+L1->ci=L1->base_ci;
+L1->size_ci=8;
+L1->end_ci=L1->base_ci+L1->size_ci-1;
+L1->stack=luaM_newvector(L,(2*20)+5,TValue);
+L1->stacksize=(2*20)+5;
+L1->top=L1->stack;
+L1->stack_last=L1->stack+(L1->stacksize-5)-1;
+L1->ci->func=L1->top;
+setnilvalue(L1->top++);
+L1->base=L1->ci->base=L1->top;
+L1->ci->top=L1->top+20;
+}
+static void freestack(lua_State*L,lua_State*L1){
+luaM_freearray(L,L1->base_ci,L1->size_ci,CallInfo);
+luaM_freearray(L,L1->stack,L1->stacksize,TValue);
+}
+static void f_luaopen(lua_State*L,void*ud){
+global_State*g=G(L);
+UNUSED(ud);
+stack_init(L,L);
+sethvalue(L,gt(L),luaH_new(L,0,2));
+sethvalue(L,registry(L),luaH_new(L,0,2));
+luaS_resize(L,32);
+luaT_init(L);
+luaX_init(L);
+luaS_fix(luaS_newliteral(L,"not enough memory"));
+g->GCthreshold=4*g->totalbytes;
+}
+static void preinit_state(lua_State*L,global_State*g){
+G(L)=g;
+L->stack=NULL;
+L->stacksize=0;
+L->errorJmp=NULL;
+L->hook=NULL;
+L->hookmask=0;
+L->basehookcount=0;
+L->allowhook=1;
+resethookcount(L);
+L->openupval=NULL;
+L->size_ci=0;
+L->nCcalls=L->baseCcalls=0;
+L->status=0;
+L->base_ci=L->ci=NULL;
+L->savedpc=NULL;
+L->errfunc=0;
+setnilvalue(gt(L));
+}
+static void close_state(lua_State*L){
+global_State*g=G(L);
+luaF_close(L,L->stack);
+luaC_freeall(L);
+luaM_freearray(L,G(L)->strt.hash,G(L)->strt.size,TString*);
+luaZ_freebuffer(L,&g->buff);
+freestack(L,L);
+(*g->frealloc)(g->ud,fromstate(L),state_size(LG),0);
+}
+static void luaE_freethread(lua_State*L,lua_State*L1){
+luaF_close(L1,L1->stack);
+freestack(L,L1);
+luaM_freemem(L,fromstate(L1),state_size(lua_State));
+}
+static lua_State*lua_newstate(lua_Alloc f,void*ud){
+int i;
+lua_State*L;
+global_State*g;
+void*l=(*f)(ud,NULL,0,state_size(LG));
+if(l==NULL)return NULL;
+L=tostate(l);
+g=&((LG*)L)->g;
+L->next=NULL;
+L->tt=8;
+g->currentwhite=bit2mask(0,5);
+L->marked=luaC_white(g);
+set2bits(L->marked,5,6);
+preinit_state(L,g);
+g->frealloc=f;
+g->ud=ud;
+g->mainthread=L;
+g->uvhead.u.l.prev=&g->uvhead;
+g->uvhead.u.l.next=&g->uvhead;
+g->GCthreshold=0;
+g->strt.size=0;
+g->strt.nuse=0;
+g->strt.hash=NULL;
+setnilvalue(registry(L));
+luaZ_initbuffer(L,&g->buff);
+g->panic=NULL;
+g->gcstate=0;
+g->rootgc=obj2gco(L);
+g->sweepstrgc=0;
+g->sweepgc=&g->rootgc;
+g->gray=NULL;
+g->grayagain=NULL;
+g->weak=NULL;
+g->tmudata=NULL;
+g->totalbytes=sizeof(LG);
+g->gcpause=200;
+g->gcstepmul=200;
+g->gcdept=0;
+for(i=0;i<(8+1);i++)g->mt[i]=NULL;
+if(luaD_rawrunprotected(L,f_luaopen,NULL)!=0){
+close_state(L);
+L=NULL;
+}
+else
+{}
+return L;
+}
+static void callallgcTM(lua_State*L,void*ud){
+UNUSED(ud);
+luaC_callGCTM(L);
+}
+static void lua_close(lua_State*L){
+L=G(L)->mainthread;
+luaF_close(L,L->stack);
+luaC_separateudata(L,1);
+L->errfunc=0;
+do{
+L->ci=L->base_ci;
+L->base=L->top=L->ci->base;
+L->nCcalls=L->baseCcalls=0;
+}while(luaD_rawrunprotected(L,callallgcTM,NULL)!=0);
+close_state(L);
+}
+#define getcode(fs,e)((fs)->f->code[(e)->u.s.info])
+#define luaK_codeAsBx(fs,o,A,sBx)luaK_codeABx(fs,o,A,(sBx)+(((1<<(9+9))-1)>>1))
+#define luaK_setmultret(fs,e)luaK_setreturns(fs,e,(-1))
+static int luaK_codeABx(FuncState*fs,OpCode o,int A,unsigned int Bx);
+static int luaK_codeABC(FuncState*fs,OpCode o,int A,int B,int C);
+static void luaK_setreturns(FuncState*fs,expdesc*e,int nresults);
+static void luaK_patchtohere(FuncState*fs,int list);
+static void luaK_concat(FuncState*fs,int*l1,int l2);
+static int currentpc(lua_State*L,CallInfo*ci){
+if(!isLua(ci))return-1;
+if(ci==L->ci)
+ci->savedpc=L->savedpc;
+return pcRel(ci->savedpc,ci_func(ci)->l.p);
+}
+static int currentline(lua_State*L,CallInfo*ci){
+int pc=currentpc(L,ci);
+if(pc<0)
+return-1;
+else
+return getline_(ci_func(ci)->l.p,pc);
+}
+static int lua_getstack(lua_State*L,int level,lua_Debug*ar){
+int status;
+CallInfo*ci;
+for(ci=L->ci;level>0&&ci>L->base_ci;ci--){
+level--;
+if(f_isLua(ci))
+level-=ci->tailcalls;
+}
+if(level==0&&ci>L->base_ci){
+status=1;
+ar->i_ci=cast_int(ci-L->base_ci);
+}
+else if(level<0){
+status=1;
+ar->i_ci=0;
+}
+else status=0;
+return status;
+}
+static Proto*getluaproto(CallInfo*ci){
+return(isLua(ci)?ci_func(ci)->l.p:NULL);
+}
+static void funcinfo(lua_Debug*ar,Closure*cl){
+if(cl->c.isC){
+ar->source="=[C]";
+ar->linedefined=-1;
+ar->lastlinedefined=-1;
+ar->what="C";
+}
+else{
+ar->source=getstr(cl->l.p->source);
+ar->linedefined=cl->l.p->linedefined;
+ar->lastlinedefined=cl->l.p->lastlinedefined;
+ar->what=(ar->linedefined==0)?"main":"Lua";
+}
+luaO_chunkid(ar->short_src,ar->source,60);
+}
+static void info_tailcall(lua_Debug*ar){
+ar->name=ar->namewhat="";
+ar->what="tail";
+ar->lastlinedefined=ar->linedefined=ar->currentline=-1;
+ar->source="=(tail call)";
+luaO_chunkid(ar->short_src,ar->source,60);
+ar->nups=0;
+}
+static void collectvalidlines(lua_State*L,Closure*f){
+if(f==NULL||f->c.isC){
+setnilvalue(L->top);
+}
+else{
+Table*t=luaH_new(L,0,0);
+int*lineinfo=f->l.p->lineinfo;
+int i;
+for(i=0;il.p->sizelineinfo;i++)
+setbvalue(luaH_setnum(L,t,lineinfo[i]),1);
+sethvalue(L,L->top,t);
+}
+incr_top(L);
+}
+static int auxgetinfo(lua_State*L,const char*what,lua_Debug*ar,
+Closure*f,CallInfo*ci){
+int status=1;
+if(f==NULL){
+info_tailcall(ar);
+return status;
+}
+for(;*what;what++){
+switch(*what){
+case'S':{
+funcinfo(ar,f);
+break;
+}
+case'l':{
+ar->currentline=(ci)?currentline(L,ci):-1;
+break;
+}
+case'u':{
+ar->nups=f->c.nupvalues;
+break;
+}
+case'n':{
+ar->namewhat=(ci)?NULL:NULL;
+if(ar->namewhat==NULL){
+ar->namewhat="";
+ar->name=NULL;
+}
+break;
+}
+case'L':
+case'f':
+break;
+default:status=0;
+}
+}
+return status;
+}
+static int lua_getinfo(lua_State*L,const char*what,lua_Debug*ar){
+int status;
+Closure*f=NULL;
+CallInfo*ci=NULL;
+if(*what=='>'){
+StkId func=L->top-1;
+luai_apicheck(L,ttisfunction(func));
+what++;
+f=clvalue(func);
+L->top--;
+}
+else if(ar->i_ci!=0){
+ci=L->base_ci+ar->i_ci;
+f=clvalue(ci->func);
+}
+status=auxgetinfo(L,what,ar,f,ci);
+if(strchr(what,'f')){
+if(f==NULL)setnilvalue(L->top);
+else setclvalue(L,L->top,f);
+incr_top(L);
+}
+if(strchr(what,'L'))
+collectvalidlines(L,f);
+return status;
+}
+static int isinstack(CallInfo*ci,const TValue*o){
+StkId p;
+for(p=ci->base;ptop;p++)
+if(o==p)return 1;
+return 0;
+}
+static void luaG_typeerror(lua_State*L,const TValue*o,const char*op){
+const char*name=NULL;
+const char*t=luaT_typenames[ttype(o)];
+const char*kind=(isinstack(L->ci,o))?
+NULL:
+NULL;
+if(kind)
+luaG_runerror(L,"attempt to %s %s "LUA_QL("%s")" (a %s value)",
+op,kind,name,t);
+else
+luaG_runerror(L,"attempt to %s a %s value",op,t);
+}
+static void luaG_concaterror(lua_State*L,StkId p1,StkId p2){
+if(ttisstring(p1)||ttisnumber(p1))p1=p2;
+luaG_typeerror(L,p1,"concatenate");
+}
+static void luaG_aritherror(lua_State*L,const TValue*p1,const TValue*p2){
+TValue temp;
+if(luaV_tonumber(p1,&temp)==NULL)
+p2=p1;
+luaG_typeerror(L,p2,"perform arithmetic on");
+}
+static int luaG_ordererror(lua_State*L,const TValue*p1,const TValue*p2){
+const char*t1=luaT_typenames[ttype(p1)];
+const char*t2=luaT_typenames[ttype(p2)];
+if(t1[2]==t2[2])
+luaG_runerror(L,"attempt to compare two %s values",t1);
+else
+luaG_runerror(L,"attempt to compare %s with %s",t1,t2);
+return 0;
+}
+static void addinfo(lua_State*L,const char*msg){
+CallInfo*ci=L->ci;
+if(isLua(ci)){
+char buff[60];
+int line=currentline(L,ci);
+luaO_chunkid(buff,getstr(getluaproto(ci)->source),60);
+luaO_pushfstring(L,"%s:%d: %s",buff,line,msg);
+}
+}
+static void luaG_errormsg(lua_State*L){
+if(L->errfunc!=0){
+StkId errfunc=restorestack(L,L->errfunc);
+if(!ttisfunction(errfunc))luaD_throw(L,5);
+setobj(L,L->top,L->top-1);
+setobj(L,L->top-1,errfunc);
+incr_top(L);
+luaD_call(L,L->top-2,1);
+}
+luaD_throw(L,2);
+}
+static void luaG_runerror(lua_State*L,const char*fmt,...){
+va_list argp;
+va_start(argp,fmt);
+addinfo(L,luaO_pushvfstring(L,fmt,argp));
+va_end(argp);
+luaG_errormsg(L);
+}
+static int luaZ_fill(ZIO*z){
+size_t size;
+lua_State*L=z->L;
+const char*buff;
+buff=z->reader(L,z->data,&size);
+if(buff==NULL||size==0)return(-1);
+z->n=size-1;
+z->p=buff;
+return char2int(*(z->p++));
+}
+static void luaZ_init(lua_State*L,ZIO*z,lua_Reader reader,void*data){
+z->L=L;
+z->reader=reader;
+z->data=data;
+z->n=0;
+z->p=NULL;
+}
+static char*luaZ_openspace(lua_State*L,Mbuffer*buff,size_t n){
+if(n>buff->buffsize){
+if(n<32)n=32;
+luaZ_resizebuffer(L,buff,n);
+}
+return buff->buffer;
+}
+#define opmode(t,a,b,c,m)(((t)<<7)|((a)<<6)|((b)<<4)|((c)<<2)|(m))
+static const lu_byte luaP_opmodes[(cast(int,OP_VARARG)+1)]={
+opmode(0,1,OpArgR,OpArgN,iABC)
+,opmode(0,1,OpArgK,OpArgN,iABx)
+,opmode(0,1,OpArgU,OpArgU,iABC)
+,opmode(0,1,OpArgR,OpArgN,iABC)
+,opmode(0,1,OpArgU,OpArgN,iABC)
+,opmode(0,1,OpArgK,OpArgN,iABx)
+,opmode(0,1,OpArgR,OpArgK,iABC)
+,opmode(0,0,OpArgK,OpArgN,iABx)
+,opmode(0,0,OpArgU,OpArgN,iABC)
+,opmode(0,0,OpArgK,OpArgK,iABC)
+,opmode(0,1,OpArgU,OpArgU,iABC)
+,opmode(0,1,OpArgR,OpArgK,iABC)
+,opmode(0,1,OpArgK,OpArgK,iABC)
+,opmode(0,1,OpArgK,OpArgK,iABC)
+,opmode(0,1,OpArgK,OpArgK,iABC)
+,opmode(0,1,OpArgK,OpArgK,iABC)
+,opmode(0,1,OpArgK,OpArgK,iABC)
+,opmode(0,1,OpArgK,OpArgK,iABC)
+,opmode(0,1,OpArgR,OpArgN,iABC)
+,opmode(0,1,OpArgR,OpArgN,iABC)
+,opmode(0,1,OpArgR,OpArgN,iABC)
+,opmode(0,1,OpArgR,OpArgR,iABC)
+,opmode(0,0,OpArgR,OpArgN,iAsBx)
+,opmode(1,0,OpArgK,OpArgK,iABC)
+,opmode(1,0,OpArgK,OpArgK,iABC)
+,opmode(1,0,OpArgK,OpArgK,iABC)
+,opmode(1,1,OpArgR,OpArgU,iABC)
+,opmode(1,1,OpArgR,OpArgU,iABC)
+,opmode(0,1,OpArgU,OpArgU,iABC)
+,opmode(0,1,OpArgU,OpArgU,iABC)
+,opmode(0,0,OpArgU,OpArgN,iABC)
+,opmode(0,1,OpArgR,OpArgN,iAsBx)
+,opmode(0,1,OpArgR,OpArgN,iAsBx)
+,opmode(1,0,OpArgN,OpArgU,iABC)
+,opmode(0,0,OpArgU,OpArgU,iABC)
+,opmode(0,0,OpArgN,OpArgN,iABC)
+,opmode(0,1,OpArgU,OpArgN,iABx)
+,opmode(0,1,OpArgU,OpArgN,iABC)
+};
+#define next(ls)(ls->current=zgetc(ls->z))
+#define currIsNewline(ls)(ls->current=='\n'||ls->current=='\r')
+static const char*const luaX_tokens[]={
+"and","break","do","else","elseif",
+"end","false","for","function","if",
+"in","local","nil","not","or","repeat",
+"return","then","true","until","while",
+"..","...","==",">=","<=","~=",
+"","","","",
+NULL
+};
+#define save_and_next(ls)(save(ls,ls->current),next(ls))
+static void save(LexState*ls,int c){
+Mbuffer*b=ls->buff;
+if(b->n+1>b->buffsize){
+size_t newsize;
+if(b->buffsize>=((size_t)(~(size_t)0)-2)/2)
+luaX_lexerror(ls,"lexical element too long",0);
+newsize=b->buffsize*2;
+luaZ_resizebuffer(ls->L,b,newsize);
+}
+b->buffer[b->n++]=cast(char,c);
+}
+static void luaX_init(lua_State*L){
+int i;
+for(i=0;i<(cast(int,TK_WHILE-257+1));i++){
+TString*ts=luaS_new(L,luaX_tokens[i]);
+luaS_fix(ts);
+ts->tsv.reserved=cast_byte(i+1);
+}
+}
+static const char*luaX_token2str(LexState*ls,int token){
+if(token<257){
+return(iscntrl(token))?luaO_pushfstring(ls->L,"char(%d)",token):
+luaO_pushfstring(ls->L,"%c",token);
+}
+else
+return luaX_tokens[token-257];
+}
+static const char*txtToken(LexState*ls,int token){
+switch(token){
+case TK_NAME:
+case TK_STRING:
+case TK_NUMBER:
+save(ls,'\0');
+return luaZ_buffer(ls->buff);
+default:
+return luaX_token2str(ls,token);
+}
+}
+static void luaX_lexerror(LexState*ls,const char*msg,int token){
+char buff[80];
+luaO_chunkid(buff,getstr(ls->source),80);
+msg=luaO_pushfstring(ls->L,"%s:%d: %s",buff,ls->linenumber,msg);
+if(token)
+luaO_pushfstring(ls->L,"%s near "LUA_QL("%s"),msg,txtToken(ls,token));
+luaD_throw(ls->L,3);
+}
+static void luaX_syntaxerror(LexState*ls,const char*msg){
+luaX_lexerror(ls,msg,ls->t.token);
+}
+static TString*luaX_newstring(LexState*ls,const char*str,size_t l){
+lua_State*L=ls->L;
+TString*ts=luaS_newlstr(L,str,l);
+TValue*o=luaH_setstr(L,ls->fs->h,ts);
+if(ttisnil(o)){
+setbvalue(o,1);
+luaC_checkGC(L);
+}
+return ts;
+}
+static void inclinenumber(LexState*ls){
+int old=ls->current;
+next(ls);
+if(currIsNewline(ls)&&ls->current!=old)
+next(ls);
+if(++ls->linenumber>=(INT_MAX-2))
+luaX_syntaxerror(ls,"chunk has too many lines");
+}
+static void luaX_setinput(lua_State*L,LexState*ls,ZIO*z,TString*source){
+ls->decpoint='.';
+ls->L=L;
+ls->lookahead.token=TK_EOS;
+ls->z=z;
+ls->fs=NULL;
+ls->linenumber=1;
+ls->lastline=1;
+ls->source=source;
+luaZ_resizebuffer(ls->L,ls->buff,32);
+next(ls);
+}
+static int check_next(LexState*ls,const char*set){
+if(!strchr(set,ls->current))
+return 0;
+save_and_next(ls);
+return 1;
+}
+static void buffreplace(LexState*ls,char from,char to){
+size_t n=luaZ_bufflen(ls->buff);
+char*p=luaZ_buffer(ls->buff);
+while(n--)
+if(p[n]==from)p[n]=to;
+}
+static void read_numeral(LexState*ls,SemInfo*seminfo){
+do{
+save_and_next(ls);
+}while(isdigit(ls->current)||ls->current=='.');
+if(check_next(ls,"Ee"))
+check_next(ls,"+-");
+while(isalnum(ls->current)||ls->current=='_')
+save_and_next(ls);
+save(ls,'\0');
+buffreplace(ls,'.',ls->decpoint);
+if(!luaO_str2d(luaZ_buffer(ls->buff),&seminfo->r))
+luaX_lexerror(ls,"malformed number",TK_NUMBER);
+}
+static int skip_sep(LexState*ls){
+int count=0;
+int s=ls->current;
+save_and_next(ls);
+while(ls->current=='='){
+save_and_next(ls);
+count++;
+}
+return(ls->current==s)?count:(-count)-1;
+}
+static void read_long_string(LexState*ls,SemInfo*seminfo,int sep){
+int cont=0;
+(void)(cont);
+save_and_next(ls);
+if(currIsNewline(ls))
+inclinenumber(ls);
+for(;;){
+switch(ls->current){
+case(-1):
+luaX_lexerror(ls,(seminfo)?"unfinished long string":
+"unfinished long comment",TK_EOS);
+break;
+case']':{
+if(skip_sep(ls)==sep){
+save_and_next(ls);
+goto endloop;
+}
+break;
+}
+case'\n':
+case'\r':{
+save(ls,'\n');
+inclinenumber(ls);
+if(!seminfo)luaZ_resetbuffer(ls->buff);
+break;
+}
+default:{
+if(seminfo)save_and_next(ls);
+else next(ls);
+}
+}
+}endloop:
+if(seminfo)
+seminfo->ts=luaX_newstring(ls,luaZ_buffer(ls->buff)+(2+sep),
+luaZ_bufflen(ls->buff)-2*(2+sep));
+}
+static void read_string(LexState*ls,int del,SemInfo*seminfo){
+save_and_next(ls);
+while(ls->current!=del){
+switch(ls->current){
+case(-1):
+luaX_lexerror(ls,"unfinished string",TK_EOS);
+continue;
+case'\n':
+case'\r':
+luaX_lexerror(ls,"unfinished string",TK_STRING);
+continue;
+case'\\':{
+int c;
+next(ls);
+switch(ls->current){
+case'a':c='\a';break;
+case'b':c='\b';break;
+case'f':c='\f';break;
+case'n':c='\n';break;
+case'r':c='\r';break;
+case't':c='\t';break;
+case'v':c='\v';break;
+case'\n':
+case'\r':save(ls,'\n');inclinenumber(ls);continue;
+case(-1):continue;
+default:{
+if(!isdigit(ls->current))
+save_and_next(ls);
+else{
+int i=0;
+c=0;
+do{
+c=10*c+(ls->current-'0');
+next(ls);
+}while(++i<3&&isdigit(ls->current));
+if(c>UCHAR_MAX)
+luaX_lexerror(ls,"escape sequence too large",TK_STRING);
+save(ls,c);
+}
+continue;
+}
+}
+save(ls,c);
+next(ls);
+continue;
+}
+default:
+save_and_next(ls);
+}
+}
+save_and_next(ls);
+seminfo->ts=luaX_newstring(ls,luaZ_buffer(ls->buff)+1,
+luaZ_bufflen(ls->buff)-2);
+}
+static int llex(LexState*ls,SemInfo*seminfo){
+luaZ_resetbuffer(ls->buff);
+for(;;){
+switch(ls->current){
+case'\n':
+case'\r':{
+inclinenumber(ls);
+continue;
+}
+case'-':{
+next(ls);
+if(ls->current!='-')return'-';
+next(ls);
+if(ls->current=='['){
+int sep=skip_sep(ls);
+luaZ_resetbuffer(ls->buff);
+if(sep>=0){
+read_long_string(ls,NULL,sep);
+luaZ_resetbuffer(ls->buff);
+continue;
+}
+}
+while(!currIsNewline(ls)&&ls->current!=(-1))
+next(ls);
+continue;
+}
+case'[':{
+int sep=skip_sep(ls);
+if(sep>=0){
+read_long_string(ls,seminfo,sep);
+return TK_STRING;
+}
+else if(sep==-1)return'[';
+else luaX_lexerror(ls,"invalid long string delimiter",TK_STRING);
+}
+case'=':{
+next(ls);
+if(ls->current!='=')return'=';
+else{next(ls);return TK_EQ;}
+}
+case'<':{
+next(ls);
+if(ls->current!='=')return'<';
+else{next(ls);return TK_LE;}
+}
+case'>':{
+next(ls);
+if(ls->current!='=')return'>';
+else{next(ls);return TK_GE;}
+}
+case'~':{
+next(ls);
+if(ls->current!='=')return'~';
+else{next(ls);return TK_NE;}
+}
+case'"':
+case'\'':{
+read_string(ls,ls->current,seminfo);
+return TK_STRING;
+}
+case'.':{
+save_and_next(ls);
+if(check_next(ls,".")){
+if(check_next(ls,"."))
+return TK_DOTS;
+else return TK_CONCAT;
+}
+else if(!isdigit(ls->current))return'.';
+else{
+read_numeral(ls,seminfo);
+return TK_NUMBER;
+}
+}
+case(-1):{
+return TK_EOS;
+}
+default:{
+if(isspace(ls->current)){
+next(ls);
+continue;
+}
+else if(isdigit(ls->current)){
+read_numeral(ls,seminfo);
+return TK_NUMBER;
+}
+else if(isalpha(ls->current)||ls->current=='_'){
+TString*ts;
+do{
+save_and_next(ls);
+}while(isalnum(ls->current)||ls->current=='_');
+ts=luaX_newstring(ls,luaZ_buffer(ls->buff),
+luaZ_bufflen(ls->buff));
+if(ts->tsv.reserved>0)
+return ts->tsv.reserved-1+257;
+else{
+seminfo->ts=ts;
+return TK_NAME;
+}
+}
+else{
+int c=ls->current;
+next(ls);
+return c;
+}
+}
+}
+}
+}
+static void luaX_next(LexState*ls){
+ls->lastline=ls->linenumber;
+if(ls->lookahead.token!=TK_EOS){
+ls->t=ls->lookahead;
+ls->lookahead.token=TK_EOS;
+}
+else
+ls->t.token=llex(ls,&ls->t.seminfo);
+}
+static void luaX_lookahead(LexState*ls){
+ls->lookahead.token=llex(ls,&ls->lookahead.seminfo);
+}
+#define hasjumps(e)((e)->t!=(e)->f)
+static int isnumeral(expdesc*e){
+return(e->k==VKNUM&&e->t==(-1)&&e->f==(-1));
+}
+static void luaK_nil(FuncState*fs,int from,int n){
+Instruction*previous;
+if(fs->pc>fs->lasttarget){
+if(fs->pc==0){
+if(from>=fs->nactvar)
+return;
+}
+else{
+previous=&fs->f->code[fs->pc-1];
+if(GET_OPCODE(*previous)==OP_LOADNIL){
+int pfrom=GETARG_A(*previous);
+int pto=GETARG_B(*previous);
+if(pfrom<=from&&from<=pto+1){
+if(from+n-1>pto)
+SETARG_B(*previous,from+n-1);
+return;
+}
+}
+}
+}
+luaK_codeABC(fs,OP_LOADNIL,from,from+n-1,0);
+}
+static int luaK_jump(FuncState*fs){
+int jpc=fs->jpc;
+int j;
+fs->jpc=(-1);
+j=luaK_codeAsBx(fs,OP_JMP,0,(-1));
+luaK_concat(fs,&j,jpc);
+return j;
+}
+static void luaK_ret(FuncState*fs,int first,int nret){
+luaK_codeABC(fs,OP_RETURN,first,nret+1,0);
+}
+static int condjump(FuncState*fs,OpCode op,int A,int B,int C){
+luaK_codeABC(fs,op,A,B,C);
+return luaK_jump(fs);
+}
+static void fixjump(FuncState*fs,int pc,int dest){
+Instruction*jmp=&fs->f->code[pc];
+int offset=dest-(pc+1);
+if(abs(offset)>(((1<<(9+9))-1)>>1))
+luaX_syntaxerror(fs->ls,"control structure too long");
+SETARG_sBx(*jmp,offset);
+}
+static int luaK_getlabel(FuncState*fs){
+fs->lasttarget=fs->pc;
+return fs->pc;
+}
+static int getjump(FuncState*fs,int pc){
+int offset=GETARG_sBx(fs->f->code[pc]);
+if(offset==(-1))
+return(-1);
+else
+return(pc+1)+offset;
+}
+static Instruction*getjumpcontrol(FuncState*fs,int pc){
+Instruction*pi=&fs->f->code[pc];
+if(pc>=1&&testTMode(GET_OPCODE(*(pi-1))))
+return pi-1;
+else
+return pi;
+}
+static int need_value(FuncState*fs,int list){
+for(;list!=(-1);list=getjump(fs,list)){
+Instruction i=*getjumpcontrol(fs,list);
+if(GET_OPCODE(i)!=OP_TESTSET)return 1;
+}
+return 0;
+}
+static int patchtestreg(FuncState*fs,int node,int reg){
+Instruction*i=getjumpcontrol(fs,node);
+if(GET_OPCODE(*i)!=OP_TESTSET)
+return 0;
+if(reg!=((1<<8)-1)&®!=GETARG_B(*i))
+SETARG_A(*i,reg);
+else
+*i=CREATE_ABC(OP_TEST,GETARG_B(*i),0,GETARG_C(*i));
+return 1;
+}
+static void removevalues(FuncState*fs,int list){
+for(;list!=(-1);list=getjump(fs,list))
+patchtestreg(fs,list,((1<<8)-1));
+}
+static void patchlistaux(FuncState*fs,int list,int vtarget,int reg,
+int dtarget){
+while(list!=(-1)){
+int next=getjump(fs,list);
+if(patchtestreg(fs,list,reg))
+fixjump(fs,list,vtarget);
+else
+fixjump(fs,list,dtarget);
+list=next;
+}
+}
+static void dischargejpc(FuncState*fs){
+patchlistaux(fs,fs->jpc,fs->pc,((1<<8)-1),fs->pc);
+fs->jpc=(-1);
+}
+static void luaK_patchlist(FuncState*fs,int list,int target){
+if(target==fs->pc)
+luaK_patchtohere(fs,list);
+else{
+patchlistaux(fs,list,target,((1<<8)-1),target);
+}
+}
+static void luaK_patchtohere(FuncState*fs,int list){
+luaK_getlabel(fs);
+luaK_concat(fs,&fs->jpc,list);
+}
+static void luaK_concat(FuncState*fs,int*l1,int l2){
+if(l2==(-1))return;
+else if(*l1==(-1))
+*l1=l2;
+else{
+int list=*l1;
+int next;
+while((next=getjump(fs,list))!=(-1))
+list=next;
+fixjump(fs,list,l2);
+}
+}
+static void luaK_checkstack(FuncState*fs,int n){
+int newstack=fs->freereg+n;
+if(newstack>fs->f->maxstacksize){
+if(newstack>=250)
+luaX_syntaxerror(fs->ls,"function or expression too complex");
+fs->f->maxstacksize=cast_byte(newstack);
+}
+}
+static void luaK_reserveregs(FuncState*fs,int n){
+luaK_checkstack(fs,n);
+fs->freereg+=n;
+}
+static void freereg(FuncState*fs,int reg){
+if(!ISK(reg)&®>=fs->nactvar){
+fs->freereg--;
+}
+}
+static void freeexp(FuncState*fs,expdesc*e){
+if(e->k==VNONRELOC)
+freereg(fs,e->u.s.info);
+}
+static int addk(FuncState*fs,TValue*k,TValue*v){
+lua_State*L=fs->L;
+TValue*idx=luaH_set(L,fs->h,k);
+Proto*f=fs->f;
+int oldsize=f->sizek;
+if(ttisnumber(idx)){
+return cast_int(nvalue(idx));
+}
+else{
+setnvalue(idx,cast_num(fs->nk));
+luaM_growvector(L,f->k,fs->nk,f->sizek,TValue,
+((1<<(9+9))-1),"constant table overflow");
+while(oldsizesizek)setnilvalue(&f->k[oldsize++]);
+setobj(L,&f->k[fs->nk],v);
+luaC_barrier(L,f,v);
+return fs->nk++;
+}
+}
+static int luaK_stringK(FuncState*fs,TString*s){
+TValue o;
+setsvalue(fs->L,&o,s);
+return addk(fs,&o,&o);
+}
+static int luaK_numberK(FuncState*fs,lua_Number r){
+TValue o;
+setnvalue(&o,r);
+return addk(fs,&o,&o);
+}
+static int boolK(FuncState*fs,int b){
+TValue o;
+setbvalue(&o,b);
+return addk(fs,&o,&o);
+}
+static int nilK(FuncState*fs){
+TValue k,v;
+setnilvalue(&v);
+sethvalue(fs->L,&k,fs->h);
+return addk(fs,&k,&v);
+}
+static void luaK_setreturns(FuncState*fs,expdesc*e,int nresults){
+if(e->k==VCALL){
+SETARG_C(getcode(fs,e),nresults+1);
+}
+else if(e->k==VVARARG){
+SETARG_B(getcode(fs,e),nresults+1);
+SETARG_A(getcode(fs,e),fs->freereg);
+luaK_reserveregs(fs,1);
+}
+}
+static void luaK_setoneret(FuncState*fs,expdesc*e){
+if(e->k==VCALL){
+e->k=VNONRELOC;
+e->u.s.info=GETARG_A(getcode(fs,e));
+}
+else if(e->k==VVARARG){
+SETARG_B(getcode(fs,e),2);
+e->k=VRELOCABLE;
+}
+}
+static void luaK_dischargevars(FuncState*fs,expdesc*e){
+switch(e->k){
+case VLOCAL:{
+e->k=VNONRELOC;
+break;
+}
+case VUPVAL:{
+e->u.s.info=luaK_codeABC(fs,OP_GETUPVAL,0,e->u.s.info,0);
+e->k=VRELOCABLE;
+break;
+}
+case VGLOBAL:{
+e->u.s.info=luaK_codeABx(fs,OP_GETGLOBAL,0,e->u.s.info);
+e->k=VRELOCABLE;
+break;
+}
+case VINDEXED:{
+freereg(fs,e->u.s.aux);
+freereg(fs,e->u.s.info);
+e->u.s.info=luaK_codeABC(fs,OP_GETTABLE,0,e->u.s.info,e->u.s.aux);
+e->k=VRELOCABLE;
+break;
+}
+case VVARARG:
+case VCALL:{
+luaK_setoneret(fs,e);
+break;
+}
+default:break;
+}
+}
+static int code_label(FuncState*fs,int A,int b,int jump){
+luaK_getlabel(fs);
+return luaK_codeABC(fs,OP_LOADBOOL,A,b,jump);
+}
+static void discharge2reg(FuncState*fs,expdesc*e,int reg){
+luaK_dischargevars(fs,e);
+switch(e->k){
+case VNIL:{
+luaK_nil(fs,reg,1);
+break;
+}
+case VFALSE:case VTRUE:{
+luaK_codeABC(fs,OP_LOADBOOL,reg,e->k==VTRUE,0);
+break;
+}
+case VK:{
+luaK_codeABx(fs,OP_LOADK,reg,e->u.s.info);
+break;
+}
+case VKNUM:{
+luaK_codeABx(fs,OP_LOADK,reg,luaK_numberK(fs,e->u.nval));
+break;
+}
+case VRELOCABLE:{
+Instruction*pc=&getcode(fs,e);
+SETARG_A(*pc,reg);
+break;
+}
+case VNONRELOC:{
+if(reg!=e->u.s.info)
+luaK_codeABC(fs,OP_MOVE,reg,e->u.s.info,0);
+break;
+}
+default:{
+return;
+}
+}
+e->u.s.info=reg;
+e->k=VNONRELOC;
+}
+static void discharge2anyreg(FuncState*fs,expdesc*e){
+if(e->k!=VNONRELOC){
+luaK_reserveregs(fs,1);
+discharge2reg(fs,e,fs->freereg-1);
+}
+}
+static void exp2reg(FuncState*fs,expdesc*e,int reg){
+discharge2reg(fs,e,reg);
+if(e->k==VJMP)
+luaK_concat(fs,&e->t,e->u.s.info);
+if(hasjumps(e)){
+int final;
+int p_f=(-1);
+int p_t=(-1);
+if(need_value(fs,e->t)||need_value(fs,e->f)){
+int fj=(e->k==VJMP)?(-1):luaK_jump(fs);
+p_f=code_label(fs,reg,0,1);
+p_t=code_label(fs,reg,1,0);
+luaK_patchtohere(fs,fj);
+}
+final=luaK_getlabel(fs);
+patchlistaux(fs,e->f,final,reg,p_f);
+patchlistaux(fs,e->t,final,reg,p_t);
+}
+e->f=e->t=(-1);
+e->u.s.info=reg;
+e->k=VNONRELOC;
+}
+static void luaK_exp2nextreg(FuncState*fs,expdesc*e){
+luaK_dischargevars(fs,e);
+freeexp(fs,e);
+luaK_reserveregs(fs,1);
+exp2reg(fs,e,fs->freereg-1);
+}
+static int luaK_exp2anyreg(FuncState*fs,expdesc*e){
+luaK_dischargevars(fs,e);
+if(e->k==VNONRELOC){
+if(!hasjumps(e))return e->u.s.info;
+if(e->u.s.info>=fs->nactvar){
+exp2reg(fs,e,e->u.s.info);
+return e->u.s.info;
+}
+}
+luaK_exp2nextreg(fs,e);
+return e->u.s.info;
+}
+static void luaK_exp2val(FuncState*fs,expdesc*e){
+if(hasjumps(e))
+luaK_exp2anyreg(fs,e);
+else
+luaK_dischargevars(fs,e);
+}
+static int luaK_exp2RK(FuncState*fs,expdesc*e){
+luaK_exp2val(fs,e);
+switch(e->k){
+case VKNUM:
+case VTRUE:
+case VFALSE:
+case VNIL:{
+if(fs->nk<=((1<<(9-1))-1)){
+e->u.s.info=(e->k==VNIL)?nilK(fs):
+(e->k==VKNUM)?luaK_numberK(fs,e->u.nval):
+boolK(fs,(e->k==VTRUE));
+e->k=VK;
+return RKASK(e->u.s.info);
+}
+else break;
+}
+case VK:{
+if(e->u.s.info<=((1<<(9-1))-1))
+return RKASK(e->u.s.info);
+else break;
+}
+default:break;
+}
+return luaK_exp2anyreg(fs,e);
+}
+static void luaK_storevar(FuncState*fs,expdesc*var,expdesc*ex){
+switch(var->k){
+case VLOCAL:{
+freeexp(fs,ex);
+exp2reg(fs,ex,var->u.s.info);
+return;
+}
+case VUPVAL:{
+int e=luaK_exp2anyreg(fs,ex);
+luaK_codeABC(fs,OP_SETUPVAL,e,var->u.s.info,0);
+break;
+}
+case VGLOBAL:{
+int e=luaK_exp2anyreg(fs,ex);
+luaK_codeABx(fs,OP_SETGLOBAL,e,var->u.s.info);
+break;
+}
+case VINDEXED:{
+int e=luaK_exp2RK(fs,ex);
+luaK_codeABC(fs,OP_SETTABLE,var->u.s.info,var->u.s.aux,e);
+break;
+}
+default:{
+break;
+}
+}
+freeexp(fs,ex);
+}
+static void luaK_self(FuncState*fs,expdesc*e,expdesc*key){
+int func;
+luaK_exp2anyreg(fs,e);
+freeexp(fs,e);
+func=fs->freereg;
+luaK_reserveregs(fs,2);
+luaK_codeABC(fs,OP_SELF,func,e->u.s.info,luaK_exp2RK(fs,key));
+freeexp(fs,key);
+e->u.s.info=func;
+e->k=VNONRELOC;
+}
+static void invertjump(FuncState*fs,expdesc*e){
+Instruction*pc=getjumpcontrol(fs,e->u.s.info);
+SETARG_A(*pc,!(GETARG_A(*pc)));
+}
+static int jumponcond(FuncState*fs,expdesc*e,int cond){
+if(e->k==VRELOCABLE){
+Instruction ie=getcode(fs,e);
+if(GET_OPCODE(ie)==OP_NOT){
+fs->pc--;
+return condjump(fs,OP_TEST,GETARG_B(ie),0,!cond);
+}
+}
+discharge2anyreg(fs,e);
+freeexp(fs,e);
+return condjump(fs,OP_TESTSET,((1<<8)-1),e->u.s.info,cond);
+}
+static void luaK_goiftrue(FuncState*fs,expdesc*e){
+int pc;
+luaK_dischargevars(fs,e);
+switch(e->k){
+case VK:case VKNUM:case VTRUE:{
+pc=(-1);
+break;
+}
+case VJMP:{
+invertjump(fs,e);
+pc=e->u.s.info;
+break;
+}
+default:{
+pc=jumponcond(fs,e,0);
+break;
+}
+}
+luaK_concat(fs,&e->f,pc);
+luaK_patchtohere(fs,e->t);
+e->t=(-1);
+}
+static void luaK_goiffalse(FuncState*fs,expdesc*e){
+int pc;
+luaK_dischargevars(fs,e);
+switch(e->k){
+case VNIL:case VFALSE:{
+pc=(-1);
+break;
+}
+case VJMP:{
+pc=e->u.s.info;
+break;
+}
+default:{
+pc=jumponcond(fs,e,1);
+break;
+}
+}
+luaK_concat(fs,&e->t,pc);
+luaK_patchtohere(fs,e->f);
+e->f=(-1);
+}
+static void codenot(FuncState*fs,expdesc*e){
+luaK_dischargevars(fs,e);
+switch(e->k){
+case VNIL:case VFALSE:{
+e->k=VTRUE;
+break;
+}
+case VK:case VKNUM:case VTRUE:{
+e->k=VFALSE;
+break;
+}
+case VJMP:{
+invertjump(fs,e);
+break;
+}
+case VRELOCABLE:
+case VNONRELOC:{
+discharge2anyreg(fs,e);
+freeexp(fs,e);
+e->u.s.info=luaK_codeABC(fs,OP_NOT,0,e->u.s.info,0);
+e->k=VRELOCABLE;
+break;
+}
+default:{
+break;
+}
+}
+{int temp=e->f;e->f=e->t;e->t=temp;}
+removevalues(fs,e->f);
+removevalues(fs,e->t);
+}
+static void luaK_indexed(FuncState*fs,expdesc*t,expdesc*k){
+t->u.s.aux=luaK_exp2RK(fs,k);
+t->k=VINDEXED;
+}
+static int constfolding(OpCode op,expdesc*e1,expdesc*e2){
+lua_Number v1,v2,r;
+if(!isnumeral(e1)||!isnumeral(e2))return 0;
+v1=e1->u.nval;
+v2=e2->u.nval;
+switch(op){
+case OP_ADD:r=luai_numadd(v1,v2);break;
+case OP_SUB:r=luai_numsub(v1,v2);break;
+case OP_MUL:r=luai_nummul(v1,v2);break;
+case OP_DIV:
+if(v2==0)return 0;
+r=luai_numdiv(v1,v2);break;
+case OP_MOD:
+if(v2==0)return 0;
+r=luai_nummod(v1,v2);break;
+case OP_POW:r=luai_numpow(v1,v2);break;
+case OP_UNM:r=luai_numunm(v1);break;
+case OP_LEN:return 0;
+default:r=0;break;
+}
+if(luai_numisnan(r))return 0;
+e1->u.nval=r;
+return 1;
+}
+static void codearith(FuncState*fs,OpCode op,expdesc*e1,expdesc*e2){
+if(constfolding(op,e1,e2))
+return;
+else{
+int o2=(op!=OP_UNM&&op!=OP_LEN)?luaK_exp2RK(fs,e2):0;
+int o1=luaK_exp2RK(fs,e1);
+if(o1>o2){
+freeexp(fs,e1);
+freeexp(fs,e2);
+}
+else{
+freeexp(fs,e2);
+freeexp(fs,e1);
+}
+e1->u.s.info=luaK_codeABC(fs,op,0,o1,o2);
+e1->k=VRELOCABLE;
+}
+}
+static void codecomp(FuncState*fs,OpCode op,int cond,expdesc*e1,
+expdesc*e2){
+int o1=luaK_exp2RK(fs,e1);
+int o2=luaK_exp2RK(fs,e2);
+freeexp(fs,e2);
+freeexp(fs,e1);
+if(cond==0&&op!=OP_EQ){
+int temp;
+temp=o1;o1=o2;o2=temp;
+cond=1;
+}
+e1->u.s.info=condjump(fs,op,cond,o1,o2);
+e1->k=VJMP;
+}
+static void luaK_prefix(FuncState*fs,UnOpr op,expdesc*e){
+expdesc e2;
+e2.t=e2.f=(-1);e2.k=VKNUM;e2.u.nval=0;
+switch(op){
+case OPR_MINUS:{
+if(!isnumeral(e))
+luaK_exp2anyreg(fs,e);
+codearith(fs,OP_UNM,e,&e2);
+break;
+}
+case OPR_NOT:codenot(fs,e);break;
+case OPR_LEN:{
+luaK_exp2anyreg(fs,e);
+codearith(fs,OP_LEN,e,&e2);
+break;
+}
+default:;
+}
+}
+static void luaK_infix(FuncState*fs,BinOpr op,expdesc*v){
+switch(op){
+case OPR_AND:{
+luaK_goiftrue(fs,v);
+break;
+}
+case OPR_OR:{
+luaK_goiffalse(fs,v);
+break;
+}
+case OPR_CONCAT:{
+luaK_exp2nextreg(fs,v);
+break;
+}
+case OPR_ADD:case OPR_SUB:case OPR_MUL:case OPR_DIV:
+case OPR_MOD:case OPR_POW:{
+if(!isnumeral(v))luaK_exp2RK(fs,v);
+break;
+}
+default:{
+luaK_exp2RK(fs,v);
+break;
+}
+}
+}
+static void luaK_posfix(FuncState*fs,BinOpr op,expdesc*e1,expdesc*e2){
+switch(op){
+case OPR_AND:{
+luaK_dischargevars(fs,e2);
+luaK_concat(fs,&e2->f,e1->f);
+*e1=*e2;
+break;
+}
+case OPR_OR:{
+luaK_dischargevars(fs,e2);
+luaK_concat(fs,&e2->t,e1->t);
+*e1=*e2;
+break;
+}
+case OPR_CONCAT:{
+luaK_exp2val(fs,e2);
+if(e2->k==VRELOCABLE&&GET_OPCODE(getcode(fs,e2))==OP_CONCAT){
+freeexp(fs,e1);
+SETARG_B(getcode(fs,e2),e1->u.s.info);
+e1->k=VRELOCABLE;e1->u.s.info=e2->u.s.info;
+}
+else{
+luaK_exp2nextreg(fs,e2);
+codearith(fs,OP_CONCAT,e1,e2);
+}
+break;
+}
+case OPR_ADD:codearith(fs,OP_ADD,e1,e2);break;
+case OPR_SUB:codearith(fs,OP_SUB,e1,e2);break;
+case OPR_MUL:codearith(fs,OP_MUL,e1,e2);break;
+case OPR_DIV:codearith(fs,OP_DIV,e1,e2);break;
+case OPR_MOD:codearith(fs,OP_MOD,e1,e2);break;
+case OPR_POW:codearith(fs,OP_POW,e1,e2);break;
+case OPR_EQ:codecomp(fs,OP_EQ,1,e1,e2);break;
+case OPR_NE:codecomp(fs,OP_EQ,0,e1,e2);break;
+case OPR_LT:codecomp(fs,OP_LT,1,e1,e2);break;
+case OPR_LE:codecomp(fs,OP_LE,1,e1,e2);break;
+case OPR_GT:codecomp(fs,OP_LT,0,e1,e2);break;
+case OPR_GE:codecomp(fs,OP_LE,0,e1,e2);break;
+default:;
+}
+}
+static void luaK_fixline(FuncState*fs,int line){
+fs->f->lineinfo[fs->pc-1]=line;
+}
+static int luaK_code(FuncState*fs,Instruction i,int line){
+Proto*f=fs->f;
+dischargejpc(fs);
+luaM_growvector(fs->L,f->code,fs->pc,f->sizecode,Instruction,
+(INT_MAX-2),"code size overflow");
+f->code[fs->pc]=i;
+luaM_growvector(fs->L,f->lineinfo,fs->pc,f->sizelineinfo,int,
+(INT_MAX-2),"code size overflow");
+f->lineinfo[fs->pc]=line;
+return fs->pc++;
+}
+static int luaK_codeABC(FuncState*fs,OpCode o,int a,int b,int c){
+return luaK_code(fs,CREATE_ABC(o,a,b,c),fs->ls->lastline);
+}
+static int luaK_codeABx(FuncState*fs,OpCode o,int a,unsigned int bc){
+return luaK_code(fs,CREATE_ABx(o,a,bc),fs->ls->lastline);
+}
+static void luaK_setlist(FuncState*fs,int base,int nelems,int tostore){
+int c=(nelems-1)/50+1;
+int b=(tostore==(-1))?0:tostore;
+if(c<=((1<<9)-1))
+luaK_codeABC(fs,OP_SETLIST,base,b,c);
+else{
+luaK_codeABC(fs,OP_SETLIST,base,b,0);
+luaK_code(fs,cast(Instruction,c),fs->ls->lastline);
+}
+fs->freereg=base+1;
+}
+#define hasmultret(k)((k)==VCALL||(k)==VVARARG)
+#define getlocvar(fs,i)((fs)->f->locvars[(fs)->actvar[i]])
+#define luaY_checklimit(fs,v,l,m)if((v)>(l))errorlimit(fs,l,m)
+typedef struct BlockCnt{
+struct BlockCnt*previous;
+int breaklist;
+lu_byte nactvar;
+lu_byte upval;
+lu_byte isbreakable;
+}BlockCnt;
+static void chunk(LexState*ls);
+static void expr(LexState*ls,expdesc*v);
+static void anchor_token(LexState*ls){
+if(ls->t.token==TK_NAME||ls->t.token==TK_STRING){
+TString*ts=ls->t.seminfo.ts;
+luaX_newstring(ls,getstr(ts),ts->tsv.len);
+}
+}
+static void error_expected(LexState*ls,int token){
+luaX_syntaxerror(ls,
+luaO_pushfstring(ls->L,LUA_QL("%s")" expected",luaX_token2str(ls,token)));
+}
+static void errorlimit(FuncState*fs,int limit,const char*what){
+const char*msg=(fs->f->linedefined==0)?
+luaO_pushfstring(fs->L,"main function has more than %d %s",limit,what):
+luaO_pushfstring(fs->L,"function at line %d has more than %d %s",
+fs->f->linedefined,limit,what);
+luaX_lexerror(fs->ls,msg,0);
+}
+static int testnext(LexState*ls,int c){
+if(ls->t.token==c){
+luaX_next(ls);
+return 1;
+}
+else return 0;
+}
+static void check(LexState*ls,int c){
+if(ls->t.token!=c)
+error_expected(ls,c);
+}
+static void checknext(LexState*ls,int c){
+check(ls,c);
+luaX_next(ls);
+}
+#define check_condition(ls,c,msg){if(!(c))luaX_syntaxerror(ls,msg);}
+static void check_match(LexState*ls,int what,int who,int where){
+if(!testnext(ls,what)){
+if(where==ls->linenumber)
+error_expected(ls,what);
+else{
+luaX_syntaxerror(ls,luaO_pushfstring(ls->L,
+LUA_QL("%s")" expected (to close "LUA_QL("%s")" at line %d)",
+luaX_token2str(ls,what),luaX_token2str(ls,who),where));
+}
+}
+}
+static TString*str_checkname(LexState*ls){
+TString*ts;
+check(ls,TK_NAME);
+ts=ls->t.seminfo.ts;
+luaX_next(ls);
+return ts;
+}
+static void init_exp(expdesc*e,expkind k,int i){
+e->f=e->t=(-1);
+e->k=k;
+e->u.s.info=i;
+}
+static void codestring(LexState*ls,expdesc*e,TString*s){
+init_exp(e,VK,luaK_stringK(ls->fs,s));
+}
+static void checkname(LexState*ls,expdesc*e){
+codestring(ls,e,str_checkname(ls));
+}
+static int registerlocalvar(LexState*ls,TString*varname){
+FuncState*fs=ls->fs;
+Proto*f=fs->f;
+int oldsize=f->sizelocvars;
+luaM_growvector(ls->L,f->locvars,fs->nlocvars,f->sizelocvars,
+LocVar,SHRT_MAX,"too many local variables");
+while(oldsizesizelocvars)f->locvars[oldsize++].varname=NULL;
+f->locvars[fs->nlocvars].varname=varname;
+luaC_objbarrier(ls->L,f,varname);
+return fs->nlocvars++;
+}
+#define new_localvarliteral(ls,v,n)new_localvar(ls,luaX_newstring(ls,""v,(sizeof(v)/sizeof(char))-1),n)
+static void new_localvar(LexState*ls,TString*name,int n){
+FuncState*fs=ls->fs;
+luaY_checklimit(fs,fs->nactvar+n+1,200,"local variables");
+fs->actvar[fs->nactvar+n]=cast(unsigned short,registerlocalvar(ls,name));
+}
+static void adjustlocalvars(LexState*ls,int nvars){
+FuncState*fs=ls->fs;
+fs->nactvar=cast_byte(fs->nactvar+nvars);
+for(;nvars;nvars--){
+getlocvar(fs,fs->nactvar-nvars).startpc=fs->pc;
+}
+}
+static void removevars(LexState*ls,int tolevel){
+FuncState*fs=ls->fs;
+while(fs->nactvar>tolevel)
+getlocvar(fs,--fs->nactvar).endpc=fs->pc;
+}
+static int indexupvalue(FuncState*fs,TString*name,expdesc*v){
+int i;
+Proto*f=fs->f;
+int oldsize=f->sizeupvalues;
+for(i=0;inups;i++){
+if(fs->upvalues[i].k==v->k&&fs->upvalues[i].info==v->u.s.info){
+return i;
+}
+}
+luaY_checklimit(fs,f->nups+1,60,"upvalues");
+luaM_growvector(fs->L,f->upvalues,f->nups,f->sizeupvalues,
+TString*,(INT_MAX-2),"");
+while(oldsizesizeupvalues)f->upvalues[oldsize++]=NULL;
+f->upvalues[f->nups]=name;
+luaC_objbarrier(fs->L,f,name);
+fs->upvalues[f->nups].k=cast_byte(v->k);
+fs->upvalues[f->nups].info=cast_byte(v->u.s.info);
+return f->nups++;
+}
+static int searchvar(FuncState*fs,TString*n){
+int i;
+for(i=fs->nactvar-1;i>=0;i--){
+if(n==getlocvar(fs,i).varname)
+return i;
+}
+return-1;
+}
+static void markupval(FuncState*fs,int level){
+BlockCnt*bl=fs->bl;
+while(bl&&bl->nactvar>level)bl=bl->previous;
+if(bl)bl->upval=1;
+}
+static int singlevaraux(FuncState*fs,TString*n,expdesc*var,int base){
+if(fs==NULL){
+init_exp(var,VGLOBAL,((1<<8)-1));
+return VGLOBAL;
+}
+else{
+int v=searchvar(fs,n);
+if(v>=0){
+init_exp(var,VLOCAL,v);
+if(!base)
+markupval(fs,v);
+return VLOCAL;
+}
+else{
+if(singlevaraux(fs->prev,n,var,0)==VGLOBAL)
+return VGLOBAL;
+var->u.s.info=indexupvalue(fs,n,var);
+var->k=VUPVAL;
+return VUPVAL;
+}
+}
+}
+static void singlevar(LexState*ls,expdesc*var){
+TString*varname=str_checkname(ls);
+FuncState*fs=ls->fs;
+if(singlevaraux(fs,varname,var,1)==VGLOBAL)
+var->u.s.info=luaK_stringK(fs,varname);
+}
+static void adjust_assign(LexState*ls,int nvars,int nexps,expdesc*e){
+FuncState*fs=ls->fs;
+int extra=nvars-nexps;
+if(hasmultret(e->k)){
+extra++;
+if(extra<0)extra=0;
+luaK_setreturns(fs,e,extra);
+if(extra>1)luaK_reserveregs(fs,extra-1);
+}
+else{
+if(e->k!=VVOID)luaK_exp2nextreg(fs,e);
+if(extra>0){
+int reg=fs->freereg;
+luaK_reserveregs(fs,extra);
+luaK_nil(fs,reg,extra);
+}
+}
+}
+static void enterlevel(LexState*ls){
+if(++ls->L->nCcalls>200)
+luaX_lexerror(ls,"chunk has too many syntax levels",0);
+}
+#define leavelevel(ls)((ls)->L->nCcalls--)
+static void enterblock(FuncState*fs,BlockCnt*bl,lu_byte isbreakable){
+bl->breaklist=(-1);
+bl->isbreakable=isbreakable;
+bl->nactvar=fs->nactvar;
+bl->upval=0;
+bl->previous=fs->bl;
+fs->bl=bl;
+}
+static void leaveblock(FuncState*fs){
+BlockCnt*bl=fs->bl;
+fs->bl=bl->previous;
+removevars(fs->ls,bl->nactvar);
+if(bl->upval)
+luaK_codeABC(fs,OP_CLOSE,bl->nactvar,0,0);
+fs->freereg=fs->nactvar;
+luaK_patchtohere(fs,bl->breaklist);
+}
+static void pushclosure(LexState*ls,FuncState*func,expdesc*v){
+FuncState*fs=ls->fs;
+Proto*f=fs->f;
+int oldsize=f->sizep;
+int i;
+luaM_growvector(ls->L,f->p,fs->np,f->sizep,Proto*,
+((1<<(9+9))-1),"constant table overflow");
+while(oldsizesizep)f->p[oldsize++]=NULL;
+f->p[fs->np++]=func->f;
+luaC_objbarrier(ls->L,f,func->f);
+init_exp(v,VRELOCABLE,luaK_codeABx(fs,OP_CLOSURE,0,fs->np-1));
+for(i=0;if->nups;i++){
+OpCode o=(func->upvalues[i].k==VLOCAL)?OP_MOVE:OP_GETUPVAL;
+luaK_codeABC(fs,o,0,func->upvalues[i].info,0);
+}
+}
+static void open_func(LexState*ls,FuncState*fs){
+lua_State*L=ls->L;
+Proto*f=luaF_newproto(L);
+fs->f=f;
+fs->prev=ls->fs;
+fs->ls=ls;
+fs->L=L;
+ls->fs=fs;
+fs->pc=0;
+fs->lasttarget=-1;
+fs->jpc=(-1);
+fs->freereg=0;
+fs->nk=0;
+fs->np=0;
+fs->nlocvars=0;
+fs->nactvar=0;
+fs->bl=NULL;
+f->source=ls->source;
+f->maxstacksize=2;
+fs->h=luaH_new(L,0,0);
+sethvalue(L,L->top,fs->h);
+incr_top(L);
+setptvalue(L,L->top,f);
+incr_top(L);
+}
+static void close_func(LexState*ls){
+lua_State*L=ls->L;
+FuncState*fs=ls->fs;
+Proto*f=fs->f;
+removevars(ls,0);
+luaK_ret(fs,0,0);
+luaM_reallocvector(L,f->code,f->sizecode,fs->pc,Instruction);
+f->sizecode=fs->pc;
+luaM_reallocvector(L,f->lineinfo,f->sizelineinfo,fs->pc,int);
+f->sizelineinfo=fs->pc;
+luaM_reallocvector(L,f->k,f->sizek,fs->nk,TValue);
+f->sizek=fs->nk;
+luaM_reallocvector(L,f->p,f->sizep,fs->np,Proto*);
+f->sizep=fs->np;
+luaM_reallocvector(L,f->locvars,f->sizelocvars,fs->nlocvars,LocVar);
+f->sizelocvars=fs->nlocvars;
+luaM_reallocvector(L,f->upvalues,f->sizeupvalues,f->nups,TString*);
+f->sizeupvalues=f->nups;
+ls->fs=fs->prev;
+if(fs)anchor_token(ls);
+L->top-=2;
+}
+static Proto*luaY_parser(lua_State*L,ZIO*z,Mbuffer*buff,const char*name){
+struct LexState lexstate;
+struct FuncState funcstate;
+lexstate.buff=buff;
+luaX_setinput(L,&lexstate,z,luaS_new(L,name));
+open_func(&lexstate,&funcstate);
+funcstate.f->is_vararg=2;
+luaX_next(&lexstate);
+chunk(&lexstate);
+check(&lexstate,TK_EOS);
+close_func(&lexstate);
+return funcstate.f;
+}
+static void field(LexState*ls,expdesc*v){
+FuncState*fs=ls->fs;
+expdesc key;
+luaK_exp2anyreg(fs,v);
+luaX_next(ls);
+checkname(ls,&key);
+luaK_indexed(fs,v,&key);
+}
+static void yindex(LexState*ls,expdesc*v){
+luaX_next(ls);
+expr(ls,v);
+luaK_exp2val(ls->fs,v);
+checknext(ls,']');
+}
+struct ConsControl{
+expdesc v;
+expdesc*t;
+int nh;
+int na;
+int tostore;
+};
+static void recfield(LexState*ls,struct ConsControl*cc){
+FuncState*fs=ls->fs;
+int reg=ls->fs->freereg;
+expdesc key,val;
+int rkkey;
+if(ls->t.token==TK_NAME){
+luaY_checklimit(fs,cc->nh,(INT_MAX-2),"items in a constructor");
+checkname(ls,&key);
+}
+else
+yindex(ls,&key);
+cc->nh++;
+checknext(ls,'=');
+rkkey=luaK_exp2RK(fs,&key);
+expr(ls,&val);
+luaK_codeABC(fs,OP_SETTABLE,cc->t->u.s.info,rkkey,luaK_exp2RK(fs,&val));
+fs->freereg=reg;
+}
+static void closelistfield(FuncState*fs,struct ConsControl*cc){
+if(cc->v.k==VVOID)return;
+luaK_exp2nextreg(fs,&cc->v);
+cc->v.k=VVOID;
+if(cc->tostore==50){
+luaK_setlist(fs,cc->t->u.s.info,cc->na,cc->tostore);
+cc->tostore=0;
+}
+}
+static void lastlistfield(FuncState*fs,struct ConsControl*cc){
+if(cc->tostore==0)return;
+if(hasmultret(cc->v.k)){
+luaK_setmultret(fs,&cc->v);
+luaK_setlist(fs,cc->t->u.s.info,cc->na,(-1));
+cc->na--;
+}
+else{
+if(cc->v.k!=VVOID)
+luaK_exp2nextreg(fs,&cc->v);
+luaK_setlist(fs,cc->t->u.s.info,cc->na,cc->tostore);
+}
+}
+static void listfield(LexState*ls,struct ConsControl*cc){
+expr(ls,&cc->v);
+luaY_checklimit(ls->fs,cc->na,(INT_MAX-2),"items in a constructor");
+cc->na++;
+cc->tostore++;
+}
+static void constructor(LexState*ls,expdesc*t){
+FuncState*fs=ls->fs;
+int line=ls->linenumber;
+int pc=luaK_codeABC(fs,OP_NEWTABLE,0,0,0);
+struct ConsControl cc;
+cc.na=cc.nh=cc.tostore=0;
+cc.t=t;
+init_exp(t,VRELOCABLE,pc);
+init_exp(&cc.v,VVOID,0);
+luaK_exp2nextreg(ls->fs,t);
+checknext(ls,'{');
+do{
+if(ls->t.token=='}')break;
+closelistfield(fs,&cc);
+switch(ls->t.token){
+case TK_NAME:{
+luaX_lookahead(ls);
+if(ls->lookahead.token!='=')
+listfield(ls,&cc);
+else
+recfield(ls,&cc);
+break;
+}
+case'[':{
+recfield(ls,&cc);
+break;
+}
+default:{
+listfield(ls,&cc);
+break;
+}
+}
+}while(testnext(ls,',')||testnext(ls,';'));
+check_match(ls,'}','{',line);
+lastlistfield(fs,&cc);
+SETARG_B(fs->f->code[pc],luaO_int2fb(cc.na));
+SETARG_C(fs->f->code[pc],luaO_int2fb(cc.nh));
+}
+static void parlist(LexState*ls){
+FuncState*fs=ls->fs;
+Proto*f=fs->f;
+int nparams=0;
+f->is_vararg=0;
+if(ls->t.token!=')'){
+do{
+switch(ls->t.token){
+case TK_NAME:{
+new_localvar(ls,str_checkname(ls),nparams++);
+break;
+}
+case TK_DOTS:{
+luaX_next(ls);
+f->is_vararg|=2;
+break;
+}
+default:luaX_syntaxerror(ls," or "LUA_QL("...")" expected");
+}
+}while(!f->is_vararg&&testnext(ls,','));
+}
+adjustlocalvars(ls,nparams);
+f->numparams=cast_byte(fs->nactvar-(f->is_vararg&1));
+luaK_reserveregs(fs,fs->nactvar);
+}
+static void body(LexState*ls,expdesc*e,int needself,int line){
+FuncState new_fs;
+open_func(ls,&new_fs);
+new_fs.f->linedefined=line;
+checknext(ls,'(');
+if(needself){
+new_localvarliteral(ls,"self",0);
+adjustlocalvars(ls,1);
+}
+parlist(ls);
+checknext(ls,')');
+chunk(ls);
+new_fs.f->lastlinedefined=ls->linenumber;
+check_match(ls,TK_END,TK_FUNCTION,line);
+close_func(ls);
+pushclosure(ls,&new_fs,e);
+}
+static int explist1(LexState*ls,expdesc*v){
+int n=1;
+expr(ls,v);
+while(testnext(ls,',')){
+luaK_exp2nextreg(ls->fs,v);
+expr(ls,v);
+n++;
+}
+return n;
+}
+static void funcargs(LexState*ls,expdesc*f){
+FuncState*fs=ls->fs;
+expdesc args;
+int base,nparams;
+int line=ls->linenumber;
+switch(ls->t.token){
+case'(':{
+if(line!=ls->lastline)
+luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)");
+luaX_next(ls);
+if(ls->t.token==')')
+args.k=VVOID;
+else{
+explist1(ls,&args);
+luaK_setmultret(fs,&args);
+}
+check_match(ls,')','(',line);
+break;
+}
+case'{':{
+constructor(ls,&args);
+break;
+}
+case TK_STRING:{
+codestring(ls,&args,ls->t.seminfo.ts);
+luaX_next(ls);
+break;
+}
+default:{
+luaX_syntaxerror(ls,"function arguments expected");
+return;
+}
+}
+base=f->u.s.info;
+if(hasmultret(args.k))
+nparams=(-1);
+else{
+if(args.k!=VVOID)
+luaK_exp2nextreg(fs,&args);
+nparams=fs->freereg-(base+1);
+}
+init_exp(f,VCALL,luaK_codeABC(fs,OP_CALL,base,nparams+1,2));
+luaK_fixline(fs,line);
+fs->freereg=base+1;
+}
+static void prefixexp(LexState*ls,expdesc*v){
+switch(ls->t.token){
+case'(':{
+int line=ls->linenumber;
+luaX_next(ls);
+expr(ls,v);
+check_match(ls,')','(',line);
+luaK_dischargevars(ls->fs,v);
+return;
+}
+case TK_NAME:{
+singlevar(ls,v);
+return;
+}
+default:{
+luaX_syntaxerror(ls,"unexpected symbol");
+return;
+}
+}
+}
+static void primaryexp(LexState*ls,expdesc*v){
+FuncState*fs=ls->fs;
+prefixexp(ls,v);
+for(;;){
+switch(ls->t.token){
+case'.':{
+field(ls,v);
+break;
+}
+case'[':{
+expdesc key;
+luaK_exp2anyreg(fs,v);
+yindex(ls,&key);
+luaK_indexed(fs,v,&key);
+break;
+}
+case':':{
+expdesc key;
+luaX_next(ls);
+checkname(ls,&key);
+luaK_self(fs,v,&key);
+funcargs(ls,v);
+break;
+}
+case'(':case TK_STRING:case'{':{
+luaK_exp2nextreg(fs,v);
+funcargs(ls,v);
+break;
+}
+default:return;
+}
+}
+}
+static void simpleexp(LexState*ls,expdesc*v){
+switch(ls->t.token){
+case TK_NUMBER:{
+init_exp(v,VKNUM,0);
+v->u.nval=ls->t.seminfo.r;
+break;
+}
+case TK_STRING:{
+codestring(ls,v,ls->t.seminfo.ts);
+break;
+}
+case TK_NIL:{
+init_exp(v,VNIL,0);
+break;
+}
+case TK_TRUE:{
+init_exp(v,VTRUE,0);
+break;
+}
+case TK_FALSE:{
+init_exp(v,VFALSE,0);
+break;
+}
+case TK_DOTS:{
+FuncState*fs=ls->fs;
+check_condition(ls,fs->f->is_vararg,
+"cannot use "LUA_QL("...")" outside a vararg function");
+fs->f->is_vararg&=~4;
+init_exp(v,VVARARG,luaK_codeABC(fs,OP_VARARG,0,1,0));
+break;
+}
+case'{':{
+constructor(ls,v);
+return;
+}
+case TK_FUNCTION:{
+luaX_next(ls);
+body(ls,v,0,ls->linenumber);
+return;
+}
+default:{
+primaryexp(ls,v);
+return;
+}
+}
+luaX_next(ls);
+}
+static UnOpr getunopr(int op){
+switch(op){
+case TK_NOT:return OPR_NOT;
+case'-':return OPR_MINUS;
+case'#':return OPR_LEN;
+default:return OPR_NOUNOPR;
+}
+}
+static BinOpr getbinopr(int op){
+switch(op){
+case'+':return OPR_ADD;
+case'-':return OPR_SUB;
+case'*':return OPR_MUL;
+case'/':return OPR_DIV;
+case'%':return OPR_MOD;
+case'^':return OPR_POW;
+case TK_CONCAT:return OPR_CONCAT;
+case TK_NE:return OPR_NE;
+case TK_EQ:return OPR_EQ;
+case'<':return OPR_LT;
+case TK_LE:return OPR_LE;
+case'>':return OPR_GT;
+case TK_GE:return OPR_GE;
+case TK_AND:return OPR_AND;
+case TK_OR:return OPR_OR;
+default:return OPR_NOBINOPR;
+}
+}
+static const struct{
+lu_byte left;
+lu_byte right;
+}priority[]={
+{6,6},{6,6},{7,7},{7,7},{7,7},
+{10,9},{5,4},
+{3,3},{3,3},
+{3,3},{3,3},{3,3},{3,3},
+{2,2},{1,1}
+};
+static BinOpr subexpr(LexState*ls,expdesc*v,unsigned int limit){
+BinOpr op;
+UnOpr uop;
+enterlevel(ls);
+uop=getunopr(ls->t.token);
+if(uop!=OPR_NOUNOPR){
+luaX_next(ls);
+subexpr(ls,v,8);
+luaK_prefix(ls->fs,uop,v);
+}
+else simpleexp(ls,v);
+op=getbinopr(ls->t.token);
+while(op!=OPR_NOBINOPR&&priority[op].left>limit){
+expdesc v2;
+BinOpr nextop;
+luaX_next(ls);
+luaK_infix(ls->fs,op,v);
+nextop=subexpr(ls,&v2,priority[op].right);
+luaK_posfix(ls->fs,op,v,&v2);
+op=nextop;
+}
+leavelevel(ls);
+return op;
+}
+static void expr(LexState*ls,expdesc*v){
+subexpr(ls,v,0);
+}
+static int block_follow(int token){
+switch(token){
+case TK_ELSE:case TK_ELSEIF:case TK_END:
+case TK_UNTIL:case TK_EOS:
+return 1;
+default:return 0;
+}
+}
+static void block(LexState*ls){
+FuncState*fs=ls->fs;
+BlockCnt bl;
+enterblock(fs,&bl,0);
+chunk(ls);
+leaveblock(fs);
+}
+struct LHS_assign{
+struct LHS_assign*prev;
+expdesc v;
+};
+static void check_conflict(LexState*ls,struct LHS_assign*lh,expdesc*v){
+FuncState*fs=ls->fs;
+int extra=fs->freereg;
+int conflict=0;
+for(;lh;lh=lh->prev){
+if(lh->v.k==VINDEXED){
+if(lh->v.u.s.info==v->u.s.info){
+conflict=1;
+lh->v.u.s.info=extra;
+}
+if(lh->v.u.s.aux==v->u.s.info){
+conflict=1;
+lh->v.u.s.aux=extra;
+}
+}
+}
+if(conflict){
+luaK_codeABC(fs,OP_MOVE,fs->freereg,v->u.s.info,0);
+luaK_reserveregs(fs,1);
+}
+}
+static void assignment(LexState*ls,struct LHS_assign*lh,int nvars){
+expdesc e;
+check_condition(ls,VLOCAL<=lh->v.k&&lh->v.k<=VINDEXED,
+"syntax error");
+if(testnext(ls,',')){
+struct LHS_assign nv;
+nv.prev=lh;
+primaryexp(ls,&nv.v);
+if(nv.v.k==VLOCAL)
+check_conflict(ls,lh,&nv.v);
+luaY_checklimit(ls->fs,nvars,200-ls->L->nCcalls,
+"variables in assignment");
+assignment(ls,&nv,nvars+1);
+}
+else{
+int nexps;
+checknext(ls,'=');
+nexps=explist1(ls,&e);
+if(nexps!=nvars){
+adjust_assign(ls,nvars,nexps,&e);
+if(nexps>nvars)
+ls->fs->freereg-=nexps-nvars;
+}
+else{
+luaK_setoneret(ls->fs,&e);
+luaK_storevar(ls->fs,&lh->v,&e);
+return;
+}
+}
+init_exp(&e,VNONRELOC,ls->fs->freereg-1);
+luaK_storevar(ls->fs,&lh->v,&e);
+}
+static int cond(LexState*ls){
+expdesc v;
+expr(ls,&v);
+if(v.k==VNIL)v.k=VFALSE;
+luaK_goiftrue(ls->fs,&v);
+return v.f;
+}
+static void breakstat(LexState*ls){
+FuncState*fs=ls->fs;
+BlockCnt*bl=fs->bl;
+int upval=0;
+while(bl&&!bl->isbreakable){
+upval|=bl->upval;
+bl=bl->previous;
+}
+if(!bl)
+luaX_syntaxerror(ls,"no loop to break");
+if(upval)
+luaK_codeABC(fs,OP_CLOSE,bl->nactvar,0,0);
+luaK_concat(fs,&bl->breaklist,luaK_jump(fs));
+}
+static void whilestat(LexState*ls,int line){
+FuncState*fs=ls->fs;
+int whileinit;
+int condexit;
+BlockCnt bl;
+luaX_next(ls);
+whileinit=luaK_getlabel(fs);
+condexit=cond(ls);
+enterblock(fs,&bl,1);
+checknext(ls,TK_DO);
+block(ls);
+luaK_patchlist(fs,luaK_jump(fs),whileinit);
+check_match(ls,TK_END,TK_WHILE,line);
+leaveblock(fs);
+luaK_patchtohere(fs,condexit);
+}
+static void repeatstat(LexState*ls,int line){
+int condexit;
+FuncState*fs=ls->fs;
+int repeat_init=luaK_getlabel(fs);
+BlockCnt bl1,bl2;
+enterblock(fs,&bl1,1);
+enterblock(fs,&bl2,0);
+luaX_next(ls);
+chunk(ls);
+check_match(ls,TK_UNTIL,TK_REPEAT,line);
+condexit=cond(ls);
+if(!bl2.upval){
+leaveblock(fs);
+luaK_patchlist(ls->fs,condexit,repeat_init);
+}
+else{
+breakstat(ls);
+luaK_patchtohere(ls->fs,condexit);
+leaveblock(fs);
+luaK_patchlist(ls->fs,luaK_jump(fs),repeat_init);
+}
+leaveblock(fs);
+}
+static int exp1(LexState*ls){
+expdesc e;
+int k;
+expr(ls,&e);
+k=e.k;
+luaK_exp2nextreg(ls->fs,&e);
+return k;
+}
+static void forbody(LexState*ls,int base,int line,int nvars,int isnum){
+BlockCnt bl;
+FuncState*fs=ls->fs;
+int prep,endfor;
+adjustlocalvars(ls,3);
+checknext(ls,TK_DO);
+prep=isnum?luaK_codeAsBx(fs,OP_FORPREP,base,(-1)):luaK_jump(fs);
+enterblock(fs,&bl,0);
+adjustlocalvars(ls,nvars);
+luaK_reserveregs(fs,nvars);
+block(ls);
+leaveblock(fs);
+luaK_patchtohere(fs,prep);
+endfor=(isnum)?luaK_codeAsBx(fs,OP_FORLOOP,base,(-1)):
+luaK_codeABC(fs,OP_TFORLOOP,base,0,nvars);
+luaK_fixline(fs,line);
+luaK_patchlist(fs,(isnum?endfor:luaK_jump(fs)),prep+1);
+}
+static void fornum(LexState*ls,TString*varname,int line){
+FuncState*fs=ls->fs;
+int base=fs->freereg;
+new_localvarliteral(ls,"(for index)",0);
+new_localvarliteral(ls,"(for limit)",1);
+new_localvarliteral(ls,"(for step)",2);
+new_localvar(ls,varname,3);
+checknext(ls,'=');
+exp1(ls);
+checknext(ls,',');
+exp1(ls);
+if(testnext(ls,','))
+exp1(ls);
+else{
+luaK_codeABx(fs,OP_LOADK,fs->freereg,luaK_numberK(fs,1));
+luaK_reserveregs(fs,1);
+}
+forbody(ls,base,line,1,1);
+}
+static void forlist(LexState*ls,TString*indexname){
+FuncState*fs=ls->fs;
+expdesc e;
+int nvars=0;
+int line;
+int base=fs->freereg;
+new_localvarliteral(ls,"(for generator)",nvars++);
+new_localvarliteral(ls,"(for state)",nvars++);
+new_localvarliteral(ls,"(for control)",nvars++);
+new_localvar(ls,indexname,nvars++);
+while(testnext(ls,','))
+new_localvar(ls,str_checkname(ls),nvars++);
+checknext(ls,TK_IN);
+line=ls->linenumber;
+adjust_assign(ls,3,explist1(ls,&e),&e);
+luaK_checkstack(fs,3);
+forbody(ls,base,line,nvars-3,0);
+}
+static void forstat(LexState*ls,int line){
+FuncState*fs=ls->fs;
+TString*varname;
+BlockCnt bl;
+enterblock(fs,&bl,1);
+luaX_next(ls);
+varname=str_checkname(ls);
+switch(ls->t.token){
+case'=':fornum(ls,varname,line);break;
+case',':case TK_IN:forlist(ls,varname);break;
+default:luaX_syntaxerror(ls,LUA_QL("=")" or "LUA_QL("in")" expected");
+}
+check_match(ls,TK_END,TK_FOR,line);
+leaveblock(fs);
+}
+static int test_then_block(LexState*ls){
+int condexit;
+luaX_next(ls);
+condexit=cond(ls);
+checknext(ls,TK_THEN);
+block(ls);
+return condexit;
+}
+static void ifstat(LexState*ls,int line){
+FuncState*fs=ls->fs;
+int flist;
+int escapelist=(-1);
+flist=test_then_block(ls);
+while(ls->t.token==TK_ELSEIF){
+luaK_concat(fs,&escapelist,luaK_jump(fs));
+luaK_patchtohere(fs,flist);
+flist=test_then_block(ls);
+}
+if(ls->t.token==TK_ELSE){
+luaK_concat(fs,&escapelist,luaK_jump(fs));
+luaK_patchtohere(fs,flist);
+luaX_next(ls);
+block(ls);
+}
+else
+luaK_concat(fs,&escapelist,flist);
+luaK_patchtohere(fs,escapelist);
+check_match(ls,TK_END,TK_IF,line);
+}
+static void localfunc(LexState*ls){
+expdesc v,b;
+FuncState*fs=ls->fs;
+new_localvar(ls,str_checkname(ls),0);
+init_exp(&v,VLOCAL,fs->freereg);
+luaK_reserveregs(fs,1);
+adjustlocalvars(ls,1);
+body(ls,&b,0,ls->linenumber);
+luaK_storevar(fs,&v,&b);
+getlocvar(fs,fs->nactvar-1).startpc=fs->pc;
+}
+static void localstat(LexState*ls){
+int nvars=0;
+int nexps;
+expdesc e;
+do{
+new_localvar(ls,str_checkname(ls),nvars++);
+}while(testnext(ls,','));
+if(testnext(ls,'='))
+nexps=explist1(ls,&e);
+else{
+e.k=VVOID;
+nexps=0;
+}
+adjust_assign(ls,nvars,nexps,&e);
+adjustlocalvars(ls,nvars);
+}
+static int funcname(LexState*ls,expdesc*v){
+int needself=0;
+singlevar(ls,v);
+while(ls->t.token=='.')
+field(ls,v);
+if(ls->t.token==':'){
+needself=1;
+field(ls,v);
+}
+return needself;
+}
+static void funcstat(LexState*ls,int line){
+int needself;
+expdesc v,b;
+luaX_next(ls);
+needself=funcname(ls,&v);
+body(ls,&b,needself,line);
+luaK_storevar(ls->fs,&v,&b);
+luaK_fixline(ls->fs,line);
+}
+static void exprstat(LexState*ls){
+FuncState*fs=ls->fs;
+struct LHS_assign v;
+primaryexp(ls,&v.v);
+if(v.v.k==VCALL)
+SETARG_C(getcode(fs,&v.v),1);
+else{
+v.prev=NULL;
+assignment(ls,&v,1);
+}
+}
+static void retstat(LexState*ls){
+FuncState*fs=ls->fs;
+expdesc e;
+int first,nret;
+luaX_next(ls);
+if(block_follow(ls->t.token)||ls->t.token==';')
+first=nret=0;
+else{
+nret=explist1(ls,&e);
+if(hasmultret(e.k)){
+luaK_setmultret(fs,&e);
+if(e.k==VCALL&&nret==1){
+SET_OPCODE(getcode(fs,&e),OP_TAILCALL);
+}
+first=fs->nactvar;
+nret=(-1);
+}
+else{
+if(nret==1)
+first=luaK_exp2anyreg(fs,&e);
+else{
+luaK_exp2nextreg(fs,&e);
+first=fs->nactvar;
+}
+}
+}
+luaK_ret(fs,first,nret);
+}
+static int statement(LexState*ls){
+int line=ls->linenumber;
+switch(ls->t.token){
+case TK_IF:{
+ifstat(ls,line);
+return 0;
+}
+case TK_WHILE:{
+whilestat(ls,line);
+return 0;
+}
+case TK_DO:{
+luaX_next(ls);
+block(ls);
+check_match(ls,TK_END,TK_DO,line);
+return 0;
+}
+case TK_FOR:{
+forstat(ls,line);
+return 0;
+}
+case TK_REPEAT:{
+repeatstat(ls,line);
+return 0;
+}
+case TK_FUNCTION:{
+funcstat(ls,line);
+return 0;
+}
+case TK_LOCAL:{
+luaX_next(ls);
+if(testnext(ls,TK_FUNCTION))
+localfunc(ls);
+else
+localstat(ls);
+return 0;
+}
+case TK_RETURN:{
+retstat(ls);
+return 1;
+}
+case TK_BREAK:{
+luaX_next(ls);
+breakstat(ls);
+return 1;
+}
+default:{
+exprstat(ls);
+return 0;
+}
+}
+}
+static void chunk(LexState*ls){
+int islast=0;
+enterlevel(ls);
+while(!islast&&!block_follow(ls->t.token)){
+islast=statement(ls);
+testnext(ls,';');
+ls->fs->freereg=ls->fs->nactvar;
+}
+leavelevel(ls);
+}
+static const TValue*luaV_tonumber(const TValue*obj,TValue*n){
+lua_Number num;
+if(ttisnumber(obj))return obj;
+if(ttisstring(obj)&&luaO_str2d(svalue(obj),&num)){
+setnvalue(n,num);
+return n;
+}
+else
+return NULL;
+}
+static int luaV_tostring(lua_State*L,StkId obj){
+if(!ttisnumber(obj))
+return 0;
+else{
+char s[32];
+lua_Number n=nvalue(obj);
+lua_number2str(s,n);
+setsvalue(L,obj,luaS_new(L,s));
+return 1;
+}
+}
+static void callTMres(lua_State*L,StkId res,const TValue*f,
+const TValue*p1,const TValue*p2){
+ptrdiff_t result=savestack(L,res);
+setobj(L,L->top,f);
+setobj(L,L->top+1,p1);
+setobj(L,L->top+2,p2);
+luaD_checkstack(L,3);
+L->top+=3;
+luaD_call(L,L->top-3,1);
+res=restorestack(L,result);
+L->top--;
+setobj(L,res,L->top);
+}
+static void callTM(lua_State*L,const TValue*f,const TValue*p1,
+const TValue*p2,const TValue*p3){
+setobj(L,L->top,f);
+setobj(L,L->top+1,p1);
+setobj(L,L->top+2,p2);
+setobj(L,L->top+3,p3);
+luaD_checkstack(L,4);
+L->top+=4;
+luaD_call(L,L->top-4,0);
+}
+static void luaV_gettable(lua_State*L,const TValue*t,TValue*key,StkId val){
+int loop;
+for(loop=0;loop<100;loop++){
+const TValue*tm;
+if(ttistable(t)){
+Table*h=hvalue(t);
+const TValue*res=luaH_get(h,key);
+if(!ttisnil(res)||
+(tm=fasttm(L,h->metatable,TM_INDEX))==NULL){
+setobj(L,val,res);
+return;
+}
+}
+else if(ttisnil(tm=luaT_gettmbyobj(L,t,TM_INDEX)))
+luaG_typeerror(L,t,"index");
+if(ttisfunction(tm)){
+callTMres(L,val,tm,t,key);
+return;
+}
+t=tm;
+}
+luaG_runerror(L,"loop in gettable");
+}
+static void luaV_settable(lua_State*L,const TValue*t,TValue*key,StkId val){
+int loop;
+TValue temp;
+for(loop=0;loop<100;loop++){
+const TValue*tm;
+if(ttistable(t)){
+Table*h=hvalue(t);
+TValue*oldval=luaH_set(L,h,key);
+if(!ttisnil(oldval)||
+(tm=fasttm(L,h->metatable,TM_NEWINDEX))==NULL){
+setobj(L,oldval,val);
+h->flags=0;
+luaC_barriert(L,h,val);
+return;
+}
+}
+else if(ttisnil(tm=luaT_gettmbyobj(L,t,TM_NEWINDEX)))
+luaG_typeerror(L,t,"index");
+if(ttisfunction(tm)){
+callTM(L,tm,t,key,val);
+return;
+}
+setobj(L,&temp,tm);
+t=&temp;
+}
+luaG_runerror(L,"loop in settable");
+}
+static int call_binTM(lua_State*L,const TValue*p1,const TValue*p2,
+StkId res,TMS event){
+const TValue*tm=luaT_gettmbyobj(L,p1,event);
+if(ttisnil(tm))
+tm=luaT_gettmbyobj(L,p2,event);
+if(ttisnil(tm))return 0;
+callTMres(L,res,tm,p1,p2);
+return 1;
+}
+static const TValue*get_compTM(lua_State*L,Table*mt1,Table*mt2,
+TMS event){
+const TValue*tm1=fasttm(L,mt1,event);
+const TValue*tm2;
+if(tm1==NULL)return NULL;
+if(mt1==mt2)return tm1;
+tm2=fasttm(L,mt2,event);
+if(tm2==NULL)return NULL;
+if(luaO_rawequalObj(tm1,tm2))
+return tm1;
+return NULL;
+}
+static int call_orderTM(lua_State*L,const TValue*p1,const TValue*p2,
+TMS event){
+const TValue*tm1=luaT_gettmbyobj(L,p1,event);
+const TValue*tm2;
+if(ttisnil(tm1))return-1;
+tm2=luaT_gettmbyobj(L,p2,event);
+if(!luaO_rawequalObj(tm1,tm2))
+return-1;
+callTMres(L,L->top,tm1,p1,p2);
+return!l_isfalse(L->top);
+}
+static int l_strcmp(const TString*ls,const TString*rs){
+const char*l=getstr(ls);
+size_t ll=ls->tsv.len;
+const char*r=getstr(rs);
+size_t lr=rs->tsv.len;
+for(;;){
+int temp=strcoll(l,r);
+if(temp!=0)return temp;
+else{
+size_t len=strlen(l);
+if(len==lr)
+return(len==ll)?0:1;
+else if(len==ll)
+return-1;
+len++;
+l+=len;ll-=len;r+=len;lr-=len;
+}
+}
+}
+static int luaV_lessthan(lua_State*L,const TValue*l,const TValue*r){
+int res;
+if(ttype(l)!=ttype(r))
+return luaG_ordererror(L,l,r);
+else if(ttisnumber(l))
+return luai_numlt(nvalue(l),nvalue(r));
+else if(ttisstring(l))
+return l_strcmp(rawtsvalue(l),rawtsvalue(r))<0;
+else if((res=call_orderTM(L,l,r,TM_LT))!=-1)
+return res;
+return luaG_ordererror(L,l,r);
+}
+static int lessequal(lua_State*L,const TValue*l,const TValue*r){
+int res;
+if(ttype(l)!=ttype(r))
+return luaG_ordererror(L,l,r);
+else if(ttisnumber(l))
+return luai_numle(nvalue(l),nvalue(r));
+else if(ttisstring(l))
+return l_strcmp(rawtsvalue(l),rawtsvalue(r))<=0;
+else if((res=call_orderTM(L,l,r,TM_LE))!=-1)
+return res;
+else if((res=call_orderTM(L,r,l,TM_LT))!=-1)
+return!res;
+return luaG_ordererror(L,l,r);
+}
+static int luaV_equalval(lua_State*L,const TValue*t1,const TValue*t2){
+const TValue*tm;
+switch(ttype(t1)){
+case 0:return 1;
+case 3:return luai_numeq(nvalue(t1),nvalue(t2));
+case 1:return bvalue(t1)==bvalue(t2);
+case 2:return pvalue(t1)==pvalue(t2);
+case 7:{
+if(uvalue(t1)==uvalue(t2))return 1;
+tm=get_compTM(L,uvalue(t1)->metatable,uvalue(t2)->metatable,
+TM_EQ);
+break;
+}
+case 5:{
+if(hvalue(t1)==hvalue(t2))return 1;
+tm=get_compTM(L,hvalue(t1)->metatable,hvalue(t2)->metatable,TM_EQ);
+break;
+}
+default:return gcvalue(t1)==gcvalue(t2);
+}
+if(tm==NULL)return 0;
+callTMres(L,L->top,tm,t1,t2);
+return!l_isfalse(L->top);
+}
+static void luaV_concat(lua_State*L,int total,int last){
+do{
+StkId top=L->base+last+1;
+int n=2;
+if(!(ttisstring(top-2)||ttisnumber(top-2))||!tostring(L,top-1)){
+if(!call_binTM(L,top-2,top-1,top-2,TM_CONCAT))
+luaG_concaterror(L,top-2,top-1);
+}else if(tsvalue(top-1)->len==0)
+(void)tostring(L,top-2);
+else{
+size_t tl=tsvalue(top-1)->len;
+char*buffer;
+int i;
+for(n=1;nlen;
+if(l>=((size_t)(~(size_t)0)-2)-tl)luaG_runerror(L,"string length overflow");
+tl+=l;
+}
+buffer=luaZ_openspace(L,&G(L)->buff,tl);
+tl=0;
+for(i=n;i>0;i--){
+size_t l=tsvalue(top-i)->len;
+memcpy(buffer+tl,svalue(top-i),l);
+tl+=l;
+}
+setsvalue(L,top-n,luaS_newlstr(L,buffer,tl));
+}
+total-=n-1;
+last-=n-1;
+}while(total>1);
+}
+static void Arith(lua_State*L,StkId ra,const TValue*rb,
+const TValue*rc,TMS op){
+TValue tempb,tempc;
+const TValue*b,*c;
+if((b=luaV_tonumber(rb,&tempb))!=NULL&&
+(c=luaV_tonumber(rc,&tempc))!=NULL){
+lua_Number nb=nvalue(b),nc=nvalue(c);
+switch(op){
+case TM_ADD:setnvalue(ra,luai_numadd(nb,nc));break;
+case TM_SUB:setnvalue(ra,luai_numsub(nb,nc));break;
+case TM_MUL:setnvalue(ra,luai_nummul(nb,nc));break;
+case TM_DIV:setnvalue(ra,luai_numdiv(nb,nc));break;
+case TM_MOD:setnvalue(ra,luai_nummod(nb,nc));break;
+case TM_POW:setnvalue(ra,luai_numpow(nb,nc));break;
+case TM_UNM:setnvalue(ra,luai_numunm(nb));break;
+default:break;
+}
+}
+else if(!call_binTM(L,rb,rc,ra,op))
+luaG_aritherror(L,rb,rc);
+}
+#define runtime_check(L,c){if(!(c))break;}
+#define RA(i)(base+GETARG_A(i))
+#define RB(i)check_exp(getBMode(GET_OPCODE(i))==OpArgR,base+GETARG_B(i))
+#define RKB(i)check_exp(getBMode(GET_OPCODE(i))==OpArgK,ISK(GETARG_B(i))?k+INDEXK(GETARG_B(i)):base+GETARG_B(i))
+#define RKC(i)check_exp(getCMode(GET_OPCODE(i))==OpArgK,ISK(GETARG_C(i))?k+INDEXK(GETARG_C(i)):base+GETARG_C(i))
+#define KBx(i)check_exp(getBMode(GET_OPCODE(i))==OpArgK,k+GETARG_Bx(i))
+#define dojump(L,pc,i){(pc)+=(i);}
+#define Protect(x){L->savedpc=pc;{x;};base=L->base;}
+#define arith_op(op,tm){TValue*rb=RKB(i);TValue*rc=RKC(i);if(ttisnumber(rb)&&ttisnumber(rc)){lua_Number nb=nvalue(rb),nc=nvalue(rc);setnvalue(ra,op(nb,nc));}else Protect(Arith(L,ra,rb,rc,tm));}
+static void luaV_execute(lua_State*L,int nexeccalls){
+LClosure*cl;
+StkId base;
+TValue*k;
+const Instruction*pc;
+reentry:
+pc=L->savedpc;
+cl=&clvalue(L->ci->func)->l;
+base=L->base;
+k=cl->p->k;
+for(;;){
+const Instruction i=*pc++;
+StkId ra;
+ra=RA(i);
+switch(GET_OPCODE(i)){
+case OP_MOVE:{
+setobj(L,ra,RB(i));
+continue;
+}
+case OP_LOADK:{
+setobj(L,ra,KBx(i));
+continue;
+}
+case OP_LOADBOOL:{
+setbvalue(ra,GETARG_B(i));
+if(GETARG_C(i))pc++;
+continue;
+}
+case OP_LOADNIL:{
+TValue*rb=RB(i);
+do{
+setnilvalue(rb--);
+}while(rb>=ra);
+continue;
+}
+case OP_GETUPVAL:{
+int b=GETARG_B(i);
+setobj(L,ra,cl->upvals[b]->v);
+continue;
+}
+case OP_GETGLOBAL:{
+TValue g;
+TValue*rb=KBx(i);
+sethvalue(L,&g,cl->env);
+Protect(luaV_gettable(L,&g,rb,ra));
+continue;
+}
+case OP_GETTABLE:{
+Protect(luaV_gettable(L,RB(i),RKC(i),ra));
+continue;
+}
+case OP_SETGLOBAL:{
+TValue g;
+sethvalue(L,&g,cl->env);
+Protect(luaV_settable(L,&g,KBx(i),ra));
+continue;
+}
+case OP_SETUPVAL:{
+UpVal*uv=cl->upvals[GETARG_B(i)];
+setobj(L,uv->v,ra);
+luaC_barrier(L,uv,ra);
+continue;
+}
+case OP_SETTABLE:{
+Protect(luaV_settable(L,ra,RKB(i),RKC(i)));
+continue;
+}
+case OP_NEWTABLE:{
+int b=GETARG_B(i);
+int c=GETARG_C(i);
+sethvalue(L,ra,luaH_new(L,luaO_fb2int(b),luaO_fb2int(c)));
+Protect(luaC_checkGC(L));
+continue;
+}
+case OP_SELF:{
+StkId rb=RB(i);
+setobj(L,ra+1,rb);
+Protect(luaV_gettable(L,rb,RKC(i),ra));
+continue;
+}
+case OP_ADD:{
+arith_op(luai_numadd,TM_ADD);
+continue;
+}
+case OP_SUB:{
+arith_op(luai_numsub,TM_SUB);
+continue;
+}
+case OP_MUL:{
+arith_op(luai_nummul,TM_MUL);
+continue;
+}
+case OP_DIV:{
+arith_op(luai_numdiv,TM_DIV);
+continue;
+}
+case OP_MOD:{
+arith_op(luai_nummod,TM_MOD);
+continue;
+}
+case OP_POW:{
+arith_op(luai_numpow,TM_POW);
+continue;
+}
+case OP_UNM:{
+TValue*rb=RB(i);
+if(ttisnumber(rb)){
+lua_Number nb=nvalue(rb);
+setnvalue(ra,luai_numunm(nb));
+}
+else{
+Protect(Arith(L,ra,rb,rb,TM_UNM));
+}
+continue;
+}
+case OP_NOT:{
+int res=l_isfalse(RB(i));
+setbvalue(ra,res);
+continue;
+}
+case OP_LEN:{
+const TValue*rb=RB(i);
+switch(ttype(rb)){
+case 5:{
+setnvalue(ra,cast_num(luaH_getn(hvalue(rb))));
+break;
+}
+case 4:{
+setnvalue(ra,cast_num(tsvalue(rb)->len));
+break;
+}
+default:{
+Protect(
+if(!call_binTM(L,rb,(&luaO_nilobject_),ra,TM_LEN))
+luaG_typeerror(L,rb,"get length of");
+)
+}
+}
+continue;
+}
+case OP_CONCAT:{
+int b=GETARG_B(i);
+int c=GETARG_C(i);
+Protect(luaV_concat(L,c-b+1,c);luaC_checkGC(L));
+setobj(L,RA(i),base+b);
+continue;
+}
+case OP_JMP:{
+dojump(L,pc,GETARG_sBx(i));
+continue;
+}
+case OP_EQ:{
+TValue*rb=RKB(i);
+TValue*rc=RKC(i);
+Protect(
+if(equalobj(L,rb,rc)==GETARG_A(i))
+dojump(L,pc,GETARG_sBx(*pc));
+)
+pc++;
+continue;
+}
+case OP_LT:{
+Protect(
+if(luaV_lessthan(L,RKB(i),RKC(i))==GETARG_A(i))
+dojump(L,pc,GETARG_sBx(*pc));
+)
+pc++;
+continue;
+}
+case OP_LE:{
+Protect(
+if(lessequal(L,RKB(i),RKC(i))==GETARG_A(i))
+dojump(L,pc,GETARG_sBx(*pc));
+)
+pc++;
+continue;
+}
+case OP_TEST:{
+if(l_isfalse(ra)!=GETARG_C(i))
+dojump(L,pc,GETARG_sBx(*pc));
+pc++;
+continue;
+}
+case OP_TESTSET:{
+TValue*rb=RB(i);
+if(l_isfalse(rb)!=GETARG_C(i)){
+setobj(L,ra,rb);
+dojump(L,pc,GETARG_sBx(*pc));
+}
+pc++;
+continue;
+}
+case OP_CALL:{
+int b=GETARG_B(i);
+int nresults=GETARG_C(i)-1;
+if(b!=0)L->top=ra+b;
+L->savedpc=pc;
+switch(luaD_precall(L,ra,nresults)){
+case 0:{
+nexeccalls++;
+goto reentry;
+}
+case 1:{
+if(nresults>=0)L->top=L->ci->top;
+base=L->base;
+continue;
+}
+default:{
+return;
+}
+}
+}
+case OP_TAILCALL:{
+int b=GETARG_B(i);
+if(b!=0)L->top=ra+b;
+L->savedpc=pc;
+switch(luaD_precall(L,ra,(-1))){
+case 0:{
+CallInfo*ci=L->ci-1;
+int aux;
+StkId func=ci->func;
+StkId pfunc=(ci+1)->func;
+if(L->openupval)luaF_close(L,ci->base);
+L->base=ci->base=ci->func+((ci+1)->base-pfunc);
+for(aux=0;pfunc+auxtop;aux++)
+setobj(L,func+aux,pfunc+aux);
+ci->top=L->top=func+aux;
+ci->savedpc=L->savedpc;
+ci->tailcalls++;
+L->ci--;
+goto reentry;
+}
+case 1:{
+base=L->base;
+continue;
+}
+default:{
+return;
+}
+}
+}
+case OP_RETURN:{
+int b=GETARG_B(i);
+if(b!=0)L->top=ra+b-1;
+if(L->openupval)luaF_close(L,base);
+L->savedpc=pc;
+b=luaD_poscall(L,ra);
+if(--nexeccalls==0)
+return;
+else{
+if(b)L->top=L->ci->top;
+goto reentry;
+}
+}
+case OP_FORLOOP:{
+lua_Number step=nvalue(ra+2);
+lua_Number idx=luai_numadd(nvalue(ra),step);
+lua_Number limit=nvalue(ra+1);
+if(luai_numlt(0,step)?luai_numle(idx,limit)
+:luai_numle(limit,idx)){
+dojump(L,pc,GETARG_sBx(i));
+setnvalue(ra,idx);
+setnvalue(ra+3,idx);
+}
+continue;
+}
+case OP_FORPREP:{
+const TValue*init=ra;
+const TValue*plimit=ra+1;
+const TValue*pstep=ra+2;
+L->savedpc=pc;
+if(!tonumber(init,ra))
+luaG_runerror(L,LUA_QL("for")" initial value must be a number");
+else if(!tonumber(plimit,ra+1))
+luaG_runerror(L,LUA_QL("for")" limit must be a number");
+else if(!tonumber(pstep,ra+2))
+luaG_runerror(L,LUA_QL("for")" step must be a number");
+setnvalue(ra,luai_numsub(nvalue(ra),nvalue(pstep)));
+dojump(L,pc,GETARG_sBx(i));
+continue;
+}
+case OP_TFORLOOP:{
+StkId cb=ra+3;
+setobj(L,cb+2,ra+2);
+setobj(L,cb+1,ra+1);
+setobj(L,cb,ra);
+L->top=cb+3;
+Protect(luaD_call(L,cb,GETARG_C(i)));
+L->top=L->ci->top;
+cb=RA(i)+3;
+if(!ttisnil(cb)){
+setobj(L,cb-1,cb);
+dojump(L,pc,GETARG_sBx(*pc));
+}
+pc++;
+continue;
+}
+case OP_SETLIST:{
+int n=GETARG_B(i);
+int c=GETARG_C(i);
+int last;
+Table*h;
+if(n==0){
+n=cast_int(L->top-ra)-1;
+L->top=L->ci->top;
+}
+if(c==0)c=cast_int(*pc++);
+runtime_check(L,ttistable(ra));
+h=hvalue(ra);
+last=((c-1)*50)+n;
+if(last>h->sizearray)
+luaH_resizearray(L,h,last);
+for(;n>0;n--){
+TValue*val=ra+n;
+setobj(L,luaH_setnum(L,h,last--),val);
+luaC_barriert(L,h,val);
+}
+continue;
+}
+case OP_CLOSE:{
+luaF_close(L,ra);
+continue;
+}
+case OP_CLOSURE:{
+Proto*p;
+Closure*ncl;
+int nup,j;
+p=cl->p->p[GETARG_Bx(i)];
+nup=p->nups;
+ncl=luaF_newLclosure(L,nup,cl->env);
+ncl->l.p=p;
+for(j=0;jl.upvals[j]=cl->upvals[GETARG_B(*pc)];
+else{
+ncl->l.upvals[j]=luaF_findupval(L,base+GETARG_B(*pc));
+}
+}
+setclvalue(L,ra,ncl);
+Protect(luaC_checkGC(L));
+continue;
+}
+case OP_VARARG:{
+int b=GETARG_B(i)-1;
+int j;
+CallInfo*ci=L->ci;
+int n=cast_int(ci->base-ci->func)-cl->p->numparams-1;
+if(b==(-1)){
+Protect(luaD_checkstack(L,n));
+ra=RA(i);
+b=n;
+L->top=ra+n;
+}
+for(j=0;jbase-n+j);
+}
+else{
+setnilvalue(ra+j);
+}
+}
+continue;
+}
+}
+}
+}
+#define api_checknelems(L,n)luai_apicheck(L,(n)<=(L->top-L->base))
+#define api_checkvalidindex(L,i)luai_apicheck(L,(i)!=(&luaO_nilobject_))
+#define api_incr_top(L){luai_apicheck(L,L->topci->top);L->top++;}
+static TValue*index2adr(lua_State*L,int idx){
+if(idx>0){
+TValue*o=L->base+(idx-1);
+luai_apicheck(L,idx<=L->ci->top-L->base);
+if(o>=L->top)return cast(TValue*,(&luaO_nilobject_));
+else return o;
+}
+else if(idx>(-10000)){
+luai_apicheck(L,idx!=0&&-idx<=L->top-L->base);
+return L->top+idx;
+}
+else switch(idx){
+case(-10000):return registry(L);
+case(-10001):{
+Closure*func=curr_func(L);
+sethvalue(L,&L->env,func->c.env);
+return&L->env;
+}
+case(-10002):return gt(L);
+default:{
+Closure*func=curr_func(L);
+idx=(-10002)-idx;
+return(idx<=func->c.nupvalues)
+?&func->c.upvalue[idx-1]
+:cast(TValue*,(&luaO_nilobject_));
+}
+}
+}
+static Table*getcurrenv(lua_State*L){
+if(L->ci==L->base_ci)
+return hvalue(gt(L));
+else{
+Closure*func=curr_func(L);
+return func->c.env;
+}
+}
+static int lua_checkstack(lua_State*L,int size){
+int res=1;
+if(size>8000||(L->top-L->base+size)>8000)
+res=0;
+else if(size>0){
+luaD_checkstack(L,size);
+if(L->ci->toptop+size)
+L->ci->top=L->top+size;
+}
+return res;
+}
+static lua_CFunction lua_atpanic(lua_State*L,lua_CFunction panicf){
+lua_CFunction old;
+old=G(L)->panic;
+G(L)->panic=panicf;
+return old;
+}
+static int lua_gettop(lua_State*L){
+return cast_int(L->top-L->base);
+}
+static void lua_settop(lua_State*L,int idx){
+if(idx>=0){
+luai_apicheck(L,idx<=L->stack_last-L->base);
+while(L->topbase+idx)
+setnilvalue(L->top++);
+L->top=L->base+idx;
+}
+else{
+luai_apicheck(L,-(idx+1)<=(L->top-L->base));
+L->top+=idx+1;
+}
+}
+static void lua_remove(lua_State*L,int idx){
+StkId p;
+p=index2adr(L,idx);
+api_checkvalidindex(L,p);
+while(++ptop)setobj(L,p-1,p);
+L->top--;
+}
+static void lua_insert(lua_State*L,int idx){
+StkId p;
+StkId q;
+p=index2adr(L,idx);
+api_checkvalidindex(L,p);
+for(q=L->top;q>p;q--)setobj(L,q,q-1);
+setobj(L,p,L->top);
+}
+static void lua_replace(lua_State*L,int idx){
+StkId o;
+if(idx==(-10001)&&L->ci==L->base_ci)
+luaG_runerror(L,"no calling environment");
+api_checknelems(L,1);
+o=index2adr(L,idx);
+api_checkvalidindex(L,o);
+if(idx==(-10001)){
+Closure*func=curr_func(L);
+luai_apicheck(L,ttistable(L->top-1));
+func->c.env=hvalue(L->top-1);
+luaC_barrier(L,func,L->top-1);
+}
+else{
+setobj(L,o,L->top-1);
+if(idx<(-10002))
+luaC_barrier(L,curr_func(L),L->top-1);
+}
+L->top--;
+}
+static void lua_pushvalue(lua_State*L,int idx){
+setobj(L,L->top,index2adr(L,idx));
+api_incr_top(L);
+}
+static int lua_type(lua_State*L,int idx){
+StkId o=index2adr(L,idx);
+return(o==(&luaO_nilobject_))?(-1):ttype(o);
+}
+static const char*lua_typename(lua_State*L,int t){
+UNUSED(L);
+return(t==(-1))?"no value":luaT_typenames[t];
+}
+static int lua_iscfunction(lua_State*L,int idx){
+StkId o=index2adr(L,idx);
+return iscfunction(o);
+}
+static int lua_isnumber(lua_State*L,int idx){
+TValue n;
+const TValue*o=index2adr(L,idx);
+return tonumber(o,&n);
+}
+static int lua_isstring(lua_State*L,int idx){
+int t=lua_type(L,idx);
+return(t==4||t==3);
+}
+static int lua_rawequal(lua_State*L,int index1,int index2){
+StkId o1=index2adr(L,index1);
+StkId o2=index2adr(L,index2);
+return(o1==(&luaO_nilobject_)||o2==(&luaO_nilobject_))?0
+:luaO_rawequalObj(o1,o2);
+}
+static int lua_lessthan(lua_State*L,int index1,int index2){
+StkId o1,o2;
+int i;
+o1=index2adr(L,index1);
+o2=index2adr(L,index2);
+i=(o1==(&luaO_nilobject_)||o2==(&luaO_nilobject_))?0
+:luaV_lessthan(L,o1,o2);
+return i;
+}
+static lua_Number lua_tonumber(lua_State*L,int idx){
+TValue n;
+const TValue*o=index2adr(L,idx);
+if(tonumber(o,&n))
+return nvalue(o);
+else
+return 0;
+}
+static lua_Integer lua_tointeger(lua_State*L,int idx){
+TValue n;
+const TValue*o=index2adr(L,idx);
+if(tonumber(o,&n)){
+lua_Integer res;
+lua_Number num=nvalue(o);
+lua_number2integer(res,num);
+return res;
+}
+else
+return 0;
+}
+static int lua_toboolean(lua_State*L,int idx){
+const TValue*o=index2adr(L,idx);
+return!l_isfalse(o);
+}
+static const char*lua_tolstring(lua_State*L,int idx,size_t*len){
+StkId o=index2adr(L,idx);
+if(!ttisstring(o)){
+if(!luaV_tostring(L,o)){
+if(len!=NULL)*len=0;
+return NULL;
+}
+luaC_checkGC(L);
+o=index2adr(L,idx);
+}
+if(len!=NULL)*len=tsvalue(o)->len;
+return svalue(o);
+}
+static size_t lua_objlen(lua_State*L,int idx){
+StkId o=index2adr(L,idx);
+switch(ttype(o)){
+case 4:return tsvalue(o)->len;
+case 7:return uvalue(o)->len;
+case 5:return luaH_getn(hvalue(o));
+case 3:{
+size_t l;
+l=(luaV_tostring(L,o)?tsvalue(o)->len:0);
+return l;
+}
+default:return 0;
+}
+}
+static lua_CFunction lua_tocfunction(lua_State*L,int idx){
+StkId o=index2adr(L,idx);
+return(!iscfunction(o))?NULL:clvalue(o)->c.f;
+}
+static void*lua_touserdata(lua_State*L,int idx){
+StkId o=index2adr(L,idx);
+switch(ttype(o)){
+case 7:return(rawuvalue(o)+1);
+case 2:return pvalue(o);
+default:return NULL;
+}
+}
+static void lua_pushnil(lua_State*L){
+setnilvalue(L->top);
+api_incr_top(L);
+}
+static void lua_pushnumber(lua_State*L,lua_Number n){
+setnvalue(L->top,n);
+api_incr_top(L);
+}
+static void lua_pushinteger(lua_State*L,lua_Integer n){
+setnvalue(L->top,cast_num(n));
+api_incr_top(L);
+}
+static void lua_pushlstring(lua_State*L,const char*s,size_t len){
+luaC_checkGC(L);
+setsvalue(L,L->top,luaS_newlstr(L,s,len));
+api_incr_top(L);
+}
+static void lua_pushstring(lua_State*L,const char*s){
+if(s==NULL)
+lua_pushnil(L);
+else
+lua_pushlstring(L,s,strlen(s));
+}
+static const char*lua_pushvfstring(lua_State*L,const char*fmt,
+va_list argp){
+const char*ret;
+luaC_checkGC(L);
+ret=luaO_pushvfstring(L,fmt,argp);
+return ret;
+}
+static const char*lua_pushfstring(lua_State*L,const char*fmt,...){
+const char*ret;
+va_list argp;
+luaC_checkGC(L);
+va_start(argp,fmt);
+ret=luaO_pushvfstring(L,fmt,argp);
+va_end(argp);
+return ret;
+}
+static void lua_pushcclosure(lua_State*L,lua_CFunction fn,int n){
+Closure*cl;
+luaC_checkGC(L);
+api_checknelems(L,n);
+cl=luaF_newCclosure(L,n,getcurrenv(L));
+cl->c.f=fn;
+L->top-=n;
+while(n--)
+setobj(L,&cl->c.upvalue[n],L->top+n);
+setclvalue(L,L->top,cl);
+api_incr_top(L);
+}
+static void lua_pushboolean(lua_State*L,int b){
+setbvalue(L->top,(b!=0));
+api_incr_top(L);
+}
+static int lua_pushthread(lua_State*L){
+setthvalue(L,L->top,L);
+api_incr_top(L);
+return(G(L)->mainthread==L);
+}
+static void lua_gettable(lua_State*L,int idx){
+StkId t;
+t=index2adr(L,idx);
+api_checkvalidindex(L,t);
+luaV_gettable(L,t,L->top-1,L->top-1);
+}
+static void lua_getfield(lua_State*L,int idx,const char*k){
+StkId t;
+TValue key;
+t=index2adr(L,idx);
+api_checkvalidindex(L,t);
+setsvalue(L,&key,luaS_new(L,k));
+luaV_gettable(L,t,&key,L->top);
+api_incr_top(L);
+}
+static void lua_rawget(lua_State*L,int idx){
+StkId t;
+t=index2adr(L,idx);
+luai_apicheck(L,ttistable(t));
+setobj(L,L->top-1,luaH_get(hvalue(t),L->top-1));
+}
+static void lua_rawgeti(lua_State*L,int idx,int n){
+StkId o;
+o=index2adr(L,idx);
+luai_apicheck(L,ttistable(o));
+setobj(L,L->top,luaH_getnum(hvalue(o),n));
+api_incr_top(L);
+}
+static void lua_createtable(lua_State*L,int narray,int nrec){
+luaC_checkGC(L);
+sethvalue(L,L->top,luaH_new(L,narray,nrec));
+api_incr_top(L);
+}
+static int lua_getmetatable(lua_State*L,int objindex){
+const TValue*obj;
+Table*mt=NULL;
+int res;
+obj=index2adr(L,objindex);
+switch(ttype(obj)){
+case 5:
+mt=hvalue(obj)->metatable;
+break;
+case 7:
+mt=uvalue(obj)->metatable;
+break;
+default:
+mt=G(L)->mt[ttype(obj)];
+break;
+}
+if(mt==NULL)
+res=0;
+else{
+sethvalue(L,L->top,mt);
+api_incr_top(L);
+res=1;
+}
+return res;
+}
+static void lua_getfenv(lua_State*L,int idx){
+StkId o;
+o=index2adr(L,idx);
+api_checkvalidindex(L,o);
+switch(ttype(o)){
+case 6:
+sethvalue(L,L->top,clvalue(o)->c.env);
+break;
+case 7:
+sethvalue(L,L->top,uvalue(o)->env);
+break;
+case 8:
+setobj(L,L->top,gt(thvalue(o)));
+break;
+default:
+setnilvalue(L->top);
+break;
+}
+api_incr_top(L);
+}
+static void lua_settable(lua_State*L,int idx){
+StkId t;
+api_checknelems(L,2);
+t=index2adr(L,idx);
+api_checkvalidindex(L,t);
+luaV_settable(L,t,L->top-2,L->top-1);
+L->top-=2;
+}
+static void lua_setfield(lua_State*L,int idx,const char*k){
+StkId t;
+TValue key;
+api_checknelems(L,1);
+t=index2adr(L,idx);
+api_checkvalidindex(L,t);
+setsvalue(L,&key,luaS_new(L,k));
+luaV_settable(L,t,&key,L->top-1);
+L->top--;
+}
+static void lua_rawset(lua_State*L,int idx){
+StkId t;
+api_checknelems(L,2);
+t=index2adr(L,idx);
+luai_apicheck(L,ttistable(t));
+setobj(L,luaH_set(L,hvalue(t),L->top-2),L->top-1);
+luaC_barriert(L,hvalue(t),L->top-1);
+L->top-=2;
+}
+static void lua_rawseti(lua_State*L,int idx,int n){
+StkId o;
+api_checknelems(L,1);
+o=index2adr(L,idx);
+luai_apicheck(L,ttistable(o));
+setobj(L,luaH_setnum(L,hvalue(o),n),L->top-1);
+luaC_barriert(L,hvalue(o),L->top-1);
+L->top--;
+}
+static int lua_setmetatable(lua_State*L,int objindex){
+TValue*obj;
+Table*mt;
+api_checknelems(L,1);
+obj=index2adr(L,objindex);
+api_checkvalidindex(L,obj);
+if(ttisnil(L->top-1))
+mt=NULL;
+else{
+luai_apicheck(L,ttistable(L->top-1));
+mt=hvalue(L->top-1);
+}
+switch(ttype(obj)){
+case 5:{
+hvalue(obj)->metatable=mt;
+if(mt)
+luaC_objbarriert(L,hvalue(obj),mt);
+break;
+}
+case 7:{
+uvalue(obj)->metatable=mt;
+if(mt)
+luaC_objbarrier(L,rawuvalue(obj),mt);
+break;
+}
+default:{
+G(L)->mt[ttype(obj)]=mt;
+break;
+}
+}
+L->top--;
+return 1;
+}
+static int lua_setfenv(lua_State*L,int idx){
+StkId o;
+int res=1;
+api_checknelems(L,1);
+o=index2adr(L,idx);
+api_checkvalidindex(L,o);
+luai_apicheck(L,ttistable(L->top-1));
+switch(ttype(o)){
+case 6:
+clvalue(o)->c.env=hvalue(L->top-1);
+break;
+case 7:
+uvalue(o)->env=hvalue(L->top-1);
+break;
+case 8:
+sethvalue(L,gt(thvalue(o)),hvalue(L->top-1));
+break;
+default:
+res=0;
+break;
+}
+if(res)luaC_objbarrier(L,gcvalue(o),hvalue(L->top-1));
+L->top--;
+return res;
+}
+#define adjustresults(L,nres){if(nres==(-1)&&L->top>=L->ci->top)L->ci->top=L->top;}
+#define checkresults(L,na,nr)luai_apicheck(L,(nr)==(-1)||(L->ci->top-L->top>=(nr)-(na)))
+static void lua_call(lua_State*L,int nargs,int nresults){
+StkId func;
+api_checknelems(L,nargs+1);
+checkresults(L,nargs,nresults);
+func=L->top-(nargs+1);
+luaD_call(L,func,nresults);
+adjustresults(L,nresults);
+}
+struct CallS{
+StkId func;
+int nresults;
+};
+static void f_call(lua_State*L,void*ud){
+struct CallS*c=cast(struct CallS*,ud);
+luaD_call(L,c->func,c->nresults);
+}
+static int lua_pcall(lua_State*L,int nargs,int nresults,int errfunc){
+struct CallS c;
+int status;
+ptrdiff_t func;
+api_checknelems(L,nargs+1);
+checkresults(L,nargs,nresults);
+if(errfunc==0)
+func=0;
+else{
+StkId o=index2adr(L,errfunc);
+api_checkvalidindex(L,o);
+func=savestack(L,o);
+}
+c.func=L->top-(nargs+1);
+c.nresults=nresults;
+status=luaD_pcall(L,f_call,&c,savestack(L,c.func),func);
+adjustresults(L,nresults);
+return status;
+}
+static int lua_load(lua_State*L,lua_Reader reader,void*data,
+const char*chunkname){
+ZIO z;
+int status;
+if(!chunkname)chunkname="?";
+luaZ_init(L,&z,reader,data);
+status=luaD_protectedparser(L,&z,chunkname);
+return status;
+}
+static int lua_error(lua_State*L){
+api_checknelems(L,1);
+luaG_errormsg(L);
+return 0;
+}
+static int lua_next(lua_State*L,int idx){
+StkId t;
+int more;
+t=index2adr(L,idx);
+luai_apicheck(L,ttistable(t));
+more=luaH_next(L,hvalue(t),L->top-1);
+if(more){
+api_incr_top(L);
+}
+else
+L->top-=1;
+return more;
+}
+static void lua_concat(lua_State*L,int n){
+api_checknelems(L,n);
+if(n>=2){
+luaC_checkGC(L);
+luaV_concat(L,n,cast_int(L->top-L->base)-1);
+L->top-=(n-1);
+}
+else if(n==0){
+setsvalue(L,L->top,luaS_newlstr(L,"",0));
+api_incr_top(L);
+}
+}
+static void*lua_newuserdata(lua_State*L,size_t size){
+Udata*u;
+luaC_checkGC(L);
+u=luaS_newudata(L,size,getcurrenv(L));
+setuvalue(L,L->top,u);
+api_incr_top(L);
+return u+1;
+}
+#define luaL_getn(L,i)((int)lua_objlen(L,i))
+#define luaL_setn(L,i,j)((void)0)
+typedef struct luaL_Reg{
+const char*name;
+lua_CFunction func;
+}luaL_Reg;
+static void luaI_openlib(lua_State*L,const char*libname,
+const luaL_Reg*l,int nup);
+static int luaL_argerror(lua_State*L,int numarg,const char*extramsg);
+static const char* luaL_checklstring(lua_State*L,int numArg,
+size_t*l);
+static const char* luaL_optlstring(lua_State*L,int numArg,
+const char*def,size_t*l);
+static lua_Integer luaL_checkinteger(lua_State*L,int numArg);
+static lua_Integer luaL_optinteger(lua_State*L,int nArg,
+lua_Integer def);
+static int luaL_error(lua_State*L,const char*fmt,...);
+static const char* luaL_findtable(lua_State*L,int idx,
+const char*fname,int szhint);
+#define luaL_argcheck(L,cond,numarg,extramsg)((void)((cond)||luaL_argerror(L,(numarg),(extramsg))))
+#define luaL_checkstring(L,n)(luaL_checklstring(L,(n),NULL))
+#define luaL_optstring(L,n,d)(luaL_optlstring(L,(n),(d),NULL))
+#define luaL_checkint(L,n)((int)luaL_checkinteger(L,(n)))
+#define luaL_optint(L,n,d)((int)luaL_optinteger(L,(n),(d)))
+#define luaL_typename(L,i)lua_typename(L,lua_type(L,(i)))
+#define luaL_getmetatable(L,n)(lua_getfield(L,(-10000),(n)))
+#define luaL_opt(L,f,n,d)(lua_isnoneornil(L,(n))?(d):f(L,(n)))
+typedef struct luaL_Buffer{
+char*p;
+int lvl;
+lua_State*L;
+char buffer[BUFSIZ];
+}luaL_Buffer;
+#define luaL_addchar(B,c)((void)((B)->p<((B)->buffer+BUFSIZ)||luaL_prepbuffer(B)),(*(B)->p++=(char)(c)))
+#define luaL_addsize(B,n)((B)->p+=(n))
+static char* luaL_prepbuffer(luaL_Buffer*B);
+static int luaL_argerror(lua_State*L,int narg,const char*extramsg){
+lua_Debug ar;
+if(!lua_getstack(L,0,&ar))
+return luaL_error(L,"bad argument #%d (%s)",narg,extramsg);
+lua_getinfo(L,"n",&ar);
+if(strcmp(ar.namewhat,"method")==0){
+narg--;
+if(narg==0)
+return luaL_error(L,"calling "LUA_QL("%s")" on bad self (%s)",
+ar.name,extramsg);
+}
+if(ar.name==NULL)
+ar.name="?";
+return luaL_error(L,"bad argument #%d to "LUA_QL("%s")" (%s)",
+narg,ar.name,extramsg);
+}
+static int luaL_typerror(lua_State*L,int narg,const char*tname){
+const char*msg=lua_pushfstring(L,"%s expected, got %s",
+tname,luaL_typename(L,narg));
+return luaL_argerror(L,narg,msg);
+}
+static void tag_error(lua_State*L,int narg,int tag){
+luaL_typerror(L,narg,lua_typename(L,tag));
+}
+static void luaL_where(lua_State*L,int level){
+lua_Debug ar;
+if(lua_getstack(L,level,&ar)){
+lua_getinfo(L,"Sl",&ar);
+if(ar.currentline>0){
+lua_pushfstring(L,"%s:%d: ",ar.short_src,ar.currentline);
+return;
+}
+}
+lua_pushliteral(L,"");
+}
+static int luaL_error(lua_State*L,const char*fmt,...){
+va_list argp;
+va_start(argp,fmt);
+luaL_where(L,1);
+lua_pushvfstring(L,fmt,argp);
+va_end(argp);
+lua_concat(L,2);
+return lua_error(L);
+}
+static int luaL_newmetatable(lua_State*L,const char*tname){
+lua_getfield(L,(-10000),tname);
+if(!lua_isnil(L,-1))
+return 0;
+lua_pop(L,1);
+lua_newtable(L);
+lua_pushvalue(L,-1);
+lua_setfield(L,(-10000),tname);
+return 1;
+}
+static void*luaL_checkudata(lua_State*L,int ud,const char*tname){
+void*p=lua_touserdata(L,ud);
+if(p!=NULL){
+if(lua_getmetatable(L,ud)){
+lua_getfield(L,(-10000),tname);
+if(lua_rawequal(L,-1,-2)){
+lua_pop(L,2);
+return p;
+}
+}
+}
+luaL_typerror(L,ud,tname);
+return NULL;
+}
+static void luaL_checkstack(lua_State*L,int space,const char*mes){
+if(!lua_checkstack(L,space))
+luaL_error(L,"stack overflow (%s)",mes);
+}
+static void luaL_checktype(lua_State*L,int narg,int t){
+if(lua_type(L,narg)!=t)
+tag_error(L,narg,t);
+}
+static void luaL_checkany(lua_State*L,int narg){
+if(lua_type(L,narg)==(-1))
+luaL_argerror(L,narg,"value expected");
+}
+static const char*luaL_checklstring(lua_State*L,int narg,size_t*len){
+const char*s=lua_tolstring(L,narg,len);
+if(!s)tag_error(L,narg,4);
+return s;
+}
+static const char*luaL_optlstring(lua_State*L,int narg,
+const char*def,size_t*len){
+if(lua_isnoneornil(L,narg)){
+if(len)
+*len=(def?strlen(def):0);
+return def;
+}
+else return luaL_checklstring(L,narg,len);
+}
+static lua_Number luaL_checknumber(lua_State*L,int narg){
+lua_Number d=lua_tonumber(L,narg);
+if(d==0&&!lua_isnumber(L,narg))
+tag_error(L,narg,3);
+return d;
+}
+static lua_Integer luaL_checkinteger(lua_State*L,int narg){
+lua_Integer d=lua_tointeger(L,narg);
+if(d==0&&!lua_isnumber(L,narg))
+tag_error(L,narg,3);
+return d;
+}
+static lua_Integer luaL_optinteger(lua_State*L,int narg,
+lua_Integer def){
+return luaL_opt(L,luaL_checkinteger,narg,def);
+}
+static int luaL_getmetafield(lua_State*L,int obj,const char*event){
+if(!lua_getmetatable(L,obj))
+return 0;
+lua_pushstring(L,event);
+lua_rawget(L,-2);
+if(lua_isnil(L,-1)){
+lua_pop(L,2);
+return 0;
+}
+else{
+lua_remove(L,-2);
+return 1;
+}
+}
+static void luaL_register(lua_State*L,const char*libname,
+const luaL_Reg*l){
+luaI_openlib(L,libname,l,0);
+}
+static int libsize(const luaL_Reg*l){
+int size=0;
+for(;l->name;l++)size++;
+return size;
+}
+static void luaI_openlib(lua_State*L,const char*libname,
+const luaL_Reg*l,int nup){
+if(libname){
+int size=libsize(l);
+luaL_findtable(L,(-10000),"_LOADED",1);
+lua_getfield(L,-1,libname);
+if(!lua_istable(L,-1)){
+lua_pop(L,1);
+if(luaL_findtable(L,(-10002),libname,size)!=NULL)
+luaL_error(L,"name conflict for module "LUA_QL("%s"),libname);
+lua_pushvalue(L,-1);
+lua_setfield(L,-3,libname);
+}
+lua_remove(L,-2);
+lua_insert(L,-(nup+1));
+}
+for(;l->name;l++){
+int i;
+for(i=0;ifunc,nup);
+lua_setfield(L,-(nup+2),l->name);
+}
+lua_pop(L,nup);
+}
+static const char*luaL_findtable(lua_State*L,int idx,
+const char*fname,int szhint){
+const char*e;
+lua_pushvalue(L,idx);
+do{
+e=strchr(fname,'.');
+if(e==NULL)e=fname+strlen(fname);
+lua_pushlstring(L,fname,e-fname);
+lua_rawget(L,-2);
+if(lua_isnil(L,-1)){
+lua_pop(L,1);
+lua_createtable(L,0,(*e=='.'?1:szhint));
+lua_pushlstring(L,fname,e-fname);
+lua_pushvalue(L,-2);
+lua_settable(L,-4);
+}
+else if(!lua_istable(L,-1)){
+lua_pop(L,2);
+return fname;
+}
+lua_remove(L,-2);
+fname=e+1;
+}while(*e=='.');
+return NULL;
+}
+#define bufflen(B)((B)->p-(B)->buffer)
+#define bufffree(B)((size_t)(BUFSIZ-bufflen(B)))
+static int emptybuffer(luaL_Buffer*B){
+size_t l=bufflen(B);
+if(l==0)return 0;
+else{
+lua_pushlstring(B->L,B->buffer,l);
+B->p=B->buffer;
+B->lvl++;
+return 1;
+}
+}
+static void adjuststack(luaL_Buffer*B){
+if(B->lvl>1){
+lua_State*L=B->L;
+int toget=1;
+size_t toplen=lua_strlen(L,-1);
+do{
+size_t l=lua_strlen(L,-(toget+1));
+if(B->lvl-toget+1>=(20/2)||toplen>l){
+toplen+=l;
+toget++;
+}
+else break;
+}while(togetlvl);
+lua_concat(L,toget);
+B->lvl=B->lvl-toget+1;
+}
+}
+static char*luaL_prepbuffer(luaL_Buffer*B){
+if(emptybuffer(B))
+adjuststack(B);
+return B->buffer;
+}
+static void luaL_addlstring(luaL_Buffer*B,const char*s,size_t l){
+while(l--)
+luaL_addchar(B,*s++);
+}
+static void luaL_pushresult(luaL_Buffer*B){
+emptybuffer(B);
+lua_concat(B->L,B->lvl);
+B->lvl=1;
+}
+static void luaL_addvalue(luaL_Buffer*B){
+lua_State*L=B->L;
+size_t vl;
+const char*s=lua_tolstring(L,-1,&vl);
+if(vl<=bufffree(B)){
+memcpy(B->p,s,vl);
+B->p+=vl;
+lua_pop(L,1);
+}
+else{
+if(emptybuffer(B))
+lua_insert(L,-2);
+B->lvl++;
+adjuststack(B);
+}
+}
+static void luaL_buffinit(lua_State*L,luaL_Buffer*B){
+B->L=L;
+B->p=B->buffer;
+B->lvl=0;
+}
+typedef struct LoadF{
+int extraline;
+FILE*f;
+char buff[BUFSIZ];
+}LoadF;
+static const char*getF(lua_State*L,void*ud,size_t*size){
+LoadF*lf=(LoadF*)ud;
+(void)L;
+if(lf->extraline){
+lf->extraline=0;
+*size=1;
+return"\n";
+}
+if(feof(lf->f))return NULL;
+*size=fread(lf->buff,1,sizeof(lf->buff),lf->f);
+return(*size>0)?lf->buff:NULL;
+}
+static int errfile(lua_State*L,const char*what,int fnameindex){
+const char*serr=strerror(errno);
+const char*filename=lua_tostring(L,fnameindex)+1;
+lua_pushfstring(L,"cannot %s %s: %s",what,filename,serr);
+lua_remove(L,fnameindex);
+return(5+1);
+}
+static int luaL_loadfile(lua_State*L,const char*filename){
+LoadF lf;
+int status,readstatus;
+int c;
+int fnameindex=lua_gettop(L)+1;
+lf.extraline=0;
+if(filename==NULL){
+lua_pushliteral(L,"=stdin");
+lf.f=stdin;
+}
+else{
+lua_pushfstring(L,"@%s",filename);
+lf.f=fopen(filename,"r");
+if(lf.f==NULL)return errfile(L,"open",fnameindex);
+}
+c=getc(lf.f);
+if(c=='#'){
+lf.extraline=1;
+while((c=getc(lf.f))!=EOF&&c!='\n');
+if(c=='\n')c=getc(lf.f);
+}
+if(c=="\033Lua"[0]&&filename){
+lf.f=freopen(filename,"rb",lf.f);
+if(lf.f==NULL)return errfile(L,"reopen",fnameindex);
+while((c=getc(lf.f))!=EOF&&c!="\033Lua"[0]);
+lf.extraline=0;
+}
+ungetc(c,lf.f);
+status=lua_load(L,getF,&lf,lua_tostring(L,-1));
+readstatus=ferror(lf.f);
+if(filename)fclose(lf.f);
+if(readstatus){
+lua_settop(L,fnameindex);
+return errfile(L,"read",fnameindex);
+}
+lua_remove(L,fnameindex);
+return status;
+}
+typedef struct LoadS{
+const char*s;
+size_t size;
+}LoadS;
+static const char*getS(lua_State*L,void*ud,size_t*size){
+LoadS*ls=(LoadS*)ud;
+(void)L;
+if(ls->size==0)return NULL;
+*size=ls->size;
+ls->size=0;
+return ls->s;
+}
+static int luaL_loadbuffer(lua_State*L,const char*buff,size_t size,
+const char*name){
+LoadS ls;
+ls.s=buff;
+ls.size=size;
+return lua_load(L,getS,&ls,name);
+}
+static void*l_alloc(void*ud,void*ptr,size_t osize,size_t nsize){
+(void)ud;
+(void)osize;
+if(nsize==0){
+free(ptr);
+return NULL;
+}
+else
+return realloc(ptr,nsize);
+}
+static int panic(lua_State*L){
+(void)L;
+fprintf(stderr,"PANIC: unprotected error in call to Lua API (%s)\n",
+lua_tostring(L,-1));
+return 0;
+}
+static lua_State*luaL_newstate(void){
+lua_State*L=lua_newstate(l_alloc,NULL);
+if(L)lua_atpanic(L,&panic);
+return L;
+}
+static int luaB_tonumber(lua_State*L){
+int base=luaL_optint(L,2,10);
+if(base==10){
+luaL_checkany(L,1);
+if(lua_isnumber(L,1)){
+lua_pushnumber(L,lua_tonumber(L,1));
+return 1;
+}
+}
+else{
+const char*s1=luaL_checkstring(L,1);
+char*s2;
+unsigned long n;
+luaL_argcheck(L,2<=base&&base<=36,2,"base out of range");
+n=strtoul(s1,&s2,base);
+if(s1!=s2){
+while(isspace((unsigned char)(*s2)))s2++;
+if(*s2=='\0'){
+lua_pushnumber(L,(lua_Number)n);
+return 1;
+}
+}
+}
+lua_pushnil(L);
+return 1;
+}
+static int luaB_error(lua_State*L){
+int level=luaL_optint(L,2,1);
+lua_settop(L,1);
+if(lua_isstring(L,1)&&level>0){
+luaL_where(L,level);
+lua_pushvalue(L,1);
+lua_concat(L,2);
+}
+return lua_error(L);
+}
+static int luaB_setmetatable(lua_State*L){
+int t=lua_type(L,2);
+luaL_checktype(L,1,5);
+luaL_argcheck(L,t==0||t==5,2,
+"nil or table expected");
+if(luaL_getmetafield(L,1,"__metatable"))
+luaL_error(L,"cannot change a protected metatable");
+lua_settop(L,2);
+lua_setmetatable(L,1);
+return 1;
+}
+static void getfunc(lua_State*L,int opt){
+if(lua_isfunction(L,1))lua_pushvalue(L,1);
+else{
+lua_Debug ar;
+int level=opt?luaL_optint(L,1,1):luaL_checkint(L,1);
+luaL_argcheck(L,level>=0,1,"level must be non-negative");
+if(lua_getstack(L,level,&ar)==0)
+luaL_argerror(L,1,"invalid level");
+lua_getinfo(L,"f",&ar);
+if(lua_isnil(L,-1))
+luaL_error(L,"no function environment for tail call at level %d",
+level);
+}
+}
+static int luaB_setfenv(lua_State*L){
+luaL_checktype(L,2,5);
+getfunc(L,0);
+lua_pushvalue(L,2);
+if(lua_isnumber(L,1)&&lua_tonumber(L,1)==0){
+lua_pushthread(L);
+lua_insert(L,-2);
+lua_setfenv(L,-2);
+return 0;
+}
+else if(lua_iscfunction(L,-2)||lua_setfenv(L,-2)==0)
+luaL_error(L,
+LUA_QL("setfenv")" cannot change environment of given object");
+return 1;
+}
+static int luaB_rawget(lua_State*L){
+luaL_checktype(L,1,5);
+luaL_checkany(L,2);
+lua_settop(L,2);
+lua_rawget(L,1);
+return 1;
+}
+static int luaB_type(lua_State*L){
+luaL_checkany(L,1);
+lua_pushstring(L,luaL_typename(L,1));
+return 1;
+}
+static int luaB_next(lua_State*L){
+luaL_checktype(L,1,5);
+lua_settop(L,2);
+if(lua_next(L,1))
+return 2;
+else{
+lua_pushnil(L);
+return 1;
+}
+}
+static int luaB_pairs(lua_State*L){
+luaL_checktype(L,1,5);
+lua_pushvalue(L,lua_upvalueindex(1));
+lua_pushvalue(L,1);
+lua_pushnil(L);
+return 3;
+}
+static int ipairsaux(lua_State*L){
+int i=luaL_checkint(L,2);
+luaL_checktype(L,1,5);
+i++;
+lua_pushinteger(L,i);
+lua_rawgeti(L,1,i);
+return(lua_isnil(L,-1))?0:2;
+}
+static int luaB_ipairs(lua_State*L){
+luaL_checktype(L,1,5);
+lua_pushvalue(L,lua_upvalueindex(1));
+lua_pushvalue(L,1);
+lua_pushinteger(L,0);
+return 3;
+}
+static int load_aux(lua_State*L,int status){
+if(status==0)
+return 1;
+else{
+lua_pushnil(L);
+lua_insert(L,-2);
+return 2;
+}
+}
+static int luaB_loadstring(lua_State*L){
+size_t l;
+const char*s=luaL_checklstring(L,1,&l);
+const char*chunkname=luaL_optstring(L,2,s);
+return load_aux(L,luaL_loadbuffer(L,s,l,chunkname));
+}
+static int luaB_loadfile(lua_State*L){
+const char*fname=luaL_optstring(L,1,NULL);
+return load_aux(L,luaL_loadfile(L,fname));
+}
+static int luaB_assert(lua_State*L){
+luaL_checkany(L,1);
+if(!lua_toboolean(L,1))
+return luaL_error(L,"%s",luaL_optstring(L,2,"assertion failed!"));
+return lua_gettop(L);
+}
+static int luaB_unpack(lua_State*L){
+int i,e,n;
+luaL_checktype(L,1,5);
+i=luaL_optint(L,2,1);
+e=luaL_opt(L,luaL_checkint,3,luaL_getn(L,1));
+if(i>e)return 0;
+n=e-i+1;
+if(n<=0||!lua_checkstack(L,n))
+return luaL_error(L,"too many results to unpack");
+lua_rawgeti(L,1,i);
+while(i++e)e=pos;
+for(i=e;i>pos;i--){
+lua_rawgeti(L,1,i-1);
+lua_rawseti(L,1,i);
+}
+break;
+}
+default:{
+return luaL_error(L,"wrong number of arguments to "LUA_QL("insert"));
+}
+}
+luaL_setn(L,1,e);
+lua_rawseti(L,1,pos);
+return 0;
+}
+static int tremove(lua_State*L){
+int e=aux_getn(L,1);
+int pos=luaL_optint(L,2,e);
+if(!(1<=pos&&pos<=e))
+return 0;
+luaL_setn(L,1,e-1);
+lua_rawgeti(L,1,pos);
+for(;posu)luaL_error(L,"invalid order function for sorting");
+lua_pop(L,1);
+}
+while(lua_rawgeti(L,1,--j),sort_comp(L,-3,-1)){
+if(j0);
+}
+l=strlen(p);
+if(l==0||p[l-1]!='\n')
+luaL_addsize(&b,l);
+else{
+luaL_addsize(&b,l-1);
+luaL_pushresult(&b);
+return 1;
+}
+}
+}
+static int read_chars(lua_State*L,FILE*f,size_t n){
+size_t rlen;
+size_t nr;
+luaL_Buffer b;
+luaL_buffinit(L,&b);
+rlen=BUFSIZ;
+do{
+char*p=luaL_prepbuffer(&b);
+if(rlen>n)rlen=n;
+nr=fread(p,sizeof(char),rlen,f);
+luaL_addsize(&b,nr);
+n-=nr;
+}while(n>0&&nr==rlen);
+luaL_pushresult(&b);
+return(n==0||lua_objlen(L,-1)>0);
+}
+static int g_read(lua_State*L,FILE*f,int first){
+int nargs=lua_gettop(L)-1;
+int success;
+int n;
+clearerr(f);
+if(nargs==0){
+success=read_line(L,f);
+n=first+1;
+}
+else{
+luaL_checkstack(L,nargs+20,"too many arguments");
+success=1;
+for(n=first;nargs--&&success;n++){
+if(lua_type(L,n)==3){
+size_t l=(size_t)lua_tointeger(L,n);
+success=(l==0)?test_eof(L,f):read_chars(L,f,l);
+}
+else{
+const char*p=lua_tostring(L,n);
+luaL_argcheck(L,p&&p[0]=='*',n,"invalid option");
+switch(p[1]){
+case'n':
+success=read_number(L,f);
+break;
+case'l':
+success=read_line(L,f);
+break;
+case'a':
+read_chars(L,f,~((size_t)0));
+success=1;
+break;
+default:
+return luaL_argerror(L,n,"invalid format");
+}
+}
+}
+}
+if(ferror(f))
+return pushresult(L,0,NULL);
+if(!success){
+lua_pop(L,1);
+lua_pushnil(L);
+}
+return n-first;
+}
+static int io_read(lua_State*L){
+return g_read(L,getiofile(L,1),1);
+}
+static int f_read(lua_State*L){
+return g_read(L,tofile(L),2);
+}
+static int io_readline(lua_State*L){
+FILE*f=*(FILE**)lua_touserdata(L,lua_upvalueindex(1));
+int sucess;
+if(f==NULL)
+luaL_error(L,"file is already closed");
+sucess=read_line(L,f);
+if(ferror(f))
+return luaL_error(L,"%s",strerror(errno));
+if(sucess)return 1;
+else{
+if(lua_toboolean(L,lua_upvalueindex(2))){
+lua_settop(L,0);
+lua_pushvalue(L,lua_upvalueindex(1));
+aux_close(L);
+}
+return 0;
+}
+}
+static int g_write(lua_State*L,FILE*f,int arg){
+int nargs=lua_gettop(L)-1;
+int status=1;
+for(;nargs--;arg++){
+if(lua_type(L,arg)==3){
+status=status&&
+fprintf(f,"%.14g",lua_tonumber(L,arg))>0;
+}
+else{
+size_t l;
+const char*s=luaL_checklstring(L,arg,&l);
+status=status&&(fwrite(s,sizeof(char),l,f)==l);
+}
+}
+return pushresult(L,status,NULL);
+}
+static int io_write(lua_State*L){
+return g_write(L,getiofile(L,2),1);
+}
+static int f_write(lua_State*L){
+return g_write(L,tofile(L),2);
+}
+static int io_flush(lua_State*L){
+return pushresult(L,fflush(getiofile(L,2))==0,NULL);
+}
+static int f_flush(lua_State*L){
+return pushresult(L,fflush(tofile(L))==0,NULL);
+}
+static const luaL_Reg iolib[]={
+{"close",io_close},
+{"flush",io_flush},
+{"input",io_input},
+{"lines",io_lines},
+{"open",io_open},
+{"output",io_output},
+{"read",io_read},
+{"type",io_type},
+{"write",io_write},
+{NULL,NULL}
+};
+static const luaL_Reg flib[]={
+{"close",io_close},
+{"flush",f_flush},
+{"lines",f_lines},
+{"read",f_read},
+{"write",f_write},
+{"__gc",io_gc},
+{NULL,NULL}
+};
+static void createmeta(lua_State*L){
+luaL_newmetatable(L,"FILE*");
+lua_pushvalue(L,-1);
+lua_setfield(L,-2,"__index");
+luaL_register(L,NULL,flib);
+}
+static void createstdfile(lua_State*L,FILE*f,int k,const char*fname){
+*newfile(L)=f;
+if(k>0){
+lua_pushvalue(L,-1);
+lua_rawseti(L,(-10001),k);
+}
+lua_pushvalue(L,-2);
+lua_setfenv(L,-2);
+lua_setfield(L,-3,fname);
+}
+static void newfenv(lua_State*L,lua_CFunction cls){
+lua_createtable(L,0,1);
+lua_pushcfunction(L,cls);
+lua_setfield(L,-2,"__close");
+}
+static int luaopen_io(lua_State*L){
+createmeta(L);
+newfenv(L,io_fclose);
+lua_replace(L,(-10001));
+luaL_register(L,"io",iolib);
+newfenv(L,io_noclose);
+createstdfile(L,stdin,1,"stdin");
+createstdfile(L,stdout,2,"stdout");
+createstdfile(L,stderr,0,"stderr");
+lua_pop(L,1);
+lua_getfield(L,-1,"popen");
+newfenv(L,io_pclose);
+lua_setfenv(L,-2);
+lua_pop(L,1);
+return 1;
+}
+static int os_pushresult(lua_State*L,int i,const char*filename){
+int en=errno;
+if(i){
+lua_pushboolean(L,1);
+return 1;
+}
+else{
+lua_pushnil(L);
+lua_pushfstring(L,"%s: %s",filename,strerror(en));
+lua_pushinteger(L,en);
+return 3;
+}
+}
+static int os_remove(lua_State*L){
+const char*filename=luaL_checkstring(L,1);
+return os_pushresult(L,remove(filename)==0,filename);
+}
+static int os_exit(lua_State*L){
+exit(luaL_optint(L,1,EXIT_SUCCESS));
+}
+static const luaL_Reg syslib[]={
+{"exit",os_exit},
+{"remove",os_remove},
+{NULL,NULL}
+};
+static int luaopen_os(lua_State*L){
+luaL_register(L,"os",syslib);
+return 1;
+}
+#define uchar(c)((unsigned char)(c))
+static ptrdiff_t posrelat(ptrdiff_t pos,size_t len){
+if(pos<0)pos+=(ptrdiff_t)len+1;
+return(pos>=0)?pos:0;
+}
+static int str_sub(lua_State*L){
+size_t l;
+const char*s=luaL_checklstring(L,1,&l);
+ptrdiff_t start=posrelat(luaL_checkinteger(L,2),l);
+ptrdiff_t end=posrelat(luaL_optinteger(L,3,-1),l);
+if(start<1)start=1;
+if(end>(ptrdiff_t)l)end=(ptrdiff_t)l;
+if(start<=end)
+lua_pushlstring(L,s+start-1,end-start+1);
+else lua_pushliteral(L,"");
+return 1;
+}
+static int str_lower(lua_State*L){
+size_t l;
+size_t i;
+luaL_Buffer b;
+const char*s=luaL_checklstring(L,1,&l);
+luaL_buffinit(L,&b);
+for(i=0;i0)
+luaL_addlstring(&b,s,l);
+luaL_pushresult(&b);
+return 1;
+}
+static int str_byte(lua_State*L){
+size_t l;
+const char*s=luaL_checklstring(L,1,&l);
+ptrdiff_t posi=posrelat(luaL_optinteger(L,2,1),l);
+ptrdiff_t pose=posrelat(luaL_optinteger(L,3,posi),l);
+int n,i;
+if(posi<=0)posi=1;
+if((size_t)pose>l)pose=l;
+if(posi>pose)return 0;
+n=(int)(pose-posi+1);
+if(posi+n<=pose)
+luaL_error(L,"string slice too long");
+luaL_checkstack(L,n,"string slice too long");
+for(i=0;i=ms->level||ms->capture[l].len==(-1))
+return luaL_error(ms->L,"invalid capture index");
+return l;
+}
+static int capture_to_close(MatchState*ms){
+int level=ms->level;
+for(level--;level>=0;level--)
+if(ms->capture[level].len==(-1))return level;
+return luaL_error(ms->L,"invalid pattern capture");
+}
+static const char*classend(MatchState*ms,const char*p){
+switch(*p++){
+case'%':{
+if(*p=='\0')
+luaL_error(ms->L,"malformed pattern (ends with "LUA_QL("%%")")");
+return p+1;
+}
+case'[':{
+if(*p=='^')p++;
+do{
+if(*p=='\0')
+luaL_error(ms->L,"malformed pattern (missing "LUA_QL("]")")");
+if(*(p++)=='%'&&*p!='\0')
+p++;
+}while(*p!=']');
+return p+1;
+}
+default:{
+return p;
+}
+}
+}
+static int match_class(int c,int cl){
+int res;
+switch(tolower(cl)){
+case'a':res=isalpha(c);break;
+case'c':res=iscntrl(c);break;
+case'd':res=isdigit(c);break;
+case'l':res=islower(c);break;
+case'p':res=ispunct(c);break;
+case's':res=isspace(c);break;
+case'u':res=isupper(c);break;
+case'w':res=isalnum(c);break;
+case'x':res=isxdigit(c);break;
+case'z':res=(c==0);break;
+default:return(cl==c);
+}
+return(islower(cl)?res:!res);
+}
+static int matchbracketclass(int c,const char*p,const char*ec){
+int sig=1;
+if(*(p+1)=='^'){
+sig=0;
+p++;
+}
+while(++pL,"unbalanced pattern");
+if(*s!=*p)return NULL;
+else{
+int b=*p;
+int e=*(p+1);
+int cont=1;
+while(++ssrc_end){
+if(*s==e){
+if(--cont==0)return s+1;
+}
+else if(*s==b)cont++;
+}
+}
+return NULL;
+}
+static const char*max_expand(MatchState*ms,const char*s,
+const char*p,const char*ep){
+ptrdiff_t i=0;
+while((s+i)src_end&&singlematch(uchar(*(s+i)),p,ep))
+i++;
+while(i>=0){
+const char*res=match(ms,(s+i),ep+1);
+if(res)return res;
+i--;
+}
+return NULL;
+}
+static const char*min_expand(MatchState*ms,const char*s,
+const char*p,const char*ep){
+for(;;){
+const char*res=match(ms,s,ep+1);
+if(res!=NULL)
+return res;
+else if(ssrc_end&&singlematch(uchar(*s),p,ep))
+s++;
+else return NULL;
+}
+}
+static const char*start_capture(MatchState*ms,const char*s,
+const char*p,int what){
+const char*res;
+int level=ms->level;
+if(level>=32)luaL_error(ms->L,"too many captures");
+ms->capture[level].init=s;
+ms->capture[level].len=what;
+ms->level=level+1;
+if((res=match(ms,s,p))==NULL)
+ms->level--;
+return res;
+}
+static const char*end_capture(MatchState*ms,const char*s,
+const char*p){
+int l=capture_to_close(ms);
+const char*res;
+ms->capture[l].len=s-ms->capture[l].init;
+if((res=match(ms,s,p))==NULL)
+ms->capture[l].len=(-1);
+return res;
+}
+static const char*match_capture(MatchState*ms,const char*s,int l){
+size_t len;
+l=check_capture(ms,l);
+len=ms->capture[l].len;
+if((size_t)(ms->src_end-s)>=len&&
+memcmp(ms->capture[l].init,s,len)==0)
+return s+len;
+else return NULL;
+}
+static const char*match(MatchState*ms,const char*s,const char*p){
+init:
+switch(*p){
+case'(':{
+if(*(p+1)==')')
+return start_capture(ms,s,p+2,(-2));
+else
+return start_capture(ms,s,p+1,(-1));
+}
+case')':{
+return end_capture(ms,s,p+1);
+}
+case'%':{
+switch(*(p+1)){
+case'b':{
+s=matchbalance(ms,s,p+2);
+if(s==NULL)return NULL;
+p+=4;goto init;
+}
+case'f':{
+const char*ep;char previous;
+p+=2;
+if(*p!='[')
+luaL_error(ms->L,"missing "LUA_QL("[")" after "
+LUA_QL("%%f")" in pattern");
+ep=classend(ms,p);
+previous=(s==ms->src_init)?'\0':*(s-1);
+if(matchbracketclass(uchar(previous),p,ep-1)||
+!matchbracketclass(uchar(*s),p,ep-1))return NULL;
+p=ep;goto init;
+}
+default:{
+if(isdigit(uchar(*(p+1)))){
+s=match_capture(ms,s,uchar(*(p+1)));
+if(s==NULL)return NULL;
+p+=2;goto init;
+}
+goto dflt;
+}
+}
+}
+case'\0':{
+return s;
+}
+case'$':{
+if(*(p+1)=='\0')
+return(s==ms->src_end)?s:NULL;
+else goto dflt;
+}
+default:dflt:{
+const char*ep=classend(ms,p);
+int m=ssrc_end&&singlematch(uchar(*s),p,ep);
+switch(*ep){
+case'?':{
+const char*res;
+if(m&&((res=match(ms,s+1,ep+1))!=NULL))
+return res;
+p=ep+1;goto init;
+}
+case'*':{
+return max_expand(ms,s,p,ep);
+}
+case'+':{
+return(m?max_expand(ms,s+1,p,ep):NULL);
+}
+case'-':{
+return min_expand(ms,s,p,ep);
+}
+default:{
+if(!m)return NULL;
+s++;p=ep;goto init;
+}
+}
+}
+}
+}
+static const char*lmemfind(const char*s1,size_t l1,
+const char*s2,size_t l2){
+if(l2==0)return s1;
+else if(l2>l1)return NULL;
+else{
+const char*init;
+l2--;
+l1=l1-l2;
+while(l1>0&&(init=(const char*)memchr(s1,*s2,l1))!=NULL){
+init++;
+if(memcmp(init,s2+1,l2)==0)
+return init-1;
+else{
+l1-=init-s1;
+s1=init;
+}
+}
+return NULL;
+}
+}
+static void push_onecapture(MatchState*ms,int i,const char*s,
+const char*e){
+if(i>=ms->level){
+if(i==0)
+lua_pushlstring(ms->L,s,e-s);
+else
+luaL_error(ms->L,"invalid capture index");
+}
+else{
+ptrdiff_t l=ms->capture[i].len;
+if(l==(-1))luaL_error(ms->L,"unfinished capture");
+if(l==(-2))
+lua_pushinteger(ms->L,ms->capture[i].init-ms->src_init+1);
+else
+lua_pushlstring(ms->L,ms->capture[i].init,l);
+}
+}
+static int push_captures(MatchState*ms,const char*s,const char*e){
+int i;
+int nlevels=(ms->level==0&&s)?1:ms->level;
+luaL_checkstack(ms->L,nlevels,"too many captures");
+for(i=0;il1)init=(ptrdiff_t)l1;
+if(find&&(lua_toboolean(L,4)||
+strpbrk(p,"^$*+?.([%-")==NULL)){
+const char*s2=lmemfind(s+init,l1-init,p,l2);
+if(s2){
+lua_pushinteger(L,s2-s+1);
+lua_pushinteger(L,s2-s+l2);
+return 2;
+}
+}
+else{
+MatchState ms;
+int anchor=(*p=='^')?(p++,1):0;
+const char*s1=s+init;
+ms.L=L;
+ms.src_init=s;
+ms.src_end=s+l1;
+do{
+const char*res;
+ms.level=0;
+if((res=match(&ms,s1,p))!=NULL){
+if(find){
+lua_pushinteger(L,s1-s+1);
+lua_pushinteger(L,res-s);
+return push_captures(&ms,NULL,0)+2;
+}
+else
+return push_captures(&ms,s1,res);
+}
+}while(s1++L,3,&l);
+for(i=0;iL;
+switch(lua_type(L,3)){
+case 3:
+case 4:{
+add_s(ms,b,s,e);
+return;
+}
+case 6:{
+int n;
+lua_pushvalue(L,3);
+n=push_captures(ms,s,e);
+lua_call(L,n,1);
+break;
+}
+case 5:{
+push_onecapture(ms,0,s,e);
+lua_gettable(L,3);
+break;
+}
+}
+if(!lua_toboolean(L,-1)){
+lua_pop(L,1);
+lua_pushlstring(L,s,e-s);
+}
+else if(!lua_isstring(L,-1))
+luaL_error(L,"invalid replacement value (a %s)",luaL_typename(L,-1));
+luaL_addvalue(b);
+}
+static int str_gsub(lua_State*L){
+size_t srcl;
+const char*src=luaL_checklstring(L,1,&srcl);
+const char*p=luaL_checkstring(L,2);
+int tr=lua_type(L,3);
+int max_s=luaL_optint(L,4,srcl+1);
+int anchor=(*p=='^')?(p++,1):0;
+int n=0;
+MatchState ms;
+luaL_Buffer b;
+luaL_argcheck(L,tr==3||tr==4||
+tr==6||tr==5,3,
+"string/function/table expected");
+luaL_buffinit(L,&b);
+ms.L=L;
+ms.src_init=src;
+ms.src_end=src+srcl;
+while(nsrc)
+src=e;
+else if(src=sizeof("-+ #0"))
+luaL_error(L,"invalid format (repeated flags)");
+if(isdigit(uchar(*p)))p++;
+if(isdigit(uchar(*p)))p++;
+if(*p=='.'){
+p++;
+if(isdigit(uchar(*p)))p++;
+if(isdigit(uchar(*p)))p++;
+}
+if(isdigit(uchar(*p)))
+luaL_error(L,"invalid format (width or precision too long)");
+*(form++)='%';
+strncpy(form,strfrmt,p-strfrmt+1);
+form+=p-strfrmt+1;
+*form='\0';
+return p;
+}
+static void addintlen(char*form){
+size_t l=strlen(form);
+char spec=form[l-1];
+strcpy(form+l-1,"l");
+form[l+sizeof("l")-2]=spec;
+form[l+sizeof("l")-1]='\0';
+}
+static int str_format(lua_State*L){
+int top=lua_gettop(L);
+int arg=1;
+size_t sfl;
+const char*strfrmt=luaL_checklstring(L,arg,&sfl);
+const char*strfrmt_end=strfrmt+sfl;
+luaL_Buffer b;
+luaL_buffinit(L,&b);
+while(strfrmttop)
+luaL_argerror(L,arg,"no value");
+strfrmt=scanformat(L,strfrmt,form);
+switch(*strfrmt++){
+case'c':{
+sprintf(buff,form,(int)luaL_checknumber(L,arg));
+break;
+}
+case'd':case'i':{
+addintlen(form);
+sprintf(buff,form,(long)luaL_checknumber(L,arg));
+break;
+}
+case'o':case'u':case'x':case'X':{
+addintlen(form);
+sprintf(buff,form,(unsigned long)luaL_checknumber(L,arg));
+break;
+}
+case'e':case'E':case'f':
+case'g':case'G':{
+sprintf(buff,form,(double)luaL_checknumber(L,arg));
+break;
+}
+case'q':{
+addquoted(L,&b,arg);
+continue;
+}
+case's':{
+size_t l;
+const char*s=luaL_checklstring(L,arg,&l);
+if(!strchr(form,'.')&&l>=100){
+lua_pushvalue(L,arg);
+luaL_addvalue(&b);
+continue;
+}
+else{
+sprintf(buff,form,s);
+break;
+}
+}
+default:{
+return luaL_error(L,"invalid option "LUA_QL("%%%c")" to "
+LUA_QL("format"),*(strfrmt-1));
+}
+}
+luaL_addlstring(&b,buff,strlen(buff));
+}
+}
+luaL_pushresult(&b);
+return 1;
+}
+static const luaL_Reg strlib[]={
+{"byte",str_byte},
+{"char",str_char},
+{"find",str_find},
+{"format",str_format},
+{"gmatch",gmatch},
+{"gsub",str_gsub},
+{"lower",str_lower},
+{"match",str_match},
+{"rep",str_rep},
+{"sub",str_sub},
+{"upper",str_upper},
+{NULL,NULL}
+};
+static void createmetatable(lua_State*L){
+lua_createtable(L,0,1);
+lua_pushliteral(L,"");
+lua_pushvalue(L,-2);
+lua_setmetatable(L,-2);
+lua_pop(L,1);
+lua_pushvalue(L,-2);
+lua_setfield(L,-2,"__index");
+lua_pop(L,1);
+}
+static int luaopen_string(lua_State*L){
+luaL_register(L,"string",strlib);
+createmetatable(L);
+return 1;
+}
+static const luaL_Reg lualibs[]={
+{"",luaopen_base},
+{"table",luaopen_table},
+{"io",luaopen_io},
+{"os",luaopen_os},
+{"string",luaopen_string},
+{NULL,NULL}
+};
+static void luaL_openlibs(lua_State*L){
+const luaL_Reg*lib=lualibs;
+for(;lib->func;lib++){
+lua_pushcfunction(L,lib->func);
+lua_pushstring(L,lib->name);
+lua_call(L,1,0);
+}
+}
+typedef unsigned int UB;
+static UB barg(lua_State*L,int idx){
+union{lua_Number n;U64 b;}bn;
+bn.n=lua_tonumber(L,idx)+6755399441055744.0;
+if(bn.n==0.0&&!lua_isnumber(L,idx))luaL_typerror(L,idx,"number");
+return(UB)bn.b;
+}
+#define BRET(b)lua_pushnumber(L,(lua_Number)(int)(b));return 1;
+static int tobit(lua_State*L){
+BRET(barg(L,1))}
+static int bnot(lua_State*L){
+BRET(~barg(L,1))}
+static int band(lua_State*L){
+int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b&=barg(L,i);BRET(b)}
+static int bor(lua_State*L){
+int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b|=barg(L,i);BRET(b)}
+static int bxor(lua_State*L){
+int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b^=barg(L,i);BRET(b)}
+static int lshift(lua_State*L){
+UB b=barg(L,1),n=barg(L,2)&31;BRET(b<>n)}
+static int arshift(lua_State*L){
+UB b=barg(L,1),n=barg(L,2)&31;BRET((int)b>>n)}
+static int rol(lua_State*L){
+UB b=barg(L,1),n=barg(L,2)&31;BRET((b<>(32-n)))}
+static int ror(lua_State*L){
+UB b=barg(L,1),n=barg(L,2)&31;BRET((b>>n)|(b<<(32-n)))}
+static int bswap(lua_State*L){
+UB b=barg(L,1);b=(b>>24)|((b>>8)&0xff00)|((b&0xff00)<<8)|(b<<24);BRET(b)}
+static int tohex(lua_State*L){
+UB b=barg(L,1);
+int n=lua_isnone(L,2)?8:(int)barg(L,2);
+const char*hexdigits="0123456789abcdef";
+char buf[8];
+int i;
+if(n<0){n=-n;hexdigits="0123456789ABCDEF";}
+if(n>8)n=8;
+for(i=(int)n;--i>=0;){buf[i]=hexdigits[b&15];b>>=4;}
+lua_pushlstring(L,buf,(size_t)n);
+return 1;
+}
+static const struct luaL_Reg bitlib[]={
+{"tobit",tobit},
+{"bnot",bnot},
+{"band",band},
+{"bor",bor},
+{"bxor",bxor},
+{"lshift",lshift},
+{"rshift",rshift},
+{"arshift",arshift},
+{"rol",rol},
+{"ror",ror},
+{"bswap",bswap},
+{"tohex",tohex},
+{NULL,NULL}
+};
+int main(int argc,char**argv){
+lua_State*L=luaL_newstate();
+int i;
+luaL_openlibs(L);
+luaL_register(L,"bit",bitlib);
+if(argc<2)return sizeof(void*);
+lua_createtable(L,0,1);
+lua_pushstring(L,argv[1]);
+lua_rawseti(L,-2,0);
+lua_setglobal(L,"arg");
+if(luaL_loadfile(L,argv[1]))
+goto err;
+for(i=2;i -- BYTECODE -- [...]
+-- print(bc.line(foo, 2)) --> 0002 KSTR 1 1 ; "hello"
+--
+-- local out = {
+-- -- Do something with each line:
+-- write = function(t, ...) io.write(...) end,
+-- close = function(t) end,
+-- flush = function(t) end,
+-- }
+-- bc.dump(foo, out)
+--
+------------------------------------------------------------------------------
+
+-- Cache some library functions and objects.
+local jit = require("jit")
+assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
+local jutil = require("jit.util")
+local vmdef = require("jit.vmdef")
+local bit = require("bit")
+local sub, gsub, format = string.sub, string.gsub, string.format
+local byte, band, shr = string.byte, bit.band, bit.rshift
+local funcinfo, funcbc, funck = jutil.funcinfo, jutil.funcbc, jutil.funck
+local funcuvname = jutil.funcuvname
+local bcnames = vmdef.bcnames
+local stdout, stderr = io.stdout, io.stderr
+
+------------------------------------------------------------------------------
+
+local function ctlsub(c)
+ if c == "\n" then return "\\n"
+ elseif c == "\r" then return "\\r"
+ elseif c == "\t" then return "\\t"
+ else return format("\\%03d", byte(c))
+ end
+end
+
+-- Return one bytecode line.
+local function bcline(func, pc, prefix)
+ local ins, m = funcbc(func, pc)
+ if not ins then return end
+ local ma, mb, mc = band(m, 7), band(m, 15*8), band(m, 15*128)
+ local a = band(shr(ins, 8), 0xff)
+ local oidx = 6*band(ins, 0xff)
+ local op = sub(bcnames, oidx+1, oidx+6)
+ local s = format("%04d %s %-6s %3s ",
+ pc, prefix or " ", op, ma == 0 and "" or a)
+ local d = shr(ins, 16)
+ if mc == 13*128 then -- BCMjump
+ return format("%s=> %04d\n", s, pc+d-0x7fff)
+ end
+ if mb ~= 0 then
+ d = band(d, 0xff)
+ elseif mc == 0 then
+ return s.."\n"
+ end
+ local kc
+ if mc == 10*128 then -- BCMstr
+ kc = funck(func, -d-1)
+ kc = format(#kc > 40 and '"%.40s"~' or '"%s"', gsub(kc, "%c", ctlsub))
+ elseif mc == 9*128 then -- BCMnum
+ kc = funck(func, d)
+ if op == "TSETM " then kc = kc - 2^52 end
+ elseif mc == 12*128 then -- BCMfunc
+ local fi = funcinfo(funck(func, -d-1))
+ if fi.ffid then
+ kc = vmdef.ffnames[fi.ffid]
+ else
+ kc = fi.loc
+ end
+ elseif mc == 5*128 then -- BCMuv
+ kc = funcuvname(func, d)
+ end
+ if ma == 5 then -- BCMuv
+ local ka = funcuvname(func, a)
+ if kc then kc = ka.." ; "..kc else kc = ka end
+ end
+ if mb ~= 0 then
+ local b = shr(ins, 24)
+ if kc then return format("%s%3d %3d ; %s\n", s, b, d, kc) end
+ return format("%s%3d %3d\n", s, b, d)
+ end
+ if kc then return format("%s%3d ; %s\n", s, d, kc) end
+ if mc == 7*128 and d > 32767 then d = d - 65536 end -- BCMlits
+ return format("%s%3d\n", s, d)
+end
+
+-- Collect branch targets of a function.
+local function bctargets(func)
+ local target = {}
+ for pc=1,1000000000 do
+ local ins, m = funcbc(func, pc)
+ if not ins then break end
+ if band(m, 15*128) == 13*128 then target[pc+shr(ins, 16)-0x7fff] = true end
+ end
+ return target
+end
+
+-- Dump bytecode instructions of a function.
+local function bcdump(func, out, all)
+ if not out then out = stdout end
+ local fi = funcinfo(func)
+ if all and fi.children then
+ for n=-1,-1000000000,-1 do
+ local k = funck(func, n)
+ if not k then break end
+ if type(k) == "proto" then bcdump(k, out, true) end
+ end
+ end
+ out:write(format("-- BYTECODE -- %s-%d\n", fi.loc, fi.lastlinedefined))
+ local target = bctargets(func)
+ for pc=1,1000000000 do
+ local s = bcline(func, pc, target[pc] and "=>")
+ if not s then break end
+ out:write(s)
+ end
+ out:write("\n")
+ out:flush()
+end
+
+------------------------------------------------------------------------------
+
+-- Active flag and output file handle.
+local active, out
+
+-- List handler.
+local function h_list(func)
+ return bcdump(func, out)
+end
+
+-- Detach list handler.
+local function bclistoff()
+ if active then
+ active = false
+ jit.attach(h_list)
+ if out and out ~= stdout and out ~= stderr then out:close() end
+ out = nil
+ end
+end
+
+-- Open the output file and attach list handler.
+local function bcliston(outfile)
+ if active then bclistoff() end
+ if not outfile then outfile = os.getenv("LUAJIT_LISTFILE") end
+ if outfile then
+ out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
+ else
+ out = stderr
+ end
+ jit.attach(h_list, "bc")
+ active = true
+end
+
+-- Public module functions.
+return {
+ line = bcline,
+ dump = bcdump,
+ targets = bctargets,
+ on = bcliston,
+ off = bclistoff,
+ start = bcliston -- For -j command line option.
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/jit/bcsave.lua b/src/host/luajit-2.1.0-beta3/src/jit/bcsave.lua
new file mode 100644
index 00000000..c17c88e0
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/jit/bcsave.lua
@@ -0,0 +1,661 @@
+----------------------------------------------------------------------------
+-- LuaJIT module to save/list bytecode.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module saves or lists the bytecode for an input file.
+-- It's run by the -b command line option.
+--
+------------------------------------------------------------------------------
+
+local jit = require("jit")
+assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
+local bit = require("bit")
+
+-- Symbol name prefix for LuaJIT bytecode.
+local LJBC_PREFIX = "luaJIT_BC_"
+
+------------------------------------------------------------------------------
+
+local function usage()
+ io.stderr:write[[
+Save LuaJIT bytecode: luajit -b[options] input output
+ -l Only list bytecode.
+ -s Strip debug info (default).
+ -g Keep debug info.
+ -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).
+ -o os Override OS for object files (default: native).
+ -e chunk Use chunk string as input.
+ -- Stop handling options.
+ - Use stdin as input and/or stdout as output.
+
+File types: c h obj o raw (default)
+]]
+ os.exit(1)
+end
+
+local function check(ok, ...)
+ if ok then return ok, ... end
+ io.stderr:write("luajit: ", ...)
+ io.stderr:write("\n")
+ os.exit(1)
+end
+
+local function readfile(input)
+ if type(input) == "function" then return input end
+ if input == "-" then input = nil end
+ return check(loadfile(input))
+end
+
+local function savefile(name, mode)
+ if name == "-" then return io.stdout end
+ return check(io.open(name, mode))
+end
+
+------------------------------------------------------------------------------
+
+local map_type = {
+ raw = "raw", c = "c", h = "h", o = "obj", obj = "obj",
+}
+
+local map_arch = {
+ x86 = true, x64 = true, arm = true, arm64 = true, arm64be = true,
+ ppc = true, mips = true, mipsel = true,
+}
+
+local map_os = {
+ linux = true, windows = true, osx = true, freebsd = true, netbsd = true,
+ openbsd = true, dragonfly = true, solaris = true,
+}
+
+local function checkarg(str, map, err)
+ str = string.lower(str)
+ local s = check(map[str], "unknown ", err)
+ return s == true and str or s
+end
+
+local function detecttype(str)
+ local ext = string.match(string.lower(str), "%.(%a+)$")
+ return map_type[ext] or "raw"
+end
+
+local function checkmodname(str)
+ check(string.match(str, "^[%w_.%-]+$"), "bad module name")
+ return string.gsub(str, "[%.%-]", "_")
+end
+
+local function detectmodname(str)
+ if type(str) == "string" then
+ local tail = string.match(str, "[^/\\]+$")
+ if tail then str = tail end
+ local head = string.match(str, "^(.*)%.[^.]*$")
+ if head then str = head end
+ str = string.match(str, "^[%w_.%-]+")
+ else
+ str = nil
+ end
+ check(str, "cannot derive module name, use -n name")
+ return string.gsub(str, "[%.%-]", "_")
+end
+
+------------------------------------------------------------------------------
+
+local function bcsave_tail(fp, output, s)
+ local ok, err = fp:write(s)
+ if ok and output ~= "-" then ok, err = fp:close() end
+ check(ok, "cannot write ", output, ": ", err)
+end
+
+local function bcsave_raw(output, s)
+ local fp = savefile(output, "wb")
+ bcsave_tail(fp, output, s)
+end
+
+local function bcsave_c(ctx, output, s)
+ local fp = savefile(output, "w")
+ if ctx.type == "c" then
+ fp:write(string.format([[
+#ifdef _cplusplus
+extern "C"
+#endif
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+const unsigned char %s%s[] = {
+]], LJBC_PREFIX, ctx.modname))
+ else
+ fp:write(string.format([[
+#define %s%s_SIZE %d
+static const unsigned char %s%s[] = {
+]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname))
+ end
+ local t, n, m = {}, 0, 0
+ for i=1,#s do
+ local b = tostring(string.byte(s, i))
+ m = m + #b + 1
+ if m > 78 then
+ fp:write(table.concat(t, ",", 1, n), ",\n")
+ n, m = 0, #b + 1
+ end
+ n = n + 1
+ t[n] = b
+ end
+ bcsave_tail(fp, output, table.concat(t, ",", 1, n).."\n};\n")
+end
+
+local function bcsave_elfobj(ctx, output, s, ffi)
+ ffi.cdef[[
+typedef struct {
+ uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
+ uint16_t type, machine;
+ uint32_t version;
+ uint32_t entry, phofs, shofs;
+ uint32_t flags;
+ uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
+} ELF32header;
+typedef struct {
+ uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
+ uint16_t type, machine;
+ uint32_t version;
+ uint64_t entry, phofs, shofs;
+ uint32_t flags;
+ uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
+} ELF64header;
+typedef struct {
+ uint32_t name, type, flags, addr, ofs, size, link, info, align, entsize;
+} ELF32sectheader;
+typedef struct {
+ uint32_t name, type;
+ uint64_t flags, addr, ofs, size;
+ uint32_t link, info;
+ uint64_t align, entsize;
+} ELF64sectheader;
+typedef struct {
+ uint32_t name, value, size;
+ uint8_t info, other;
+ uint16_t sectidx;
+} ELF32symbol;
+typedef struct {
+ uint32_t name;
+ uint8_t info, other;
+ uint16_t sectidx;
+ uint64_t value, size;
+} ELF64symbol;
+typedef struct {
+ ELF32header hdr;
+ ELF32sectheader sect[6];
+ ELF32symbol sym[2];
+ uint8_t space[4096];
+} ELF32obj;
+typedef struct {
+ ELF64header hdr;
+ ELF64sectheader sect[6];
+ ELF64symbol sym[2];
+ uint8_t space[4096];
+} ELF64obj;
+]]
+ local symname = LJBC_PREFIX..ctx.modname
+ local is64, isbe = false, false
+ if ctx.arch == "x64" or ctx.arch == "arm64" or ctx.arch == "arm64be" then
+ is64 = true
+ elseif ctx.arch == "ppc" or ctx.arch == "mips" then
+ isbe = true
+ end
+
+ -- Handle different host/target endianess.
+ local function f32(x) return x end
+ local f16, fofs = f32, f32
+ if ffi.abi("be") ~= isbe then
+ f32 = bit.bswap
+ function f16(x) return bit.rshift(bit.bswap(x), 16) end
+ if is64 then
+ local two32 = ffi.cast("int64_t", 2^32)
+ function fofs(x) return bit.bswap(x)*two32 end
+ else
+ fofs = f32
+ end
+ end
+
+ -- Create ELF object and fill in header.
+ local o = ffi.new(is64 and "ELF64obj" or "ELF32obj")
+ local hdr = o.hdr
+ if ctx.os == "bsd" or ctx.os == "other" then -- Determine native hdr.eosabi.
+ local bf = assert(io.open("/bin/ls", "rb"))
+ local bs = bf:read(9)
+ bf:close()
+ ffi.copy(o, bs, 9)
+ check(hdr.emagic[0] == 127, "no support for writing native object files")
+ else
+ hdr.emagic = "\127ELF"
+ hdr.eosabi = ({ freebsd=9, netbsd=2, openbsd=12, solaris=6 })[ctx.os] or 0
+ end
+ hdr.eclass = is64 and 2 or 1
+ hdr.eendian = isbe and 2 or 1
+ hdr.eversion = 1
+ hdr.type = f16(1)
+ hdr.machine = f16(({ x86=3, x64=62, arm=40, arm64=183, arm64be=183, ppc=20, mips=8, mipsel=8 })[ctx.arch])
+ if ctx.arch == "mips" or ctx.arch == "mipsel" then
+ hdr.flags = f32(0x50001006)
+ end
+ hdr.version = f32(1)
+ hdr.shofs = fofs(ffi.offsetof(o, "sect"))
+ hdr.ehsize = f16(ffi.sizeof(hdr))
+ hdr.shentsize = f16(ffi.sizeof(o.sect[0]))
+ hdr.shnum = f16(6)
+ hdr.shstridx = f16(2)
+
+ -- Fill in sections and symbols.
+ local sofs, ofs = ffi.offsetof(o, "space"), 1
+ for i,name in ipairs{
+ ".symtab", ".shstrtab", ".strtab", ".rodata", ".note.GNU-stack",
+ } do
+ local sect = o.sect[i]
+ sect.align = fofs(1)
+ sect.name = f32(ofs)
+ ffi.copy(o.space+ofs, name)
+ ofs = ofs + #name+1
+ end
+ o.sect[1].type = f32(2) -- .symtab
+ o.sect[1].link = f32(3)
+ o.sect[1].info = f32(1)
+ o.sect[1].align = fofs(8)
+ o.sect[1].ofs = fofs(ffi.offsetof(o, "sym"))
+ o.sect[1].entsize = fofs(ffi.sizeof(o.sym[0]))
+ o.sect[1].size = fofs(ffi.sizeof(o.sym))
+ o.sym[1].name = f32(1)
+ o.sym[1].sectidx = f16(4)
+ o.sym[1].size = fofs(#s)
+ o.sym[1].info = 17
+ o.sect[2].type = f32(3) -- .shstrtab
+ o.sect[2].ofs = fofs(sofs)
+ o.sect[2].size = fofs(ofs)
+ o.sect[3].type = f32(3) -- .strtab
+ o.sect[3].ofs = fofs(sofs + ofs)
+ o.sect[3].size = fofs(#symname+1)
+ ffi.copy(o.space+ofs+1, symname)
+ ofs = ofs + #symname + 2
+ o.sect[4].type = f32(1) -- .rodata
+ o.sect[4].flags = fofs(2)
+ o.sect[4].ofs = fofs(sofs + ofs)
+ o.sect[4].size = fofs(#s)
+ o.sect[5].type = f32(1) -- .note.GNU-stack
+ o.sect[5].ofs = fofs(sofs + ofs + #s)
+
+ -- Write ELF object file.
+ local fp = savefile(output, "wb")
+ fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs))
+ bcsave_tail(fp, output, s)
+end
+
+local function bcsave_peobj(ctx, output, s, ffi)
+ ffi.cdef[[
+typedef struct {
+ uint16_t arch, nsects;
+ uint32_t time, symtabofs, nsyms;
+ uint16_t opthdrsz, flags;
+} PEheader;
+typedef struct {
+ char name[8];
+ uint32_t vsize, vaddr, size, ofs, relocofs, lineofs;
+ uint16_t nreloc, nline;
+ uint32_t flags;
+} PEsection;
+typedef struct __attribute((packed)) {
+ union {
+ char name[8];
+ uint32_t nameref[2];
+ };
+ uint32_t value;
+ int16_t sect;
+ uint16_t type;
+ uint8_t scl, naux;
+} PEsym;
+typedef struct __attribute((packed)) {
+ uint32_t size;
+ uint16_t nreloc, nline;
+ uint32_t cksum;
+ uint16_t assoc;
+ uint8_t comdatsel, unused[3];
+} PEsymaux;
+typedef struct {
+ PEheader hdr;
+ PEsection sect[2];
+ // Must be an even number of symbol structs.
+ PEsym sym0;
+ PEsymaux sym0aux;
+ PEsym sym1;
+ PEsymaux sym1aux;
+ PEsym sym2;
+ PEsym sym3;
+ uint32_t strtabsize;
+ uint8_t space[4096];
+} PEobj;
+]]
+ local symname = LJBC_PREFIX..ctx.modname
+ local is64 = false
+ if ctx.arch == "x86" then
+ symname = "_"..symname
+ elseif ctx.arch == "x64" then
+ is64 = true
+ end
+ local symexport = " /EXPORT:"..symname..",DATA "
+
+ -- The file format is always little-endian. Swap if the host is big-endian.
+ local function f32(x) return x end
+ local f16 = f32
+ if ffi.abi("be") then
+ f32 = bit.bswap
+ function f16(x) return bit.rshift(bit.bswap(x), 16) end
+ end
+
+ -- Create PE object and fill in header.
+ local o = ffi.new("PEobj")
+ local hdr = o.hdr
+ hdr.arch = f16(({ x86=0x14c, x64=0x8664, arm=0x1c0, ppc=0x1f2, mips=0x366, mipsel=0x366 })[ctx.arch])
+ hdr.nsects = f16(2)
+ hdr.symtabofs = f32(ffi.offsetof(o, "sym0"))
+ hdr.nsyms = f32(6)
+
+ -- Fill in sections and symbols.
+ o.sect[0].name = ".drectve"
+ o.sect[0].size = f32(#symexport)
+ o.sect[0].flags = f32(0x00100a00)
+ o.sym0.sect = f16(1)
+ o.sym0.scl = 3
+ o.sym0.name = ".drectve"
+ o.sym0.naux = 1
+ o.sym0aux.size = f32(#symexport)
+ o.sect[1].name = ".rdata"
+ o.sect[1].size = f32(#s)
+ o.sect[1].flags = f32(0x40300040)
+ o.sym1.sect = f16(2)
+ o.sym1.scl = 3
+ o.sym1.name = ".rdata"
+ o.sym1.naux = 1
+ o.sym1aux.size = f32(#s)
+ o.sym2.sect = f16(2)
+ o.sym2.scl = 2
+ o.sym2.nameref[1] = f32(4)
+ o.sym3.sect = f16(-1)
+ o.sym3.scl = 2
+ o.sym3.value = f32(1)
+ o.sym3.name = "@feat.00" -- Mark as SafeSEH compliant.
+ ffi.copy(o.space, symname)
+ local ofs = #symname + 1
+ o.strtabsize = f32(ofs + 4)
+ o.sect[0].ofs = f32(ffi.offsetof(o, "space") + ofs)
+ ffi.copy(o.space + ofs, symexport)
+ ofs = ofs + #symexport
+ o.sect[1].ofs = f32(ffi.offsetof(o, "space") + ofs)
+
+ -- Write PE object file.
+ local fp = savefile(output, "wb")
+ fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs))
+ bcsave_tail(fp, output, s)
+end
+
+local function bcsave_machobj(ctx, output, s, ffi)
+ ffi.cdef[[
+typedef struct
+{
+ uint32_t magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags;
+} mach_header;
+typedef struct
+{
+ mach_header; uint32_t reserved;
+} mach_header_64;
+typedef struct {
+ uint32_t cmd, cmdsize;
+ char segname[16];
+ uint32_t vmaddr, vmsize, fileoff, filesize;
+ uint32_t maxprot, initprot, nsects, flags;
+} mach_segment_command;
+typedef struct {
+ uint32_t cmd, cmdsize;
+ char segname[16];
+ uint64_t vmaddr, vmsize, fileoff, filesize;
+ uint32_t maxprot, initprot, nsects, flags;
+} mach_segment_command_64;
+typedef struct {
+ char sectname[16], segname[16];
+ uint32_t addr, size;
+ uint32_t offset, align, reloff, nreloc, flags;
+ uint32_t reserved1, reserved2;
+} mach_section;
+typedef struct {
+ char sectname[16], segname[16];
+ uint64_t addr, size;
+ uint32_t offset, align, reloff, nreloc, flags;
+ uint32_t reserved1, reserved2, reserved3;
+} mach_section_64;
+typedef struct {
+ uint32_t cmd, cmdsize, symoff, nsyms, stroff, strsize;
+} mach_symtab_command;
+typedef struct {
+ int32_t strx;
+ uint8_t type, sect;
+ int16_t desc;
+ uint32_t value;
+} mach_nlist;
+typedef struct {
+ uint32_t strx;
+ uint8_t type, sect;
+ uint16_t desc;
+ uint64_t value;
+} mach_nlist_64;
+typedef struct
+{
+ uint32_t magic, nfat_arch;
+} mach_fat_header;
+typedef struct
+{
+ uint32_t cputype, cpusubtype, offset, size, align;
+} mach_fat_arch;
+typedef struct {
+ struct {
+ mach_header hdr;
+ mach_segment_command seg;
+ mach_section sec;
+ mach_symtab_command sym;
+ } arch[1];
+ mach_nlist sym_entry;
+ uint8_t space[4096];
+} mach_obj;
+typedef struct {
+ struct {
+ mach_header_64 hdr;
+ mach_segment_command_64 seg;
+ mach_section_64 sec;
+ mach_symtab_command sym;
+ } arch[1];
+ mach_nlist_64 sym_entry;
+ uint8_t space[4096];
+} mach_obj_64;
+typedef struct {
+ mach_fat_header fat;
+ mach_fat_arch fat_arch[2];
+ struct {
+ mach_header hdr;
+ mach_segment_command seg;
+ mach_section sec;
+ mach_symtab_command sym;
+ } arch[2];
+ mach_nlist sym_entry;
+ uint8_t space[4096];
+} mach_fat_obj;
+]]
+ local symname = '_'..LJBC_PREFIX..ctx.modname
+ local isfat, is64, align, mobj = false, false, 4, "mach_obj"
+ if ctx.arch == "x64" then
+ is64, align, mobj = true, 8, "mach_obj_64"
+ elseif ctx.arch == "arm" then
+ isfat, mobj = true, "mach_fat_obj"
+ elseif ctx.arch == "arm64" then
+ is64, align, isfat, mobj = true, 8, true, "mach_fat_obj"
+ else
+ check(ctx.arch == "x86", "unsupported architecture for OSX")
+ end
+ local function aligned(v, a) return bit.band(v+a-1, -a) end
+ local be32 = bit.bswap -- Mach-O FAT is BE, supported archs are LE.
+
+ -- Create Mach-O object and fill in header.
+ local o = ffi.new(mobj)
+ local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align)
+ local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12}, arm64={0x01000007,0x0100000c} })[ctx.arch]
+ local cpusubtype = ({ x86={3}, x64={3}, arm={3,9}, arm64={3,0} })[ctx.arch]
+ if isfat then
+ o.fat.magic = be32(0xcafebabe)
+ o.fat.nfat_arch = be32(#cpusubtype)
+ end
+
+ -- Fill in sections and symbols.
+ for i=0,#cpusubtype-1 do
+ local ofs = 0
+ if isfat then
+ local a = o.fat_arch[i]
+ a.cputype = be32(cputype[i+1])
+ a.cpusubtype = be32(cpusubtype[i+1])
+ -- Subsequent slices overlap each other to share data.
+ ofs = ffi.offsetof(o, "arch") + i*ffi.sizeof(o.arch[0])
+ a.offset = be32(ofs)
+ a.size = be32(mach_size-ofs+#s)
+ end
+ local a = o.arch[i]
+ a.hdr.magic = is64 and 0xfeedfacf or 0xfeedface
+ a.hdr.cputype = cputype[i+1]
+ a.hdr.cpusubtype = cpusubtype[i+1]
+ a.hdr.filetype = 1
+ a.hdr.ncmds = 2
+ a.hdr.sizeofcmds = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)+ffi.sizeof(a.sym)
+ a.seg.cmd = is64 and 0x19 or 0x1
+ a.seg.cmdsize = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)
+ a.seg.vmsize = #s
+ a.seg.fileoff = mach_size-ofs
+ a.seg.filesize = #s
+ a.seg.maxprot = 1
+ a.seg.initprot = 1
+ a.seg.nsects = 1
+ ffi.copy(a.sec.sectname, "__data")
+ ffi.copy(a.sec.segname, "__DATA")
+ a.sec.size = #s
+ a.sec.offset = mach_size-ofs
+ a.sym.cmd = 2
+ a.sym.cmdsize = ffi.sizeof(a.sym)
+ a.sym.symoff = ffi.offsetof(o, "sym_entry")-ofs
+ a.sym.nsyms = 1
+ a.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry)-ofs
+ a.sym.strsize = aligned(#symname+2, align)
+ end
+ o.sym_entry.type = 0xf
+ o.sym_entry.sect = 1
+ o.sym_entry.strx = 1
+ ffi.copy(o.space+1, symname)
+
+ -- Write Macho-O object file.
+ local fp = savefile(output, "wb")
+ fp:write(ffi.string(o, mach_size))
+ bcsave_tail(fp, output, s)
+end
+
+local function bcsave_obj(ctx, output, s)
+ local ok, ffi = pcall(require, "ffi")
+ check(ok, "FFI library required to write this file type")
+ if ctx.os == "windows" then
+ return bcsave_peobj(ctx, output, s, ffi)
+ elseif ctx.os == "osx" then
+ return bcsave_machobj(ctx, output, s, ffi)
+ else
+ return bcsave_elfobj(ctx, output, s, ffi)
+ end
+end
+
+------------------------------------------------------------------------------
+
+local function bclist(input, output)
+ local f = readfile(input)
+ require("jit.bc").dump(f, savefile(output, "w"), true)
+end
+
+local function bcsave(ctx, input, output)
+ local f = readfile(input)
+ local s = string.dump(f, ctx.strip)
+ local t = ctx.type
+ if not t then
+ t = detecttype(output)
+ ctx.type = t
+ end
+ if t == "raw" then
+ bcsave_raw(output, s)
+ else
+ if not ctx.modname then ctx.modname = detectmodname(input) end
+ if t == "obj" then
+ bcsave_obj(ctx, output, s)
+ else
+ bcsave_c(ctx, output, s)
+ end
+ end
+end
+
+local function docmd(...)
+ local arg = {...}
+ local n = 1
+ local list = false
+ local ctx = {
+ strip = true, arch = jit.arch, os = string.lower(jit.os),
+ type = false, modname = false,
+ }
+ while n <= #arg do
+ local a = arg[n]
+ if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then
+ table.remove(arg, n)
+ if a == "--" then break end
+ for m=2,#a do
+ local opt = string.sub(a, m, m)
+ if opt == "l" then
+ list = true
+ elseif opt == "s" then
+ ctx.strip = true
+ elseif opt == "g" then
+ ctx.strip = false
+ 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]))
+ elseif opt == "n" then
+ ctx.modname = checkmodname(table.remove(arg, n))
+ elseif opt == "t" then
+ ctx.type = checkarg(table.remove(arg, n), map_type, "file type")
+ elseif opt == "a" then
+ ctx.arch = checkarg(table.remove(arg, n), map_arch, "architecture")
+ elseif opt == "o" then
+ ctx.os = checkarg(table.remove(arg, n), map_os, "OS name")
+ else
+ usage()
+ end
+ end
+ end
+ else
+ n = n + 1
+ end
+ end
+ if list then
+ if #arg == 0 or #arg > 2 then usage() end
+ bclist(arg[1], arg[2] or "-")
+ else
+ if #arg ~= 2 then usage() end
+ bcsave(ctx, arg[1], arg[2])
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Public module functions.
+return {
+ start = docmd -- Process -b command line option.
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/jit/dis_arm.lua b/src/host/luajit-2.1.0-beta3/src/jit/dis_arm.lua
new file mode 100644
index 00000000..c2dd7769
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/jit/dis_arm.lua
@@ -0,0 +1,689 @@
+----------------------------------------------------------------------------
+-- LuaJIT ARM disassembler module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This is a helper module used by the LuaJIT machine code dumper module.
+--
+-- It disassembles most user-mode ARMv7 instructions
+-- NYI: Advanced SIMD and VFP instructions.
+------------------------------------------------------------------------------
+
+local type = type
+local sub, byte, format = string.sub, string.byte, string.format
+local match, gmatch = string.match, string.gmatch
+local concat = table.concat
+local bit = require("bit")
+local band, bor, ror, tohex = bit.band, bit.bor, bit.ror, bit.tohex
+local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
+
+------------------------------------------------------------------------------
+-- Opcode maps
+------------------------------------------------------------------------------
+
+local map_loadc = {
+ shift = 8, mask = 15,
+ [10] = {
+ shift = 20, mask = 1,
+ [0] = {
+ shift = 23, mask = 3,
+ [0] = "vmovFmDN", "vstmFNdr",
+ _ = {
+ shift = 21, mask = 1,
+ [0] = "vstrFdl",
+ { shift = 16, mask = 15, [13] = "vpushFdr", _ = "vstmdbFNdr", }
+ },
+ },
+ {
+ shift = 23, mask = 3,
+ [0] = "vmovFDNm",
+ { shift = 16, mask = 15, [13] = "vpopFdr", _ = "vldmFNdr", },
+ _ = {
+ shift = 21, mask = 1,
+ [0] = "vldrFdl", "vldmdbFNdr",
+ },
+ },
+ },
+ [11] = {
+ shift = 20, mask = 1,
+ [0] = {
+ shift = 23, mask = 3,
+ [0] = "vmovGmDN", "vstmGNdr",
+ _ = {
+ shift = 21, mask = 1,
+ [0] = "vstrGdl",
+ { shift = 16, mask = 15, [13] = "vpushGdr", _ = "vstmdbGNdr", }
+ },
+ },
+ {
+ shift = 23, mask = 3,
+ [0] = "vmovGDNm",
+ { shift = 16, mask = 15, [13] = "vpopGdr", _ = "vldmGNdr", },
+ _ = {
+ shift = 21, mask = 1,
+ [0] = "vldrGdl", "vldmdbGNdr",
+ },
+ },
+ },
+ _ = {
+ shift = 0, mask = 0 -- NYI ldc, mcrr, mrrc.
+ },
+}
+
+local map_vfps = {
+ shift = 6, mask = 0x2c001,
+ [0] = "vmlaF.dnm", "vmlsF.dnm",
+ [0x04000] = "vnmlsF.dnm", [0x04001] = "vnmlaF.dnm",
+ [0x08000] = "vmulF.dnm", [0x08001] = "vnmulF.dnm",
+ [0x0c000] = "vaddF.dnm", [0x0c001] = "vsubF.dnm",
+ [0x20000] = "vdivF.dnm",
+ [0x24000] = "vfnmsF.dnm", [0x24001] = "vfnmaF.dnm",
+ [0x28000] = "vfmaF.dnm", [0x28001] = "vfmsF.dnm",
+ [0x2c000] = "vmovF.dY",
+ [0x2c001] = {
+ shift = 7, mask = 0x1e01,
+ [0] = "vmovF.dm", "vabsF.dm",
+ [0x0200] = "vnegF.dm", [0x0201] = "vsqrtF.dm",
+ [0x0800] = "vcmpF.dm", [0x0801] = "vcmpeF.dm",
+ [0x0a00] = "vcmpzF.d", [0x0a01] = "vcmpzeF.d",
+ [0x0e01] = "vcvtG.dF.m",
+ [0x1000] = "vcvt.f32.u32Fdm", [0x1001] = "vcvt.f32.s32Fdm",
+ [0x1800] = "vcvtr.u32F.dm", [0x1801] = "vcvt.u32F.dm",
+ [0x1a00] = "vcvtr.s32F.dm", [0x1a01] = "vcvt.s32F.dm",
+ },
+}
+
+local map_vfpd = {
+ shift = 6, mask = 0x2c001,
+ [0] = "vmlaG.dnm", "vmlsG.dnm",
+ [0x04000] = "vnmlsG.dnm", [0x04001] = "vnmlaG.dnm",
+ [0x08000] = "vmulG.dnm", [0x08001] = "vnmulG.dnm",
+ [0x0c000] = "vaddG.dnm", [0x0c001] = "vsubG.dnm",
+ [0x20000] = "vdivG.dnm",
+ [0x24000] = "vfnmsG.dnm", [0x24001] = "vfnmaG.dnm",
+ [0x28000] = "vfmaG.dnm", [0x28001] = "vfmsG.dnm",
+ [0x2c000] = "vmovG.dY",
+ [0x2c001] = {
+ shift = 7, mask = 0x1e01,
+ [0] = "vmovG.dm", "vabsG.dm",
+ [0x0200] = "vnegG.dm", [0x0201] = "vsqrtG.dm",
+ [0x0800] = "vcmpG.dm", [0x0801] = "vcmpeG.dm",
+ [0x0a00] = "vcmpzG.d", [0x0a01] = "vcmpzeG.d",
+ [0x0e01] = "vcvtF.dG.m",
+ [0x1000] = "vcvt.f64.u32GdFm", [0x1001] = "vcvt.f64.s32GdFm",
+ [0x1800] = "vcvtr.u32FdG.m", [0x1801] = "vcvt.u32FdG.m",
+ [0x1a00] = "vcvtr.s32FdG.m", [0x1a01] = "vcvt.s32FdG.m",
+ },
+}
+
+local map_datac = {
+ shift = 24, mask = 1,
+ [0] = {
+ shift = 4, mask = 1,
+ [0] = {
+ shift = 8, mask = 15,
+ [10] = map_vfps,
+ [11] = map_vfpd,
+ -- NYI cdp, mcr, mrc.
+ },
+ {
+ shift = 8, mask = 15,
+ [10] = {
+ shift = 20, mask = 15,
+ [0] = "vmovFnD", "vmovFDn",
+ [14] = "vmsrD",
+ [15] = { shift = 12, mask = 15, [15] = "vmrs", _ = "vmrsD", },
+ },
+ },
+ },
+ "svcT",
+}
+
+local map_loadcu = {
+ shift = 0, mask = 0, -- NYI unconditional CP load/store.
+}
+
+local map_datacu = {
+ shift = 0, mask = 0, -- NYI unconditional CP data.
+}
+
+local map_simddata = {
+ shift = 0, mask = 0, -- NYI SIMD data.
+}
+
+local map_simdload = {
+ shift = 0, mask = 0, -- NYI SIMD load/store, preload.
+}
+
+local map_preload = {
+ shift = 0, mask = 0, -- NYI preload.
+}
+
+local map_media = {
+ shift = 20, mask = 31,
+ [0] = false,
+ { --01
+ shift = 5, mask = 7,
+ [0] = "sadd16DNM", "sasxDNM", "ssaxDNM", "ssub16DNM",
+ "sadd8DNM", false, false, "ssub8DNM",
+ },
+ { --02
+ shift = 5, mask = 7,
+ [0] = "qadd16DNM", "qasxDNM", "qsaxDNM", "qsub16DNM",
+ "qadd8DNM", false, false, "qsub8DNM",
+ },
+ { --03
+ shift = 5, mask = 7,
+ [0] = "shadd16DNM", "shasxDNM", "shsaxDNM", "shsub16DNM",
+ "shadd8DNM", false, false, "shsub8DNM",
+ },
+ false,
+ { --05
+ shift = 5, mask = 7,
+ [0] = "uadd16DNM", "uasxDNM", "usaxDNM", "usub16DNM",
+ "uadd8DNM", false, false, "usub8DNM",
+ },
+ { --06
+ shift = 5, mask = 7,
+ [0] = "uqadd16DNM", "uqasxDNM", "uqsaxDNM", "uqsub16DNM",
+ "uqadd8DNM", false, false, "uqsub8DNM",
+ },
+ { --07
+ shift = 5, mask = 7,
+ [0] = "uhadd16DNM", "uhasxDNM", "uhsaxDNM", "uhsub16DNM",
+ "uhadd8DNM", false, false, "uhsub8DNM",
+ },
+ { --08
+ shift = 5, mask = 7,
+ [0] = "pkhbtDNMU", false, "pkhtbDNMU",
+ { shift = 16, mask = 15, [15] = "sxtb16DMU", _ = "sxtab16DNMU", },
+ "pkhbtDNMU", "selDNM", "pkhtbDNMU",
+ },
+ false,
+ { --0a
+ shift = 5, mask = 7,
+ [0] = "ssatDxMu", "ssat16DxM", "ssatDxMu",
+ { shift = 16, mask = 15, [15] = "sxtbDMU", _ = "sxtabDNMU", },
+ "ssatDxMu", false, "ssatDxMu",
+ },
+ { --0b
+ shift = 5, mask = 7,
+ [0] = "ssatDxMu", "revDM", "ssatDxMu",
+ { shift = 16, mask = 15, [15] = "sxthDMU", _ = "sxtahDNMU", },
+ "ssatDxMu", "rev16DM", "ssatDxMu",
+ },
+ { --0c
+ shift = 5, mask = 7,
+ [3] = { shift = 16, mask = 15, [15] = "uxtb16DMU", _ = "uxtab16DNMU", },
+ },
+ false,
+ { --0e
+ shift = 5, mask = 7,
+ [0] = "usatDwMu", "usat16DwM", "usatDwMu",
+ { shift = 16, mask = 15, [15] = "uxtbDMU", _ = "uxtabDNMU", },
+ "usatDwMu", false, "usatDwMu",
+ },
+ { --0f
+ shift = 5, mask = 7,
+ [0] = "usatDwMu", "rbitDM", "usatDwMu",
+ { shift = 16, mask = 15, [15] = "uxthDMU", _ = "uxtahDNMU", },
+ "usatDwMu", "revshDM", "usatDwMu",
+ },
+ { --10
+ shift = 12, mask = 15,
+ [15] = {
+ shift = 5, mask = 7,
+ "smuadNMS", "smuadxNMS", "smusdNMS", "smusdxNMS",
+ },
+ _ = {
+ shift = 5, mask = 7,
+ [0] = "smladNMSD", "smladxNMSD", "smlsdNMSD", "smlsdxNMSD",
+ },
+ },
+ false, false, false,
+ { --14
+ shift = 5, mask = 7,
+ [0] = "smlaldDNMS", "smlaldxDNMS", "smlsldDNMS", "smlsldxDNMS",
+ },
+ { --15
+ shift = 5, mask = 7,
+ [0] = { shift = 12, mask = 15, [15] = "smmulNMS", _ = "smmlaNMSD", },
+ { shift = 12, mask = 15, [15] = "smmulrNMS", _ = "smmlarNMSD", },
+ false, false, false, false,
+ "smmlsNMSD", "smmlsrNMSD",
+ },
+ false, false,
+ { --18
+ shift = 5, mask = 7,
+ [0] = { shift = 12, mask = 15, [15] = "usad8NMS", _ = "usada8NMSD", },
+ },
+ false,
+ { --1a
+ shift = 5, mask = 3, [2] = "sbfxDMvw",
+ },
+ { --1b
+ shift = 5, mask = 3, [2] = "sbfxDMvw",
+ },
+ { --1c
+ shift = 5, mask = 3,
+ [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", },
+ },
+ { --1d
+ shift = 5, mask = 3,
+ [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", },
+ },
+ { --1e
+ shift = 5, mask = 3, [2] = "ubfxDMvw",
+ },
+ { --1f
+ shift = 5, mask = 3, [2] = "ubfxDMvw",
+ },
+}
+
+local map_load = {
+ shift = 21, mask = 9,
+ {
+ shift = 20, mask = 5,
+ [0] = "strtDL", "ldrtDL", [4] = "strbtDL", [5] = "ldrbtDL",
+ },
+ _ = {
+ shift = 20, mask = 5,
+ [0] = "strDL", "ldrDL", [4] = "strbDL", [5] = "ldrbDL",
+ }
+}
+
+local map_load1 = {
+ shift = 4, mask = 1,
+ [0] = map_load, map_media,
+}
+
+local map_loadm = {
+ shift = 20, mask = 1,
+ [0] = {
+ shift = 23, mask = 3,
+ [0] = "stmdaNR", "stmNR",
+ { shift = 16, mask = 63, [45] = "pushR", _ = "stmdbNR", }, "stmibNR",
+ },
+ {
+ shift = 23, mask = 3,
+ [0] = "ldmdaNR", { shift = 16, mask = 63, [61] = "popR", _ = "ldmNR", },
+ "ldmdbNR", "ldmibNR",
+ },
+}
+
+local map_data = {
+ shift = 21, mask = 15,
+ [0] = "andDNPs", "eorDNPs", "subDNPs", "rsbDNPs",
+ "addDNPs", "adcDNPs", "sbcDNPs", "rscDNPs",
+ "tstNP", "teqNP", "cmpNP", "cmnNP",
+ "orrDNPs", "movDPs", "bicDNPs", "mvnDPs",
+}
+
+local map_mul = {
+ shift = 21, mask = 7,
+ [0] = "mulNMSs", "mlaNMSDs", "umaalDNMS", "mlsDNMS",
+ "umullDNMSs", "umlalDNMSs", "smullDNMSs", "smlalDNMSs",
+}
+
+local map_sync = {
+ shift = 20, mask = 15, -- NYI: brackets around N. R(D+1) for ldrexd/strexd.
+ [0] = "swpDMN", false, false, false,
+ "swpbDMN", false, false, false,
+ "strexDMN", "ldrexDN", "strexdDN", "ldrexdDN",
+ "strexbDMN", "ldrexbDN", "strexhDN", "ldrexhDN",
+}
+
+local map_mulh = {
+ shift = 21, mask = 3,
+ [0] = { shift = 5, mask = 3,
+ [0] = "smlabbNMSD", "smlatbNMSD", "smlabtNMSD", "smlattNMSD", },
+ { shift = 5, mask = 3,
+ [0] = "smlawbNMSD", "smulwbNMS", "smlawtNMSD", "smulwtNMS", },
+ { shift = 5, mask = 3,
+ [0] = "smlalbbDNMS", "smlaltbDNMS", "smlalbtDNMS", "smlalttDNMS", },
+ { shift = 5, mask = 3,
+ [0] = "smulbbNMS", "smultbNMS", "smulbtNMS", "smulttNMS", },
+}
+
+local map_misc = {
+ shift = 4, mask = 7,
+ -- NYI: decode PSR bits of msr.
+ [0] = { shift = 21, mask = 1, [0] = "mrsD", "msrM", },
+ { shift = 21, mask = 3, "bxM", false, "clzDM", },
+ { shift = 21, mask = 3, "bxjM", },
+ { shift = 21, mask = 3, "blxM", },
+ false,
+ { shift = 21, mask = 3, [0] = "qaddDMN", "qsubDMN", "qdaddDMN", "qdsubDMN", },
+ false,
+ { shift = 21, mask = 3, "bkptK", },
+}
+
+local map_datar = {
+ shift = 4, mask = 9,
+ [9] = {
+ shift = 5, mask = 3,
+ [0] = { shift = 24, mask = 1, [0] = map_mul, map_sync, },
+ { shift = 20, mask = 1, [0] = "strhDL", "ldrhDL", },
+ { shift = 20, mask = 1, [0] = "ldrdDL", "ldrsbDL", },
+ { shift = 20, mask = 1, [0] = "strdDL", "ldrshDL", },
+ },
+ _ = {
+ shift = 20, mask = 25,
+ [16] = { shift = 7, mask = 1, [0] = map_misc, map_mulh, },
+ _ = {
+ shift = 0, mask = 0xffffffff,
+ [bor(0xe1a00000)] = "nop",
+ _ = map_data,
+ }
+ },
+}
+
+local map_datai = {
+ shift = 20, mask = 31, -- NYI: decode PSR bits of msr. Decode imm12.
+ [16] = "movwDW", [20] = "movtDW",
+ [18] = { shift = 0, mask = 0xf00ff, [0] = "nopv6", _ = "msrNW", },
+ [22] = "msrNW",
+ _ = map_data,
+}
+
+local map_branch = {
+ shift = 24, mask = 1,
+ [0] = "bB", "blB"
+}
+
+local map_condins = {
+ [0] = map_datar, map_datai, map_load, map_load1,
+ map_loadm, map_branch, map_loadc, map_datac
+}
+
+-- NYI: setend.
+local map_uncondins = {
+ [0] = false, map_simddata, map_simdload, map_preload,
+ false, "blxB", map_loadcu, map_datacu,
+}
+
+------------------------------------------------------------------------------
+
+local map_gpr = {
+ [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
+}
+
+local map_cond = {
+ [0] = "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
+ "hi", "ls", "ge", "lt", "gt", "le", "al",
+}
+
+local map_shift = { [0] = "lsl", "lsr", "asr", "ror", }
+
+------------------------------------------------------------------------------
+
+-- Output a nicely formatted line with an opcode and operands.
+local function putop(ctx, text, operands)
+ local pos = ctx.pos
+ local extra = ""
+ if ctx.rel then
+ local sym = ctx.symtab[ctx.rel]
+ if sym then
+ extra = "\t->"..sym
+ elseif band(ctx.op, 0x0e000000) ~= 0x0a000000 then
+ extra = "\t; 0x"..tohex(ctx.rel)
+ end
+ end
+ if ctx.hexdump > 0 then
+ ctx.out(format("%08x %s %-5s %s%s\n",
+ ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
+ else
+ ctx.out(format("%08x %-5s %s%s\n",
+ ctx.addr+pos, text, concat(operands, ", "), extra))
+ end
+ ctx.pos = pos + 4
+end
+
+-- Fallback for unknown opcodes.
+local function unknown(ctx)
+ return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
+end
+
+-- Format operand 2 of load/store opcodes.
+local function fmtload(ctx, op, pos)
+ local base = map_gpr[band(rshift(op, 16), 15)]
+ local x, ofs
+ local ext = (band(op, 0x04000000) == 0)
+ if not ext and band(op, 0x02000000) == 0 then
+ ofs = band(op, 4095)
+ if band(op, 0x00800000) == 0 then ofs = -ofs end
+ if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
+ ofs = "#"..ofs
+ elseif ext and band(op, 0x00400000) ~= 0 then
+ ofs = band(op, 15) + band(rshift(op, 4), 0xf0)
+ if band(op, 0x00800000) == 0 then ofs = -ofs end
+ if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
+ ofs = "#"..ofs
+ else
+ ofs = map_gpr[band(op, 15)]
+ if ext or band(op, 0xfe0) == 0 then
+ elseif band(op, 0xfe0) == 0x60 then
+ ofs = format("%s, rrx", ofs)
+ else
+ local sh = band(rshift(op, 7), 31)
+ if sh == 0 then sh = 32 end
+ ofs = format("%s, %s #%d", ofs, map_shift[band(rshift(op, 5), 3)], sh)
+ end
+ if band(op, 0x00800000) == 0 then ofs = "-"..ofs end
+ end
+ if ofs == "#0" then
+ x = format("[%s]", base)
+ elseif band(op, 0x01000000) == 0 then
+ x = format("[%s], %s", base, ofs)
+ else
+ x = format("[%s, %s]", base, ofs)
+ end
+ if band(op, 0x01200000) == 0x01200000 then x = x.."!" end
+ return x
+end
+
+-- Format operand 2 of vector load/store opcodes.
+local function fmtvload(ctx, op, pos)
+ local base = map_gpr[band(rshift(op, 16), 15)]
+ local ofs = band(op, 255)*4
+ if band(op, 0x00800000) == 0 then ofs = -ofs end
+ if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
+ if ofs == 0 then
+ return format("[%s]", base)
+ else
+ return format("[%s, #%d]", base, ofs)
+ end
+end
+
+local function fmtvr(op, vr, sh0, sh1)
+ if vr == "s" then
+ return format("s%d", 2*band(rshift(op, sh0), 15)+band(rshift(op, sh1), 1))
+ else
+ return format("d%d", band(rshift(op, sh0), 15)+band(rshift(op, sh1-4), 16))
+ end
+end
+
+-- Disassemble a single instruction.
+local function disass_ins(ctx)
+ local pos = ctx.pos
+ local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
+ local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
+ local operands = {}
+ local suffix = ""
+ local last, name, pat
+ local vr
+ ctx.op = op
+ ctx.rel = nil
+
+ local cond = rshift(op, 28)
+ local opat
+ if cond == 15 then
+ opat = map_uncondins[band(rshift(op, 25), 7)]
+ else
+ if cond ~= 14 then suffix = map_cond[cond] end
+ opat = map_condins[band(rshift(op, 25), 7)]
+ end
+ while type(opat) ~= "string" do
+ if not opat then return unknown(ctx) end
+ opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
+ end
+ name, pat = match(opat, "^([a-z0-9]*)(.*)")
+ if sub(pat, 1, 1) == "." then
+ local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)")
+ suffix = suffix..s2
+ pat = p2
+ end
+
+ for p in gmatch(pat, ".") do
+ local x = nil
+ if p == "D" then
+ x = map_gpr[band(rshift(op, 12), 15)]
+ elseif p == "N" then
+ x = map_gpr[band(rshift(op, 16), 15)]
+ elseif p == "S" then
+ x = map_gpr[band(rshift(op, 8), 15)]
+ elseif p == "M" then
+ x = map_gpr[band(op, 15)]
+ elseif p == "d" then
+ x = fmtvr(op, vr, 12, 22)
+ elseif p == "n" then
+ x = fmtvr(op, vr, 16, 7)
+ elseif p == "m" then
+ x = fmtvr(op, vr, 0, 5)
+ elseif p == "P" then
+ if band(op, 0x02000000) ~= 0 then
+ x = ror(band(op, 255), 2*band(rshift(op, 8), 15))
+ else
+ x = map_gpr[band(op, 15)]
+ if band(op, 0xff0) ~= 0 then
+ operands[#operands+1] = x
+ local s = map_shift[band(rshift(op, 5), 3)]
+ local r = nil
+ if band(op, 0xf90) == 0 then
+ if s == "ror" then s = "rrx" else r = "#32" end
+ elseif band(op, 0x10) == 0 then
+ r = "#"..band(rshift(op, 7), 31)
+ else
+ r = map_gpr[band(rshift(op, 8), 15)]
+ end
+ if name == "mov" then name = s; x = r
+ elseif r then x = format("%s %s", s, r)
+ else x = s end
+ end
+ end
+ elseif p == "L" then
+ x = fmtload(ctx, op, pos)
+ elseif p == "l" then
+ x = fmtvload(ctx, op, pos)
+ elseif p == "B" then
+ local addr = ctx.addr + pos + 8 + arshift(lshift(op, 8), 6)
+ if cond == 15 then addr = addr + band(rshift(op, 23), 2) end
+ ctx.rel = addr
+ x = "0x"..tohex(addr)
+ elseif p == "F" then
+ vr = "s"
+ elseif p == "G" then
+ vr = "d"
+ elseif p == "." then
+ suffix = suffix..(vr == "s" and ".f32" or ".f64")
+ elseif p == "R" then
+ if band(op, 0x00200000) ~= 0 and #operands == 1 then
+ operands[1] = operands[1].."!"
+ end
+ local t = {}
+ for i=0,15 do
+ if band(rshift(op, i), 1) == 1 then t[#t+1] = map_gpr[i] end
+ end
+ x = "{"..concat(t, ", ").."}"
+ elseif p == "r" then
+ if band(op, 0x00200000) ~= 0 and #operands == 2 then
+ operands[1] = operands[1].."!"
+ end
+ local s = tonumber(sub(last, 2))
+ local n = band(op, 255)
+ if vr == "d" then n = rshift(n, 1) end
+ operands[#operands] = format("{%s-%s%d}", last, vr, s+n-1)
+ elseif p == "W" then
+ x = band(op, 0x0fff) + band(rshift(op, 4), 0xf000)
+ elseif p == "T" then
+ x = "#0x"..tohex(band(op, 0x00ffffff), 6)
+ elseif p == "U" then
+ x = band(rshift(op, 7), 31)
+ if x == 0 then x = nil end
+ elseif p == "u" then
+ x = band(rshift(op, 7), 31)
+ if band(op, 0x40) == 0 then
+ if x == 0 then x = nil else x = "lsl #"..x end
+ else
+ if x == 0 then x = "asr #32" else x = "asr #"..x end
+ end
+ elseif p == "v" then
+ x = band(rshift(op, 7), 31)
+ elseif p == "w" then
+ x = band(rshift(op, 16), 31)
+ elseif p == "x" then
+ x = band(rshift(op, 16), 31) + 1
+ elseif p == "X" then
+ x = band(rshift(op, 16), 31) - last + 1
+ elseif p == "Y" then
+ x = band(rshift(op, 12), 0xf0) + band(op, 0x0f)
+ elseif p == "K" then
+ x = "#0x"..tohex(band(rshift(op, 4), 0x0000fff0) + band(op, 15), 4)
+ elseif p == "s" then
+ if band(op, 0x00100000) ~= 0 then suffix = "s"..suffix end
+ else
+ assert(false)
+ end
+ if x then
+ last = x
+ if type(x) == "number" then x = "#"..x end
+ operands[#operands+1] = x
+ end
+ end
+
+ return putop(ctx, name..suffix, operands)
+end
+
+------------------------------------------------------------------------------
+
+-- Disassemble a block of code.
+local function disass_block(ctx, ofs, len)
+ if not ofs then ofs = 0 end
+ local stop = len and ofs+len or #ctx.code
+ ctx.pos = ofs
+ ctx.rel = nil
+ while ctx.pos < stop do disass_ins(ctx) end
+end
+
+-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
+local function create(code, addr, out)
+ local ctx = {}
+ ctx.code = code
+ ctx.addr = addr or 0
+ ctx.out = out or io.write
+ ctx.symtab = {}
+ ctx.disass = disass_block
+ ctx.hexdump = 8
+ return ctx
+end
+
+-- Simple API: disassemble code (a string) at address and output via out.
+local function disass(code, addr, out)
+ create(code, addr, out):disass()
+end
+
+-- Return register name for RID.
+local function regname(r)
+ if r < 16 then return map_gpr[r] end
+ return "d"..(r-16)
+end
+
+-- Public module functions.
+return {
+ create = create,
+ disass = disass,
+ regname = regname
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/jit/dis_arm64.lua b/src/host/luajit-2.1.0-beta3/src/jit/dis_arm64.lua
new file mode 100644
index 00000000..a7173326
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/jit/dis_arm64.lua
@@ -0,0 +1,1216 @@
+----------------------------------------------------------------------------
+-- LuaJIT ARM64 disassembler module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+--
+-- Contributed by Djordje Kovacevic and Stefan Pejic from RT-RK.com.
+-- Sponsored by Cisco Systems, Inc.
+----------------------------------------------------------------------------
+-- This is a helper module used by the LuaJIT machine code dumper module.
+--
+-- It disassembles most user-mode AArch64 instructions.
+-- NYI: Advanced SIMD and VFP instructions.
+------------------------------------------------------------------------------
+
+local type = type
+local sub, byte, format = string.sub, string.byte, string.format
+local match, gmatch, gsub = string.match, string.gmatch, string.gsub
+local concat = table.concat
+local bit = require("bit")
+local band, bor, bxor, tohex = bit.band, bit.bor, bit.bxor, bit.tohex
+local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
+local ror = bit.ror
+
+------------------------------------------------------------------------------
+-- Opcode maps
+------------------------------------------------------------------------------
+
+local map_adr = { -- PC-relative addressing.
+ shift = 31, mask = 1,
+ [0] = "adrDBx", "adrpDBx"
+}
+
+local map_addsubi = { -- Add/subtract immediate.
+ shift = 29, mask = 3,
+ [0] = "add|movDNIg", "adds|cmnD0NIg", "subDNIg", "subs|cmpD0NIg",
+}
+
+local map_logi = { -- Logical immediate.
+ shift = 31, mask = 1,
+ [0] = {
+ shift = 22, mask = 1,
+ [0] = {
+ shift = 29, mask = 3,
+ [0] = "andDNig", "orr|movDN0ig", "eorDNig", "ands|tstD0Nig"
+ },
+ false -- unallocated
+ },
+ {
+ shift = 29, mask = 3,
+ [0] = "andDNig", "orr|movDN0ig", "eorDNig", "ands|tstD0Nig"
+ }
+}
+
+local map_movwi = { -- Move wide immediate.
+ shift = 31, mask = 1,
+ [0] = {
+ shift = 22, mask = 1,
+ [0] = {
+ shift = 29, mask = 3,
+ [0] = "movnDWRg", false, "movz|movDYRg", "movkDWRg"
+ }, false -- unallocated
+ },
+ {
+ shift = 29, mask = 3,
+ [0] = "movnDWRg", false, "movz|movDYRg", "movkDWRg"
+ },
+}
+
+local map_bitf = { -- Bitfield.
+ shift = 31, mask = 1,
+ [0] = {
+ shift = 22, mask = 1,
+ [0] = {
+ shift = 29, mask = 3,
+ [0] = "sbfm|sbfiz|sbfx|asr|sxtw|sxth|sxtbDN12w",
+ "bfm|bfi|bfxilDN13w",
+ "ubfm|ubfiz|ubfx|lsr|lsl|uxth|uxtbDN12w"
+ }
+ },
+ {
+ shift = 22, mask = 1,
+ {
+ shift = 29, mask = 3,
+ [0] = "sbfm|sbfiz|sbfx|asr|sxtw|sxth|sxtbDN12x",
+ "bfm|bfi|bfxilDN13x",
+ "ubfm|ubfiz|ubfx|lsr|lsl|uxth|uxtbDN12x"
+ }
+ }
+}
+
+local map_datai = { -- Data processing - immediate.
+ shift = 23, mask = 7,
+ [0] = map_adr, map_adr, map_addsubi, false,
+ map_logi, map_movwi, map_bitf,
+ {
+ shift = 15, mask = 0x1c0c1,
+ [0] = "extr|rorDNM4w", [0x10080] = "extr|rorDNM4x",
+ [0x10081] = "extr|rorDNM4x"
+ }
+}
+
+local map_logsr = { -- Logical, shifted register.
+ shift = 31, mask = 1,
+ [0] = {
+ shift = 15, mask = 1,
+ [0] = {
+ shift = 29, mask = 3,
+ [0] = {
+ shift = 21, mask = 7,
+ [0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg",
+ "andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg"
+ },
+ {
+ shift = 21, mask = 7,
+ [0] ="orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg",
+ "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg"
+ },
+ {
+ shift = 21, mask = 7,
+ [0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg",
+ "eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg"
+ },
+ {
+ shift = 21, mask = 7,
+ [0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg",
+ "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg"
+ }
+ },
+ false -- unallocated
+ },
+ {
+ shift = 29, mask = 3,
+ [0] = {
+ shift = 21, mask = 7,
+ [0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg",
+ "andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg"
+ },
+ {
+ shift = 21, mask = 7,
+ [0] = "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg",
+ "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg"
+ },
+ {
+ shift = 21, mask = 7,
+ [0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg",
+ "eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg"
+ },
+ {
+ shift = 21, mask = 7,
+ [0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg",
+ "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg"
+ }
+ }
+}
+
+local map_assh = {
+ shift = 31, mask = 1,
+ [0] = {
+ shift = 15, mask = 1,
+ [0] = {
+ shift = 29, mask = 3,
+ [0] = {
+ shift = 22, mask = 3,
+ [0] = "addDNMSg", "addDNMSg", "addDNMSg", "addDNMg"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "adds|cmnD0NMSg", "adds|cmnD0NMSg",
+ "adds|cmnD0NMSg", "adds|cmnD0NMg"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0Mg"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg",
+ "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0Mzg"
+ },
+ },
+ false -- unallocated
+ },
+ {
+ shift = 29, mask = 3,
+ [0] = {
+ shift = 22, mask = 3,
+ [0] = "addDNMSg", "addDNMSg", "addDNMSg", "addDNMg"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "adds|cmnD0NMSg", "adds|cmnD0NMSg", "adds|cmnD0NMSg",
+ "adds|cmnD0NMg"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0Mg"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg",
+ "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0Mzg"
+ }
+ }
+}
+
+local map_addsubsh = { -- Add/subtract, shifted register.
+ shift = 22, mask = 3,
+ [0] = map_assh, map_assh, map_assh
+}
+
+local map_addsubex = { -- Add/subtract, extended register.
+ shift = 22, mask = 3,
+ [0] = {
+ shift = 29, mask = 3,
+ [0] = "addDNMXg", "adds|cmnD0NMXg", "subDNMXg", "subs|cmpD0NMzXg",
+ }
+}
+
+local map_addsubc = { -- Add/subtract, with carry.
+ shift = 10, mask = 63,
+ [0] = {
+ shift = 29, mask = 3,
+ [0] = "adcDNMg", "adcsDNMg", "sbc|ngcDN0Mg", "sbcs|ngcsDN0Mg",
+ }
+}
+
+local map_ccomp = {
+ shift = 4, mask = 1,
+ [0] = {
+ shift = 10, mask = 3,
+ [0] = { -- Conditional compare register.
+ shift = 29, mask = 3,
+ "ccmnNMVCg", false, "ccmpNMVCg",
+ },
+ [2] = { -- Conditional compare immediate.
+ shift = 29, mask = 3,
+ "ccmnN5VCg", false, "ccmpN5VCg",
+ }
+ }
+}
+
+local map_csel = { -- Conditional select.
+ shift = 11, mask = 1,
+ [0] = {
+ shift = 10, mask = 1,
+ [0] = {
+ shift = 29, mask = 3,
+ [0] = "cselDNMzCg", false, "csinv|cinv|csetmDNMcg", false,
+ },
+ {
+ shift = 29, mask = 3,
+ [0] = "csinc|cinc|csetDNMcg", false, "csneg|cnegDNMcg", false,
+ }
+ }
+}
+
+local map_data1s = { -- Data processing, 1 source.
+ shift = 29, mask = 1,
+ [0] = {
+ shift = 31, mask = 1,
+ [0] = {
+ shift = 10, mask = 0x7ff,
+ [0] = "rbitDNg", "rev16DNg", "revDNw", false, "clzDNg", "clsDNg"
+ },
+ {
+ shift = 10, mask = 0x7ff,
+ [0] = "rbitDNg", "rev16DNg", "rev32DNx", "revDNx", "clzDNg", "clsDNg"
+ }
+ }
+}
+
+local map_data2s = { -- Data processing, 2 sources.
+ shift = 29, mask = 1,
+ [0] = {
+ shift = 10, mask = 63,
+ false, "udivDNMg", "sdivDNMg", false, false, false, false, "lslDNMg",
+ "lsrDNMg", "asrDNMg", "rorDNMg"
+ }
+}
+
+local map_data3s = { -- Data processing, 3 sources.
+ shift = 29, mask = 7,
+ [0] = {
+ shift = 21, mask = 7,
+ [0] = {
+ shift = 15, mask = 1,
+ [0] = "madd|mulDNMA0g", "msub|mnegDNMA0g"
+ }
+ }, false, false, false,
+ {
+ shift = 15, mask = 1,
+ [0] = {
+ shift = 21, mask = 7,
+ [0] = "madd|mulDNMA0g", "smaddl|smullDxNMwA0x", "smulhDNMx", false,
+ false, "umaddl|umullDxNMwA0x", "umulhDNMx"
+ },
+ {
+ shift = 21, mask = 7,
+ [0] = "msub|mnegDNMA0g", "smsubl|smneglDxNMwA0x", false, false,
+ false, "umsubl|umneglDxNMwA0x"
+ }
+ }
+}
+
+local map_datar = { -- Data processing, register.
+ shift = 28, mask = 1,
+ [0] = {
+ shift = 24, mask = 1,
+ [0] = map_logsr,
+ {
+ shift = 21, mask = 1,
+ [0] = map_addsubsh, map_addsubex
+ }
+ },
+ {
+ shift = 21, mask = 15,
+ [0] = map_addsubc, false, map_ccomp, false, map_csel, false,
+ {
+ shift = 30, mask = 1,
+ [0] = map_data2s, map_data1s
+ },
+ false, map_data3s, map_data3s, map_data3s, map_data3s, map_data3s,
+ map_data3s, map_data3s, map_data3s
+ }
+}
+
+local map_lrl = { -- Load register, literal.
+ shift = 26, mask = 1,
+ [0] = {
+ shift = 30, mask = 3,
+ [0] = "ldrDwB", "ldrDxB", "ldrswDxB"
+ },
+ {
+ shift = 30, mask = 3,
+ [0] = "ldrDsB", "ldrDdB"
+ }
+}
+
+local map_lsriind = { -- Load/store register, immediate pre/post-indexed.
+ shift = 30, mask = 3,
+ [0] = {
+ shift = 26, mask = 1,
+ [0] = {
+ shift = 22, mask = 3,
+ [0] = "strbDwzL", "ldrbDwzL", "ldrsbDxzL", "ldrsbDwzL"
+ }
+ },
+ {
+ shift = 26, mask = 1,
+ [0] = {
+ shift = 22, mask = 3,
+ [0] = "strhDwzL", "ldrhDwzL", "ldrshDxzL", "ldrshDwzL"
+ }
+ },
+ {
+ shift = 26, mask = 1,
+ [0] = {
+ shift = 22, mask = 3,
+ [0] = "strDwzL", "ldrDwzL", "ldrswDxzL"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "strDszL", "ldrDszL"
+ }
+ },
+ {
+ shift = 26, mask = 1,
+ [0] = {
+ shift = 22, mask = 3,
+ [0] = "strDxzL", "ldrDxzL"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "strDdzL", "ldrDdzL"
+ }
+ }
+}
+
+local map_lsriro = {
+ shift = 21, mask = 1,
+ [0] = { -- Load/store register immediate.
+ shift = 10, mask = 3,
+ [0] = { -- Unscaled immediate.
+ shift = 26, mask = 1,
+ [0] = {
+ shift = 30, mask = 3,
+ [0] = {
+ shift = 22, mask = 3,
+ [0] = "sturbDwK", "ldurbDwK"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "sturhDwK", "ldurhDwK"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "sturDwK", "ldurDwK"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "sturDxK", "ldurDxK"
+ }
+ }
+ }, map_lsriind, false, map_lsriind
+ },
+ { -- Load/store register, register offset.
+ shift = 10, mask = 3,
+ [2] = {
+ shift = 26, mask = 1,
+ [0] = {
+ shift = 30, mask = 3,
+ [0] = {
+ shift = 22, mask = 3,
+ [0] = "strbDwO", "ldrbDwO", "ldrsbDxO", "ldrsbDwO"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "strhDwO", "ldrhDwO", "ldrshDxO", "ldrshDwO"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "strDwO", "ldrDwO", "ldrswDxO"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "strDxO", "ldrDxO"
+ }
+ },
+ {
+ shift = 30, mask = 3,
+ [2] = {
+ shift = 22, mask = 3,
+ [0] = "strDsO", "ldrDsO"
+ },
+ [3] = {
+ shift = 22, mask = 3,
+ [0] = "strDdO", "ldrDdO"
+ }
+ }
+ }
+ }
+}
+
+local map_lsp = { -- Load/store register pair, offset.
+ shift = 22, mask = 1,
+ [0] = {
+ shift = 30, mask = 3,
+ [0] = {
+ shift = 26, mask = 1,
+ [0] = "stpDzAzwP", "stpDzAzsP",
+ },
+ {
+ shift = 26, mask = 1,
+ "stpDzAzdP"
+ },
+ {
+ shift = 26, mask = 1,
+ [0] = "stpDzAzxP"
+ }
+ },
+ {
+ shift = 30, mask = 3,
+ [0] = {
+ shift = 26, mask = 1,
+ [0] = "ldpDzAzwP", "ldpDzAzsP",
+ },
+ {
+ shift = 26, mask = 1,
+ [0] = "ldpswDAxP", "ldpDzAzdP"
+ },
+ {
+ shift = 26, mask = 1,
+ [0] = "ldpDzAzxP"
+ }
+ }
+}
+
+local map_ls = { -- Loads and stores.
+ shift = 24, mask = 0x31,
+ [0x10] = map_lrl, [0x30] = map_lsriro,
+ [0x20] = {
+ shift = 23, mask = 3,
+ map_lsp, map_lsp, map_lsp
+ },
+ [0x21] = {
+ shift = 23, mask = 3,
+ map_lsp, map_lsp, map_lsp
+ },
+ [0x31] = {
+ shift = 26, mask = 1,
+ [0] = {
+ shift = 30, mask = 3,
+ [0] = {
+ shift = 22, mask = 3,
+ [0] = "strbDwzU", "ldrbDwzU"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "strhDwzU", "ldrhDwzU"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "strDwzU", "ldrDwzU"
+ },
+ {
+ shift = 22, mask = 3,
+ [0] = "strDxzU", "ldrDxzU"
+ }
+ },
+ {
+ shift = 30, mask = 3,
+ [2] = {
+ shift = 22, mask = 3,
+ [0] = "strDszU", "ldrDszU"
+ },
+ [3] = {
+ shift = 22, mask = 3,
+ [0] = "strDdzU", "ldrDdzU"
+ }
+ }
+ },
+}
+
+local map_datafp = { -- Data processing, SIMD and FP.
+ shift = 28, mask = 7,
+ { -- 001
+ shift = 24, mask = 1,
+ [0] = {
+ shift = 21, mask = 1,
+ {
+ shift = 10, mask = 3,
+ [0] = {
+ shift = 12, mask = 1,
+ [0] = {
+ shift = 13, mask = 1,
+ [0] = {
+ shift = 14, mask = 1,
+ [0] = {
+ shift = 15, mask = 1,
+ [0] = { -- FP/int conversion.
+ shift = 31, mask = 1,
+ [0] = {
+ shift = 16, mask = 0xff,
+ [0x20] = "fcvtnsDwNs", [0x21] = "fcvtnuDwNs",
+ [0x22] = "scvtfDsNw", [0x23] = "ucvtfDsNw",
+ [0x24] = "fcvtasDwNs", [0x25] = "fcvtauDwNs",
+ [0x26] = "fmovDwNs", [0x27] = "fmovDsNw",
+ [0x28] = "fcvtpsDwNs", [0x29] = "fcvtpuDwNs",
+ [0x30] = "fcvtmsDwNs", [0x31] = "fcvtmuDwNs",
+ [0x38] = "fcvtzsDwNs", [0x39] = "fcvtzuDwNs",
+ [0x60] = "fcvtnsDwNd", [0x61] = "fcvtnuDwNd",
+ [0x62] = "scvtfDdNw", [0x63] = "ucvtfDdNw",
+ [0x64] = "fcvtasDwNd", [0x65] = "fcvtauDwNd",
+ [0x68] = "fcvtpsDwNd", [0x69] = "fcvtpuDwNd",
+ [0x70] = "fcvtmsDwNd", [0x71] = "fcvtmuDwNd",
+ [0x78] = "fcvtzsDwNd", [0x79] = "fcvtzuDwNd"
+ },
+ {
+ shift = 16, mask = 0xff,
+ [0x20] = "fcvtnsDxNs", [0x21] = "fcvtnuDxNs",
+ [0x22] = "scvtfDsNx", [0x23] = "ucvtfDsNx",
+ [0x24] = "fcvtasDxNs", [0x25] = "fcvtauDxNs",
+ [0x28] = "fcvtpsDxNs", [0x29] = "fcvtpuDxNs",
+ [0x30] = "fcvtmsDxNs", [0x31] = "fcvtmuDxNs",
+ [0x38] = "fcvtzsDxNs", [0x39] = "fcvtzuDxNs",
+ [0x60] = "fcvtnsDxNd", [0x61] = "fcvtnuDxNd",
+ [0x62] = "scvtfDdNx", [0x63] = "ucvtfDdNx",
+ [0x64] = "fcvtasDxNd", [0x65] = "fcvtauDxNd",
+ [0x66] = "fmovDxNd", [0x67] = "fmovDdNx",
+ [0x68] = "fcvtpsDxNd", [0x69] = "fcvtpuDxNd",
+ [0x70] = "fcvtmsDxNd", [0x71] = "fcvtmuDxNd",
+ [0x78] = "fcvtzsDxNd", [0x79] = "fcvtzuDxNd"
+ }
+ }
+ },
+ { -- FP data-processing, 1 source.
+ shift = 31, mask = 1,
+ [0] = {
+ shift = 22, mask = 3,
+ [0] = {
+ shift = 15, mask = 63,
+ [0] = "fmovDNf", "fabsDNf", "fnegDNf",
+ "fsqrtDNf", false, "fcvtDdNs", false, false,
+ "frintnDNf", "frintpDNf", "frintmDNf", "frintzDNf",
+ "frintaDNf", false, "frintxDNf", "frintiDNf",
+ },
+ {
+ shift = 15, mask = 63,
+ [0] = "fmovDNf", "fabsDNf", "fnegDNf",
+ "fsqrtDNf", "fcvtDsNd", false, false, false,
+ "frintnDNf", "frintpDNf", "frintmDNf", "frintzDNf",
+ "frintaDNf", false, "frintxDNf", "frintiDNf",
+ }
+ }
+ }
+ },
+ { -- FP compare.
+ shift = 31, mask = 1,
+ [0] = {
+ shift = 14, mask = 3,
+ [0] = {
+ shift = 23, mask = 1,
+ [0] = {
+ shift = 0, mask = 31,
+ [0] = "fcmpNMf", [8] = "fcmpNZf",
+ [16] = "fcmpeNMf", [24] = "fcmpeNZf",
+ }
+ }
+ }
+ }
+ },
+ { -- FP immediate.
+ shift = 31, mask = 1,
+ [0] = {
+ shift = 5, mask = 31,
+ [0] = {
+ shift = 23, mask = 1,
+ [0] = "fmovDFf"
+ }
+ }
+ }
+ },
+ { -- FP conditional compare.
+ shift = 31, mask = 1,
+ [0] = {
+ shift = 23, mask = 1,
+ [0] = {
+ shift = 4, mask = 1,
+ [0] = "fccmpNMVCf", "fccmpeNMVCf"
+ }
+ }
+ },
+ { -- FP data-processing, 2 sources.
+ shift = 31, mask = 1,
+ [0] = {
+ shift = 23, mask = 1,
+ [0] = {
+ shift = 12, mask = 15,
+ [0] = "fmulDNMf", "fdivDNMf", "faddDNMf", "fsubDNMf",
+ "fmaxDNMf", "fminDNMf", "fmaxnmDNMf", "fminnmDNMf",
+ "fnmulDNMf"
+ }
+ }
+ },
+ { -- FP conditional select.
+ shift = 31, mask = 1,
+ [0] = {
+ shift = 23, mask = 1,
+ [0] = "fcselDNMCf"
+ }
+ }
+ }
+ },
+ { -- FP data-processing, 3 sources.
+ shift = 31, mask = 1,
+ [0] = {
+ shift = 15, mask = 1,
+ [0] = {
+ shift = 21, mask = 5,
+ [0] = "fmaddDNMAf", "fnmaddDNMAf"
+ },
+ {
+ shift = 21, mask = 5,
+ [0] = "fmsubDNMAf", "fnmsubDNMAf"
+ }
+ }
+ }
+ }
+}
+
+local map_br = { -- Branches, exception generating and system instructions.
+ shift = 29, mask = 7,
+ [0] = "bB",
+ { -- Compare & branch, immediate.
+ shift = 24, mask = 3,
+ [0] = "cbzDBg", "cbnzDBg", "tbzDTBw", "tbnzDTBw"
+ },
+ { -- Conditional branch, immediate.
+ shift = 24, mask = 3,
+ [0] = {
+ shift = 4, mask = 1,
+ [0] = {
+ shift = 0, mask = 15,
+ [0] = "beqB", "bneB", "bhsB", "bloB", "bmiB", "bplB", "bvsB", "bvcB",
+ "bhiB", "blsB", "bgeB", "bltB", "bgtB", "bleB", "balB"
+ }
+ }
+ }, false, "blB",
+ { -- Compare & branch, immediate.
+ shift = 24, mask = 3,
+ [0] = "cbzDBg", "cbnzDBg", "tbzDTBx", "tbnzDTBx"
+ },
+ {
+ shift = 24, mask = 3,
+ [0] = { -- Exception generation.
+ shift = 0, mask = 0xe0001f,
+ [0x200000] = "brkW"
+ },
+ { -- System instructions.
+ shift = 0, mask = 0x3fffff,
+ [0x03201f] = "nop"
+ },
+ { -- Unconditional branch, register.
+ shift = 0, mask = 0xfffc1f,
+ [0x1f0000] = "brNx", [0x3f0000] = "blrNx",
+ [0x5f0000] = "retNx"
+ },
+ }
+}
+
+local map_init = {
+ shift = 25, mask = 15,
+ [0] = false, false, false, false, map_ls, map_datar, map_ls, map_datafp,
+ map_datai, map_datai, map_br, map_br, map_ls, map_datar, map_ls, map_datafp
+}
+
+------------------------------------------------------------------------------
+
+local map_regs = { x = {}, w = {}, d = {}, s = {} }
+
+for i=0,30 do
+ map_regs.x[i] = "x"..i
+ map_regs.w[i] = "w"..i
+ map_regs.d[i] = "d"..i
+ map_regs.s[i] = "s"..i
+end
+map_regs.x[31] = "sp"
+map_regs.w[31] = "wsp"
+map_regs.d[31] = "d31"
+map_regs.s[31] = "s31"
+
+local map_cond = {
+ [0] = "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
+ "hi", "ls", "ge", "lt", "gt", "le", "al",
+}
+
+local map_shift = { [0] = "lsl", "lsr", "asr", }
+
+local map_extend = {
+ [0] = "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx",
+}
+
+------------------------------------------------------------------------------
+
+-- Output a nicely formatted line with an opcode and operands.
+local function putop(ctx, text, operands)
+ local pos = ctx.pos
+ local extra = ""
+ if ctx.rel then
+ local sym = ctx.symtab[ctx.rel]
+ if sym then
+ extra = "\t->"..sym
+ end
+ end
+ if ctx.hexdump > 0 then
+ ctx.out(format("%08x %s %-5s %s%s\n",
+ ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
+ else
+ ctx.out(format("%08x %-5s %s%s\n",
+ ctx.addr+pos, text, concat(operands, ", "), extra))
+ end
+ ctx.pos = pos + 4
+end
+
+-- Fallback for unknown opcodes.
+local function unknown(ctx)
+ return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
+end
+
+local function match_reg(p, pat, regnum)
+ return map_regs[match(pat, p.."%w-([xwds])")][regnum]
+end
+
+local function fmt_hex32(x)
+ if x < 0 then
+ return tohex(x)
+ else
+ return format("%x", x)
+ end
+end
+
+local imm13_rep = { 0x55555555, 0x11111111, 0x01010101, 0x00010001, 0x00000001 }
+
+local function decode_imm13(op)
+ local imms = band(rshift(op, 10), 63)
+ local immr = band(rshift(op, 16), 63)
+ if band(op, 0x00400000) == 0 then
+ local len = 5
+ if imms >= 56 then
+ if imms >= 60 then len = 1 else len = 2 end
+ elseif imms >= 48 then len = 3 elseif imms >= 32 then len = 4 end
+ local l = lshift(1, len)-1
+ local s = band(imms, l)
+ local r = band(immr, l)
+ local imm = ror(rshift(-1, 31-s), r)
+ if len ~= 5 then imm = band(imm, lshift(1, l)-1) + rshift(imm, 31-l) end
+ imm = imm * imm13_rep[len]
+ local ix = fmt_hex32(imm)
+ if rshift(op, 31) ~= 0 then
+ return ix..tohex(imm)
+ else
+ return ix
+ end
+ else
+ local lo, hi = -1, 0
+ if imms < 32 then lo = rshift(-1, 31-imms) else hi = rshift(-1, 63-imms) end
+ if immr ~= 0 then
+ lo, hi = ror(lo, immr), ror(hi, immr)
+ local x = immr == 32 and 0 or band(bxor(lo, hi), lshift(-1, 32-immr))
+ lo, hi = bxor(lo, x), bxor(hi, x)
+ if immr >= 32 then lo, hi = hi, lo end
+ end
+ if hi ~= 0 then
+ return fmt_hex32(hi)..tohex(lo)
+ else
+ return fmt_hex32(lo)
+ end
+ end
+end
+
+local function parse_immpc(op, name)
+ if name == "b" or name == "bl" then
+ return arshift(lshift(op, 6), 4)
+ elseif name == "adr" or name == "adrp" then
+ local immlo = band(rshift(op, 29), 3)
+ local immhi = lshift(arshift(lshift(op, 8), 13), 2)
+ return bor(immhi, immlo)
+ elseif name == "tbz" or name == "tbnz" then
+ return lshift(arshift(lshift(op, 13), 18), 2)
+ else
+ return lshift(arshift(lshift(op, 8), 13), 2)
+ end
+end
+
+local function parse_fpimm8(op)
+ local sign = band(op, 0x100000) == 0 and 1 or -1
+ local exp = bxor(rshift(arshift(lshift(op, 12), 5), 24), 0x80) - 131
+ local frac = 16+band(rshift(op, 13), 15)
+ return sign * frac * 2^exp
+end
+
+local function prefer_bfx(sf, uns, imms, immr)
+ if imms < immr or imms == 31 or imms == 63 then
+ return false
+ end
+ if immr == 0 then
+ if sf == 0 and (imms == 7 or imms == 15) then
+ return false
+ end
+ if sf ~= 0 and uns == 0 and (imms == 7 or imms == 15 or imms == 31) then
+ return false
+ end
+ end
+ return true
+end
+
+-- Disassemble a single instruction.
+local function disass_ins(ctx)
+ local pos = ctx.pos
+ local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
+ local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
+ local operands = {}
+ local suffix = ""
+ local last, name, pat
+ local map_reg
+ ctx.op = op
+ ctx.rel = nil
+ last = nil
+ local opat
+ opat = map_init[band(rshift(op, 25), 15)]
+ while type(opat) ~= "string" do
+ if not opat then return unknown(ctx) end
+ opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
+ end
+ name, pat = match(opat, "^([a-z0-9]*)(.*)")
+ local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)")
+ if altname then pat = pat2 end
+ if sub(pat, 1, 1) == "." then
+ local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)")
+ suffix = suffix..s2
+ pat = p2
+ end
+
+ local rt = match(pat, "[gf]")
+ if rt then
+ if rt == "g" then
+ map_reg = band(op, 0x80000000) ~= 0 and map_regs.x or map_regs.w
+ else
+ map_reg = band(op, 0x400000) ~= 0 and map_regs.d or map_regs.s
+ end
+ end
+
+ local second0, immr
+
+ for p in gmatch(pat, ".") do
+ local x = nil
+ if p == "D" then
+ local regnum = band(op, 31)
+ x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
+ elseif p == "N" then
+ local regnum = band(rshift(op, 5), 31)
+ x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
+ elseif p == "M" then
+ local regnum = band(rshift(op, 16), 31)
+ x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
+ elseif p == "A" then
+ local regnum = band(rshift(op, 10), 31)
+ x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
+ elseif p == "B" then
+ local addr = ctx.addr + pos + parse_immpc(op, name)
+ ctx.rel = addr
+ x = "0x"..tohex(addr)
+ elseif p == "T" then
+ x = bor(band(rshift(op, 26), 32), band(rshift(op, 19), 31))
+ elseif p == "V" then
+ x = band(op, 15)
+ elseif p == "C" then
+ x = map_cond[band(rshift(op, 12), 15)]
+ elseif p == "c" then
+ local rn = band(rshift(op, 5), 31)
+ local rm = band(rshift(op, 16), 31)
+ local cond = band(rshift(op, 12), 15)
+ local invc = bxor(cond, 1)
+ x = map_cond[cond]
+ if altname and cond ~= 14 and cond ~= 15 then
+ local a1, a2 = match(altname, "([^|]*)|(.*)")
+ if rn == rm then
+ local n = #operands
+ operands[n] = nil
+ x = map_cond[invc]
+ if rn ~= 31 then
+ if a1 then name = a1 else name = altname end
+ else
+ operands[n-1] = nil
+ name = a2
+ end
+ end
+ end
+ elseif p == "W" then
+ x = band(rshift(op, 5), 0xffff)
+ elseif p == "Y" then
+ x = band(rshift(op, 5), 0xffff)
+ local hw = band(rshift(op, 21), 3)
+ if altname and (hw == 0 or x ~= 0) then
+ name = altname
+ end
+ elseif p == "L" then
+ local rn = map_regs.x[band(rshift(op, 5), 31)]
+ local imm9 = arshift(lshift(op, 11), 23)
+ if band(op, 0x800) ~= 0 then
+ x = "["..rn..", #"..imm9.."]!"
+ else
+ x = "["..rn.."], #"..imm9
+ end
+ elseif p == "U" then
+ local rn = map_regs.x[band(rshift(op, 5), 31)]
+ local sz = band(rshift(op, 30), 3)
+ local imm12 = lshift(arshift(lshift(op, 10), 20), sz)
+ if imm12 ~= 0 then
+ x = "["..rn..", #"..imm12.."]"
+ else
+ x = "["..rn.."]"
+ end
+ elseif p == "K" then
+ local rn = map_regs.x[band(rshift(op, 5), 31)]
+ local imm9 = arshift(lshift(op, 11), 23)
+ if imm9 ~= 0 then
+ x = "["..rn..", #"..imm9.."]"
+ else
+ x = "["..rn.."]"
+ end
+ elseif p == "O" then
+ local rn, rm = map_regs.x[band(rshift(op, 5), 31)]
+ local m = band(rshift(op, 13), 1)
+ if m == 0 then
+ rm = map_regs.w[band(rshift(op, 16), 31)]
+ else
+ rm = map_regs.x[band(rshift(op, 16), 31)]
+ end
+ x = "["..rn..", "..rm
+ local opt = band(rshift(op, 13), 7)
+ local s = band(rshift(op, 12), 1)
+ local sz = band(rshift(op, 30), 3)
+ -- extension to be applied
+ if opt == 3 then
+ if s == 0 then x = x.."]"
+ else x = x..", lsl #"..sz.."]" end
+ elseif opt == 2 or opt == 6 or opt == 7 then
+ if s == 0 then x = x..", "..map_extend[opt].."]"
+ else x = x..", "..map_extend[opt].." #"..sz.."]" end
+ else
+ x = x.."]"
+ end
+ elseif p == "P" then
+ local opcv, sh = rshift(op, 26), 2
+ if opcv >= 0x2a then sh = 4 elseif opcv >= 0x1b then sh = 3 end
+ local imm7 = lshift(arshift(lshift(op, 10), 25), sh)
+ local rn = map_regs.x[band(rshift(op, 5), 31)]
+ local ind = band(rshift(op, 23), 3)
+ if ind == 1 then
+ x = "["..rn.."], #"..imm7
+ elseif ind == 2 then
+ if imm7 == 0 then
+ x = "["..rn.."]"
+ else
+ x = "["..rn..", #"..imm7.."]"
+ end
+ elseif ind == 3 then
+ x = "["..rn..", #"..imm7.."]!"
+ end
+ elseif p == "I" then
+ local shf = band(rshift(op, 22), 3)
+ local imm12 = band(rshift(op, 10), 0x0fff)
+ local rn, rd = band(rshift(op, 5), 31), band(op, 31)
+ if altname == "mov" and shf == 0 and imm12 == 0 and (rn == 31 or rd == 31) then
+ name = altname
+ x = nil
+ elseif shf == 0 then
+ x = imm12
+ elseif shf == 1 then
+ x = imm12..", lsl #12"
+ end
+ elseif p == "i" then
+ x = "#0x"..decode_imm13(op)
+ elseif p == "1" then
+ immr = band(rshift(op, 16), 63)
+ x = immr
+ elseif p == "2" then
+ x = band(rshift(op, 10), 63)
+ if altname then
+ local a1, a2, a3, a4, a5, a6 =
+ match(altname, "([^|]*)|([^|]*)|([^|]*)|([^|]*)|([^|]*)|(.*)")
+ local sf = band(rshift(op, 26), 32)
+ local uns = band(rshift(op, 30), 1)
+ if prefer_bfx(sf, uns, x, immr) then
+ name = a2
+ x = x - immr + 1
+ elseif immr == 0 and x == 7 then
+ local n = #operands
+ operands[n] = nil
+ if sf ~= 0 then
+ operands[n-1] = gsub(operands[n-1], "x", "w")
+ end
+ last = operands[n-1]
+ name = a6
+ x = nil
+ elseif immr == 0 and x == 15 then
+ local n = #operands
+ operands[n] = nil
+ if sf ~= 0 then
+ operands[n-1] = gsub(operands[n-1], "x", "w")
+ end
+ last = operands[n-1]
+ name = a5
+ x = nil
+ elseif x == 31 or x == 63 then
+ if x == 31 and immr == 0 and name == "sbfm" then
+ name = a4
+ local n = #operands
+ operands[n] = nil
+ if sf ~= 0 then
+ operands[n-1] = gsub(operands[n-1], "x", "w")
+ end
+ last = operands[n-1]
+ else
+ name = a3
+ end
+ x = nil
+ elseif band(x, 31) ~= 31 and immr == x+1 and name == "ubfm" then
+ name = a4
+ last = "#"..(sf+32 - immr)
+ operands[#operands] = last
+ x = nil
+ elseif x < immr then
+ name = a1
+ last = "#"..(sf+32 - immr)
+ operands[#operands] = last
+ x = x + 1
+ end
+ end
+ elseif p == "3" then
+ x = band(rshift(op, 10), 63)
+ if altname then
+ local a1, a2 = match(altname, "([^|]*)|(.*)")
+ if x < immr then
+ name = a1
+ local sf = band(rshift(op, 26), 32)
+ last = "#"..(sf+32 - immr)
+ operands[#operands] = last
+ x = x + 1
+ elseif x >= immr then
+ name = a2
+ x = x - immr + 1
+ end
+ end
+ elseif p == "4" then
+ x = band(rshift(op, 10), 63)
+ local rn = band(rshift(op, 5), 31)
+ local rm = band(rshift(op, 16), 31)
+ if altname and rn == rm then
+ local n = #operands
+ operands[n] = nil
+ last = operands[n-1]
+ name = altname
+ end
+ elseif p == "5" then
+ x = band(rshift(op, 16), 31)
+ elseif p == "S" then
+ x = band(rshift(op, 10), 63)
+ if x == 0 then x = nil
+ else x = map_shift[band(rshift(op, 22), 3)].." #"..x end
+ elseif p == "X" then
+ local opt = band(rshift(op, 13), 7)
+ -- Width specifier .
+ if opt ~= 3 and opt ~= 7 then
+ last = map_regs.w[band(rshift(op, 16), 31)]
+ operands[#operands] = last
+ end
+ x = band(rshift(op, 10), 7)
+ -- Extension.
+ if opt == 2 + band(rshift(op, 31), 1) and
+ band(rshift(op, second0 and 5 or 0), 31) == 31 then
+ if x == 0 then x = nil
+ else x = "lsl #"..x end
+ else
+ if x == 0 then x = map_extend[band(rshift(op, 13), 7)]
+ else x = map_extend[band(rshift(op, 13), 7)].." #"..x end
+ end
+ elseif p == "R" then
+ x = band(rshift(op,21), 3)
+ if x == 0 then x = nil
+ else x = "lsl #"..x*16 end
+ elseif p == "z" then
+ local n = #operands
+ if operands[n] == "sp" then operands[n] = "xzr"
+ elseif operands[n] == "wsp" then operands[n] = "wzr"
+ end
+ elseif p == "Z" then
+ x = 0
+ elseif p == "F" then
+ x = parse_fpimm8(op)
+ elseif p == "g" or p == "f" or p == "x" or p == "w" or
+ p == "d" or p == "s" then
+ -- These are handled in D/N/M/A.
+ elseif p == "0" then
+ if last == "sp" or last == "wsp" then
+ local n = #operands
+ operands[n] = nil
+ last = operands[n-1]
+ if altname then
+ local a1, a2 = match(altname, "([^|]*)|(.*)")
+ if not a1 then
+ name = altname
+ elseif second0 then
+ name, altname = a2, a1
+ else
+ name, altname = a1, a2
+ end
+ end
+ end
+ second0 = true
+ else
+ assert(false)
+ end
+ if x then
+ last = x
+ if type(x) == "number" then x = "#"..x end
+ operands[#operands+1] = x
+ end
+ end
+
+ return putop(ctx, name..suffix, operands)
+end
+
+------------------------------------------------------------------------------
+
+-- Disassemble a block of code.
+local function disass_block(ctx, ofs, len)
+ if not ofs then ofs = 0 end
+ local stop = len and ofs+len or #ctx.code
+ ctx.pos = ofs
+ ctx.rel = nil
+ while ctx.pos < stop do disass_ins(ctx) end
+end
+
+-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
+local function create(code, addr, out)
+ local ctx = {}
+ ctx.code = code
+ ctx.addr = addr or 0
+ ctx.out = out or io.write
+ ctx.symtab = {}
+ ctx.disass = disass_block
+ ctx.hexdump = 8
+ return ctx
+end
+
+-- Simple API: disassemble code (a string) at address and output via out.
+local function disass(code, addr, out)
+ create(code, addr, out):disass()
+end
+
+-- Return register name for RID.
+local function regname(r)
+ if r < 32 then return map_regs.x[r] end
+ return map_regs.d[r-32]
+end
+
+-- Public module functions.
+return {
+ create = create,
+ disass = disass,
+ regname = regname
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/jit/dis_arm64be.lua b/src/host/luajit-2.1.0-beta3/src/jit/dis_arm64be.lua
new file mode 100644
index 00000000..7eb389e2
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/jit/dis_arm64be.lua
@@ -0,0 +1,12 @@
+----------------------------------------------------------------------------
+-- LuaJIT ARM64BE disassembler wrapper module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- ARM64 instructions are always little-endian. So just forward to the
+-- common ARM64 disassembler module. All the interesting stuff is there.
+------------------------------------------------------------------------------
+
+return require((string.match(..., ".*%.") or "").."dis_arm64")
+
diff --git a/src/host/luajit-2.1.0-beta3/src/jit/dis_mips.lua b/src/host/luajit-2.1.0-beta3/src/jit/dis_mips.lua
new file mode 100644
index 00000000..a12b8e62
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/jit/dis_mips.lua
@@ -0,0 +1,443 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS disassembler module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- Released under the MIT/X license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This is a helper module used by the LuaJIT machine code dumper module.
+--
+-- It disassembles all standard MIPS32R1/R2 instructions.
+-- Default mode is big-endian, but see: dis_mipsel.lua
+------------------------------------------------------------------------------
+
+local type = type
+local byte, format = string.byte, string.format
+local match, gmatch = string.match, string.gmatch
+local concat = table.concat
+local bit = require("bit")
+local band, bor, tohex = bit.band, bit.bor, bit.tohex
+local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
+
+------------------------------------------------------------------------------
+-- Primary and extended opcode maps
+------------------------------------------------------------------------------
+
+local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", }
+local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", }
+local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", }
+
+local map_special = {
+ shift = 0, mask = 63,
+ [0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
+ map_movci, map_srl, "sraDTA",
+ "sllvDTS", false, map_srlv, "sravDTS",
+ "jrS", "jalrD1S", "movzDST", "movnDST",
+ "syscallY", "breakY", false, "sync",
+ "mfhiD", "mthiS", "mfloD", "mtloS",
+ "dsllvDST", false, "dsrlvDST", "dsravDST",
+ "multST", "multuST", "divST", "divuST",
+ "dmultST", "dmultuST", "ddivST", "ddivuST",
+ "addDST", "addu|moveDST0", "subDST", "subu|neguDS0T",
+ "andDST", "or|moveDST0", "xorDST", "nor|notDST0",
+ false, false, "sltDST", "sltuDST",
+ "daddDST", "dadduDST", "dsubDST", "dsubuDST",
+ "tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ",
+ "teqSTZ", false, "tneSTZ", false,
+ "dsllDTA", false, "dsrlDTA", "dsraDTA",
+ "dsll32DTA", false, "dsrl32DTA", "dsra32DTA",
+}
+
+local map_special2 = {
+ shift = 0, mask = 63,
+ [0] = "maddST", "madduST", "mulDST", false,
+ "msubST", "msubuST",
+ [32] = "clzDS", [33] = "cloDS",
+ [63] = "sdbbpY",
+}
+
+local map_bshfl = {
+ shift = 6, mask = 31,
+ [2] = "wsbhDT",
+ [16] = "sebDT",
+ [24] = "sehDT",
+}
+
+local map_dbshfl = {
+ shift = 6, mask = 31,
+ [2] = "dsbhDT",
+ [5] = "dshdDT",
+}
+
+local map_special3 = {
+ shift = 0, mask = 63,
+ [0] = "extTSAK", [1] = "dextmTSAP", [3] = "dextTSAK",
+ [4] = "insTSAL", [6] = "dinsuTSEQ", [7] = "dinsTSAL",
+ [32] = map_bshfl, [36] = map_dbshfl, [59] = "rdhwrTD",
+}
+
+local map_regimm = {
+ shift = 16, mask = 31,
+ [0] = "bltzSB", "bgezSB", "bltzlSB", "bgezlSB",
+ false, false, false, false,
+ "tgeiSI", "tgeiuSI", "tltiSI", "tltiuSI",
+ "teqiSI", false, "tneiSI", false,
+ "bltzalSB", "bgezalSB", "bltzallSB", "bgezallSB",
+ false, false, false, false,
+ false, false, false, false,
+ false, false, false, "synciSO",
+}
+
+local map_cop0 = {
+ shift = 25, mask = 1,
+ [0] = {
+ shift = 21, mask = 15,
+ [0] = "mfc0TDW", [4] = "mtc0TDW",
+ [10] = "rdpgprDT",
+ [11] = { shift = 5, mask = 1, [0] = "diT0", "eiT0", },
+ [14] = "wrpgprDT",
+ }, {
+ shift = 0, mask = 63,
+ [1] = "tlbr", [2] = "tlbwi", [6] = "tlbwr", [8] = "tlbp",
+ [24] = "eret", [31] = "deret",
+ [32] = "wait",
+ },
+}
+
+local map_cop1s = {
+ shift = 0, mask = 63,
+ [0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH",
+ "sqrt.sFG", "abs.sFG", "mov.sFG", "neg.sFG",
+ "round.l.sFG", "trunc.l.sFG", "ceil.l.sFG", "floor.l.sFG",
+ "round.w.sFG", "trunc.w.sFG", "ceil.w.sFG", "floor.w.sFG",
+ false,
+ { shift = 16, mask = 1, [0] = "movf.sFGC", "movt.sFGC" },
+ "movz.sFGT", "movn.sFGT",
+ false, "recip.sFG", "rsqrt.sFG", false,
+ false, false, false, false,
+ false, false, false, false,
+ false, "cvt.d.sFG", false, false,
+ "cvt.w.sFG", "cvt.l.sFG", "cvt.ps.sFGH", false,
+ false, false, false, false,
+ false, false, false, false,
+ "c.f.sVGH", "c.un.sVGH", "c.eq.sVGH", "c.ueq.sVGH",
+ "c.olt.sVGH", "c.ult.sVGH", "c.ole.sVGH", "c.ule.sVGH",
+ "c.sf.sVGH", "c.ngle.sVGH", "c.seq.sVGH", "c.ngl.sVGH",
+ "c.lt.sVGH", "c.nge.sVGH", "c.le.sVGH", "c.ngt.sVGH",
+}
+
+local map_cop1d = {
+ shift = 0, mask = 63,
+ [0] = "add.dFGH", "sub.dFGH", "mul.dFGH", "div.dFGH",
+ "sqrt.dFG", "abs.dFG", "mov.dFG", "neg.dFG",
+ "round.l.dFG", "trunc.l.dFG", "ceil.l.dFG", "floor.l.dFG",
+ "round.w.dFG", "trunc.w.dFG", "ceil.w.dFG", "floor.w.dFG",
+ false,
+ { shift = 16, mask = 1, [0] = "movf.dFGC", "movt.dFGC" },
+ "movz.dFGT", "movn.dFGT",
+ false, "recip.dFG", "rsqrt.dFG", false,
+ false, false, false, false,
+ false, false, false, false,
+ "cvt.s.dFG", false, false, false,
+ "cvt.w.dFG", "cvt.l.dFG", false, false,
+ false, false, false, false,
+ false, false, false, false,
+ "c.f.dVGH", "c.un.dVGH", "c.eq.dVGH", "c.ueq.dVGH",
+ "c.olt.dVGH", "c.ult.dVGH", "c.ole.dVGH", "c.ule.dVGH",
+ "c.df.dVGH", "c.ngle.dVGH", "c.deq.dVGH", "c.ngl.dVGH",
+ "c.lt.dVGH", "c.nge.dVGH", "c.le.dVGH", "c.ngt.dVGH",
+}
+
+local map_cop1ps = {
+ shift = 0, mask = 63,
+ [0] = "add.psFGH", "sub.psFGH", "mul.psFGH", false,
+ false, "abs.psFG", "mov.psFG", "neg.psFG",
+ false, false, false, false,
+ false, false, false, false,
+ false,
+ { shift = 16, mask = 1, [0] = "movf.psFGC", "movt.psFGC" },
+ "movz.psFGT", "movn.psFGT",
+ false, false, false, false,
+ false, false, false, false,
+ false, false, false, false,
+ "cvt.s.puFG", false, false, false,
+ false, false, false, false,
+ "cvt.s.plFG", false, false, false,
+ "pll.psFGH", "plu.psFGH", "pul.psFGH", "puu.psFGH",
+ "c.f.psVGH", "c.un.psVGH", "c.eq.psVGH", "c.ueq.psVGH",
+ "c.olt.psVGH", "c.ult.psVGH", "c.ole.psVGH", "c.ule.psVGH",
+ "c.psf.psVGH", "c.ngle.psVGH", "c.pseq.psVGH", "c.ngl.psVGH",
+ "c.lt.psVGH", "c.nge.psVGH", "c.le.psVGH", "c.ngt.psVGH",
+}
+
+local map_cop1w = {
+ shift = 0, mask = 63,
+ [32] = "cvt.s.wFG", [33] = "cvt.d.wFG",
+}
+
+local map_cop1l = {
+ shift = 0, mask = 63,
+ [32] = "cvt.s.lFG", [33] = "cvt.d.lFG",
+}
+
+local map_cop1bc = {
+ shift = 16, mask = 3,
+ [0] = "bc1fCB", "bc1tCB", "bc1flCB", "bc1tlCB",
+}
+
+local map_cop1 = {
+ shift = 21, mask = 31,
+ [0] = "mfc1TG", "dmfc1TG", "cfc1TG", "mfhc1TG",
+ "mtc1TG", "dmtc1TG", "ctc1TG", "mthc1TG",
+ map_cop1bc, false, false, false,
+ false, false, false, false,
+ map_cop1s, map_cop1d, false, false,
+ map_cop1w, map_cop1l, map_cop1ps,
+}
+
+local map_cop1x = {
+ shift = 0, mask = 63,
+ [0] = "lwxc1FSX", "ldxc1FSX", false, false,
+ false, "luxc1FSX", false, false,
+ "swxc1FSX", "sdxc1FSX", false, false,
+ false, "suxc1FSX", false, "prefxMSX",
+ false, false, false, false,
+ false, false, false, false,
+ false, false, false, false,
+ false, false, "alnv.psFGHS", false,
+ "madd.sFRGH", "madd.dFRGH", false, false,
+ false, false, "madd.psFRGH", false,
+ "msub.sFRGH", "msub.dFRGH", false, false,
+ false, false, "msub.psFRGH", false,
+ "nmadd.sFRGH", "nmadd.dFRGH", false, false,
+ false, false, "nmadd.psFRGH", false,
+ "nmsub.sFRGH", "nmsub.dFRGH", false, false,
+ false, false, "nmsub.psFRGH", false,
+}
+
+local map_pri = {
+ [0] = map_special, map_regimm, "jJ", "jalJ",
+ "beq|beqz|bST00B", "bne|bnezST0B", "blezSB", "bgtzSB",
+ "addiTSI", "addiu|liTS0I", "sltiTSI", "sltiuTSI",
+ "andiTSU", "ori|liTS0U", "xoriTSU", "luiTU",
+ map_cop0, map_cop1, false, map_cop1x,
+ "beql|beqzlST0B", "bnel|bnezlST0B", "blezlSB", "bgtzlSB",
+ "daddiTSI", "daddiuTSI", false, false,
+ map_special2, "jalxJ", false, map_special3,
+ "lbTSO", "lhTSO", "lwlTSO", "lwTSO",
+ "lbuTSO", "lhuTSO", "lwrTSO", false,
+ "sbTSO", "shTSO", "swlTSO", "swTSO",
+ false, false, "swrTSO", "cacheNSO",
+ "llTSO", "lwc1HSO", "lwc2TSO", "prefNSO",
+ false, "ldc1HSO", "ldc2TSO", "ldTSO",
+ "scTSO", "swc1HSO", "swc2TSO", false,
+ false, "sdc1HSO", "sdc2TSO", "sdTSO",
+}
+
+------------------------------------------------------------------------------
+
+local map_gpr = {
+ [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "sp", "r30", "ra",
+}
+
+------------------------------------------------------------------------------
+
+-- Output a nicely formatted line with an opcode and operands.
+local function putop(ctx, text, operands)
+ local pos = ctx.pos
+ local extra = ""
+ if ctx.rel then
+ local sym = ctx.symtab[ctx.rel]
+ if sym then extra = "\t->"..sym end
+ end
+ if ctx.hexdump > 0 then
+ ctx.out(format("%08x %s %-7s %s%s\n",
+ ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
+ else
+ ctx.out(format("%08x %-7s %s%s\n",
+ ctx.addr+pos, text, concat(operands, ", "), extra))
+ end
+ ctx.pos = pos + 4
+end
+
+-- Fallback for unknown opcodes.
+local function unknown(ctx)
+ return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
+end
+
+local function get_be(ctx)
+ local pos = ctx.pos
+ local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
+ return bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3)
+end
+
+local function get_le(ctx)
+ local pos = ctx.pos
+ local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
+ return bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
+end
+
+-- Disassemble a single instruction.
+local function disass_ins(ctx)
+ local op = ctx:get()
+ local operands = {}
+ local last = nil
+ ctx.op = op
+ ctx.rel = nil
+
+ local opat = map_pri[rshift(op, 26)]
+ while type(opat) ~= "string" do
+ if not opat then return unknown(ctx) end
+ opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
+ end
+ local name, pat = match(opat, "^([a-z0-9_.]*)(.*)")
+ local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)")
+ if altname then pat = pat2 end
+
+ for p in gmatch(pat, ".") do
+ local x = nil
+ if p == "S" then
+ x = map_gpr[band(rshift(op, 21), 31)]
+ elseif p == "T" then
+ x = map_gpr[band(rshift(op, 16), 31)]
+ elseif p == "D" then
+ x = map_gpr[band(rshift(op, 11), 31)]
+ elseif p == "F" then
+ x = "f"..band(rshift(op, 6), 31)
+ elseif p == "G" then
+ x = "f"..band(rshift(op, 11), 31)
+ elseif p == "H" then
+ x = "f"..band(rshift(op, 16), 31)
+ elseif p == "R" then
+ x = "f"..band(rshift(op, 21), 31)
+ elseif p == "A" then
+ x = band(rshift(op, 6), 31)
+ elseif p == "E" then
+ x = band(rshift(op, 6), 31) + 32
+ elseif p == "M" then
+ x = band(rshift(op, 11), 31)
+ elseif p == "N" then
+ x = band(rshift(op, 16), 31)
+ elseif p == "C" then
+ x = band(rshift(op, 18), 7)
+ if x == 0 then x = nil end
+ elseif p == "K" then
+ x = band(rshift(op, 11), 31) + 1
+ elseif p == "P" then
+ x = band(rshift(op, 11), 31) + 33
+ elseif p == "L" then
+ x = band(rshift(op, 11), 31) - last + 1
+ elseif p == "Q" then
+ x = band(rshift(op, 11), 31) - last + 33
+ elseif p == "I" then
+ x = arshift(lshift(op, 16), 16)
+ elseif p == "U" then
+ x = band(op, 0xffff)
+ elseif p == "O" then
+ local disp = arshift(lshift(op, 16), 16)
+ operands[#operands] = format("%d(%s)", disp, last)
+ elseif p == "X" then
+ local index = map_gpr[band(rshift(op, 16), 31)]
+ operands[#operands] = format("%s(%s)", index, last)
+ elseif p == "B" then
+ x = ctx.addr + ctx.pos + arshift(lshift(op, 16), 16)*4 + 4
+ ctx.rel = x
+ x = format("0x%08x", x)
+ elseif p == "J" then
+ local a = ctx.addr + ctx.pos
+ x = a - band(a, 0x0fffffff) + band(op, 0x03ffffff)*4
+ ctx.rel = x
+ x = format("0x%08x", x)
+ elseif p == "V" then
+ x = band(rshift(op, 8), 7)
+ if x == 0 then x = nil end
+ elseif p == "W" then
+ x = band(op, 7)
+ if x == 0 then x = nil end
+ elseif p == "Y" then
+ x = band(rshift(op, 6), 0x000fffff)
+ if x == 0 then x = nil end
+ elseif p == "Z" then
+ x = band(rshift(op, 6), 1023)
+ if x == 0 then x = nil end
+ elseif p == "0" then
+ if last == "r0" or last == 0 then
+ local n = #operands
+ operands[n] = nil
+ last = operands[n-1]
+ if altname then
+ local a1, a2 = match(altname, "([^|]*)|(.*)")
+ if a1 then name, altname = a1, a2
+ else name = altname end
+ end
+ end
+ elseif p == "1" then
+ if last == "ra" then
+ operands[#operands] = nil
+ end
+ else
+ assert(false)
+ end
+ if x then operands[#operands+1] = x; last = x end
+ end
+
+ return putop(ctx, name, operands)
+end
+
+------------------------------------------------------------------------------
+
+-- Disassemble a block of code.
+local function disass_block(ctx, ofs, len)
+ if not ofs then ofs = 0 end
+ local stop = len and ofs+len or #ctx.code
+ stop = stop - stop % 4
+ ctx.pos = ofs - ofs % 4
+ ctx.rel = nil
+ while ctx.pos < stop do disass_ins(ctx) end
+end
+
+-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
+local function create(code, addr, out)
+ local ctx = {}
+ ctx.code = code
+ ctx.addr = addr or 0
+ ctx.out = out or io.write
+ ctx.symtab = {}
+ ctx.disass = disass_block
+ ctx.hexdump = 8
+ ctx.get = get_be
+ return ctx
+end
+
+local function create_el(code, addr, out)
+ local ctx = create(code, addr, out)
+ ctx.get = get_le
+ return ctx
+end
+
+-- Simple API: disassemble code (a string) at address and output via out.
+local function disass(code, addr, out)
+ create(code, addr, out):disass()
+end
+
+local function disass_el(code, addr, out)
+ create_el(code, addr, out):disass()
+end
+
+-- Return register name for RID.
+local function regname(r)
+ if r < 32 then return map_gpr[r] end
+ return "f"..(r-32)
+end
+
+-- Public module functions.
+return {
+ create = create,
+ create_el = create_el,
+ disass = disass,
+ disass_el = disass_el,
+ regname = regname
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/jit/dis_mips64.lua b/src/host/luajit-2.1.0-beta3/src/jit/dis_mips64.lua
new file mode 100644
index 00000000..c4374928
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/jit/dis_mips64.lua
@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64 disassembler wrapper module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This module just exports the big-endian functions from the
+-- MIPS disassembler module. All the interesting stuff is there.
+------------------------------------------------------------------------------
+
+local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
+return {
+ create = dis_mips.create,
+ disass = dis_mips.disass,
+ regname = dis_mips.regname
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/jit/dis_mips64el.lua b/src/host/luajit-2.1.0-beta3/src/jit/dis_mips64el.lua
new file mode 100644
index 00000000..2b1470af
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/jit/dis_mips64el.lua
@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64EL disassembler wrapper module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This module just exports the little-endian functions from the
+-- MIPS disassembler module. All the interesting stuff is there.
+------------------------------------------------------------------------------
+
+local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
+return {
+ create = dis_mips.create_el,
+ disass = dis_mips.disass_el,
+ regname = dis_mips.regname
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/jit/dis_mipsel.lua b/src/host/luajit-2.1.0-beta3/src/jit/dis_mipsel.lua
new file mode 100644
index 00000000..f69b11f0
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/jit/dis_mipsel.lua
@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPSEL disassembler wrapper module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This module just exports the little-endian functions from the
+-- MIPS disassembler module. All the interesting stuff is there.
+------------------------------------------------------------------------------
+
+local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
+return {
+ create = dis_mips.create_el,
+ disass = dis_mips.disass_el,
+ regname = dis_mips.regname
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/jit/dis_ppc.lua b/src/host/luajit-2.1.0-beta3/src/jit/dis_ppc.lua
new file mode 100644
index 00000000..2aeb1b29
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/jit/dis_ppc.lua
@@ -0,0 +1,591 @@
+----------------------------------------------------------------------------
+-- LuaJIT PPC disassembler module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- Released under the MIT/X license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This is a helper module used by the LuaJIT machine code dumper module.
+--
+-- It disassembles all common, non-privileged 32/64 bit PowerPC instructions
+-- plus the e500 SPE instructions and some Cell/Xenon extensions.
+--
+-- NYI: VMX, VMX128
+------------------------------------------------------------------------------
+
+local type = type
+local byte, format = string.byte, string.format
+local match, gmatch, gsub = string.match, string.gmatch, string.gsub
+local concat = table.concat
+local bit = require("bit")
+local band, bor, tohex = bit.band, bit.bor, bit.tohex
+local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
+
+------------------------------------------------------------------------------
+-- Primary and extended opcode maps
+------------------------------------------------------------------------------
+
+local map_crops = {
+ shift = 1, mask = 1023,
+ [0] = "mcrfXX",
+ [33] = "crnor|crnotCCC=", [129] = "crandcCCC",
+ [193] = "crxor|crclrCCC%", [225] = "crnandCCC",
+ [257] = "crandCCC", [289] = "creqv|crsetCCC%",
+ [417] = "crorcCCC", [449] = "cror|crmoveCCC=",
+ [16] = "b_lrKB", [528] = "b_ctrKB",
+ [150] = "isync",
+}
+
+local map_rlwinm = setmetatable({
+ shift = 0, mask = -1,
+},
+{ __index = function(t, x)
+ local rot = band(rshift(x, 11), 31)
+ local mb = band(rshift(x, 6), 31)
+ local me = band(rshift(x, 1), 31)
+ if mb == 0 and me == 31-rot then
+ return "slwiRR~A."
+ elseif me == 31 and mb == 32-rot then
+ return "srwiRR~-A."
+ else
+ return "rlwinmRR~AAA."
+ end
+ end
+})
+
+local map_rld = {
+ shift = 2, mask = 7,
+ [0] = "rldiclRR~HM.", "rldicrRR~HM.", "rldicRR~HM.", "rldimiRR~HM.",
+ {
+ shift = 1, mask = 1,
+ [0] = "rldclRR~RM.", "rldcrRR~RM.",
+ },
+}
+
+local map_ext = setmetatable({
+ shift = 1, mask = 1023,
+
+ [0] = "cmp_YLRR", [32] = "cmpl_YLRR",
+ [4] = "twARR", [68] = "tdARR",
+
+ [8] = "subfcRRR.", [40] = "subfRRR.",
+ [104] = "negRR.", [136] = "subfeRRR.",
+ [200] = "subfzeRR.", [232] = "subfmeRR.",
+ [520] = "subfcoRRR.", [552] = "subfoRRR.",
+ [616] = "negoRR.", [648] = "subfeoRRR.",
+ [712] = "subfzeoRR.", [744] = "subfmeoRR.",
+
+ [9] = "mulhduRRR.", [73] = "mulhdRRR.", [233] = "mulldRRR.",
+ [457] = "divduRRR.", [489] = "divdRRR.",
+ [745] = "mulldoRRR.",
+ [969] = "divduoRRR.", [1001] = "divdoRRR.",
+
+ [10] = "addcRRR.", [138] = "addeRRR.",
+ [202] = "addzeRR.", [234] = "addmeRR.", [266] = "addRRR.",
+ [522] = "addcoRRR.", [650] = "addeoRRR.",
+ [714] = "addzeoRR.", [746] = "addmeoRR.", [778] = "addoRRR.",
+
+ [11] = "mulhwuRRR.", [75] = "mulhwRRR.", [235] = "mullwRRR.",
+ [459] = "divwuRRR.", [491] = "divwRRR.",
+ [747] = "mullwoRRR.",
+ [971] = "divwouRRR.", [1003] = "divwoRRR.",
+
+ [15] = "iselltRRR", [47] = "iselgtRRR", [79] = "iseleqRRR",
+
+ [144] = { shift = 20, mask = 1, [0] = "mtcrfRZ~", "mtocrfRZ~", },
+ [19] = { shift = 20, mask = 1, [0] = "mfcrR", "mfocrfRZ", },
+ [371] = { shift = 11, mask = 1023, [392] = "mftbR", [424] = "mftbuR", },
+ [339] = {
+ shift = 11, mask = 1023,
+ [32] = "mferR", [256] = "mflrR", [288] = "mfctrR", [16] = "mfspefscrR",
+ },
+ [467] = {
+ shift = 11, mask = 1023,
+ [32] = "mtxerR", [256] = "mtlrR", [288] = "mtctrR", [16] = "mtspefscrR",
+ },
+
+ [20] = "lwarxRR0R", [84] = "ldarxRR0R",
+
+ [21] = "ldxRR0R", [53] = "lduxRRR",
+ [149] = "stdxRR0R", [181] = "stduxRRR",
+ [341] = "lwaxRR0R", [373] = "lwauxRRR",
+
+ [23] = "lwzxRR0R", [55] = "lwzuxRRR",
+ [87] = "lbzxRR0R", [119] = "lbzuxRRR",
+ [151] = "stwxRR0R", [183] = "stwuxRRR",
+ [215] = "stbxRR0R", [247] = "stbuxRRR",
+ [279] = "lhzxRR0R", [311] = "lhzuxRRR",
+ [343] = "lhaxRR0R", [375] = "lhauxRRR",
+ [407] = "sthxRR0R", [439] = "sthuxRRR",
+
+ [54] = "dcbst-R0R", [86] = "dcbf-R0R",
+ [150] = "stwcxRR0R.", [214] = "stdcxRR0R.",
+ [246] = "dcbtst-R0R", [278] = "dcbt-R0R",
+ [310] = "eciwxRR0R", [438] = "ecowxRR0R",
+ [470] = "dcbi-RR",
+
+ [598] = {
+ shift = 21, mask = 3,
+ [0] = "sync", "lwsync", "ptesync",
+ },
+ [758] = "dcba-RR",
+ [854] = "eieio", [982] = "icbi-R0R", [1014] = "dcbz-R0R",
+
+ [26] = "cntlzwRR~", [58] = "cntlzdRR~",
+ [122] = "popcntbRR~",
+ [154] = "prtywRR~", [186] = "prtydRR~",
+
+ [28] = "andRR~R.", [60] = "andcRR~R.", [124] = "nor|notRR~R=.",
+ [284] = "eqvRR~R.", [316] = "xorRR~R.",
+ [412] = "orcRR~R.", [444] = "or|mrRR~R=.", [476] = "nandRR~R.",
+ [508] = "cmpbRR~R",
+
+ [512] = "mcrxrX",
+
+ [532] = "ldbrxRR0R", [660] = "stdbrxRR0R",
+
+ [533] = "lswxRR0R", [597] = "lswiRR0A",
+ [661] = "stswxRR0R", [725] = "stswiRR0A",
+
+ [534] = "lwbrxRR0R", [662] = "stwbrxRR0R",
+ [790] = "lhbrxRR0R", [918] = "sthbrxRR0R",
+
+ [535] = "lfsxFR0R", [567] = "lfsuxFRR",
+ [599] = "lfdxFR0R", [631] = "lfduxFRR",
+ [663] = "stfsxFR0R", [695] = "stfsuxFRR",
+ [727] = "stfdxFR0R", [759] = "stfduxFR0R",
+ [855] = "lfiwaxFR0R",
+ [983] = "stfiwxFR0R",
+
+ [24] = "slwRR~R.",
+
+ [27] = "sldRR~R.", [536] = "srwRR~R.",
+ [792] = "srawRR~R.", [824] = "srawiRR~A.",
+
+ [794] = "sradRR~R.", [826] = "sradiRR~H.", [827] = "sradiRR~H.",
+ [922] = "extshRR~.", [954] = "extsbRR~.", [986] = "extswRR~.",
+
+ [539] = "srdRR~R.",
+},
+{ __index = function(t, x)
+ if band(x, 31) == 15 then return "iselRRRC" end
+ end
+})
+
+local map_ld = {
+ shift = 0, mask = 3,
+ [0] = "ldRRE", "lduRRE", "lwaRRE",
+}
+
+local map_std = {
+ shift = 0, mask = 3,
+ [0] = "stdRRE", "stduRRE",
+}
+
+local map_fps = {
+ shift = 5, mask = 1,
+ {
+ shift = 1, mask = 15,
+ [0] = false, false, "fdivsFFF.", false,
+ "fsubsFFF.", "faddsFFF.", "fsqrtsF-F.", false,
+ "fresF-F.", "fmulsFF-F.", "frsqrtesF-F.", false,
+ "fmsubsFFFF~.", "fmaddsFFFF~.", "fnmsubsFFFF~.", "fnmaddsFFFF~.",
+ }
+}
+
+local map_fpd = {
+ shift = 5, mask = 1,
+ [0] = {
+ shift = 1, mask = 1023,
+ [0] = "fcmpuXFF", [32] = "fcmpoXFF", [64] = "mcrfsXX",
+ [38] = "mtfsb1A.", [70] = "mtfsb0A.", [134] = "mtfsfiA>>-A>",
+ [8] = "fcpsgnFFF.", [40] = "fnegF-F.", [72] = "fmrF-F.",
+ [136] = "fnabsF-F.", [264] = "fabsF-F.",
+ [12] = "frspF-F.",
+ [14] = "fctiwF-F.", [15] = "fctiwzF-F.",
+ [583] = "mffsF.", [711] = "mtfsfZF.",
+ [392] = "frinF-F.", [424] = "frizF-F.",
+ [456] = "fripF-F.", [488] = "frimF-F.",
+ [814] = "fctidF-F.", [815] = "fctidzF-F.", [846] = "fcfidF-F.",
+ },
+ {
+ shift = 1, mask = 15,
+ [0] = false, false, "fdivFFF.", false,
+ "fsubFFF.", "faddFFF.", "fsqrtF-F.", "fselFFFF~.",
+ "freF-F.", "fmulFF-F.", "frsqrteF-F.", false,
+ "fmsubFFFF~.", "fmaddFFFF~.", "fnmsubFFFF~.", "fnmaddFFFF~.",
+ }
+}
+
+local map_spe = {
+ shift = 0, mask = 2047,
+
+ [512] = "evaddwRRR", [514] = "evaddiwRAR~",
+ [516] = "evsubwRRR~", [518] = "evsubiwRAR~",
+ [520] = "evabsRR", [521] = "evnegRR",
+ [522] = "evextsbRR", [523] = "evextshRR", [524] = "evrndwRR",
+ [525] = "evcntlzwRR", [526] = "evcntlswRR",
+
+ [527] = "brincRRR",
+
+ [529] = "evandRRR", [530] = "evandcRRR", [534] = "evxorRRR",
+ [535] = "evor|evmrRRR=", [536] = "evnor|evnotRRR=",
+ [537] = "eveqvRRR", [539] = "evorcRRR", [542] = "evnandRRR",
+
+ [544] = "evsrwuRRR", [545] = "evsrwsRRR",
+ [546] = "evsrwiuRRA", [547] = "evsrwisRRA",
+ [548] = "evslwRRR", [550] = "evslwiRRA",
+ [552] = "evrlwRRR", [553] = "evsplatiRS",
+ [554] = "evrlwiRRA", [555] = "evsplatfiRS",
+ [556] = "evmergehiRRR", [557] = "evmergeloRRR",
+ [558] = "evmergehiloRRR", [559] = "evmergelohiRRR",
+
+ [560] = "evcmpgtuYRR", [561] = "evcmpgtsYRR",
+ [562] = "evcmpltuYRR", [563] = "evcmpltsYRR",
+ [564] = "evcmpeqYRR",
+
+ [632] = "evselRRR", [633] = "evselRRRW",
+ [634] = "evselRRRW", [635] = "evselRRRW",
+ [636] = "evselRRRW", [637] = "evselRRRW",
+ [638] = "evselRRRW", [639] = "evselRRRW",
+
+ [640] = "evfsaddRRR", [641] = "evfssubRRR",
+ [644] = "evfsabsRR", [645] = "evfsnabsRR", [646] = "evfsnegRR",
+ [648] = "evfsmulRRR", [649] = "evfsdivRRR",
+ [652] = "evfscmpgtYRR", [653] = "evfscmpltYRR", [654] = "evfscmpeqYRR",
+ [656] = "evfscfuiR-R", [657] = "evfscfsiR-R",
+ [658] = "evfscfufR-R", [659] = "evfscfsfR-R",
+ [660] = "evfsctuiR-R", [661] = "evfsctsiR-R",
+ [662] = "evfsctufR-R", [663] = "evfsctsfR-R",
+ [664] = "evfsctuizR-R", [666] = "evfsctsizR-R",
+ [668] = "evfststgtYRR", [669] = "evfststltYRR", [670] = "evfststeqYRR",
+
+ [704] = "efsaddRRR", [705] = "efssubRRR",
+ [708] = "efsabsRR", [709] = "efsnabsRR", [710] = "efsnegRR",
+ [712] = "efsmulRRR", [713] = "efsdivRRR",
+ [716] = "efscmpgtYRR", [717] = "efscmpltYRR", [718] = "efscmpeqYRR",
+ [719] = "efscfdR-R",
+ [720] = "efscfuiR-R", [721] = "efscfsiR-R",
+ [722] = "efscfufR-R", [723] = "efscfsfR-R",
+ [724] = "efsctuiR-R", [725] = "efsctsiR-R",
+ [726] = "efsctufR-R", [727] = "efsctsfR-R",
+ [728] = "efsctuizR-R", [730] = "efsctsizR-R",
+ [732] = "efststgtYRR", [733] = "efststltYRR", [734] = "efststeqYRR",
+
+ [736] = "efdaddRRR", [737] = "efdsubRRR",
+ [738] = "efdcfuidR-R", [739] = "efdcfsidR-R",
+ [740] = "efdabsRR", [741] = "efdnabsRR", [742] = "efdnegRR",
+ [744] = "efdmulRRR", [745] = "efddivRRR",
+ [746] = "efdctuidzR-R", [747] = "efdctsidzR-R",
+ [748] = "efdcmpgtYRR", [749] = "efdcmpltYRR", [750] = "efdcmpeqYRR",
+ [751] = "efdcfsR-R",
+ [752] = "efdcfuiR-R", [753] = "efdcfsiR-R",
+ [754] = "efdcfufR-R", [755] = "efdcfsfR-R",
+ [756] = "efdctuiR-R", [757] = "efdctsiR-R",
+ [758] = "efdctufR-R", [759] = "efdctsfR-R",
+ [760] = "efdctuizR-R", [762] = "efdctsizR-R",
+ [764] = "efdtstgtYRR", [765] = "efdtstltYRR", [766] = "efdtsteqYRR",
+
+ [768] = "evlddxRR0R", [769] = "evlddRR8",
+ [770] = "evldwxRR0R", [771] = "evldwRR8",
+ [772] = "evldhxRR0R", [773] = "evldhRR8",
+ [776] = "evlhhesplatxRR0R", [777] = "evlhhesplatRR2",
+ [780] = "evlhhousplatxRR0R", [781] = "evlhhousplatRR2",
+ [782] = "evlhhossplatxRR0R", [783] = "evlhhossplatRR2",
+ [784] = "evlwhexRR0R", [785] = "evlwheRR4",
+ [788] = "evlwhouxRR0R", [789] = "evlwhouRR4",
+ [790] = "evlwhosxRR0R", [791] = "evlwhosRR4",
+ [792] = "evlwwsplatxRR0R", [793] = "evlwwsplatRR4",
+ [796] = "evlwhsplatxRR0R", [797] = "evlwhsplatRR4",
+
+ [800] = "evstddxRR0R", [801] = "evstddRR8",
+ [802] = "evstdwxRR0R", [803] = "evstdwRR8",
+ [804] = "evstdhxRR0R", [805] = "evstdhRR8",
+ [816] = "evstwhexRR0R", [817] = "evstwheRR4",
+ [820] = "evstwhoxRR0R", [821] = "evstwhoRR4",
+ [824] = "evstwwexRR0R", [825] = "evstwweRR4",
+ [828] = "evstwwoxRR0R", [829] = "evstwwoRR4",
+
+ [1027] = "evmhessfRRR", [1031] = "evmhossfRRR", [1032] = "evmheumiRRR",
+ [1033] = "evmhesmiRRR", [1035] = "evmhesmfRRR", [1036] = "evmhoumiRRR",
+ [1037] = "evmhosmiRRR", [1039] = "evmhosmfRRR", [1059] = "evmhessfaRRR",
+ [1063] = "evmhossfaRRR", [1064] = "evmheumiaRRR", [1065] = "evmhesmiaRRR",
+ [1067] = "evmhesmfaRRR", [1068] = "evmhoumiaRRR", [1069] = "evmhosmiaRRR",
+ [1071] = "evmhosmfaRRR", [1095] = "evmwhssfRRR", [1096] = "evmwlumiRRR",
+ [1100] = "evmwhumiRRR", [1101] = "evmwhsmiRRR", [1103] = "evmwhsmfRRR",
+ [1107] = "evmwssfRRR", [1112] = "evmwumiRRR", [1113] = "evmwsmiRRR",
+ [1115] = "evmwsmfRRR", [1127] = "evmwhssfaRRR", [1128] = "evmwlumiaRRR",
+ [1132] = "evmwhumiaRRR", [1133] = "evmwhsmiaRRR", [1135] = "evmwhsmfaRRR",
+ [1139] = "evmwssfaRRR", [1144] = "evmwumiaRRR", [1145] = "evmwsmiaRRR",
+ [1147] = "evmwsmfaRRR",
+
+ [1216] = "evaddusiaawRR", [1217] = "evaddssiaawRR",
+ [1218] = "evsubfusiaawRR", [1219] = "evsubfssiaawRR",
+ [1220] = "evmraRR",
+ [1222] = "evdivwsRRR", [1223] = "evdivwuRRR",
+ [1224] = "evaddumiaawRR", [1225] = "evaddsmiaawRR",
+ [1226] = "evsubfumiaawRR", [1227] = "evsubfsmiaawRR",
+
+ [1280] = "evmheusiaawRRR", [1281] = "evmhessiaawRRR",
+ [1283] = "evmhessfaawRRR", [1284] = "evmhousiaawRRR",
+ [1285] = "evmhossiaawRRR", [1287] = "evmhossfaawRRR",
+ [1288] = "evmheumiaawRRR", [1289] = "evmhesmiaawRRR",
+ [1291] = "evmhesmfaawRRR", [1292] = "evmhoumiaawRRR",
+ [1293] = "evmhosmiaawRRR", [1295] = "evmhosmfaawRRR",
+ [1320] = "evmhegumiaaRRR", [1321] = "evmhegsmiaaRRR",
+ [1323] = "evmhegsmfaaRRR", [1324] = "evmhogumiaaRRR",
+ [1325] = "evmhogsmiaaRRR", [1327] = "evmhogsmfaaRRR",
+ [1344] = "evmwlusiaawRRR", [1345] = "evmwlssiaawRRR",
+ [1352] = "evmwlumiaawRRR", [1353] = "evmwlsmiaawRRR",
+ [1363] = "evmwssfaaRRR", [1368] = "evmwumiaaRRR",
+ [1369] = "evmwsmiaaRRR", [1371] = "evmwsmfaaRRR",
+ [1408] = "evmheusianwRRR", [1409] = "evmhessianwRRR",
+ [1411] = "evmhessfanwRRR", [1412] = "evmhousianwRRR",
+ [1413] = "evmhossianwRRR", [1415] = "evmhossfanwRRR",
+ [1416] = "evmheumianwRRR", [1417] = "evmhesmianwRRR",
+ [1419] = "evmhesmfanwRRR", [1420] = "evmhoumianwRRR",
+ [1421] = "evmhosmianwRRR", [1423] = "evmhosmfanwRRR",
+ [1448] = "evmhegumianRRR", [1449] = "evmhegsmianRRR",
+ [1451] = "evmhegsmfanRRR", [1452] = "evmhogumianRRR",
+ [1453] = "evmhogsmianRRR", [1455] = "evmhogsmfanRRR",
+ [1472] = "evmwlusianwRRR", [1473] = "evmwlssianwRRR",
+ [1480] = "evmwlumianwRRR", [1481] = "evmwlsmianwRRR",
+ [1491] = "evmwssfanRRR", [1496] = "evmwumianRRR",
+ [1497] = "evmwsmianRRR", [1499] = "evmwsmfanRRR",
+}
+
+local map_pri = {
+ [0] = false, false, "tdiARI", "twiARI",
+ map_spe, false, false, "mulliRRI",
+ "subficRRI", false, "cmpl_iYLRU", "cmp_iYLRI",
+ "addicRRI", "addic.RRI", "addi|liRR0I", "addis|lisRR0I",
+ "b_KBJ", "sc", "bKJ", map_crops,
+ "rlwimiRR~AAA.", map_rlwinm, false, "rlwnmRR~RAA.",
+ "oriNRR~U", "orisRR~U", "xoriRR~U", "xorisRR~U",
+ "andi.RR~U", "andis.RR~U", map_rld, map_ext,
+ "lwzRRD", "lwzuRRD", "lbzRRD", "lbzuRRD",
+ "stwRRD", "stwuRRD", "stbRRD", "stbuRRD",
+ "lhzRRD", "lhzuRRD", "lhaRRD", "lhauRRD",
+ "sthRRD", "sthuRRD", "lmwRRD", "stmwRRD",
+ "lfsFRD", "lfsuFRD", "lfdFRD", "lfduFRD",
+ "stfsFRD", "stfsuFRD", "stfdFRD", "stfduFRD",
+ false, false, map_ld, map_fps,
+ false, false, map_std, map_fpd,
+}
+
+------------------------------------------------------------------------------
+
+local map_gpr = {
+ [0] = "r0", "sp", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+}
+
+local map_cond = { [0] = "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", }
+
+-- Format a condition bit.
+local function condfmt(cond)
+ if cond <= 3 then
+ return map_cond[band(cond, 3)]
+ else
+ return format("4*cr%d+%s", rshift(cond, 2), map_cond[band(cond, 3)])
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Output a nicely formatted line with an opcode and operands.
+local function putop(ctx, text, operands)
+ local pos = ctx.pos
+ local extra = ""
+ if ctx.rel then
+ local sym = ctx.symtab[ctx.rel]
+ if sym then extra = "\t->"..sym end
+ end
+ if ctx.hexdump > 0 then
+ ctx.out(format("%08x %s %-7s %s%s\n",
+ ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
+ else
+ ctx.out(format("%08x %-7s %s%s\n",
+ ctx.addr+pos, text, concat(operands, ", "), extra))
+ end
+ ctx.pos = pos + 4
+end
+
+-- Fallback for unknown opcodes.
+local function unknown(ctx)
+ return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
+end
+
+-- Disassemble a single instruction.
+local function disass_ins(ctx)
+ local pos = ctx.pos
+ local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
+ local op = bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3)
+ local operands = {}
+ local last = nil
+ local rs = 21
+ ctx.op = op
+ ctx.rel = nil
+
+ local opat = map_pri[rshift(b0, 2)]
+ while type(opat) ~= "string" do
+ if not opat then return unknown(ctx) end
+ opat = opat[band(rshift(op, opat.shift), opat.mask)]
+ end
+ local name, pat = match(opat, "^([a-z0-9_.]*)(.*)")
+ local altname, pat2 = match(pat, "|([a-z0-9_.]*)(.*)")
+ if altname then pat = pat2 end
+
+ for p in gmatch(pat, ".") do
+ local x = nil
+ if p == "R" then
+ x = map_gpr[band(rshift(op, rs), 31)]
+ rs = rs - 5
+ elseif p == "F" then
+ x = "f"..band(rshift(op, rs), 31)
+ rs = rs - 5
+ elseif p == "A" then
+ x = band(rshift(op, rs), 31)
+ rs = rs - 5
+ elseif p == "S" then
+ x = arshift(lshift(op, 27-rs), 27)
+ rs = rs - 5
+ elseif p == "I" then
+ x = arshift(lshift(op, 16), 16)
+ elseif p == "U" then
+ x = band(op, 0xffff)
+ elseif p == "D" or p == "E" then
+ local disp = arshift(lshift(op, 16), 16)
+ if p == "E" then disp = band(disp, -4) end
+ if last == "r0" then last = "0" end
+ operands[#operands] = format("%d(%s)", disp, last)
+ elseif p >= "2" and p <= "8" then
+ local disp = band(rshift(op, rs), 31) * p
+ if last == "r0" then last = "0" end
+ operands[#operands] = format("%d(%s)", disp, last)
+ elseif p == "H" then
+ x = band(rshift(op, rs), 31) + lshift(band(op, 2), 4)
+ rs = rs - 5
+ elseif p == "M" then
+ x = band(rshift(op, rs), 31) + band(op, 0x20)
+ elseif p == "C" then
+ x = condfmt(band(rshift(op, rs), 31))
+ rs = rs - 5
+ elseif p == "B" then
+ local bo = rshift(op, 21)
+ local cond = band(rshift(op, 16), 31)
+ local cn = ""
+ rs = rs - 10
+ if band(bo, 4) == 0 then
+ cn = band(bo, 2) == 0 and "dnz" or "dz"
+ if band(bo, 0x10) == 0 then
+ cn = cn..(band(bo, 8) == 0 and "f" or "t")
+ end
+ if band(bo, 0x10) == 0 then x = condfmt(cond) end
+ name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+")
+ elseif band(bo, 0x10) == 0 then
+ cn = map_cond[band(cond, 3) + (band(bo, 8) == 0 and 4 or 0)]
+ if cond > 3 then x = "cr"..rshift(cond, 2) end
+ name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+")
+ end
+ name = gsub(name, "_", cn)
+ elseif p == "J" then
+ x = arshift(lshift(op, 27-rs), 29-rs)*4
+ if band(op, 2) == 0 then x = ctx.addr + pos + x end
+ ctx.rel = x
+ x = "0x"..tohex(x)
+ elseif p == "K" then
+ if band(op, 1) ~= 0 then name = name.."l" end
+ if band(op, 2) ~= 0 then name = name.."a" end
+ elseif p == "X" or p == "Y" then
+ x = band(rshift(op, rs+2), 7)
+ if x == 0 and p == "Y" then x = nil else x = "cr"..x end
+ rs = rs - 5
+ elseif p == "W" then
+ x = "cr"..band(op, 7)
+ elseif p == "Z" then
+ x = band(rshift(op, rs-4), 255)
+ rs = rs - 10
+ elseif p == ">" then
+ operands[#operands] = rshift(operands[#operands], 1)
+ elseif p == "0" then
+ if last == "r0" then
+ operands[#operands] = nil
+ if altname then name = altname end
+ end
+ elseif p == "L" then
+ name = gsub(name, "_", band(op, 0x00200000) ~= 0 and "d" or "w")
+ elseif p == "." then
+ if band(op, 1) == 1 then name = name.."." end
+ elseif p == "N" then
+ if op == 0x60000000 then name = "nop"; break end
+ elseif p == "~" then
+ local n = #operands
+ operands[n-1], operands[n] = operands[n], operands[n-1]
+ elseif p == "=" then
+ local n = #operands
+ if last == operands[n-1] then
+ operands[n] = nil
+ name = altname
+ end
+ elseif p == "%" then
+ local n = #operands
+ if last == operands[n-1] and last == operands[n-2] then
+ operands[n] = nil
+ operands[n-1] = nil
+ name = altname
+ end
+ elseif p == "-" then
+ rs = rs - 5
+ else
+ assert(false)
+ end
+ if x then operands[#operands+1] = x; last = x end
+ end
+
+ return putop(ctx, name, operands)
+end
+
+------------------------------------------------------------------------------
+
+-- Disassemble a block of code.
+local function disass_block(ctx, ofs, len)
+ if not ofs then ofs = 0 end
+ local stop = len and ofs+len or #ctx.code
+ stop = stop - stop % 4
+ ctx.pos = ofs - ofs % 4
+ ctx.rel = nil
+ while ctx.pos < stop do disass_ins(ctx) end
+end
+
+-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
+local function create(code, addr, out)
+ local ctx = {}
+ ctx.code = code
+ ctx.addr = addr or 0
+ ctx.out = out or io.write
+ ctx.symtab = {}
+ ctx.disass = disass_block
+ ctx.hexdump = 8
+ return ctx
+end
+
+-- Simple API: disassemble code (a string) at address and output via out.
+local function disass(code, addr, out)
+ create(code, addr, out):disass()
+end
+
+-- Return register name for RID.
+local function regname(r)
+ if r < 32 then return map_gpr[r] end
+ return "f"..(r-32)
+end
+
+-- Public module functions.
+return {
+ create = create,
+ disass = disass,
+ regname = regname
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/jit/dis_x64.lua b/src/host/luajit-2.1.0-beta3/src/jit/dis_x64.lua
new file mode 100644
index 00000000..d5714ee1
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/jit/dis_x64.lua
@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT x64 disassembler wrapper module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This module just exports the 64 bit functions from the combined
+-- x86/x64 disassembler module. All the interesting stuff is there.
+------------------------------------------------------------------------------
+
+local dis_x86 = require((string.match(..., ".*%.") or "").."dis_x86")
+return {
+ create = dis_x86.create64,
+ disass = dis_x86.disass64,
+ regname = dis_x86.regname64
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/jit/dis_x86.lua b/src/host/luajit-2.1.0-beta3/src/jit/dis_x86.lua
new file mode 100644
index 00000000..4371233d
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/jit/dis_x86.lua
@@ -0,0 +1,931 @@
+----------------------------------------------------------------------------
+-- LuaJIT x86/x64 disassembler module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This is a helper module used by the LuaJIT machine code dumper module.
+--
+-- Sending small code snippets to an external disassembler and mixing the
+-- output with our own stuff was too fragile. So I had to bite the bullet
+-- and write yet another x86 disassembler. Oh well ...
+--
+-- The output format is very similar to what ndisasm generates. But it has
+-- been developed independently by looking at the opcode tables from the
+-- Intel and AMD manuals. The supported instruction set is quite extensive
+-- and reflects what a current generation Intel or AMD CPU implements in
+-- 32 bit and 64 bit mode. Yes, this includes MMX, SSE, SSE2, SSE3, SSSE3,
+-- SSE4.1, SSE4.2, SSE4a, AVX, AVX2 and even privileged and hypervisor
+-- (VMX/SVM) instructions.
+--
+-- Notes:
+-- * The (useless) a16 prefix, 3DNow and pre-586 opcodes are unsupported.
+-- * No attempt at optimization has been made -- it's fast enough for my needs.
+------------------------------------------------------------------------------
+
+local type = type
+local sub, byte, format = string.sub, string.byte, string.format
+local match, gmatch, gsub = string.match, string.gmatch, string.gsub
+local lower, rep = string.lower, string.rep
+local bit = require("bit")
+local tohex = bit.tohex
+
+-- Map for 1st opcode byte in 32 bit mode. Ugly? Well ... read on.
+local map_opc1_32 = {
+--0x
+[0]="addBmr","addVmr","addBrm","addVrm","addBai","addVai","push es","pop es",
+"orBmr","orVmr","orBrm","orVrm","orBai","orVai","push cs","opc2*",
+--1x
+"adcBmr","adcVmr","adcBrm","adcVrm","adcBai","adcVai","push ss","pop ss",
+"sbbBmr","sbbVmr","sbbBrm","sbbVrm","sbbBai","sbbVai","push ds","pop ds",
+--2x
+"andBmr","andVmr","andBrm","andVrm","andBai","andVai","es:seg","daa",
+"subBmr","subVmr","subBrm","subVrm","subBai","subVai","cs:seg","das",
+--3x
+"xorBmr","xorVmr","xorBrm","xorVrm","xorBai","xorVai","ss:seg","aaa",
+"cmpBmr","cmpVmr","cmpBrm","cmpVrm","cmpBai","cmpVai","ds:seg","aas",
+--4x
+"incVR","incVR","incVR","incVR","incVR","incVR","incVR","incVR",
+"decVR","decVR","decVR","decVR","decVR","decVR","decVR","decVR",
+--5x
+"pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR",
+"popUR","popUR","popUR","popUR","popUR","popUR","popUR","popUR",
+--6x
+"sz*pushaw,pusha","sz*popaw,popa","boundVrm","arplWmr",
+"fs:seg","gs:seg","o16:","a16",
+"pushUi","imulVrmi","pushBs","imulVrms",
+"insb","insVS","outsb","outsVS",
+--7x
+"joBj","jnoBj","jbBj","jnbBj","jzBj","jnzBj","jbeBj","jaBj",
+"jsBj","jnsBj","jpeBj","jpoBj","jlBj","jgeBj","jleBj","jgBj",
+--8x
+"arith!Bmi","arith!Vmi","arith!Bmi","arith!Vms",
+"testBmr","testVmr","xchgBrm","xchgVrm",
+"movBmr","movVmr","movBrm","movVrm",
+"movVmg","leaVrm","movWgm","popUm",
+--9x
+"nop*xchgVaR|pause|xchgWaR|repne nop","xchgVaR","xchgVaR","xchgVaR",
+"xchgVaR","xchgVaR","xchgVaR","xchgVaR",
+"sz*cbw,cwde,cdqe","sz*cwd,cdq,cqo","call farViw","wait",
+"sz*pushfw,pushf","sz*popfw,popf","sahf","lahf",
+--Ax
+"movBao","movVao","movBoa","movVoa",
+"movsb","movsVS","cmpsb","cmpsVS",
+"testBai","testVai","stosb","stosVS",
+"lodsb","lodsVS","scasb","scasVS",
+--Bx
+"movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi",
+"movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI",
+--Cx
+"shift!Bmu","shift!Vmu","retBw","ret","vex*3$lesVrm","vex*2$ldsVrm","movBmi","movVmi",
+"enterBwu","leave","retfBw","retf","int3","intBu","into","iretVS",
+--Dx
+"shift!Bm1","shift!Vm1","shift!Bmc","shift!Vmc","aamBu","aadBu","salc","xlatb",
+"fp*0","fp*1","fp*2","fp*3","fp*4","fp*5","fp*6","fp*7",
+--Ex
+"loopneBj","loopeBj","loopBj","sz*jcxzBj,jecxzBj,jrcxzBj",
+"inBau","inVau","outBua","outVua",
+"callVj","jmpVj","jmp farViw","jmpBj","inBad","inVad","outBda","outVda",
+--Fx
+"lock:","int1","repne:rep","rep:","hlt","cmc","testb!Bm","testv!Vm",
+"clc","stc","cli","sti","cld","std","incb!Bm","incd!Vm",
+}
+assert(#map_opc1_32 == 255)
+
+-- Map for 1st opcode byte in 64 bit mode (overrides only).
+local map_opc1_64 = setmetatable({
+ [0x06]=false, [0x07]=false, [0x0e]=false,
+ [0x16]=false, [0x17]=false, [0x1e]=false, [0x1f]=false,
+ [0x27]=false, [0x2f]=false, [0x37]=false, [0x3f]=false,
+ [0x60]=false, [0x61]=false, [0x62]=false, [0x63]="movsxdVrDmt", [0x67]="a32:",
+ [0x40]="rex*", [0x41]="rex*b", [0x42]="rex*x", [0x43]="rex*xb",
+ [0x44]="rex*r", [0x45]="rex*rb", [0x46]="rex*rx", [0x47]="rex*rxb",
+ [0x48]="rex*w", [0x49]="rex*wb", [0x4a]="rex*wx", [0x4b]="rex*wxb",
+ [0x4c]="rex*wr", [0x4d]="rex*wrb", [0x4e]="rex*wrx", [0x4f]="rex*wrxb",
+ [0x82]=false, [0x9a]=false, [0xc4]="vex*3", [0xc5]="vex*2", [0xce]=false,
+ [0xd4]=false, [0xd5]=false, [0xd6]=false, [0xea]=false,
+}, { __index = map_opc1_32 })
+
+-- Map for 2nd opcode byte (0F xx). True CISC hell. Hey, I told you.
+-- Prefix dependent MMX/SSE opcodes: (none)|rep|o16|repne, -|F3|66|F2
+local map_opc2 = {
+--0x
+[0]="sldt!Dmp","sgdt!Ump","larVrm","lslVrm",nil,"syscall","clts","sysret",
+"invd","wbinvd",nil,"ud1",nil,"$prefetch!Bm","femms","3dnowMrmu",
+--1x
+"movupsXrm|movssXrvm|movupdXrm|movsdXrvm",
+"movupsXmr|movssXmvr|movupdXmr|movsdXmvr",
+"movhlpsXrm$movlpsXrm|movsldupXrm|movlpdXrm|movddupXrm",
+"movlpsXmr||movlpdXmr",
+"unpcklpsXrvm||unpcklpdXrvm",
+"unpckhpsXrvm||unpckhpdXrvm",
+"movlhpsXrm$movhpsXrm|movshdupXrm|movhpdXrm",
+"movhpsXmr||movhpdXmr",
+"$prefetcht!Bm","hintnopVm","hintnopVm","hintnopVm",
+"hintnopVm","hintnopVm","hintnopVm","hintnopVm",
+--2x
+"movUmx$","movUmy$","movUxm$","movUym$","movUmz$",nil,"movUzm$",nil,
+"movapsXrm||movapdXrm",
+"movapsXmr||movapdXmr",
+"cvtpi2psXrMm|cvtsi2ssXrvVmt|cvtpi2pdXrMm|cvtsi2sdXrvVmt",
+"movntpsXmr|movntssXmr|movntpdXmr|movntsdXmr",
+"cvttps2piMrXm|cvttss2siVrXm|cvttpd2piMrXm|cvttsd2siVrXm",
+"cvtps2piMrXm|cvtss2siVrXm|cvtpd2piMrXm|cvtsd2siVrXm",
+"ucomissXrm||ucomisdXrm",
+"comissXrm||comisdXrm",
+--3x
+"wrmsr","rdtsc","rdmsr","rdpmc","sysenter","sysexit",nil,"getsec",
+"opc3*38",nil,"opc3*3a",nil,nil,nil,nil,nil,
+--4x
+"cmovoVrm","cmovnoVrm","cmovbVrm","cmovnbVrm",
+"cmovzVrm","cmovnzVrm","cmovbeVrm","cmovaVrm",
+"cmovsVrm","cmovnsVrm","cmovpeVrm","cmovpoVrm",
+"cmovlVrm","cmovgeVrm","cmovleVrm","cmovgVrm",
+--5x
+"movmskpsVrXm$||movmskpdVrXm$","sqrtpsXrm|sqrtssXrm|sqrtpdXrm|sqrtsdXrm",
+"rsqrtpsXrm|rsqrtssXrvm","rcppsXrm|rcpssXrvm",
+"andpsXrvm||andpdXrvm","andnpsXrvm||andnpdXrvm",
+"orpsXrvm||orpdXrvm","xorpsXrvm||xorpdXrvm",
+"addpsXrvm|addssXrvm|addpdXrvm|addsdXrvm","mulpsXrvm|mulssXrvm|mulpdXrvm|mulsdXrvm",
+"cvtps2pdXrm|cvtss2sdXrvm|cvtpd2psXrm|cvtsd2ssXrvm",
+"cvtdq2psXrm|cvttps2dqXrm|cvtps2dqXrm",
+"subpsXrvm|subssXrvm|subpdXrvm|subsdXrvm","minpsXrvm|minssXrvm|minpdXrvm|minsdXrvm",
+"divpsXrvm|divssXrvm|divpdXrvm|divsdXrvm","maxpsXrvm|maxssXrvm|maxpdXrvm|maxsdXrvm",
+--6x
+"punpcklbwPrvm","punpcklwdPrvm","punpckldqPrvm","packsswbPrvm",
+"pcmpgtbPrvm","pcmpgtwPrvm","pcmpgtdPrvm","packuswbPrvm",
+"punpckhbwPrvm","punpckhwdPrvm","punpckhdqPrvm","packssdwPrvm",
+"||punpcklqdqXrvm","||punpckhqdqXrvm",
+"movPrVSm","movqMrm|movdquXrm|movdqaXrm",
+--7x
+"pshufwMrmu|pshufhwXrmu|pshufdXrmu|pshuflwXrmu","pshiftw!Pvmu",
+"pshiftd!Pvmu","pshiftq!Mvmu||pshiftdq!Xvmu",
+"pcmpeqbPrvm","pcmpeqwPrvm","pcmpeqdPrvm","emms*|",
+"vmreadUmr||extrqXmuu$|insertqXrmuu$","vmwriteUrm||extrqXrm$|insertqXrm$",
+nil,nil,
+"||haddpdXrvm|haddpsXrvm","||hsubpdXrvm|hsubpsXrvm",
+"movVSmMr|movqXrm|movVSmXr","movqMmr|movdquXmr|movdqaXmr",
+--8x
+"joVj","jnoVj","jbVj","jnbVj","jzVj","jnzVj","jbeVj","jaVj",
+"jsVj","jnsVj","jpeVj","jpoVj","jlVj","jgeVj","jleVj","jgVj",
+--9x
+"setoBm","setnoBm","setbBm","setnbBm","setzBm","setnzBm","setbeBm","setaBm",
+"setsBm","setnsBm","setpeBm","setpoBm","setlBm","setgeBm","setleBm","setgBm",
+--Ax
+"push fs","pop fs","cpuid","btVmr","shldVmru","shldVmrc",nil,nil,
+"push gs","pop gs","rsm","btsVmr","shrdVmru","shrdVmrc","fxsave!Dmp","imulVrm",
+--Bx
+"cmpxchgBmr","cmpxchgVmr","$lssVrm","btrVmr",
+"$lfsVrm","$lgsVrm","movzxVrBmt","movzxVrWmt",
+"|popcntVrm","ud2Dp","bt!Vmu","btcVmr",
+"bsfVrm","bsrVrm|lzcntVrm|bsrWrm","movsxVrBmt","movsxVrWmt",
+--Cx
+"xaddBmr","xaddVmr",
+"cmppsXrvmu|cmpssXrvmu|cmppdXrvmu|cmpsdXrvmu","$movntiVmr|",
+"pinsrwPrvWmu","pextrwDrPmu",
+"shufpsXrvmu||shufpdXrvmu","$cmpxchg!Qmp",
+"bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR",
+--Dx
+"||addsubpdXrvm|addsubpsXrvm","psrlwPrvm","psrldPrvm","psrlqPrvm",
+"paddqPrvm","pmullwPrvm",
+"|movq2dqXrMm|movqXmr|movdq2qMrXm$","pmovmskbVrMm||pmovmskbVrXm",
+"psubusbPrvm","psubuswPrvm","pminubPrvm","pandPrvm",
+"paddusbPrvm","padduswPrvm","pmaxubPrvm","pandnPrvm",
+--Ex
+"pavgbPrvm","psrawPrvm","psradPrvm","pavgwPrvm",
+"pmulhuwPrvm","pmulhwPrvm",
+"|cvtdq2pdXrm|cvttpd2dqXrm|cvtpd2dqXrm","$movntqMmr||$movntdqXmr",
+"psubsbPrvm","psubswPrvm","pminswPrvm","porPrvm",
+"paddsbPrvm","paddswPrvm","pmaxswPrvm","pxorPrvm",
+--Fx
+"|||lddquXrm","psllwPrvm","pslldPrvm","psllqPrvm",
+"pmuludqPrvm","pmaddwdPrvm","psadbwPrvm","maskmovqMrm||maskmovdquXrm$",
+"psubbPrvm","psubwPrvm","psubdPrvm","psubqPrvm",
+"paddbPrvm","paddwPrvm","padddPrvm","ud",
+}
+assert(map_opc2[255] == "ud")
+
+-- Map for three-byte opcodes. Can't wait for their next invention.
+local map_opc3 = {
+["38"] = { -- [66] 0f 38 xx
+--0x
+[0]="pshufbPrvm","phaddwPrvm","phadddPrvm","phaddswPrvm",
+"pmaddubswPrvm","phsubwPrvm","phsubdPrvm","phsubswPrvm",
+"psignbPrvm","psignwPrvm","psigndPrvm","pmulhrswPrvm",
+"||permilpsXrvm","||permilpdXrvm",nil,nil,
+--1x
+"||pblendvbXrma",nil,nil,nil,
+"||blendvpsXrma","||blendvpdXrma","||permpsXrvm","||ptestXrm",
+"||broadcastssXrm","||broadcastsdXrm","||broadcastf128XrlXm",nil,
+"pabsbPrm","pabswPrm","pabsdPrm",nil,
+--2x
+"||pmovsxbwXrm","||pmovsxbdXrm","||pmovsxbqXrm","||pmovsxwdXrm",
+"||pmovsxwqXrm","||pmovsxdqXrm",nil,nil,
+"||pmuldqXrvm","||pcmpeqqXrvm","||$movntdqaXrm","||packusdwXrvm",
+"||maskmovpsXrvm","||maskmovpdXrvm","||maskmovpsXmvr","||maskmovpdXmvr",
+--3x
+"||pmovzxbwXrm","||pmovzxbdXrm","||pmovzxbqXrm","||pmovzxwdXrm",
+"||pmovzxwqXrm","||pmovzxdqXrm","||permdXrvm","||pcmpgtqXrvm",
+"||pminsbXrvm","||pminsdXrvm","||pminuwXrvm","||pminudXrvm",
+"||pmaxsbXrvm","||pmaxsdXrvm","||pmaxuwXrvm","||pmaxudXrvm",
+--4x
+"||pmulddXrvm","||phminposuwXrm",nil,nil,
+nil,"||psrlvVSXrvm","||psravdXrvm","||psllvVSXrvm",
+--5x
+[0x58] = "||pbroadcastdXrlXm",[0x59] = "||pbroadcastqXrlXm",
+[0x5a] = "||broadcasti128XrlXm",
+--7x
+[0x78] = "||pbroadcastbXrlXm",[0x79] = "||pbroadcastwXrlXm",
+--8x
+[0x8c] = "||pmaskmovXrvVSm",
+[0x8e] = "||pmaskmovVSmXvr",
+--Dx
+[0xdc] = "||aesencXrvm", [0xdd] = "||aesenclastXrvm",
+[0xde] = "||aesdecXrvm", [0xdf] = "||aesdeclastXrvm",
+--Fx
+[0xf0] = "|||crc32TrBmt",[0xf1] = "|||crc32TrVmt",
+[0xf7] = "| sarxVrmv| shlxVrmv| shrxVrmv",
+},
+
+["3a"] = { -- [66] 0f 3a xx
+--0x
+[0x00]="||permqXrmu","||permpdXrmu","||pblenddXrvmu",nil,
+"||permilpsXrmu","||permilpdXrmu","||perm2f128Xrvmu",nil,
+"||roundpsXrmu","||roundpdXrmu","||roundssXrvmu","||roundsdXrvmu",
+"||blendpsXrvmu","||blendpdXrvmu","||pblendwXrvmu","palignrPrvmu",
+--1x
+nil,nil,nil,nil,
+"||pextrbVmXru","||pextrwVmXru","||pextrVmSXru","||extractpsVmXru",
+"||insertf128XrvlXmu","||extractf128XlXmYru",nil,nil,
+nil,nil,nil,nil,
+--2x
+"||pinsrbXrvVmu","||insertpsXrvmu","||pinsrXrvVmuS",nil,
+--3x
+[0x38] = "||inserti128Xrvmu",[0x39] = "||extracti128XlXmYru",
+--4x
+[0x40] = "||dppsXrvmu",
+[0x41] = "||dppdXrvmu",
+[0x42] = "||mpsadbwXrvmu",
+[0x44] = "||pclmulqdqXrvmu",
+[0x46] = "||perm2i128Xrvmu",
+[0x4a] = "||blendvpsXrvmb",[0x4b] = "||blendvpdXrvmb",
+[0x4c] = "||pblendvbXrvmb",
+--6x
+[0x60] = "||pcmpestrmXrmu",[0x61] = "||pcmpestriXrmu",
+[0x62] = "||pcmpistrmXrmu",[0x63] = "||pcmpistriXrmu",
+[0xdf] = "||aeskeygenassistXrmu",
+--Fx
+[0xf0] = "||| rorxVrmu",
+},
+}
+
+-- Map for VMX/SVM opcodes 0F 01 C0-FF (sgdt group with register operands).
+local map_opcvm = {
+[0xc1]="vmcall",[0xc2]="vmlaunch",[0xc3]="vmresume",[0xc4]="vmxoff",
+[0xc8]="monitor",[0xc9]="mwait",
+[0xd8]="vmrun",[0xd9]="vmmcall",[0xda]="vmload",[0xdb]="vmsave",
+[0xdc]="stgi",[0xdd]="clgi",[0xde]="skinit",[0xdf]="invlpga",
+[0xf8]="swapgs",[0xf9]="rdtscp",
+}
+
+-- Map for FP opcodes. And you thought stack machines are simple?
+local map_opcfp = {
+-- D8-DF 00-BF: opcodes with a memory operand.
+-- D8
+[0]="faddFm","fmulFm","fcomFm","fcompFm","fsubFm","fsubrFm","fdivFm","fdivrFm",
+"fldFm",nil,"fstFm","fstpFm","fldenvVm","fldcwWm","fnstenvVm","fnstcwWm",
+-- DA
+"fiaddDm","fimulDm","ficomDm","ficompDm",
+"fisubDm","fisubrDm","fidivDm","fidivrDm",
+-- DB
+"fildDm","fisttpDm","fistDm","fistpDm",nil,"fld twordFmp",nil,"fstp twordFmp",
+-- DC
+"faddGm","fmulGm","fcomGm","fcompGm","fsubGm","fsubrGm","fdivGm","fdivrGm",
+-- DD
+"fldGm","fisttpQm","fstGm","fstpGm","frstorDmp",nil,"fnsaveDmp","fnstswWm",
+-- DE
+"fiaddWm","fimulWm","ficomWm","ficompWm",
+"fisubWm","fisubrWm","fidivWm","fidivrWm",
+-- DF
+"fildWm","fisttpWm","fistWm","fistpWm",
+"fbld twordFmp","fildQm","fbstp twordFmp","fistpQm",
+-- xx C0-FF: opcodes with a pseudo-register operand.
+-- D8
+"faddFf","fmulFf","fcomFf","fcompFf","fsubFf","fsubrFf","fdivFf","fdivrFf",
+-- D9
+"fldFf","fxchFf",{"fnop"},nil,
+{"fchs","fabs",nil,nil,"ftst","fxam"},
+{"fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz"},
+{"f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp"},
+{"fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"},
+-- DA
+"fcmovbFf","fcmoveFf","fcmovbeFf","fcmovuFf",nil,{nil,"fucompp"},nil,nil,
+-- DB
+"fcmovnbFf","fcmovneFf","fcmovnbeFf","fcmovnuFf",
+{nil,nil,"fnclex","fninit"},"fucomiFf","fcomiFf",nil,
+-- DC
+"fadd toFf","fmul toFf",nil,nil,
+"fsub toFf","fsubr toFf","fdivr toFf","fdiv toFf",
+-- DD
+"ffreeFf",nil,"fstFf","fstpFf","fucomFf","fucompFf",nil,nil,
+-- DE
+"faddpFf","fmulpFf",nil,{nil,"fcompp"},
+"fsubrpFf","fsubpFf","fdivrpFf","fdivpFf",
+-- DF
+nil,nil,nil,nil,{"fnstsw ax"},"fucomipFf","fcomipFf",nil,
+}
+assert(map_opcfp[126] == "fcomipFf")
+
+-- Map for opcode groups. The subkey is sp from the ModRM byte.
+local map_opcgroup = {
+ arith = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" },
+ shift = { "rol", "ror", "rcl", "rcr", "shl", "shr", "sal", "sar" },
+ testb = { "testBmi", "testBmi", "not", "neg", "mul", "imul", "div", "idiv" },
+ testv = { "testVmi", "testVmi", "not", "neg", "mul", "imul", "div", "idiv" },
+ incb = { "inc", "dec" },
+ incd = { "inc", "dec", "callUmp", "$call farDmp",
+ "jmpUmp", "$jmp farDmp", "pushUm" },
+ sldt = { "sldt", "str", "lldt", "ltr", "verr", "verw" },
+ sgdt = { "vm*$sgdt", "vm*$sidt", "$lgdt", "vm*$lidt",
+ "smsw", nil, "lmsw", "vm*$invlpg" },
+ bt = { nil, nil, nil, nil, "bt", "bts", "btr", "btc" },
+ cmpxchg = { nil, "sz*,cmpxchg8bQmp,cmpxchg16bXmp", nil, nil,
+ nil, nil, "vmptrld|vmxon|vmclear", "vmptrst" },
+ pshiftw = { nil, nil, "psrlw", nil, "psraw", nil, "psllw" },
+ pshiftd = { nil, nil, "psrld", nil, "psrad", nil, "pslld" },
+ pshiftq = { nil, nil, "psrlq", nil, nil, nil, "psllq" },
+ pshiftdq = { nil, nil, "psrlq", "psrldq", nil, nil, "psllq", "pslldq" },
+ fxsave = { "$fxsave", "$fxrstor", "$ldmxcsr", "$stmxcsr",
+ nil, "lfenceDp$", "mfenceDp$", "sfenceDp$clflush" },
+ prefetch = { "prefetch", "prefetchw" },
+ prefetcht = { "prefetchnta", "prefetcht0", "prefetcht1", "prefetcht2" },
+}
+
+------------------------------------------------------------------------------
+
+-- Maps for register names.
+local map_regs = {
+ B = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh",
+ "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" },
+ B64 = { "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
+ "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" },
+ W = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
+ "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" },
+ D = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
+ "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" },
+ Q = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" },
+ M = { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
+ "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }, -- No x64 ext!
+ X = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
+ "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" },
+ Y = { "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7",
+ "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15" },
+}
+local map_segregs = { "es", "cs", "ss", "ds", "fs", "gs", "segr6", "segr7" }
+
+-- Maps for size names.
+local map_sz2n = {
+ B = 1, W = 2, D = 4, Q = 8, M = 8, X = 16, Y = 32,
+}
+local map_sz2prefix = {
+ B = "byte", W = "word", D = "dword",
+ Q = "qword",
+ M = "qword", X = "xword", Y = "yword",
+ F = "dword", G = "qword", -- No need for sizes/register names for these two.
+}
+
+------------------------------------------------------------------------------
+
+-- Output a nicely formatted line with an opcode and operands.
+local function putop(ctx, text, operands)
+ local code, pos, hex = ctx.code, ctx.pos, ""
+ local hmax = ctx.hexdump
+ if hmax > 0 then
+ for i=ctx.start,pos-1 do
+ hex = hex..format("%02X", byte(code, i, i))
+ end
+ if #hex > hmax then hex = sub(hex, 1, hmax)..". "
+ else hex = hex..rep(" ", hmax-#hex+2) end
+ end
+ if operands then text = text.." "..operands end
+ if ctx.o16 then text = "o16 "..text; ctx.o16 = false end
+ if ctx.a32 then text = "a32 "..text; ctx.a32 = false end
+ if ctx.rep then text = ctx.rep.." "..text; ctx.rep = false end
+ if ctx.rex then
+ local t = (ctx.rexw and "w" or "")..(ctx.rexr and "r" or "")..
+ (ctx.rexx and "x" or "")..(ctx.rexb and "b" or "")..
+ (ctx.vexl and "l" or "")
+ if ctx.vexv and ctx.vexv ~= 0 then t = t.."v"..ctx.vexv end
+ if t ~= "" then text = ctx.rex.."."..t.." "..gsub(text, "^ ", "")
+ elseif ctx.rex == "vex" then text = gsub("v"..text, "^v ", "") end
+ ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false
+ ctx.rex = false; ctx.vexl = false; ctx.vexv = false
+ end
+ if ctx.seg then
+ local text2, n = gsub(text, "%[", "["..ctx.seg..":")
+ if n == 0 then text = ctx.seg.." "..text else text = text2 end
+ ctx.seg = false
+ end
+ if ctx.lock then text = "lock "..text; ctx.lock = false end
+ local imm = ctx.imm
+ if imm then
+ local sym = ctx.symtab[imm]
+ if sym then text = text.."\t->"..sym end
+ end
+ ctx.out(format("%08x %s%s\n", ctx.addr+ctx.start, hex, text))
+ ctx.mrm = false
+ ctx.vexv = false
+ ctx.start = pos
+ ctx.imm = nil
+end
+
+-- Clear all prefix flags.
+local function clearprefixes(ctx)
+ ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false
+ ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false
+ ctx.rex = false; ctx.a32 = false; ctx.vexl = false
+end
+
+-- Fallback for incomplete opcodes at the end.
+local function incomplete(ctx)
+ ctx.pos = ctx.stop+1
+ clearprefixes(ctx)
+ return putop(ctx, "(incomplete)")
+end
+
+-- Fallback for unknown opcodes.
+local function unknown(ctx)
+ clearprefixes(ctx)
+ return putop(ctx, "(unknown)")
+end
+
+-- Return an immediate of the specified size.
+local function getimm(ctx, pos, n)
+ if pos+n-1 > ctx.stop then return incomplete(ctx) end
+ local code = ctx.code
+ if n == 1 then
+ local b1 = byte(code, pos, pos)
+ return b1
+ elseif n == 2 then
+ local b1, b2 = byte(code, pos, pos+1)
+ return b1+b2*256
+ else
+ local b1, b2, b3, b4 = byte(code, pos, pos+3)
+ local imm = b1+b2*256+b3*65536+b4*16777216
+ ctx.imm = imm
+ return imm
+ end
+end
+
+-- Process pattern string and generate the operands.
+local function putpat(ctx, name, pat)
+ local operands, regs, sz, mode, sp, rm, sc, rx, sdisp
+ local code, pos, stop, vexl = ctx.code, ctx.pos, ctx.stop, ctx.vexl
+
+ -- Chars used: 1DFGIMPQRSTUVWXYabcdfgijlmoprstuvwxyz
+ for p in gmatch(pat, ".") do
+ local x = nil
+ if p == "V" or p == "U" then
+ if ctx.rexw then sz = "Q"; ctx.rexw = false
+ elseif ctx.o16 then sz = "W"; ctx.o16 = false
+ elseif p == "U" and ctx.x64 then sz = "Q"
+ else sz = "D" end
+ regs = map_regs[sz]
+ elseif p == "T" then
+ if ctx.rexw then sz = "Q"; ctx.rexw = false else sz = "D" end
+ regs = map_regs[sz]
+ elseif p == "B" then
+ sz = "B"
+ regs = ctx.rex and map_regs.B64 or map_regs.B
+ elseif match(p, "[WDQMXYFG]") then
+ sz = p
+ if sz == "X" and vexl then sz = "Y"; ctx.vexl = false end
+ regs = map_regs[sz]
+ elseif p == "P" then
+ sz = ctx.o16 and "X" or "M"; ctx.o16 = false
+ if sz == "X" and vexl then sz = "Y"; ctx.vexl = false end
+ regs = map_regs[sz]
+ elseif p == "S" then
+ name = name..lower(sz)
+ elseif p == "s" then
+ local imm = getimm(ctx, pos, 1); if not imm then return end
+ x = imm <= 127 and format("+0x%02x", imm)
+ or format("-0x%02x", 256-imm)
+ pos = pos+1
+ elseif p == "u" then
+ local imm = getimm(ctx, pos, 1); if not imm then return end
+ x = format("0x%02x", imm)
+ pos = pos+1
+ elseif p == "b" then
+ local imm = getimm(ctx, pos, 1); if not imm then return end
+ x = regs[imm/16+1]
+ pos = pos+1
+ elseif p == "w" then
+ local imm = getimm(ctx, pos, 2); if not imm then return end
+ x = format("0x%x", imm)
+ pos = pos+2
+ elseif p == "o" then -- [offset]
+ if ctx.x64 then
+ local imm1 = getimm(ctx, pos, 4); if not imm1 then return end
+ local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end
+ x = format("[0x%08x%08x]", imm2, imm1)
+ pos = pos+8
+ else
+ local imm = getimm(ctx, pos, 4); if not imm then return end
+ x = format("[0x%08x]", imm)
+ pos = pos+4
+ end
+ elseif p == "i" or p == "I" then
+ local n = map_sz2n[sz]
+ if n == 8 and ctx.x64 and p == "I" then
+ local imm1 = getimm(ctx, pos, 4); if not imm1 then return end
+ local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end
+ x = format("0x%08x%08x", imm2, imm1)
+ else
+ if n == 8 then n = 4 end
+ local imm = getimm(ctx, pos, n); if not imm then return end
+ if sz == "Q" and (imm < 0 or imm > 0x7fffffff) then
+ imm = (0xffffffff+1)-imm
+ x = format(imm > 65535 and "-0x%08x" or "-0x%x", imm)
+ else
+ x = format(imm > 65535 and "0x%08x" or "0x%x", imm)
+ end
+ end
+ pos = pos+n
+ elseif p == "j" then
+ local n = map_sz2n[sz]
+ if n == 8 then n = 4 end
+ local imm = getimm(ctx, pos, n); if not imm then return end
+ if sz == "B" and imm > 127 then imm = imm-256
+ elseif imm > 2147483647 then imm = imm-4294967296 end
+ pos = pos+n
+ imm = imm + pos + ctx.addr
+ if imm > 4294967295 and not ctx.x64 then imm = imm-4294967296 end
+ ctx.imm = imm
+ if sz == "W" then
+ x = format("word 0x%04x", imm%65536)
+ elseif ctx.x64 then
+ local lo = imm % 0x1000000
+ x = format("0x%02x%06x", (imm-lo) / 0x1000000, lo)
+ else
+ x = "0x"..tohex(imm)
+ end
+ elseif p == "R" then
+ local r = byte(code, pos-1, pos-1)%8
+ if ctx.rexb then r = r + 8; ctx.rexb = false end
+ x = regs[r+1]
+ elseif p == "a" then x = regs[1]
+ elseif p == "c" then x = "cl"
+ elseif p == "d" then x = "dx"
+ elseif p == "1" then x = "1"
+ else
+ if not mode then
+ mode = ctx.mrm
+ if not mode then
+ if pos > stop then return incomplete(ctx) end
+ mode = byte(code, pos, pos)
+ pos = pos+1
+ end
+ rm = mode%8; mode = (mode-rm)/8
+ sp = mode%8; mode = (mode-sp)/8
+ sdisp = ""
+ if mode < 3 then
+ if rm == 4 then
+ if pos > stop then return incomplete(ctx) end
+ sc = byte(code, pos, pos)
+ pos = pos+1
+ rm = sc%8; sc = (sc-rm)/8
+ rx = sc%8; sc = (sc-rx)/8
+ if ctx.rexx then rx = rx + 8; ctx.rexx = false end
+ if rx == 4 then rx = nil end
+ end
+ if mode > 0 or rm == 5 then
+ local dsz = mode
+ if dsz ~= 1 then dsz = 4 end
+ local disp = getimm(ctx, pos, dsz); if not disp then return end
+ if mode == 0 then rm = nil end
+ if rm or rx or (not sc and ctx.x64 and not ctx.a32) then
+ if dsz == 1 and disp > 127 then
+ sdisp = format("-0x%x", 256-disp)
+ elseif disp >= 0 and disp <= 0x7fffffff then
+ sdisp = format("+0x%x", disp)
+ else
+ sdisp = format("-0x%x", (0xffffffff+1)-disp)
+ end
+ else
+ sdisp = format(ctx.x64 and not ctx.a32 and
+ not (disp >= 0 and disp <= 0x7fffffff)
+ and "0xffffffff%08x" or "0x%08x", disp)
+ end
+ pos = pos+dsz
+ end
+ end
+ if rm and ctx.rexb then rm = rm + 8; ctx.rexb = false end
+ if ctx.rexr then sp = sp + 8; ctx.rexr = false end
+ end
+ if p == "m" then
+ if mode == 3 then x = regs[rm+1]
+ else
+ local aregs = ctx.a32 and map_regs.D or ctx.aregs
+ local srm, srx = "", ""
+ if rm then srm = aregs[rm+1]
+ elseif not sc and ctx.x64 and not ctx.a32 then srm = "rip" end
+ ctx.a32 = false
+ if rx then
+ if rm then srm = srm.."+" end
+ srx = aregs[rx+1]
+ if sc > 0 then srx = srx.."*"..(2^sc) end
+ end
+ x = format("[%s%s%s]", srm, srx, sdisp)
+ end
+ if mode < 3 and
+ (not match(pat, "[aRrgp]") or match(pat, "t")) then -- Yuck.
+ x = map_sz2prefix[sz].." "..x
+ end
+ elseif p == "r" then x = regs[sp+1]
+ elseif p == "g" then x = map_segregs[sp+1]
+ elseif p == "p" then -- Suppress prefix.
+ elseif p == "f" then x = "st"..rm
+ elseif p == "x" then
+ if sp == 0 and ctx.lock and not ctx.x64 then
+ x = "CR8"; ctx.lock = false
+ else
+ x = "CR"..sp
+ end
+ elseif p == "v" then
+ if ctx.vexv then
+ x = regs[ctx.vexv+1]; ctx.vexv = false
+ end
+ elseif p == "y" then x = "DR"..sp
+ elseif p == "z" then x = "TR"..sp
+ elseif p == "l" then vexl = false
+ elseif p == "t" then
+ else
+ error("bad pattern `"..pat.."'")
+ end
+ end
+ if x then operands = operands and operands..", "..x or x end
+ end
+ ctx.pos = pos
+ return putop(ctx, name, operands)
+end
+
+-- Forward declaration.
+local map_act
+
+-- Fetch and cache MRM byte.
+local function getmrm(ctx)
+ local mrm = ctx.mrm
+ if not mrm then
+ local pos = ctx.pos
+ if pos > ctx.stop then return nil end
+ mrm = byte(ctx.code, pos, pos)
+ ctx.pos = pos+1
+ ctx.mrm = mrm
+ end
+ return mrm
+end
+
+-- Dispatch to handler depending on pattern.
+local function dispatch(ctx, opat, patgrp)
+ if not opat then return unknown(ctx) end
+ if match(opat, "%|") then -- MMX/SSE variants depending on prefix.
+ local p
+ if ctx.rep then
+ p = ctx.rep=="rep" and "%|([^%|]*)" or "%|[^%|]*%|[^%|]*%|([^%|]*)"
+ ctx.rep = false
+ elseif ctx.o16 then p = "%|[^%|]*%|([^%|]*)"; ctx.o16 = false
+ else p = "^[^%|]*" end
+ opat = match(opat, p)
+ if not opat then return unknown(ctx) end
+-- ctx.rep = false; ctx.o16 = false
+ --XXX fails for 66 f2 0f 38 f1 06 crc32 eax,WORD PTR [esi]
+ --XXX remove in branches?
+ end
+ if match(opat, "%$") then -- reg$mem variants.
+ local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
+ opat = match(opat, mrm >= 192 and "^[^%$]*" or "%$(.*)")
+ if opat == "" then return unknown(ctx) end
+ end
+ if opat == "" then return unknown(ctx) end
+ local name, pat = match(opat, "^([a-z0-9 ]*)(.*)")
+ if pat == "" and patgrp then pat = patgrp end
+ return map_act[sub(pat, 1, 1)](ctx, name, pat)
+end
+
+-- Get a pattern from an opcode map and dispatch to handler.
+local function dispatchmap(ctx, opcmap)
+ local pos = ctx.pos
+ local opat = opcmap[byte(ctx.code, pos, pos)]
+ pos = pos + 1
+ ctx.pos = pos
+ return dispatch(ctx, opat)
+end
+
+-- Map for action codes. The key is the first char after the name.
+map_act = {
+ -- Simple opcodes without operands.
+ [""] = function(ctx, name, pat)
+ return putop(ctx, name)
+ end,
+
+ -- Operand size chars fall right through.
+ B = putpat, W = putpat, D = putpat, Q = putpat,
+ V = putpat, U = putpat, T = putpat,
+ M = putpat, X = putpat, P = putpat,
+ F = putpat, G = putpat, Y = putpat,
+
+ -- Collect prefixes.
+ [":"] = function(ctx, name, pat)
+ ctx[pat == ":" and name or sub(pat, 2)] = name
+ if ctx.pos - ctx.start > 5 then return unknown(ctx) end -- Limit #prefixes.
+ end,
+
+ -- Chain to special handler specified by name.
+ ["*"] = function(ctx, name, pat)
+ return map_act[name](ctx, name, sub(pat, 2))
+ end,
+
+ -- Use named subtable for opcode group.
+ ["!"] = function(ctx, name, pat)
+ local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
+ return dispatch(ctx, map_opcgroup[name][((mrm-(mrm%8))/8)%8+1], sub(pat, 2))
+ end,
+
+ -- o16,o32[,o64] variants.
+ sz = function(ctx, name, pat)
+ if ctx.o16 then ctx.o16 = false
+ else
+ pat = match(pat, ",(.*)")
+ if ctx.rexw then
+ local p = match(pat, ",(.*)")
+ if p then pat = p; ctx.rexw = false end
+ end
+ end
+ pat = match(pat, "^[^,]*")
+ return dispatch(ctx, pat)
+ end,
+
+ -- Two-byte opcode dispatch.
+ opc2 = function(ctx, name, pat)
+ return dispatchmap(ctx, map_opc2)
+ end,
+
+ -- Three-byte opcode dispatch.
+ opc3 = function(ctx, name, pat)
+ return dispatchmap(ctx, map_opc3[pat])
+ end,
+
+ -- VMX/SVM dispatch.
+ vm = function(ctx, name, pat)
+ return dispatch(ctx, map_opcvm[ctx.mrm])
+ end,
+
+ -- Floating point opcode dispatch.
+ fp = function(ctx, name, pat)
+ local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
+ local rm = mrm%8
+ local idx = pat*8 + ((mrm-rm)/8)%8
+ if mrm >= 192 then idx = idx + 64 end
+ local opat = map_opcfp[idx]
+ if type(opat) == "table" then opat = opat[rm+1] end
+ return dispatch(ctx, opat)
+ end,
+
+ -- REX prefix.
+ rex = function(ctx, name, pat)
+ if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed.
+ for p in gmatch(pat, ".") do ctx["rex"..p] = true end
+ ctx.rex = "rex"
+ end,
+
+ -- VEX prefix.
+ vex = function(ctx, name, pat)
+ if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed.
+ ctx.rex = "vex"
+ local pos = ctx.pos
+ if ctx.mrm then
+ ctx.mrm = nil
+ pos = pos-1
+ end
+ local b = byte(ctx.code, pos, pos)
+ if not b then return incomplete(ctx) end
+ pos = pos+1
+ if b < 128 then ctx.rexr = true end
+ local m = 1
+ if pat == "3" then
+ m = b%32; b = (b-m)/32
+ local nb = b%2; b = (b-nb)/2
+ if nb == 0 then ctx.rexb = true end
+ local nx = b%2
+ if nx == 0 then ctx.rexx = true end
+ b = byte(ctx.code, pos, pos)
+ if not b then return incomplete(ctx) end
+ pos = pos+1
+ if b >= 128 then ctx.rexw = true end
+ end
+ ctx.pos = pos
+ local map
+ if m == 1 then map = map_opc2
+ elseif m == 2 then map = map_opc3["38"]
+ elseif m == 3 then map = map_opc3["3a"]
+ else return unknown(ctx) end
+ local p = b%4; b = (b-p)/4
+ if p == 1 then ctx.o16 = "o16"
+ elseif p == 2 then ctx.rep = "rep"
+ elseif p == 3 then ctx.rep = "repne" end
+ local l = b%2; b = (b-l)/2
+ if l ~= 0 then ctx.vexl = true end
+ ctx.vexv = (-1-b)%16
+ return dispatchmap(ctx, map)
+ end,
+
+ -- Special case for nop with REX prefix.
+ nop = function(ctx, name, pat)
+ return dispatch(ctx, ctx.rex and pat or "nop")
+ end,
+
+ -- Special case for 0F 77.
+ emms = function(ctx, name, pat)
+ if ctx.rex ~= "vex" then
+ return putop(ctx, "emms")
+ elseif ctx.vexl then
+ ctx.vexl = false
+ return putop(ctx, "zeroall")
+ else
+ return putop(ctx, "zeroupper")
+ end
+ end,
+}
+
+------------------------------------------------------------------------------
+
+-- Disassemble a block of code.
+local function disass_block(ctx, ofs, len)
+ if not ofs then ofs = 0 end
+ local stop = len and ofs+len or #ctx.code
+ ofs = ofs + 1
+ ctx.start = ofs
+ ctx.pos = ofs
+ ctx.stop = stop
+ ctx.imm = nil
+ ctx.mrm = false
+ clearprefixes(ctx)
+ while ctx.pos <= stop do dispatchmap(ctx, ctx.map1) end
+ if ctx.pos ~= ctx.start then incomplete(ctx) end
+end
+
+-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
+local function create(code, addr, out)
+ local ctx = {}
+ ctx.code = code
+ ctx.addr = (addr or 0) - 1
+ ctx.out = out or io.write
+ ctx.symtab = {}
+ ctx.disass = disass_block
+ ctx.hexdump = 16
+ ctx.x64 = false
+ ctx.map1 = map_opc1_32
+ ctx.aregs = map_regs.D
+ return ctx
+end
+
+local function create64(code, addr, out)
+ local ctx = create(code, addr, out)
+ ctx.x64 = true
+ ctx.map1 = map_opc1_64
+ ctx.aregs = map_regs.Q
+ return ctx
+end
+
+-- Simple API: disassemble code (a string) at address and output via out.
+local function disass(code, addr, out)
+ create(code, addr, out):disass()
+end
+
+local function disass64(code, addr, out)
+ create64(code, addr, out):disass()
+end
+
+-- Return register name for RID.
+local function regname(r)
+ if r < 8 then return map_regs.D[r+1] end
+ return map_regs.X[r-7]
+end
+
+local function regname64(r)
+ if r < 16 then return map_regs.Q[r+1] end
+ return map_regs.X[r-15]
+end
+
+-- Public module functions.
+return {
+ create = create,
+ create64 = create64,
+ disass = disass,
+ disass64 = disass64,
+ regname = regname,
+ regname64 = regname64
+}
+
diff --git a/src/host/luajit-2.1.0-beta3/src/jit/dump.lua b/src/host/luajit-2.1.0-beta3/src/jit/dump.lua
new file mode 100644
index 00000000..2bea652b
--- /dev/null
+++ b/src/host/luajit-2.1.0-beta3/src/jit/dump.lua
@@ -0,0 +1,712 @@
+----------------------------------------------------------------------------
+-- LuaJIT compiler dump module.
+--
+-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module can be used to debug the JIT compiler itself. It dumps the
+-- code representations and structures used in various compiler stages.
+--
+-- Example usage:
+--
+-- luajit -jdump -e "local x=0; for i=1,1e6 do x=x+i end; print(x)"
+-- luajit -jdump=im -e "for i=1,1000 do for j=1,1000 do end end" | less -R
+-- luajit -jdump=is myapp.lua | less -R
+-- luajit -jdump=-b myapp.lua
+-- luajit -jdump=+aH,myapp.html myapp.lua
+-- luajit -jdump=ixT,myapp.dump myapp.lua
+--
+-- The first argument specifies the dump mode. The second argument gives
+-- the output file name. Default output is to stdout, unless the environment
+-- variable LUAJIT_DUMPFILE is set. The file is overwritten every time the
+-- module is started.
+--
+-- Different features can be turned on or off with the dump mode. If the
+-- mode starts with a '+', the following features are added to the default
+-- set of features; a '-' removes them. Otherwise the features are replaced.
+--
+-- The following dump features are available (* marks the default):
+--
+-- * t Print a line for each started, ended or aborted trace (see also -jv).
+-- * b Dump the traced bytecode.
+-- * i Dump the IR (intermediate representation).
+-- r Augment the IR with register/stack slots.
+-- s Dump the snapshot map.
+-- * m Dump the generated machine code.
+-- x Print each taken trace exit.
+-- X Print each taken trace exit and the contents of all registers.
+-- a Print the IR of aborted traces, too.
+--
+-- The output format can be set with the following characters:
+--
+-- T Plain text output.
+-- A ANSI-colored text output
+-- H Colorized HTML + CSS output.
+--
+-- The default output format is plain text. It's set to ANSI-colored text
+-- if the COLORTERM variable is set. Note: this is independent of any output
+-- redirection, which is actually considered a feature.
+--
+-- You probably want to use less -R to enjoy viewing ANSI-colored text from
+-- a pipe or a file. Add this to your ~/.bashrc: export LESS="-R"
+--
+------------------------------------------------------------------------------
+
+-- Cache some library functions and objects.
+local jit = require("jit")
+assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
+local jutil = require("jit.util")
+local vmdef = require("jit.vmdef")
+local funcinfo, funcbc = jutil.funcinfo, jutil.funcbc
+local traceinfo, traceir, tracek = jutil.traceinfo, jutil.traceir, jutil.tracek
+local tracemc, tracesnap = jutil.tracemc, jutil.tracesnap
+local traceexitstub, ircalladdr = jutil.traceexitstub, jutil.ircalladdr
+local bit = require("bit")
+local band, shr, tohex = bit.band, bit.rshift, bit.tohex
+local sub, gsub, format = string.sub, string.gsub, string.format
+local byte, rep = string.byte, string.rep
+local type, tostring = type, tostring
+local stdout, stderr = io.stdout, io.stderr
+
+-- Load other modules on-demand.
+local bcline, disass
+
+-- Active flag, output file handle and dump mode.
+local active, out, dumpmode
+
+------------------------------------------------------------------------------
+
+local symtabmt = { __index = false }
+local symtab = {}
+local nexitsym = 0
+
+-- Fill nested symbol table with per-trace exit stub addresses.
+local function fillsymtab_tr(tr, nexit)
+ local t = {}
+ symtabmt.__index = t
+ if jit.arch:sub(1, 4) == "mips" then
+ t[traceexitstub(tr, 0)] = "exit"
+ return
+ end
+ for i=0,nexit-1 do
+ local addr = traceexitstub(tr, i)
+ if addr < 0 then addr = addr + 2^32 end
+ t[addr] = tostring(i)
+ end
+ local addr = traceexitstub(tr, nexit)
+ if addr then t[addr] = "stack_check" end
+end
+
+-- Fill symbol table with trace exit stub addresses.
+local function fillsymtab(tr, nexit)
+ local t = symtab
+ if nexitsym == 0 then
+ local ircall = vmdef.ircall
+ for i=0,#ircall do
+ local addr = ircalladdr(i)
+ if addr ~= 0 then
+ if addr < 0 then addr = addr + 2^32 end
+ t[addr] = ircall[i]
+ end
+ end
+ end
+ if nexitsym == 1000000 then -- Per-trace exit stubs.
+ fillsymtab_tr(tr, nexit)
+ elseif nexit > nexitsym then -- Shared exit stubs.
+ for i=nexitsym,nexit-1 do
+ local addr = traceexitstub(i)
+ if addr == nil then -- Fall back to per-trace exit stubs.
+ fillsymtab_tr(tr, nexit)
+ setmetatable(symtab, symtabmt)
+ nexit = 1000000
+ break
+ end
+ if addr < 0 then addr = addr + 2^32 end
+ t[addr] = tostring(i)
+ end
+ nexitsym = nexit
+ end
+ return t
+end
+
+local function dumpwrite(s)
+ out:write(s)
+end
+
+-- Disassemble machine code.
+local function dump_mcode(tr)
+ local info = traceinfo(tr)
+ if not info then return end
+ local mcode, addr, loop = tracemc(tr)
+ if not mcode then return end
+ if not disass then disass = require("jit.dis_"..jit.arch) end
+ if addr < 0 then addr = addr + 2^32 end
+ out:write("---- TRACE ", tr, " mcode ", #mcode, "\n")
+ local ctx = disass.create(mcode, addr, dumpwrite)
+ ctx.hexdump = 0
+ ctx.symtab = fillsymtab(tr, info.nexit)
+ if loop ~= 0 then
+ symtab[addr+loop] = "LOOP"
+ ctx:disass(0, loop)
+ out:write("->LOOP:\n")
+ ctx:disass(loop, #mcode-loop)
+ symtab[addr+loop] = nil
+ else
+ ctx:disass(0, #mcode)
+ end
+end
+
+------------------------------------------------------------------------------
+
+local irtype_text = {
+ [0] = "nil",
+ "fal",
+ "tru",
+ "lud",
+ "str",
+ "p32",
+ "thr",
+ "pro",
+ "fun",
+ "p64",
+ "cdt",
+ "tab",
+ "udt",
+ "flt",
+ "num",
+ "i8 ",
+ "u8 ",
+ "i16",
+ "u16",
+ "int",
+ "u32",
+ "i64",
+ "u64",
+ "sfp",
+}
+
+local colortype_ansi = {
+ [0] = "%s",
+ "%s",
+ "%s",
+ "\027[36m%s\027[m",
+ "\027[32m%s\027[m",
+ "%s",
+ "\027[1m%s\027[m",
+ "%s",
+ "\027[1m%s\027[m",
+ "%s",
+ "\027[33m%s\027[m",
+ "\027[31m%s\027[m",
+ "\027[36m%s\027[m",
+ "\027[34m%s\027[m",
+ "\027[34m%s\027[m",
+ "\027[35m%s\027[m",
+ "\027[35m%s\027[m",
+ "\027[35m%s\027[m",
+ "\027[35m%s\027[m",
+ "\027[35m%s\027[m",
+ "\027[35m%s\027[m",
+ "\027[35m%s\027[m",
+ "\027[35m%s\027[m",
+ "\027[35m%s\027[m",
+}
+
+local function colorize_text(s)
+ return s
+end
+
+local function colorize_ansi(s, t)
+ return format(colortype_ansi[t], s)
+end
+
+local irtype_ansi = setmetatable({},
+ { __index = function(tab, t)
+ local s = colorize_ansi(irtype_text[t], t); tab[t] = s; return s; end })
+
+local html_escape = { ["<"] = "<", [">"] = ">", ["&"] = "&", }
+
+local function colorize_html(s, t)
+ s = gsub(s, "[<>&]", html_escape)
+ return format('%s', irtype_text[t], s)
+end
+
+local irtype_html = setmetatable({},
+ { __index = function(tab, t)
+ local s = colorize_html(irtype_text[t], t); tab[t] = s; return s; end })
+
+local header_html = [[
+
+]]
+
+local colorize, irtype
+
+-- Lookup tables to convert some literals into names.
+local litname = {
+ ["SLOAD "] = setmetatable({}, { __index = function(t, mode)
+ local s = ""
+ if band(mode, 1) ~= 0 then s = s.."P" end
+ if band(mode, 2) ~= 0 then s = s.."F" end
+ if band(mode, 4) ~= 0 then s = s.."T" end
+ if band(mode, 8) ~= 0 then s = s.."C" end
+ if band(mode, 16) ~= 0 then s = s.."R" end
+ if band(mode, 32) ~= 0 then s = s.."I" end
+ t[mode] = s
+ return s
+ end}),
+ ["XLOAD "] = { [0] = "", "R", "V", "RV", "U", "RU", "VU", "RVU", },
+ ["CONV "] = setmetatable({}, { __index = function(t, mode)
+ local s = irtype[band(mode, 31)]
+ s = irtype[band(shr(mode, 5), 31)].."."..s
+ if band(mode, 0x800) ~= 0 then s = s.." sext" end
+ local c = shr(mode, 14)
+ if c == 2 then s = s.." index" elseif c == 3 then s = s.." check" end
+ t[mode] = s
+ return s
+ end}),
+ ["FLOAD "] = vmdef.irfield,
+ ["FREF "] = vmdef.irfield,
+ ["FPMATH"] = vmdef.irfpm,
+ ["BUFHDR"] = { [0] = "RESET", "APPEND" },
+ ["TOSTR "] = { [0] = "INT", "NUM", "CHAR" },
+}
+
+local function ctlsub(c)
+ if c == "\n" then return "\\n"
+ elseif c == "\r" then return "\\r"
+ elseif c == "\t" then return "\\t"
+ else return format("\\%03d", byte(c))
+ end
+end
+
+local function fmtfunc(func, pc)
+ local fi = funcinfo(func, pc)
+ if fi.loc then
+ return fi.loc
+ elseif fi.ffid then
+ return vmdef.ffnames[fi.ffid]
+ elseif fi.addr then
+ return format("C:%x", fi.addr)
+ else
+ return "(?)"
+ end
+end
+
+local function formatk(tr, idx, sn)
+ local k, t, slot = tracek(tr, idx)
+ local tn = type(k)
+ local s
+ if tn == "number" then
+ if band(sn or 0, 0x30000) ~= 0 then
+ s = band(sn, 0x20000) ~= 0 and "contpc" or "ftsz"
+ elseif k == 2^52+2^51 then
+ s = "bias"
+ else
+ s = format(0 < k and k < 0x1p-1026 and "%+a" or "%+.14g", k)
+ end
+ elseif tn == "string" then
+ s = format(#k > 20 and '"%.20s"~' or '"%s"', gsub(k, "%c", ctlsub))
+ elseif tn == "function" then
+ s = fmtfunc(k)
+ elseif tn == "table" then
+ s = format("{%p}", k)
+ elseif tn == "userdata" then
+ if t == 12 then
+ s = format("userdata:%p", k)
+ else
+ s = format("[%p]", k)
+ if s == "[NULL]" then s = "NULL" end
+ end
+ elseif t == 21 then -- int64_t
+ s = sub(tostring(k), 1, -3)
+ if sub(s, 1, 1) ~= "-" then s = "+"..s end
+ elseif sn == 0x1057fff then -- SNAP(1, SNAP_FRAME | SNAP_NORESTORE, REF_NIL)
+ return "----" -- Special case for LJ_FR2 slot 1.
+ else
+ s = tostring(k) -- For primitives.
+ end
+ s = colorize(format("%-4s", s), t)
+ if slot then
+ s = format("%s @%d", s, slot)
+ end
+ return s
+end
+
+local function printsnap(tr, snap)
+ local n = 2
+ for s=0,snap[1]-1 do
+ local sn = snap[n]
+ if shr(sn, 24) == s then
+ n = n + 1
+ local ref = band(sn, 0xffff) - 0x8000 -- REF_BIAS
+ if ref < 0 then
+ out:write(formatk(tr, ref, sn))
+ elseif band(sn, 0x80000) ~= 0 then -- SNAP_SOFTFPNUM
+ out:write(colorize(format("%04d/%04d", ref, ref+1), 14))
+ else
+ local m, ot, op1, op2 = traceir(tr, ref)
+ out:write(colorize(format("%04d", ref), band(ot, 31)))
+ end
+ out:write(band(sn, 0x10000) == 0 and " " or "|") -- SNAP_FRAME
+ else
+ out:write("---- ")
+ end
+ end
+ out:write("]\n")
+end
+
+-- Dump snapshots (not interleaved with IR).
+local function dump_snap(tr)
+ out:write("---- TRACE ", tr, " snapshots\n")
+ for i=0,1000000000 do
+ local snap = tracesnap(tr, i)
+ if not snap then break end
+ out:write(format("#%-3d %04d [ ", i, snap[0]))
+ printsnap(tr, snap)
+ end
+end
+
+-- Return a register name or stack slot for a rid/sp location.
+local function ridsp_name(ridsp, ins)
+ if not disass then disass = require("jit.dis_"..jit.arch) end
+ local rid, slot = band(ridsp, 0xff), shr(ridsp, 8)
+ if rid == 253 or rid == 254 then
+ return (slot == 0 or slot == 255) and " {sink" or format(" {%04d", ins-slot)
+ end
+ if ridsp > 255 then return format("[%x]", slot*4) end
+ if rid < 128 then return disass.regname(rid) end
+ return ""
+end
+
+-- Dump CALL* function ref and return optional ctype.
+local function dumpcallfunc(tr, ins)
+ local ctype
+ if ins > 0 then
+ local m, ot, op1, op2 = traceir(tr, ins)
+ if band(ot, 31) == 0 then -- nil type means CARG(func, ctype).
+ ins = op1
+ ctype = formatk(tr, op2)
+ end
+ end
+ if ins < 0 then
+ out:write(format("[0x%x](", tonumber((tracek(tr, ins)))))
+ else
+ out:write(format("%04d (", ins))
+ end
+ return ctype
+end
+
+-- Recursively gather CALL* args and dump them.
+local function dumpcallargs(tr, ins)
+ if ins < 0 then
+ out:write(formatk(tr, ins))
+ else
+ local m, ot, op1, op2 = traceir(tr, ins)
+ local oidx = 6*shr(ot, 8)
+ local op = sub(vmdef.irnames, oidx+1, oidx+6)
+ if op == "CARG " then
+ dumpcallargs(tr, op1)
+ if op2 < 0 then
+ out:write(" ", formatk(tr, op2))
+ else
+ out:write(" ", format("%04d", op2))
+ end
+ else
+ out:write(format("%04d", ins))
+ end
+ end
+end
+
+-- Dump IR and interleaved snapshots.
+local function dump_ir(tr, dumpsnap, dumpreg)
+ local info = traceinfo(tr)
+ if not info then return end
+ local nins = info.nins
+ out:write("---- TRACE ", tr, " IR\n")
+ local irnames = vmdef.irnames
+ local snapref = 65536
+ local snap, snapno
+ if dumpsnap then
+ snap = tracesnap(tr, 0)
+ snapref = snap[0]
+ snapno = 0
+ end
+ for ins=1,nins do
+ if ins >= snapref then
+ if dumpreg then
+ out:write(format(".... SNAP #%-3d [ ", snapno))
+ else
+ out:write(format(".... SNAP #%-3d [ ", snapno))
+ end
+ printsnap(tr, snap)
+ snapno = snapno + 1
+ snap = tracesnap(tr, snapno)
+ snapref = snap and snap[0] or 65536
+ end
+ local m, ot, op1, op2, ridsp = traceir(tr, ins)
+ local oidx, t = 6*shr(ot, 8), band(ot, 31)
+ local op = sub(irnames, oidx+1, oidx+6)
+ if op == "LOOP " then
+ if dumpreg then
+ out:write(format("%04d ------------ LOOP ------------\n", ins))
+ else
+ out:write(format("%04d ------ LOOP ------------\n", ins))
+ end
+ elseif op ~= "NOP " and op ~= "CARG " and
+ (dumpreg or op ~= "RENAME") then
+ local rid = band(ridsp, 255)
+ if dumpreg then
+ out:write(format("%04d %-6s", ins, ridsp_name(ridsp, ins)))
+ else
+ out:write(format("%04d ", ins))
+ end
+ out:write(format("%s%s %s %s ",
+ (rid == 254 or rid == 253) and "}" or
+ (band(ot, 128) == 0 and " " or ">"),
+ band(ot, 64) == 0 and " " or "+",
+ irtype[t], op))
+ local m1, m2 = band(m, 3), band(m, 3*4)
+ if sub(op, 1, 4) == "CALL" then
+ local ctype
+ if m2 == 1*4 then -- op2 == IRMlit
+ out:write(format("%-10s (", vmdef.ircall[op2]))
+ else
+ ctype = dumpcallfunc(tr, op2)
+ end
+ if op1 ~= -1 then dumpcallargs(tr, op1) end
+ out:write(")")
+ if ctype then out:write(" ctype ", ctype) end
+ elseif op == "CNEW " and op2 == -1 then
+ out:write(formatk(tr, op1))
+ elseif m1 ~= 3 then -- op1 != IRMnone
+ if op1 < 0 then
+ out:write(formatk(tr, op1))
+ else
+ out:write(format(m1 == 0 and "%04d" or "#%-3d", op1))
+ end
+ if m2 ~= 3*4 then -- op2 != IRMnone
+ if m2 == 1*4 then -- op2 == IRMlit
+ local litn = litname[op]
+ if litn and litn[op2] then
+ out:write(" ", litn[op2])
+ elseif op == "UREFO " or op == "UREFC " then
+ out:write(format(" #%-3d", shr(op2, 8)))
+ else
+ out:write(format(" #%-3d", op2))
+ end
+ elseif op2 < 0 then
+ out:write(" ", formatk(tr, op2))
+ else
+ out:write(format(" %04d", op2))
+ end
+ end
+ end
+ out:write("\n")
+ end
+ end
+ if snap then
+ if dumpreg then
+ out:write(format(".... SNAP #%-3d [ ", snapno))
+ else
+ out:write(format(".... SNAP #%-3d [ ", snapno))
+ end
+ printsnap(tr, snap)
+ end
+end
+
+------------------------------------------------------------------------------
+
+local recprefix = ""
+local recdepth = 0
+
+-- Format trace error message.
+local function fmterr(err, info)
+ if type(err) == "number" then
+ if type(info) == "function" then info = fmtfunc(info) end
+ err = format(vmdef.traceerr[err], info)
+ end
+ return err
+end
+
+-- Dump trace states.
+local function dump_trace(what, tr, func, pc, otr, oex)
+ if what == "stop" or (what == "abort" and dumpmode.a) then
+ if dumpmode.i then dump_ir(tr, dumpmode.s, dumpmode.r and what == "stop")
+ elseif dumpmode.s then dump_snap(tr) end
+ if dumpmode.m then dump_mcode(tr) end
+ end
+ if what == "start" then
+ if dumpmode.H then out:write('
\n') end
+ out:write("---- TRACE ", tr, " ", what)
+ if otr then out:write(" ", otr, "/", oex == -1 and "stitch" or oex) end
+ out:write(" ", fmtfunc(func, pc), "\n")
+ elseif what == "stop" or what == "abort" then
+ out:write("---- TRACE ", tr, " ", what)
+ if what == "abort" then
+ out:write(" ", fmtfunc(func, pc), " -- ", fmterr(otr, oex), "\n")
+ else
+ local info = traceinfo(tr)
+ local link, ltype = info.link, info.linktype
+ if link == tr or link == 0 then
+ out:write(" -> ", ltype, "\n")
+ elseif ltype == "root" then
+ out:write(" -> ", link, "\n")
+ else
+ out:write(" -> ", link, " ", ltype, "\n")
+ end
+ end
+ if dumpmode.H then out:write("