Browse Source

Update LuaJIT to LuaJIT/LuaJIT@b4b2dce9fc3ffaaa

Miku AuahDark 4 years ago
parent
commit
a3ea2d5ca0
100 changed files with 27986 additions and 118 deletions
  1. 190 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/bc.lua
  2. 665 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/bcsave.lua
  3. 689 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_arm.lua
  4. 1216 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_arm64.lua
  5. 12 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_arm64be.lua
  6. 694 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_mips.lua
  7. 17 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_mips64.lua
  8. 17 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_mips64el.lua
  9. 17 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_mips64r6.lua
  10. 17 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_mips64r6el.lua
  11. 17 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_mipsel.lua
  12. 591 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_ppc.lua
  13. 17 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_x64.lua
  14. 953 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_x86.lua
  15. 726 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dump.lua
  16. 312 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/p.lua
  17. 170 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/v.lua
  18. 395 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/vmdef.lua
  19. 45 0
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/zone.lua
  20. BIN
      love/src/jni/LuaJIT-2.1/android/arm64-v8a/libluajit.a
  21. 190 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/bc.lua
  22. 665 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/bcsave.lua
  23. 689 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_arm.lua
  24. 1216 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_arm64.lua
  25. 12 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_arm64be.lua
  26. 694 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_mips.lua
  27. 17 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_mips64.lua
  28. 17 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_mips64el.lua
  29. 17 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_mips64r6.lua
  30. 17 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_mips64r6el.lua
  31. 17 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_mipsel.lua
  32. 591 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_ppc.lua
  33. 17 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_x64.lua
  34. 953 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_x86.lua
  35. 726 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dump.lua
  36. 312 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/p.lua
  37. 170 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/v.lua
  38. 395 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/vmdef.lua
  39. 45 0
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/zone.lua
  40. BIN
      love/src/jni/LuaJIT-2.1/android/armeabi-v7a/libluajit.a
  41. 190 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/bc.lua
  42. 665 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/bcsave.lua
  43. 689 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/dis_arm.lua
  44. 1216 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/dis_arm64.lua
  45. 12 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/dis_arm64be.lua
  46. 694 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/dis_mips.lua
  47. 17 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/dis_mips64.lua
  48. 17 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/dis_mips64el.lua
  49. 17 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/dis_mips64r6.lua
  50. 17 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/dis_mips64r6el.lua
  51. 17 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/dis_mipsel.lua
  52. 591 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/dis_ppc.lua
  53. 17 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/dis_x64.lua
  54. 953 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/dis_x86.lua
  55. 726 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/dump.lua
  56. 312 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/p.lua
  57. 170 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/v.lua
  58. 395 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/vmdef.lua
  59. 45 0
      love/src/jni/LuaJIT-2.1/android/x86/jit/zone.lua
  60. BIN
      love/src/jni/LuaJIT-2.1/android/x86/libluajit.a
  61. 190 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/bc.lua
  62. 665 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/bcsave.lua
  63. 689 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_arm.lua
  64. 1216 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_arm64.lua
  65. 12 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_arm64be.lua
  66. 694 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_mips.lua
  67. 17 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_mips64.lua
  68. 17 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_mips64el.lua
  69. 17 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_mips64r6.lua
  70. 17 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_mips64r6el.lua
  71. 17 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_mipsel.lua
  72. 591 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_ppc.lua
  73. 17 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_x64.lua
  74. 953 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_x86.lua
  75. 726 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/dump.lua
  76. 312 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/p.lua
  77. 170 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/v.lua
  78. 395 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/vmdef.lua
  79. 45 0
      love/src/jni/LuaJIT-2.1/android/x86_64/jit/zone.lua
  80. BIN
      love/src/jni/LuaJIT-2.1/android/x86_64/libluajit.a
  81. 4 0
      love/src/jni/LuaJIT-2.1/build_instructions.bat
  82. 4 2
      love/src/jni/LuaJIT-2.1/doc/contact.html
  83. 693 0
      love/src/jni/LuaJIT-2.1/doc/ext_buffer.html
  84. 4 2
      love/src/jni/LuaJIT-2.1/doc/ext_c_api.html
  85. 4 2
      love/src/jni/LuaJIT-2.1/doc/ext_ffi.html
  86. 4 2
      love/src/jni/LuaJIT-2.1/doc/ext_ffi_api.html
  87. 4 2
      love/src/jni/LuaJIT-2.1/doc/ext_ffi_semantics.html
  88. 4 2
      love/src/jni/LuaJIT-2.1/doc/ext_ffi_tutorial.html
  89. 4 2
      love/src/jni/LuaJIT-2.1/doc/ext_jit.html
  90. 4 2
      love/src/jni/LuaJIT-2.1/doc/ext_profiler.html
  91. 13 19
      love/src/jni/LuaJIT-2.1/doc/extensions.html
  92. 19 5
      love/src/jni/LuaJIT-2.1/doc/faq.html
  93. 19 10
      love/src/jni/LuaJIT-2.1/doc/install.html
  94. 4 2
      love/src/jni/LuaJIT-2.1/doc/luajit.html
  95. 6 4
      love/src/jni/LuaJIT-2.1/doc/running.html
  96. 4 8
      love/src/jni/LuaJIT-2.1/doc/status.html
  97. 5 2
      love/src/jni/LuaJIT-2.1/dynasm/dasm_arm.h
  98. 3 3
      love/src/jni/LuaJIT-2.1/dynasm/dasm_arm.lua
  99. 50 8
      love/src/jni/LuaJIT-2.1/dynasm/dasm_arm64.h
  100. 94 41
      love/src/jni/LuaJIT-2.1/dynasm/dasm_arm64.lua

+ 190 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/bc.lua

@@ -0,0 +1,190 @@
+----------------------------------------------------------------------------
+-- LuaJIT bytecode listing module.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module lists the bytecode of a Lua function. If it's loaded by -jbc
+-- it hooks into the parser and lists all functions of a chunk as they
+-- are parsed.
+--
+-- Example usage:
+--
+--   luajit -jbc -e 'local x=0; for i=1,1e6 do x=x+i end; print(x)'
+--   luajit -jbc=- foo.lua
+--   luajit -jbc=foo.list foo.lua
+--
+-- Default output is to stderr. To redirect the output to a file, pass a
+-- filename as an argument (use '-' for stdout) or set the environment
+-- variable LUAJIT_LISTFILE. The file is overwritten every time the module
+-- is started.
+--
+-- This module can also be used programmatically:
+--
+--   local bc = require("jit.bc")
+--
+--   local function foo() print("hello") end
+--
+--   bc.dump(foo)           --> -- 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.
+}
+

+ 665 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/bcsave.lua

@@ -0,0 +1,665 @@
+----------------------------------------------------------------------------
+-- LuaJIT module to save/list bytecode.
+--
+-- Copyright (C) 2005-2021 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 type, assert = type, assert
+local format = string.format
+local tremove, tconcat = table.remove, table.concat
+
+------------------------------------------------------------------------------
+
+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 =		{ e = "le", b = 32, m = 3, p = 0x14c, },
+  x64 =		{ e = "le", b = 64, m = 62, p = 0x8664, },
+  arm =		{ e = "le", b = 32, m = 40, p = 0x1c0, },
+  arm64 =	{ e = "le", b = 64, m = 183, p = 0xaa64, },
+  arm64be =	{ e = "be", b = 64, m = 183, },
+  ppc =		{ e = "be", b = 32, m = 20, },
+  mips =	{ e = "be", b = 32, m = 8, f = 0x50001006, },
+  mipsel =	{ e = "le", b = 32, m = 8, f = 0x50001006, },
+  mips64 =	{ e = "be", b = 64, m = 8, f = 0x80000007, },
+  mips64el =	{ e = "le", b = 64, m = 8, f = 0x80000007, },
+  mips64r6 =	{ e = "be", b = 64, m = 8, f = 0xa0000407, },
+  mips64r6el =	{ e = "le", b = 64, m = 8, f = 0xa0000407, },
+}
+
+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 = str:lower()
+  local s = check(map[str], "unknown ", err)
+  return type(s) == "string" and s or str
+end
+
+local function detecttype(str)
+  local ext = str:lower():match("%.(%a+)$")
+  return map_type[ext] or "raw"
+end
+
+local function checkmodname(str)
+  check(str:match("^[%w_.%-]+$"), "bad module name")
+  return str:gsub("[%.%-]", "_")
+end
+
+local function detectmodname(str)
+  if type(str) == "string" then
+    local tail = str:match("[^/\\]+$")
+    if tail then str = tail end
+    local head = str:match("^(.*)%.[^.]*$")
+    if head then str = head end
+    str = str:match("^[%w_.%-]+")
+  else
+    str = nil
+  end
+  check(str, "cannot derive module name, use -n name")
+  return str:gsub("[%.%-]", "_")
+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(format([[
+#ifdef __cplusplus
+extern "C"
+#endif
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+const unsigned char %s%s[] = {
+]], LJBC_PREFIX, ctx.modname))
+  else
+    fp:write(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(tconcat(t, ",", 1, n), ",\n")
+      n, m = 0, #b + 1
+    end
+    n = n + 1
+    t[n] = b
+  end
+  bcsave_tail(fp, output, tconcat(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 ai = assert(map_arch[ctx.arch])
+  local is64, isbe = ai.b == 64, ai.e == "be"
+
+  -- 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(ai.m)
+  hdr.flags = f32(ai.f or 0)
+  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+2)
+  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 ai = assert(map_arch[ctx.arch])
+  local is64 = ai.b == 64
+  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(assert(ai.p))
+  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 = jit.os:lower(),
+    type = false, modname = false,
+  }
+  while n <= #arg do
+    local a = arg[n]
+    if type(a) == "string" and a:sub(1, 1) == "-" and a ~= "-" then
+      tremove(arg, n)
+      if a == "--" then break end
+      for m=2,#a do
+	local opt = a:sub(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(tremove(arg, n))
+	  elseif opt == "t" then
+	    ctx.type = checkarg(tremove(arg, n), map_type, "file type")
+	  elseif opt == "a" then
+	    ctx.arch = checkarg(tremove(arg, n), map_arch, "architecture")
+	  elseif opt == "o" then
+	    ctx.os = checkarg(tremove(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.
+}
+

+ 689 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_arm.lua

@@ -0,0 +1,689 @@
+----------------------------------------------------------------------------
+-- LuaJIT ARM disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 1216 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_arm64.lua

@@ -0,0 +1,1216 @@
+----------------------------------------------------------------------------
+-- LuaJIT ARM64 disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+	else
+	  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 <R>.
+      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
+}
+

+ 12 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_arm64be.lua

@@ -0,0 +1,12 @@
+----------------------------------------------------------------------------
+-- LuaJIT ARM64BE disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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")
+

+ 694 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_mips.lua

@@ -0,0 +1,694 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+
+------------------------------------------------------------------------------
+-- Extended opcode maps common to all MIPS releases
+------------------------------------------------------------------------------
+
+local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", }
+local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", }
+
+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",
+  },
+}
+
+------------------------------------------------------------------------------
+-- Primary and extended opcode maps for MIPS R1-R5
+------------------------------------------------------------------------------
+
+local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", }
+
+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_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",
+}
+
+------------------------------------------------------------------------------
+-- Primary and extended opcode maps for MIPS R6
+------------------------------------------------------------------------------
+
+local map_mul_r6 =   { shift = 6, mask = 3, [2] = "mulDST",   [3] = "muhDST" }
+local map_mulu_r6 =  { shift = 6, mask = 3, [2] = "muluDST",  [3] = "muhuDST" }
+local map_div_r6 =   { shift = 6, mask = 3, [2] = "divDST",   [3] = "modDST" }
+local map_divu_r6 =  { shift = 6, mask = 3, [2] = "divuDST",  [3] = "moduDST" }
+local map_dmul_r6 =  { shift = 6, mask = 3, [2] = "dmulDST",  [3] = "dmuhDST" }
+local map_dmulu_r6 = { shift = 6, mask = 3, [2] = "dmuluDST", [3] = "dmuhuDST" }
+local map_ddiv_r6 =  { shift = 6, mask = 3, [2] = "ddivDST",  [3] = "dmodDST" }
+local map_ddivu_r6 = { shift = 6, mask = 3, [2] = "ddivuDST", [3] = "dmoduDST" }
+
+local map_special_r6 = {
+  shift = 0, mask = 63,
+  [0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
+  false,	map_srl,	"sraDTA",
+  "sllvDTS",	false,		map_srlv,	"sravDTS",
+  "jrS",	"jalrD1S",	false,		false,
+  "syscallY",	"breakY",	false,		"sync",
+  "clzDS",	"cloDS",	"dclzDS",	"dcloDS",
+  "dsllvDST",	"dlsaDSTA",	"dsrlvDST",	"dsravDST",
+  map_mul_r6,	map_mulu_r6,	map_div_r6,	map_divu_r6,
+  map_dmul_r6,	map_dmulu_r6,	map_ddiv_r6,	map_ddivu_r6,
+  "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",	"seleqzDST",	"tneSTZ",	"selnezDST",
+  "dsllDTA",	false,		"dsrlDTA",	"dsraDTA",
+  "dsll32DTA",	false,		"dsrl32DTA",	"dsra32DTA",
+}
+
+local map_bshfl_r6 = {
+  shift = 9, mask = 3,
+  [1] = "alignDSTa",
+  _ = {
+    shift = 6, mask = 31,
+    [0] = "bitswapDT",
+    [2] = "wsbhDT",
+    [16] = "sebDT",
+    [24] = "sehDT",
+  }
+}
+
+local map_dbshfl_r6 = {
+  shift = 9, mask = 3,
+  [1] = "dalignDSTa",
+  _ = {
+    shift = 6, mask = 31,
+    [0] = "dbitswapDT",
+    [2] = "dsbhDT",
+    [5] = "dshdDT",
+  }
+}
+
+local map_special3_r6 = {
+  shift = 0, mask = 63,
+  [0]  = "extTSAK", [1]  = "dextmTSAP", [3]  = "dextTSAK",
+  [4]  = "insTSAL", [6]  = "dinsuTSEQ", [7]  = "dinsTSAL",
+  [32] = map_bshfl_r6, [36] = map_dbshfl_r6,  [59] = "rdhwrTD",
+}
+
+local map_regimm_r6 = {
+  shift = 16, mask = 31,
+  [0] = "bltzSB", [1] = "bgezSB",
+  [6] = "dahiSI", [30] = "datiSI",
+  [23] = "sigrieI", [31] = "synciSO",
+}
+
+local map_pcrel_r6 = {
+  shift = 19, mask = 3,
+  [0] = "addiupcS2", "lwpcS2", "lwupcS2", {
+    shift = 18, mask = 1,
+    [0] = "ldpcS3", { shift = 16, mask = 3, [2] = "auipcSI", [3] = "aluipcSI" }
+  }
+}
+
+local map_cop1s_r6 = {
+  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",
+  "sel.sFGH",		false,		false,		false,
+  "seleqz.sFGH",	"recip.sFG",	"rsqrt.sFG",	"selnez.sFGH",
+  "maddf.sFGH",		"msubf.sFGH",	"rint.sFG",	"class.sFG",
+  "min.sFGH",		"mina.sFGH",	"max.sFGH",	"maxa.sFGH",
+  false,		"cvt.d.sFG",	false,		false,
+  "cvt.w.sFG",		"cvt.l.sFG",
+}
+
+local map_cop1d_r6 = {
+  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",
+  "sel.dFGH",		false,		false,		false,
+  "seleqz.dFGH",	"recip.dFG",	"rsqrt.dFG",	"selnez.dFGH",
+  "maddf.dFGH",		"msubf.dFGH",	"rint.dFG",	"class.dFG",
+  "min.dFGH",		"mina.dFGH",	"max.dFGH",	"maxa.dFGH",
+  "cvt.s.dFG",		false,		false,		false,
+  "cvt.w.dFG",		"cvt.l.dFG",
+}
+
+local map_cop1w_r6 = {
+  shift = 0, mask = 63,
+  [0] = "cmp.af.sFGH",	"cmp.un.sFGH",	"cmp.eq.sFGH",	"cmp.ueq.sFGH",
+  "cmp.lt.sFGH",	"cmp.ult.sFGH",	"cmp.le.sFGH",	"cmp.ule.sFGH",
+  "cmp.saf.sFGH",	"cmp.sun.sFGH",	"cmp.seq.sFGH",	"cmp.sueq.sFGH",
+  "cmp.slt.sFGH",	"cmp.sult.sFGH",	"cmp.sle.sFGH",	"cmp.sule.sFGH",
+  false,		"cmp.or.sFGH",	"cmp.une.sFGH",	"cmp.ne.sFGH",
+  false,		false,		false,		false,
+  false,		"cmp.sor.sFGH",	"cmp.sune.sFGH",	"cmp.sne.sFGH",
+  false,		false,		false,		false,
+  "cvt.s.wFG", "cvt.d.wFG",
+}
+
+local map_cop1l_r6 = {
+  shift = 0, mask = 63,
+  [0] = "cmp.af.dFGH",	"cmp.un.dFGH",	"cmp.eq.dFGH",	"cmp.ueq.dFGH",
+  "cmp.lt.dFGH",	"cmp.ult.dFGH",	"cmp.le.dFGH",	"cmp.ule.dFGH",
+  "cmp.saf.dFGH",	"cmp.sun.dFGH",	"cmp.seq.dFGH",	"cmp.sueq.dFGH",
+  "cmp.slt.dFGH",	"cmp.sult.dFGH",	"cmp.sle.dFGH",	"cmp.sule.dFGH",
+  false,		"cmp.or.dFGH",	"cmp.une.dFGH",	"cmp.ne.dFGH",
+  false,		false,		false,		false,
+  false,		"cmp.sor.dFGH",	"cmp.sune.dFGH",	"cmp.sne.dFGH",
+  false,		false,		false,		false,
+  "cvt.s.lFG", "cvt.d.lFG",
+}
+
+local map_cop1_r6 = {
+  shift = 21, mask = 31,
+  [0] = "mfc1TG", "dmfc1TG",	"cfc1TG",	"mfhc1TG",
+  "mtc1TG",	"dmtc1TG",	"ctc1TG",	"mthc1TG",
+  false,	"bc1eqzHB",	false,		false,
+  false,	"bc1nezHB",	false,		false,
+  map_cop1s_r6,	map_cop1d_r6,	false,		false,
+  map_cop1w_r6,	map_cop1l_r6,
+}
+
+local function maprs_popTS(rs, rt)
+  if rt == 0 then return 0 elseif rs == 0 then return 1
+  elseif rs == rt then return 2 else return 3 end
+end
+
+local map_pop06_r6 = {
+  maprs = maprs_popTS, [0] = "blezSB", "blezalcTB", "bgezalcTB", "bgeucSTB"
+}
+local map_pop07_r6 = {
+  maprs = maprs_popTS, [0] = "bgtzSB", "bgtzalcTB", "bltzalcTB", "bltucSTB"
+}
+local map_pop26_r6 = {
+  maprs = maprs_popTS, "blezcTB", "bgezcTB", "bgecSTB"
+}
+local map_pop27_r6 = {
+  maprs = maprs_popTS, "bgtzcTB", "bltzcTB", "bltcSTB"
+}
+
+local function maprs_popS(rs, rt)
+  if rs == 0 then return 0 else return 1 end
+end
+
+local map_pop66_r6 = {
+  maprs = maprs_popS, [0] = "jicTI", "beqzcSb"
+}
+local map_pop76_r6 = {
+  maprs = maprs_popS, [0] = "jialcTI", "bnezcSb"
+}
+
+local function maprs_popST(rs, rt)
+  if rs >= rt then return 0 elseif rs == 0 then return 1 else return 2 end
+end
+
+local map_pop10_r6 = {
+  maprs = maprs_popST, [0] = "bovcSTB", "beqzalcTB", "beqcSTB"
+}
+local map_pop30_r6 = {
+  maprs = maprs_popST, [0] = "bnvcSTB", "bnezalcTB", "bnecSTB"
+}
+
+local map_pri_r6 = {
+  [0] = map_special_r6,	map_regimm_r6,	"jJ",	"jalJ",
+  "beq|beqz|bST00B",	"bne|bnezST0B",		map_pop06_r6,	map_pop07_r6,
+  map_pop10_r6,	"addiu|liTS0I",	"sltiTSI",	"sltiuTSI",
+  "andiTSU",	"ori|liTS0U",	"xoriTSU",	"aui|luiTS0U",
+  map_cop0,	map_cop1_r6,	false,		false,
+  false,	false,		map_pop26_r6,	map_pop27_r6,
+  map_pop30_r6,	"daddiuTSI",	false,		false,
+  false,	"dauiTSI",	false,		map_special3_r6,
+  "lbTSO",	"lhTSO",	false,		"lwTSO",
+  "lbuTSO",	"lhuTSO",	false,		false,
+  "sbTSO",	"shTSO",	false,		"swTSO",
+  false,	false,		false,		false,
+  false,	"lwc1HSO",	"bc#",		false,
+  false,	"ldc1HSO",	map_pop66_r6,	"ldTSO",
+  false,	"swc1HSO",	"balc#",	map_pcrel_r6,
+  false,	"sdc1HSO",	map_pop76_r6,	"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 = ctx.map_pri[rshift(op, 26)]
+  while type(opat) ~= "string" do
+    if not opat then return unknown(ctx) end
+    if opat.maprs then
+      opat = opat[opat.maprs(band(rshift(op,21),31), band(rshift(op,16),31))]
+    else
+      opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
+    end
+  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 == "a" then
+      x = band(rshift(op, 6), 7)
+    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 == "2" then
+      x = arshift(lshift(op, 13), 11)
+    elseif p == "3" then
+      x = arshift(lshift(op, 14), 11)
+    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), 14) + 4
+      ctx.rel = x
+      x = format("0x%08x", x)
+    elseif p == "b" then
+      x = ctx.addr + ctx.pos + arshift(lshift(op, 11), 9) + 4
+      ctx.rel = x
+      x = format("0x%08x", x)
+    elseif p == "#" then
+      x = ctx.addr + ctx.pos + arshift(lshift(op, 6), 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
+  ctx.map_pri = map_pri
+  return ctx
+end
+
+local function create_el(code, addr, out)
+  local ctx = create(code, addr, out)
+  ctx.get = get_le
+  return ctx
+end
+
+local function create_r6(code, addr, out)
+  local ctx = create(code, addr, out)
+  ctx.map_pri = map_pri_r6
+  return ctx
+end
+
+local function create_r6_el(code, addr, out)
+  local ctx = create(code, addr, out)
+  ctx.get = get_le
+  ctx.map_pri = map_pri_r6
+  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
+
+local function disass_r6(code, addr, out)
+  create_r6(code, addr, out):disass()
+end
+
+local function disass_r6_el(code, addr, out)
+  create_r6_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,
+  create_r6 = create_r6,
+  create_r6_el = create_r6_el,
+  disass = disass,
+  disass_el = disass_el,
+  disass_r6 = disass_r6,
+  disass_r6_el = disass_r6_el,
+  regname = regname
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_mips64.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64 disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_mips64el.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64EL disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_mips64r6.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64R6 disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This module just exports the r6 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_r6,
+  disass = dis_mips.disass_r6,
+  regname = dis_mips.regname
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_mips64r6el.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64R6EL disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This module just exports the r6 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_r6_el,
+  disass = dis_mips.disass_r6_el,
+  regname = dis_mips.regname
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_mipsel.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPSEL disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 591 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_ppc.lua

@@ -0,0 +1,591 @@
+----------------------------------------------------------------------------
+-- LuaJIT PPC disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_x64.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT x64 disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 953 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dis_x86.lua

@@ -0,0 +1,953 @@
+----------------------------------------------------------------------------
+-- LuaJIT x86/x64 disassembler module.
+--
+-- Copyright (C) 2005-2021 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",
+--9x
+[0x96] = "||fmaddsub132pHXrvm",[0x97] = "||fmsubadd132pHXrvm",
+[0x98] = "||fmadd132pHXrvm",[0x99] = "||fmadd132sHXrvm",
+[0x9a] = "||fmsub132pHXrvm",[0x9b] = "||fmsub132sHXrvm",
+[0x9c] = "||fnmadd132pHXrvm",[0x9d] = "||fnmadd132sHXrvm",
+[0x9e] = "||fnmsub132pHXrvm",[0x9f] = "||fnmsub132sHXrvm",
+--Ax
+[0xa6] = "||fmaddsub213pHXrvm",[0xa7] = "||fmsubadd213pHXrvm",
+[0xa8] = "||fmadd213pHXrvm",[0xa9] = "||fmadd213sHXrvm",
+[0xaa] = "||fmsub213pHXrvm",[0xab] = "||fmsub213sHXrvm",
+[0xac] = "||fnmadd213pHXrvm",[0xad] = "||fnmadd213sHXrvm",
+[0xae] = "||fnmsub213pHXrvm",[0xaf] = "||fnmsub213sHXrvm",
+--Bx
+[0xb6] = "||fmaddsub231pHXrvm",[0xb7] = "||fmsubadd231pHXrvm",
+[0xb8] = "||fmadd231pHXrvm",[0xb9] = "||fmadd231sHXrvm",
+[0xba] = "||fmsub231pHXrvm",[0xbb] = "||fmsub231sHXrvm",
+[0xbc] = "||fnmadd231pHXrvm",[0xbd] = "||fnmadd231sHXrvm",
+[0xbe] = "||fnmsub231pHXrvm",[0xbf] = "||fnmsub231sHXrvm",
+--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: 1DFGHIMPQRSTUVWXYabcdfgijlmoprstuvwxyz
+  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 == "H" then
+      name = name..(ctx.rexw and "d" or "s")
+      ctx.rexw = false
+    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,
+  H = 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
+}
+

+ 726 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/dump.lua

@@ -0,0 +1,726 @@
+----------------------------------------------------------------------------
+-- LuaJIT compiler dump module.
+--
+-- Copyright (C) 2005-2021 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 maskaddr = jit.arch == "arm" and -2
+    local ircall = vmdef.ircall
+    for i=0,#ircall do
+      local addr = ircalladdr(i)
+      if addr ~= 0 then
+	if maskaddr then addr = band(addr, maskaddr) end
+	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, extra)
+  local out = format(colortype_ansi[t], s)
+  if extra then out = "\027[3m"..out end
+  return out
+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 = { ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;", }
+
+local function colorize_html(s, t, extra)
+  s = gsub(s, "[<>&]", html_escape)
+  return format('<span class="irt_%s%s">%s</span>',
+		irtype_text[t], extra and " irt_extra" or "", 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 = [[
+<style type="text/css">
+background { background: #ffffff; color: #000000; }
+pre.ljdump {
+font-size: 10pt;
+background: #f0f4ff;
+color: #000000;
+border: 1px solid #bfcfff;
+padding: 0.5em;
+margin-left: 2em;
+margin-right: 2em;
+}
+span.irt_str { color: #00a000; }
+span.irt_thr, span.irt_fun { color: #404040; font-weight: bold; }
+span.irt_tab { color: #c00000; }
+span.irt_udt, span.irt_lud { color: #00c0c0; }
+span.irt_num { color: #4040c0; }
+span.irt_int, span.irt_i8, span.irt_u8, span.irt_i16, span.irt_u16 { color: #b040b0; }
+span.irt_extra { font-style: italic; }
+</style>
+]]
+
+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
+    if band(mode, 64) ~= 0 then s = s.."K" 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, 12)
+    if c == 1 then s = s.." none"
+    elseif 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,
+  ["TMPREF"] = { [0] = "", "IN", "OUT", "INOUT", "", "", "OUT2", "INOUT2" },
+  ["BUFHDR"] = { [0] = "RESET", "APPEND", "WRITE" },
+  ["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 t < 12 then
+      s = k == 0 and "NULL" or format("[0x%08x]", k)
+    elseif 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, band(sn or 0, 0x100000) ~= 0)
+  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), band(sn, 0x100000) ~= 0))
+      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('<pre class="ljdump">\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("</pre>\n\n") else out:write("\n") end
+  else
+    if what == "flush" then symtab, nexitsym = {}, 0 end
+    out:write("---- TRACE ", what, "\n\n")
+  end
+  out:flush()
+end
+
+-- Dump recorded bytecode.
+local function dump_record(tr, func, pc, depth)
+  if depth ~= recdepth then
+    recdepth = depth
+    recprefix = rep(" .", depth)
+  end
+  local line
+  if pc >= 0 then
+    line = bcline(func, pc, recprefix)
+    if dumpmode.H then line = gsub(line, "[<>&]", html_escape) end
+  else
+    line = "0000 "..recprefix.." FUNCC      \n"
+  end
+  if pc <= 0 then
+    out:write(sub(line, 1, -2), "         ; ", fmtfunc(func), "\n")
+  else
+    out:write(line)
+  end
+  if pc >= 0 and band(funcbc(func, pc), 0xff) < 16 then -- ORDER BC
+    out:write(bcline(func, pc+1, recprefix)) -- Write JMP for cond.
+  end
+end
+
+------------------------------------------------------------------------------
+
+local gpr64 = jit.arch:match("64")
+local fprmips32 = jit.arch == "mips" or jit.arch == "mipsel"
+
+-- Dump taken trace exits.
+local function dump_texit(tr, ex, ngpr, nfpr, ...)
+  out:write("---- TRACE ", tr, " exit ", ex, "\n")
+  if dumpmode.X then
+    local regs = {...}
+    if gpr64 then
+      for i=1,ngpr do
+	out:write(format(" %016x", regs[i]))
+	if i % 4 == 0 then out:write("\n") end
+      end
+    else
+      for i=1,ngpr do
+	out:write(" ", tohex(regs[i]))
+	if i % 8 == 0 then out:write("\n") end
+      end
+    end
+    if fprmips32 then
+      for i=1,nfpr,2 do
+	out:write(format(" %+17.14g", regs[ngpr+i]))
+	if i % 8 == 7 then out:write("\n") end
+      end
+    else
+      for i=1,nfpr do
+	out:write(format(" %+17.14g", regs[ngpr+i]))
+	if i % 4 == 0 then out:write("\n") end
+      end
+    end
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Detach dump handlers.
+local function dumpoff()
+  if active then
+    active = false
+    jit.attach(dump_texit)
+    jit.attach(dump_record)
+    jit.attach(dump_trace)
+    if out and out ~= stdout and out ~= stderr then out:close() end
+    out = nil
+  end
+end
+
+-- Open the output file and attach dump handlers.
+local function dumpon(opt, outfile)
+  if active then dumpoff() end
+
+  local term = os.getenv("TERM")
+  local colormode = (term and term:match("color") or os.getenv("COLORTERM")) and "A" or "T"
+  if opt then
+    opt = gsub(opt, "[TAH]", function(mode) colormode = mode; return ""; end)
+  end
+
+  local m = { t=true, b=true, i=true, m=true, }
+  if opt and opt ~= "" then
+    local o = sub(opt, 1, 1)
+    if o ~= "+" and o ~= "-" then m = {} end
+    for i=1,#opt do m[sub(opt, i, i)] = (o ~= "-") end
+  end
+  dumpmode = m
+
+  if m.t or m.b or m.i or m.s or m.m then
+    jit.attach(dump_trace, "trace")
+  end
+  if m.b then
+    jit.attach(dump_record, "record")
+    if not bcline then bcline = require("jit.bc").line end
+  end
+  if m.x or m.X then
+    jit.attach(dump_texit, "texit")
+  end
+
+  if not outfile then outfile = os.getenv("LUAJIT_DUMPFILE") end
+  if outfile then
+    out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
+  else
+    out = stdout
+  end
+
+  m[colormode] = true
+  if colormode == "A" then
+    colorize = colorize_ansi
+    irtype = irtype_ansi
+  elseif colormode == "H" then
+    colorize = colorize_html
+    irtype = irtype_html
+    out:write(header_html)
+  else
+    colorize = colorize_text
+    irtype = irtype_text
+  end
+
+  active = true
+end
+
+-- Public module functions.
+return {
+  on = dumpon,
+  off = dumpoff,
+  start = dumpon -- For -j command line option.
+}
+

+ 312 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/p.lua

@@ -0,0 +1,312 @@
+----------------------------------------------------------------------------
+-- LuaJIT profiler.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module is a simple command line interface to the built-in
+-- low-overhead profiler of LuaJIT.
+--
+-- The lower-level API of the profiler is accessible via the "jit.profile"
+-- module or the luaJIT_profile_* C API.
+--
+-- Example usage:
+--
+--   luajit -jp myapp.lua
+--   luajit -jp=s myapp.lua
+--   luajit -jp=-s myapp.lua
+--   luajit -jp=vl myapp.lua
+--   luajit -jp=G,profile.txt myapp.lua
+--
+-- The following dump features are available:
+--
+--   f  Stack dump: function name, otherwise module:line. Default mode.
+--   F  Stack dump: ditto, but always prepend module.
+--   l  Stack dump: module:line.
+--   <number> stack dump depth (callee < caller). Default: 1.
+--   -<number> Inverse stack dump depth (caller > callee).
+--   s  Split stack dump after first stack level. Implies abs(depth) >= 2.
+--   p  Show full path for module names.
+--   v  Show VM states. Can be combined with stack dumps, e.g. vf or fv.
+--   z  Show zones. Can be combined with stack dumps, e.g. zf or fz.
+--   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 (e.g. flame graphs).
+--   m<number> Minimum sample percentage to be shown. Default: 3.
+--   i<number> Sampling interval in milliseconds. Default: 10.
+--
+----------------------------------------------------------------------------
+
+-- Cache some library functions and objects.
+local jit = require("jit")
+assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
+local profile = require("jit.profile")
+local vmdef = require("jit.vmdef")
+local math = math
+local pairs, ipairs, tonumber, floor = pairs, ipairs, tonumber, math.floor
+local sort, format = table.sort, string.format
+local stdout = io.stdout
+local zone -- Load jit.zone module on demand.
+
+-- Output file handle.
+local out
+
+------------------------------------------------------------------------------
+
+local prof_ud
+local prof_states, prof_split, prof_min, prof_raw, prof_fmt, prof_depth
+local prof_ann, prof_count1, prof_count2, prof_samples
+
+local map_vmmode = {
+  N = "Compiled",
+  I = "Interpreted",
+  C = "C code",
+  G = "Garbage Collector",
+  J = "JIT Compiler",
+}
+
+-- Profiler callback.
+local function prof_cb(th, samples, vmmode)
+  prof_samples = prof_samples + samples
+  local key_stack, key_stack2, key_state
+  -- Collect keys for sample.
+  if prof_states then
+    if prof_states == "v" then
+      key_state = map_vmmode[vmmode] or vmmode
+    else
+      key_state = zone:get() or "(none)"
+    end
+  end
+  if prof_fmt then
+    key_stack = profile.dumpstack(th, prof_fmt, prof_depth)
+    key_stack = key_stack:gsub("%[builtin#(%d+)%]", function(x)
+      return vmdef.ffnames[tonumber(x)]
+    end)
+    if prof_split == 2 then
+      local k1, k2 = key_stack:match("(.-) [<>] (.*)")
+      if k2 then key_stack, key_stack2 = k1, k2 end
+    elseif prof_split == 3 then
+      key_stack2 = profile.dumpstack(th, "l", 1)
+    end
+  end
+  -- Order keys.
+  local k1, k2
+  if prof_split == 1 then
+    if key_state then
+      k1 = key_state
+      if key_stack then k2 = key_stack end
+    end
+  elseif key_stack then
+    k1 = key_stack
+    if key_stack2 then k2 = key_stack2 elseif key_state then k2 = key_state end
+  end
+  -- Coalesce samples in one or two levels.
+  if k1 then
+    local t1 = prof_count1
+    t1[k1] = (t1[k1] or 0) + samples
+    if k2 then
+      local t2 = prof_count2
+      local t3 = t2[k1]
+      if not t3 then t3 = {}; t2[k1] = t3 end
+      t3[k2] = (t3[k2] or 0) + samples
+    end
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Show top N list.
+local function prof_top(count1, count2, samples, indent)
+  local t, n = {}, 0
+  for k in pairs(count1) do
+    n = n + 1
+    t[n] = k
+  end
+  sort(t, function(a, b) return count1[a] > count1[b] end)
+  for i=1,n do
+    local k = t[i]
+    local v = count1[k]
+    local pct = floor(v*100/samples + 0.5)
+    if pct < prof_min then break end
+    if not prof_raw then
+      out:write(format("%s%2d%%  %s\n", indent, pct, k))
+    elseif prof_raw == "r" then
+      out:write(format("%s%5d  %s\n", indent, v, k))
+    else
+      out:write(format("%s %d\n", k, v))
+    end
+    if count2 then
+      local r = count2[k]
+      if r then
+	prof_top(r, nil, v, (prof_split == 3 or prof_split == 1) and "  -- " or
+			    (prof_depth < 0 and "  -> " or "  <- "))
+      end
+    end
+  end
+end
+
+-- Annotate source code
+local function prof_annotate(count1, samples)
+  local files = {}
+  local ms = 0
+  for k, v in pairs(count1) do
+    local pct = floor(v*100/samples + 0.5)
+    ms = math.max(ms, v)
+    if pct >= prof_min then
+      local file, line = k:match("^(.*):(%d+)$")
+      if not file then file = k; line = 0 end
+      local fl = files[file]
+      if not fl then fl = {}; files[file] = fl; files[#files+1] = file end
+      line = tonumber(line)
+      fl[line] = prof_raw and v or pct
+    end
+  end
+  sort(files)
+  local fmtv, fmtn = " %3d%% | %s\n", "      | %s\n"
+  if prof_raw then
+    local n = math.max(5, math.ceil(math.log10(ms)))
+    fmtv = "%"..n.."d | %s\n"
+    fmtn = (" "):rep(n).." | %s\n"
+  end
+  local ann = prof_ann
+  for _, file in ipairs(files) do
+    local f0 = file:byte()
+    if f0 == 40 or f0 == 91 then
+      out:write(format("\n====== %s ======\n[Cannot annotate non-file]\n", file))
+      break
+    end
+    local fp, err = io.open(file)
+    if not fp then
+      out:write(format("====== ERROR: %s: %s\n", file, err))
+      break
+    end
+    out:write(format("\n====== %s ======\n", file))
+    local fl = files[file]
+    local n, show = 1, false
+    if ann ~= 0 then
+      for i=1,ann do
+	if fl[i] then show = true; out:write("@@ 1 @@\n"); break end
+      end
+    end
+    for line in fp:lines() do
+      if line:byte() == 27 then
+	out:write("[Cannot annotate bytecode file]\n")
+	break
+      end
+      local v = fl[n]
+      if ann ~= 0 then
+	local v2 = fl[n+ann]
+	if show then
+	  if v2 then show = n+ann elseif v then show = n
+	  elseif show+ann < n then show = false end
+	elseif v2 then
+	  show = n+ann
+	  out:write(format("@@ %d @@\n", n))
+	end
+	if not show then goto next end
+      end
+      if v then
+	out:write(format(fmtv, v, line))
+      else
+	out:write(format(fmtn, line))
+      end
+    ::next::
+      n = n + 1
+    end
+    fp:close()
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Finish profiling and dump result.
+local function prof_finish()
+  if prof_ud then
+    profile.stop()
+    local samples = prof_samples
+    if samples == 0 then
+      if prof_raw ~= true then out:write("[No samples collected]\n") end
+      return
+    end
+    if prof_ann then
+      prof_annotate(prof_count1, samples)
+    else
+      prof_top(prof_count1, prof_count2, samples, "")
+    end
+    prof_count1 = nil
+    prof_count2 = nil
+    prof_ud = nil
+    if out ~= stdout then out:close() end
+  end
+end
+
+-- Start profiling.
+local function prof_start(mode)
+  local interval = ""
+  mode = mode:gsub("i%d*", function(s) interval = s; return "" end)
+  prof_min = 3
+  mode = mode:gsub("m(%d+)", function(s) prof_min = tonumber(s); return "" end)
+  prof_depth = 1
+  mode = mode:gsub("%-?%d+", function(s) prof_depth = tonumber(s); return "" end)
+  local m = {}
+  for c in mode:gmatch(".") do m[c] = c end
+  prof_states = m.z or m.v
+  if prof_states == "z" then zone = require("jit.zone") end
+  local scope = m.l or m.f or m.F or (prof_states and "" or "f")
+  local flags = (m.p or "")
+  prof_raw = m.r
+  if m.s then
+    prof_split = 2
+    if prof_depth == -1 or m["-"] then prof_depth = -2
+    elseif prof_depth == 1 then prof_depth = 2 end
+  elseif mode:find("[fF].*l") then
+    scope = "l"
+    prof_split = 3
+  else
+    prof_split = (scope == "" or mode:find("[zv].*[lfF]")) and 1 or 0
+  end
+  prof_ann = m.A and 0 or (m.a and 3)
+  if prof_ann then
+    scope = "l"
+    prof_fmt = "pl"
+    prof_split = 0
+    prof_depth = 1
+  elseif m.G and scope ~= "" then
+    prof_fmt = flags..scope.."Z;"
+    prof_depth = -100
+    prof_raw = true
+    prof_min = 0
+  elseif scope == "" then
+    prof_fmt = false
+  else
+    local sc = prof_split == 3 and m.f or m.F or scope
+    prof_fmt = flags..sc..(prof_depth >= 0 and "Z < " or "Z > ")
+  end
+  prof_count1 = {}
+  prof_count2 = {}
+  prof_samples = 0
+  profile.start(scope:lower()..interval, prof_cb)
+  prof_ud = newproxy(true)
+  getmetatable(prof_ud).__gc = prof_finish
+end
+
+------------------------------------------------------------------------------
+
+local function start(mode, outfile)
+  if not outfile then outfile = os.getenv("LUAJIT_PROFILEFILE") end
+  if outfile then
+    out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
+  else
+    out = stdout
+  end
+  prof_start(mode or "f")
+end
+
+-- Public module functions.
+return {
+  start = start, -- For -j command line option.
+  stop = prof_finish
+}
+

+ 170 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/v.lua

@@ -0,0 +1,170 @@
+----------------------------------------------------------------------------
+-- Verbose mode of the LuaJIT compiler.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module shows verbose information about the progress of the
+-- JIT compiler. It prints one line for each generated trace. This module
+-- is useful to see which code has been compiled or where the compiler
+-- punts and falls back to the interpreter.
+--
+-- Example usage:
+--
+--   luajit -jv -e "for i=1,1000 do for j=1,1000 do end end"
+--   luajit -jv=myapp.out myapp.lua
+--
+-- Default output is to stderr. To redirect the output to a file, pass a
+-- filename as an argument (use '-' for stdout) or set the environment
+-- variable LUAJIT_VERBOSEFILE. The file is overwritten every time the
+-- module is started.
+--
+-- The output from the first example should look like this:
+--
+-- [TRACE   1 (command line):1 loop]
+-- [TRACE   2 (1/3) (command line):1 -> 1]
+--
+-- The first number in each line is the internal trace number. Next are
+-- the file name ('(command line)') and the line number (':1') where the
+-- trace has started. Side traces also show the parent trace number and
+-- the exit number where they are attached to in parentheses ('(1/3)').
+-- An arrow at the end shows where the trace links to ('-> 1'), unless
+-- it loops to itself.
+--
+-- In this case the inner loop gets hot and is traced first, generating
+-- a root trace. Then the last exit from the 1st trace gets hot, too,
+-- and triggers generation of the 2nd trace. The side trace follows the
+-- path along the outer loop and *around* the inner loop, back to its
+-- start, and then links to the 1st trace. Yes, this may seem unusual,
+-- if you know how traditional compilers work. Trace compilers are full
+-- of surprises like this -- have fun! :-)
+--
+-- Aborted traces are shown like this:
+--
+-- [TRACE --- foo.lua:44 -- leaving loop in root trace at foo:lua:50]
+--
+-- Don't worry -- trace aborts are quite common, even in programs which
+-- can be fully compiled. The compiler may retry several times until it
+-- finds a suitable trace.
+--
+-- Of course this doesn't work with features that are not-yet-implemented
+-- (NYI error messages). The VM simply falls back to the interpreter. This
+-- may not matter at all if the particular trace is not very high up in
+-- the CPU usage profile. Oh, and the interpreter is quite fast, too.
+--
+-- Also check out the -jdump module, which prints all the gory details.
+--
+------------------------------------------------------------------------------
+
+-- 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, traceinfo = jutil.funcinfo, jutil.traceinfo
+local type, format = type, string.format
+local stdout, stderr = io.stdout, io.stderr
+
+-- Active flag and output file handle.
+local active, out
+
+------------------------------------------------------------------------------
+
+local startloc, startex
+
+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
+
+-- 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 == "start" then
+    startloc = fmtfunc(func, pc)
+    startex = otr and "("..otr.."/"..(oex == -1 and "stitch" or oex)..") " or ""
+  else
+    if what == "abort" then
+      local loc = fmtfunc(func, pc)
+      if loc ~= startloc then
+	out:write(format("[TRACE --- %s%s -- %s at %s]\n",
+	  startex, startloc, fmterr(otr, oex), loc))
+      else
+	out:write(format("[TRACE --- %s%s -- %s]\n",
+	  startex, startloc, fmterr(otr, oex)))
+      end
+    elseif what == "stop" then
+      local info = traceinfo(tr)
+      local link, ltype = info.link, info.linktype
+      if ltype == "interpreter" then
+	out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n",
+	  tr, startex, startloc))
+      elseif ltype == "stitch" then
+	out:write(format("[TRACE %3s %s%s %s %s]\n",
+	  tr, startex, startloc, ltype, fmtfunc(func, pc)))
+      elseif link == tr or link == 0 then
+	out:write(format("[TRACE %3s %s%s %s]\n",
+	  tr, startex, startloc, ltype))
+      elseif ltype == "root" then
+	out:write(format("[TRACE %3s %s%s -> %d]\n",
+	  tr, startex, startloc, link))
+      else
+	out:write(format("[TRACE %3s %s%s -> %d %s]\n",
+	  tr, startex, startloc, link, ltype))
+      end
+    else
+      out:write(format("[TRACE %s]\n", what))
+    end
+    out:flush()
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Detach dump handlers.
+local function dumpoff()
+  if active then
+    active = false
+    jit.attach(dump_trace)
+    if out and out ~= stdout and out ~= stderr then out:close() end
+    out = nil
+  end
+end
+
+-- Open the output file and attach dump handlers.
+local function dumpon(outfile)
+  if active then dumpoff() end
+  if not outfile then outfile = os.getenv("LUAJIT_VERBOSEFILE") end
+  if outfile then
+    out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
+  else
+    out = stderr
+  end
+  jit.attach(dump_trace, "trace")
+  active = true
+end
+
+-- Public module functions.
+return {
+  on = dumpon,
+  off = dumpoff,
+  start = dumpon -- For -j command line option.
+}
+

+ 395 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/vmdef.lua

@@ -0,0 +1,395 @@
+-- This is a generated file. DO NOT EDIT!
+
+return {
+
+bcnames = "ISLT  ISGE  ISLE  ISGT  ISEQV ISNEV ISEQS ISNES ISEQN ISNEN ISEQP ISNEP ISTC  ISFC  IST   ISF   ISTYPEISNUM MOV   NOT   UNM   LEN   ADDVN SUBVN MULVN DIVVN MODVN ADDNV SUBNV MULNV DIVNV MODNV ADDVV SUBVV MULVV DIVVV MODVV POW   CAT   KSTR  KCDATAKSHORTKNUM  KPRI  KNIL  UGET  USETV USETS USETN USETP UCLO  FNEW  TNEW  TDUP  GGET  GSET  TGETV TGETS TGETB TGETR TSETV TSETS TSETB TSETM TSETR CALLM CALL  CALLMTCALLT ITERC ITERN VARG  ISNEXTRETM  RET   RET0  RET1  FORI  JFORI FORL  IFORL JFORL ITERL IITERLJITERLLOOP  ILOOP JLOOP JMP   FUNCF IFUNCFJFUNCFFUNCV IFUNCVJFUNCVFUNCC FUNCCW",
+
+irnames = "LT    GE    LE    GT    ULT   UGE   ULE   UGT   EQ    NE    ABC   RETF  NOP   BASE  PVAL  GCSTEPHIOP  LOOP  USE   PHI   RENAMEPROF  KPRI  KINT  KGC   KPTR  KKPTR KNULL KNUM  KINT64KSLOT BNOT  BSWAP BAND  BOR   BXOR  BSHL  BSHR  BSAR  BROL  BROR  ADD   SUB   MUL   DIV   MOD   POW   NEG   ABS   LDEXP MIN   MAX   FPMATHADDOV SUBOV MULOV AREF  HREFK HREF  NEWREFUREFO UREFC FREF  TMPREFSTRREFLREF  ALOAD HLOAD ULOAD FLOAD XLOAD SLOAD VLOAD ALEN  ASTOREHSTOREUSTOREFSTOREXSTORESNEW  XSNEW TNEW  TDUP  CNEW  CNEWI BUFHDRBUFPUTBUFSTRTBAR  OBAR  XBAR  CONV  TOBIT TOSTR STRTO CALLN CALLA CALLL CALLS CALLXSCARG  ",
+
+irfpm = { [0]="floor", "ceil", "trunc", "sqrt", "log", "log2", "other", },
+
+irfield = { [0]="str.len", "func.env", "func.pc", "func.ffid", "thread.env", "tab.meta", "tab.array", "tab.node", "tab.asize", "tab.hmask", "tab.nomm", "udata.meta", "udata.udtype", "udata.file", "sbuf.w", "sbuf.e", "sbuf.b", "sbuf.l", "sbuf.ref", "sbuf.r", "cdata.ctypeid", "cdata.ptr", "cdata.int", "cdata.int64", "cdata.int64_4", },
+
+ircall = {
+[0]="lj_str_cmp",
+"lj_str_find",
+"lj_str_new",
+"lj_strscan_num",
+"lj_strfmt_int",
+"lj_strfmt_num",
+"lj_strfmt_char",
+"lj_strfmt_putint",
+"lj_strfmt_putnum",
+"lj_strfmt_putquoted",
+"lj_strfmt_putfxint",
+"lj_strfmt_putfnum_int",
+"lj_strfmt_putfnum_uint",
+"lj_strfmt_putfnum",
+"lj_strfmt_putfstr",
+"lj_strfmt_putfchar",
+"lj_buf_putmem",
+"lj_buf_putstr",
+"lj_buf_putchar",
+"lj_buf_putstr_reverse",
+"lj_buf_putstr_lower",
+"lj_buf_putstr_upper",
+"lj_buf_putstr_rep",
+"lj_buf_puttab",
+"lj_bufx_set",
+"lj_bufx_more",
+"lj_serialize_put",
+"lj_serialize_get",
+"lj_serialize_encode",
+"lj_serialize_decode",
+"lj_buf_tostr",
+"lj_tab_new_ah",
+"lj_tab_new1",
+"lj_tab_dup",
+"lj_tab_clear",
+"lj_tab_newkey",
+"lj_tab_keyindex",
+"lj_vm_next",
+"lj_tab_len",
+"lj_tab_len_hint",
+"lj_gc_step_jit",
+"lj_gc_barrieruv",
+"lj_mem_newgco",
+"lj_prng_u64d",
+"lj_vm_modi",
+"log10",
+"exp",
+"sin",
+"cos",
+"tan",
+"asin",
+"acos",
+"atan",
+"sinh",
+"cosh",
+"tanh",
+"fputc",
+"fwrite",
+"fflush",
+"lj_vm_floor",
+"lj_vm_ceil",
+"lj_vm_trunc",
+"sqrt",
+"log",
+"lj_vm_log2",
+"lj_vm_powi",
+"pow",
+"atan2",
+"ldexp",
+"lj_vm_tobit",
+"softfp_add",
+"softfp_sub",
+"softfp_mul",
+"softfp_div",
+"softfp_cmp",
+"softfp_i2d",
+"softfp_d2i",
+"lj_vm_sfmin",
+"lj_vm_sfmax",
+"lj_vm_tointg",
+"softfp_ui2d",
+"softfp_f2d",
+"softfp_d2ui",
+"softfp_d2f",
+"softfp_i2f",
+"softfp_ui2f",
+"softfp_f2i",
+"softfp_f2ui",
+"fp64_l2d",
+"fp64_ul2d",
+"fp64_l2f",
+"fp64_ul2f",
+"fp64_d2l",
+"fp64_d2ul",
+"fp64_f2l",
+"fp64_f2ul",
+"lj_carith_divi64",
+"lj_carith_divu64",
+"lj_carith_modi64",
+"lj_carith_modu64",
+"lj_carith_powi64",
+"lj_carith_powu64",
+"lj_cdata_newv",
+"lj_cdata_setfin",
+"strlen",
+"memcpy",
+"memset",
+"lj_vm_errno",
+"lj_carith_mul64",
+"lj_carith_shl64",
+"lj_carith_shr64",
+"lj_carith_sar64",
+"lj_carith_rol64",
+"lj_carith_ror64",
+},
+
+traceerr = {
+[0]="error thrown or hook called during recording",
+"trace too short",
+"trace too long",
+"trace too deep",
+"too many snapshots",
+"blacklisted",
+"retry recording",
+"NYI: bytecode %d",
+"leaving loop in root trace",
+"inner loop in root trace",
+"loop unroll limit reached",
+"bad argument type",
+"JIT compilation disabled for function",
+"call unroll limit reached",
+"down-recursion, restarting",
+"NYI: unsupported variant of FastFunc %s",
+"NYI: return to lower frame",
+"store with nil or NaN key",
+"missing metamethod",
+"looping index lookup",
+"NYI: mixed sparse/dense table",
+"symbol not in cache",
+"NYI: unsupported C type conversion",
+"NYI: unsupported C function type",
+"guard would always fail",
+"too many PHIs",
+"persistent type instability",
+"failed to allocate mcode memory",
+"machine code too long",
+"hit mcode limit (retrying)",
+"too many spill slots",
+"inconsistent register allocation",
+"NYI: cannot assemble IR instruction %d",
+"NYI: PHI shuffling too complex",
+"NYI: register coalescing too complex",
+},
+
+ffnames = {
+[0]="Lua",
+"C",
+"assert",
+"type",
+"next",
+"pairs",
+"ipairs_aux",
+"ipairs",
+"getmetatable",
+"setmetatable",
+"getfenv",
+"setfenv",
+"rawget",
+"rawset",
+"rawequal",
+"unpack",
+"select",
+"tonumber",
+"tostring",
+"error",
+"pcall",
+"xpcall",
+"loadfile",
+"load",
+"loadstring",
+"dofile",
+"gcinfo",
+"collectgarbage",
+"newproxy",
+"print",
+"coroutine.status",
+"coroutine.running",
+"coroutine.isyieldable",
+"coroutine.create",
+"coroutine.yield",
+"coroutine.resume",
+"coroutine.wrap_aux",
+"coroutine.wrap",
+"math.abs",
+"math.floor",
+"math.ceil",
+"math.sqrt",
+"math.log10",
+"math.exp",
+"math.sin",
+"math.cos",
+"math.tan",
+"math.asin",
+"math.acos",
+"math.atan",
+"math.sinh",
+"math.cosh",
+"math.tanh",
+"math.frexp",
+"math.modf",
+"math.log",
+"math.atan2",
+"math.pow",
+"math.fmod",
+"math.ldexp",
+"math.min",
+"math.max",
+"math.random",
+"math.randomseed",
+"bit.tobit",
+"bit.bnot",
+"bit.bswap",
+"bit.lshift",
+"bit.rshift",
+"bit.arshift",
+"bit.rol",
+"bit.ror",
+"bit.band",
+"bit.bor",
+"bit.bxor",
+"bit.tohex",
+"string.byte",
+"string.char",
+"string.sub",
+"string.rep",
+"string.reverse",
+"string.lower",
+"string.upper",
+"string.dump",
+"string.find",
+"string.match",
+"string.gmatch_aux",
+"string.gmatch",
+"string.gsub",
+"string.format",
+"table.maxn",
+"table.insert",
+"table.concat",
+"table.sort",
+"table.new",
+"table.clear",
+"io.method.close",
+"io.method.read",
+"io.method.write",
+"io.method.flush",
+"io.method.seek",
+"io.method.setvbuf",
+"io.method.lines",
+"io.method.__gc",
+"io.method.__tostring",
+"io.open",
+"io.popen",
+"io.tmpfile",
+"io.close",
+"io.read",
+"io.write",
+"io.flush",
+"io.input",
+"io.output",
+"io.lines",
+"io.type",
+"os.execute",
+"os.remove",
+"os.rename",
+"os.tmpname",
+"os.getenv",
+"os.exit",
+"os.clock",
+"os.date",
+"os.time",
+"os.difftime",
+"os.setlocale",
+"debug.getregistry",
+"debug.getmetatable",
+"debug.setmetatable",
+"debug.getfenv",
+"debug.setfenv",
+"debug.getinfo",
+"debug.getlocal",
+"debug.setlocal",
+"debug.getupvalue",
+"debug.setupvalue",
+"debug.upvalueid",
+"debug.upvaluejoin",
+"debug.sethook",
+"debug.gethook",
+"debug.debug",
+"debug.traceback",
+"jit.on",
+"jit.off",
+"jit.flush",
+"jit.status",
+"jit.security",
+"jit.attach",
+"jit.util.funcinfo",
+"jit.util.funcbc",
+"jit.util.funck",
+"jit.util.funcuvname",
+"jit.util.traceinfo",
+"jit.util.traceir",
+"jit.util.tracek",
+"jit.util.tracesnap",
+"jit.util.tracemc",
+"jit.util.traceexitstub",
+"jit.util.ircalladdr",
+"jit.opt.start",
+"jit.profile.start",
+"jit.profile.stop",
+"jit.profile.dumpstack",
+"ffi.meta.__index",
+"ffi.meta.__newindex",
+"ffi.meta.__eq",
+"ffi.meta.__len",
+"ffi.meta.__lt",
+"ffi.meta.__le",
+"ffi.meta.__concat",
+"ffi.meta.__call",
+"ffi.meta.__add",
+"ffi.meta.__sub",
+"ffi.meta.__mul",
+"ffi.meta.__div",
+"ffi.meta.__mod",
+"ffi.meta.__pow",
+"ffi.meta.__unm",
+"ffi.meta.__tostring",
+"ffi.meta.__pairs",
+"ffi.meta.__ipairs",
+"ffi.clib.__index",
+"ffi.clib.__newindex",
+"ffi.clib.__gc",
+"ffi.callback.free",
+"ffi.callback.set",
+"ffi.cdef",
+"ffi.new",
+"ffi.cast",
+"ffi.typeof",
+"ffi.typeinfo",
+"ffi.istype",
+"ffi.sizeof",
+"ffi.alignof",
+"ffi.offsetof",
+"ffi.errno",
+"ffi.string",
+"ffi.copy",
+"ffi.fill",
+"ffi.abi",
+"ffi.metatype",
+"ffi.gc",
+"ffi.load",
+"buffer.method.free",
+"buffer.method.reset",
+"buffer.method.skip",
+"buffer.method.set",
+"buffer.method.put",
+"buffer.method.putf",
+"buffer.method.get",
+"buffer.method.putcdata",
+"buffer.method.reserve",
+"buffer.method.commit",
+"buffer.method.ref",
+"buffer.method.encode",
+"buffer.method.decode",
+"buffer.method.__gc",
+"buffer.method.__tostring",
+"buffer.method.__len",
+"buffer.new",
+"buffer.encode",
+"buffer.decode",
+},
+
+}
+

+ 45 - 0
love/src/jni/LuaJIT-2.1/android/arm64-v8a/jit/zone.lua

@@ -0,0 +1,45 @@
+----------------------------------------------------------------------------
+-- LuaJIT profiler zones.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module implements a simple hierarchical zone model.
+--
+-- Example usage:
+--
+--   local zone = require("jit.zone")
+--   zone("AI")
+--   ...
+--     zone("A*")
+--     ...
+--     print(zone:get()) --> "A*"
+--     ...
+--     zone()
+--   ...
+--   print(zone:get()) --> "AI"
+--   ...
+--   zone()
+--
+----------------------------------------------------------------------------
+
+local remove = table.remove
+
+return setmetatable({
+  flush = function(t)
+    for i=#t,1,-1 do t[i] = nil end
+  end,
+  get = function(t)
+    return t[#t]
+  end
+}, {
+  __call = function(t, zone)
+    if zone then
+      t[#t+1] = zone
+    else
+      return (assert(remove(t), "empty zone stack"))
+    end
+  end
+})
+

BIN
love/src/jni/LuaJIT-2.1/android/arm64-v8a/libluajit.a


+ 190 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/bc.lua

@@ -0,0 +1,190 @@
+----------------------------------------------------------------------------
+-- LuaJIT bytecode listing module.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module lists the bytecode of a Lua function. If it's loaded by -jbc
+-- it hooks into the parser and lists all functions of a chunk as they
+-- are parsed.
+--
+-- Example usage:
+--
+--   luajit -jbc -e 'local x=0; for i=1,1e6 do x=x+i end; print(x)'
+--   luajit -jbc=- foo.lua
+--   luajit -jbc=foo.list foo.lua
+--
+-- Default output is to stderr. To redirect the output to a file, pass a
+-- filename as an argument (use '-' for stdout) or set the environment
+-- variable LUAJIT_LISTFILE. The file is overwritten every time the module
+-- is started.
+--
+-- This module can also be used programmatically:
+--
+--   local bc = require("jit.bc")
+--
+--   local function foo() print("hello") end
+--
+--   bc.dump(foo)           --> -- 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.
+}
+

+ 665 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/bcsave.lua

@@ -0,0 +1,665 @@
+----------------------------------------------------------------------------
+-- LuaJIT module to save/list bytecode.
+--
+-- Copyright (C) 2005-2021 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 type, assert = type, assert
+local format = string.format
+local tremove, tconcat = table.remove, table.concat
+
+------------------------------------------------------------------------------
+
+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 =		{ e = "le", b = 32, m = 3, p = 0x14c, },
+  x64 =		{ e = "le", b = 64, m = 62, p = 0x8664, },
+  arm =		{ e = "le", b = 32, m = 40, p = 0x1c0, },
+  arm64 =	{ e = "le", b = 64, m = 183, p = 0xaa64, },
+  arm64be =	{ e = "be", b = 64, m = 183, },
+  ppc =		{ e = "be", b = 32, m = 20, },
+  mips =	{ e = "be", b = 32, m = 8, f = 0x50001006, },
+  mipsel =	{ e = "le", b = 32, m = 8, f = 0x50001006, },
+  mips64 =	{ e = "be", b = 64, m = 8, f = 0x80000007, },
+  mips64el =	{ e = "le", b = 64, m = 8, f = 0x80000007, },
+  mips64r6 =	{ e = "be", b = 64, m = 8, f = 0xa0000407, },
+  mips64r6el =	{ e = "le", b = 64, m = 8, f = 0xa0000407, },
+}
+
+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 = str:lower()
+  local s = check(map[str], "unknown ", err)
+  return type(s) == "string" and s or str
+end
+
+local function detecttype(str)
+  local ext = str:lower():match("%.(%a+)$")
+  return map_type[ext] or "raw"
+end
+
+local function checkmodname(str)
+  check(str:match("^[%w_.%-]+$"), "bad module name")
+  return str:gsub("[%.%-]", "_")
+end
+
+local function detectmodname(str)
+  if type(str) == "string" then
+    local tail = str:match("[^/\\]+$")
+    if tail then str = tail end
+    local head = str:match("^(.*)%.[^.]*$")
+    if head then str = head end
+    str = str:match("^[%w_.%-]+")
+  else
+    str = nil
+  end
+  check(str, "cannot derive module name, use -n name")
+  return str:gsub("[%.%-]", "_")
+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(format([[
+#ifdef __cplusplus
+extern "C"
+#endif
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+const unsigned char %s%s[] = {
+]], LJBC_PREFIX, ctx.modname))
+  else
+    fp:write(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(tconcat(t, ",", 1, n), ",\n")
+      n, m = 0, #b + 1
+    end
+    n = n + 1
+    t[n] = b
+  end
+  bcsave_tail(fp, output, tconcat(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 ai = assert(map_arch[ctx.arch])
+  local is64, isbe = ai.b == 64, ai.e == "be"
+
+  -- 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(ai.m)
+  hdr.flags = f32(ai.f or 0)
+  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+2)
+  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 ai = assert(map_arch[ctx.arch])
+  local is64 = ai.b == 64
+  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(assert(ai.p))
+  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 = jit.os:lower(),
+    type = false, modname = false,
+  }
+  while n <= #arg do
+    local a = arg[n]
+    if type(a) == "string" and a:sub(1, 1) == "-" and a ~= "-" then
+      tremove(arg, n)
+      if a == "--" then break end
+      for m=2,#a do
+	local opt = a:sub(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(tremove(arg, n))
+	  elseif opt == "t" then
+	    ctx.type = checkarg(tremove(arg, n), map_type, "file type")
+	  elseif opt == "a" then
+	    ctx.arch = checkarg(tremove(arg, n), map_arch, "architecture")
+	  elseif opt == "o" then
+	    ctx.os = checkarg(tremove(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.
+}
+

+ 689 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_arm.lua

@@ -0,0 +1,689 @@
+----------------------------------------------------------------------------
+-- LuaJIT ARM disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 1216 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_arm64.lua

@@ -0,0 +1,1216 @@
+----------------------------------------------------------------------------
+-- LuaJIT ARM64 disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+	else
+	  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 <R>.
+      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
+}
+

+ 12 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_arm64be.lua

@@ -0,0 +1,12 @@
+----------------------------------------------------------------------------
+-- LuaJIT ARM64BE disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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")
+

+ 694 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_mips.lua

@@ -0,0 +1,694 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+
+------------------------------------------------------------------------------
+-- Extended opcode maps common to all MIPS releases
+------------------------------------------------------------------------------
+
+local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", }
+local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", }
+
+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",
+  },
+}
+
+------------------------------------------------------------------------------
+-- Primary and extended opcode maps for MIPS R1-R5
+------------------------------------------------------------------------------
+
+local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", }
+
+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_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",
+}
+
+------------------------------------------------------------------------------
+-- Primary and extended opcode maps for MIPS R6
+------------------------------------------------------------------------------
+
+local map_mul_r6 =   { shift = 6, mask = 3, [2] = "mulDST",   [3] = "muhDST" }
+local map_mulu_r6 =  { shift = 6, mask = 3, [2] = "muluDST",  [3] = "muhuDST" }
+local map_div_r6 =   { shift = 6, mask = 3, [2] = "divDST",   [3] = "modDST" }
+local map_divu_r6 =  { shift = 6, mask = 3, [2] = "divuDST",  [3] = "moduDST" }
+local map_dmul_r6 =  { shift = 6, mask = 3, [2] = "dmulDST",  [3] = "dmuhDST" }
+local map_dmulu_r6 = { shift = 6, mask = 3, [2] = "dmuluDST", [3] = "dmuhuDST" }
+local map_ddiv_r6 =  { shift = 6, mask = 3, [2] = "ddivDST",  [3] = "dmodDST" }
+local map_ddivu_r6 = { shift = 6, mask = 3, [2] = "ddivuDST", [3] = "dmoduDST" }
+
+local map_special_r6 = {
+  shift = 0, mask = 63,
+  [0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
+  false,	map_srl,	"sraDTA",
+  "sllvDTS",	false,		map_srlv,	"sravDTS",
+  "jrS",	"jalrD1S",	false,		false,
+  "syscallY",	"breakY",	false,		"sync",
+  "clzDS",	"cloDS",	"dclzDS",	"dcloDS",
+  "dsllvDST",	"dlsaDSTA",	"dsrlvDST",	"dsravDST",
+  map_mul_r6,	map_mulu_r6,	map_div_r6,	map_divu_r6,
+  map_dmul_r6,	map_dmulu_r6,	map_ddiv_r6,	map_ddivu_r6,
+  "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",	"seleqzDST",	"tneSTZ",	"selnezDST",
+  "dsllDTA",	false,		"dsrlDTA",	"dsraDTA",
+  "dsll32DTA",	false,		"dsrl32DTA",	"dsra32DTA",
+}
+
+local map_bshfl_r6 = {
+  shift = 9, mask = 3,
+  [1] = "alignDSTa",
+  _ = {
+    shift = 6, mask = 31,
+    [0] = "bitswapDT",
+    [2] = "wsbhDT",
+    [16] = "sebDT",
+    [24] = "sehDT",
+  }
+}
+
+local map_dbshfl_r6 = {
+  shift = 9, mask = 3,
+  [1] = "dalignDSTa",
+  _ = {
+    shift = 6, mask = 31,
+    [0] = "dbitswapDT",
+    [2] = "dsbhDT",
+    [5] = "dshdDT",
+  }
+}
+
+local map_special3_r6 = {
+  shift = 0, mask = 63,
+  [0]  = "extTSAK", [1]  = "dextmTSAP", [3]  = "dextTSAK",
+  [4]  = "insTSAL", [6]  = "dinsuTSEQ", [7]  = "dinsTSAL",
+  [32] = map_bshfl_r6, [36] = map_dbshfl_r6,  [59] = "rdhwrTD",
+}
+
+local map_regimm_r6 = {
+  shift = 16, mask = 31,
+  [0] = "bltzSB", [1] = "bgezSB",
+  [6] = "dahiSI", [30] = "datiSI",
+  [23] = "sigrieI", [31] = "synciSO",
+}
+
+local map_pcrel_r6 = {
+  shift = 19, mask = 3,
+  [0] = "addiupcS2", "lwpcS2", "lwupcS2", {
+    shift = 18, mask = 1,
+    [0] = "ldpcS3", { shift = 16, mask = 3, [2] = "auipcSI", [3] = "aluipcSI" }
+  }
+}
+
+local map_cop1s_r6 = {
+  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",
+  "sel.sFGH",		false,		false,		false,
+  "seleqz.sFGH",	"recip.sFG",	"rsqrt.sFG",	"selnez.sFGH",
+  "maddf.sFGH",		"msubf.sFGH",	"rint.sFG",	"class.sFG",
+  "min.sFGH",		"mina.sFGH",	"max.sFGH",	"maxa.sFGH",
+  false,		"cvt.d.sFG",	false,		false,
+  "cvt.w.sFG",		"cvt.l.sFG",
+}
+
+local map_cop1d_r6 = {
+  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",
+  "sel.dFGH",		false,		false,		false,
+  "seleqz.dFGH",	"recip.dFG",	"rsqrt.dFG",	"selnez.dFGH",
+  "maddf.dFGH",		"msubf.dFGH",	"rint.dFG",	"class.dFG",
+  "min.dFGH",		"mina.dFGH",	"max.dFGH",	"maxa.dFGH",
+  "cvt.s.dFG",		false,		false,		false,
+  "cvt.w.dFG",		"cvt.l.dFG",
+}
+
+local map_cop1w_r6 = {
+  shift = 0, mask = 63,
+  [0] = "cmp.af.sFGH",	"cmp.un.sFGH",	"cmp.eq.sFGH",	"cmp.ueq.sFGH",
+  "cmp.lt.sFGH",	"cmp.ult.sFGH",	"cmp.le.sFGH",	"cmp.ule.sFGH",
+  "cmp.saf.sFGH",	"cmp.sun.sFGH",	"cmp.seq.sFGH",	"cmp.sueq.sFGH",
+  "cmp.slt.sFGH",	"cmp.sult.sFGH",	"cmp.sle.sFGH",	"cmp.sule.sFGH",
+  false,		"cmp.or.sFGH",	"cmp.une.sFGH",	"cmp.ne.sFGH",
+  false,		false,		false,		false,
+  false,		"cmp.sor.sFGH",	"cmp.sune.sFGH",	"cmp.sne.sFGH",
+  false,		false,		false,		false,
+  "cvt.s.wFG", "cvt.d.wFG",
+}
+
+local map_cop1l_r6 = {
+  shift = 0, mask = 63,
+  [0] = "cmp.af.dFGH",	"cmp.un.dFGH",	"cmp.eq.dFGH",	"cmp.ueq.dFGH",
+  "cmp.lt.dFGH",	"cmp.ult.dFGH",	"cmp.le.dFGH",	"cmp.ule.dFGH",
+  "cmp.saf.dFGH",	"cmp.sun.dFGH",	"cmp.seq.dFGH",	"cmp.sueq.dFGH",
+  "cmp.slt.dFGH",	"cmp.sult.dFGH",	"cmp.sle.dFGH",	"cmp.sule.dFGH",
+  false,		"cmp.or.dFGH",	"cmp.une.dFGH",	"cmp.ne.dFGH",
+  false,		false,		false,		false,
+  false,		"cmp.sor.dFGH",	"cmp.sune.dFGH",	"cmp.sne.dFGH",
+  false,		false,		false,		false,
+  "cvt.s.lFG", "cvt.d.lFG",
+}
+
+local map_cop1_r6 = {
+  shift = 21, mask = 31,
+  [0] = "mfc1TG", "dmfc1TG",	"cfc1TG",	"mfhc1TG",
+  "mtc1TG",	"dmtc1TG",	"ctc1TG",	"mthc1TG",
+  false,	"bc1eqzHB",	false,		false,
+  false,	"bc1nezHB",	false,		false,
+  map_cop1s_r6,	map_cop1d_r6,	false,		false,
+  map_cop1w_r6,	map_cop1l_r6,
+}
+
+local function maprs_popTS(rs, rt)
+  if rt == 0 then return 0 elseif rs == 0 then return 1
+  elseif rs == rt then return 2 else return 3 end
+end
+
+local map_pop06_r6 = {
+  maprs = maprs_popTS, [0] = "blezSB", "blezalcTB", "bgezalcTB", "bgeucSTB"
+}
+local map_pop07_r6 = {
+  maprs = maprs_popTS, [0] = "bgtzSB", "bgtzalcTB", "bltzalcTB", "bltucSTB"
+}
+local map_pop26_r6 = {
+  maprs = maprs_popTS, "blezcTB", "bgezcTB", "bgecSTB"
+}
+local map_pop27_r6 = {
+  maprs = maprs_popTS, "bgtzcTB", "bltzcTB", "bltcSTB"
+}
+
+local function maprs_popS(rs, rt)
+  if rs == 0 then return 0 else return 1 end
+end
+
+local map_pop66_r6 = {
+  maprs = maprs_popS, [0] = "jicTI", "beqzcSb"
+}
+local map_pop76_r6 = {
+  maprs = maprs_popS, [0] = "jialcTI", "bnezcSb"
+}
+
+local function maprs_popST(rs, rt)
+  if rs >= rt then return 0 elseif rs == 0 then return 1 else return 2 end
+end
+
+local map_pop10_r6 = {
+  maprs = maprs_popST, [0] = "bovcSTB", "beqzalcTB", "beqcSTB"
+}
+local map_pop30_r6 = {
+  maprs = maprs_popST, [0] = "bnvcSTB", "bnezalcTB", "bnecSTB"
+}
+
+local map_pri_r6 = {
+  [0] = map_special_r6,	map_regimm_r6,	"jJ",	"jalJ",
+  "beq|beqz|bST00B",	"bne|bnezST0B",		map_pop06_r6,	map_pop07_r6,
+  map_pop10_r6,	"addiu|liTS0I",	"sltiTSI",	"sltiuTSI",
+  "andiTSU",	"ori|liTS0U",	"xoriTSU",	"aui|luiTS0U",
+  map_cop0,	map_cop1_r6,	false,		false,
+  false,	false,		map_pop26_r6,	map_pop27_r6,
+  map_pop30_r6,	"daddiuTSI",	false,		false,
+  false,	"dauiTSI",	false,		map_special3_r6,
+  "lbTSO",	"lhTSO",	false,		"lwTSO",
+  "lbuTSO",	"lhuTSO",	false,		false,
+  "sbTSO",	"shTSO",	false,		"swTSO",
+  false,	false,		false,		false,
+  false,	"lwc1HSO",	"bc#",		false,
+  false,	"ldc1HSO",	map_pop66_r6,	"ldTSO",
+  false,	"swc1HSO",	"balc#",	map_pcrel_r6,
+  false,	"sdc1HSO",	map_pop76_r6,	"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 = ctx.map_pri[rshift(op, 26)]
+  while type(opat) ~= "string" do
+    if not opat then return unknown(ctx) end
+    if opat.maprs then
+      opat = opat[opat.maprs(band(rshift(op,21),31), band(rshift(op,16),31))]
+    else
+      opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
+    end
+  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 == "a" then
+      x = band(rshift(op, 6), 7)
+    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 == "2" then
+      x = arshift(lshift(op, 13), 11)
+    elseif p == "3" then
+      x = arshift(lshift(op, 14), 11)
+    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), 14) + 4
+      ctx.rel = x
+      x = format("0x%08x", x)
+    elseif p == "b" then
+      x = ctx.addr + ctx.pos + arshift(lshift(op, 11), 9) + 4
+      ctx.rel = x
+      x = format("0x%08x", x)
+    elseif p == "#" then
+      x = ctx.addr + ctx.pos + arshift(lshift(op, 6), 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
+  ctx.map_pri = map_pri
+  return ctx
+end
+
+local function create_el(code, addr, out)
+  local ctx = create(code, addr, out)
+  ctx.get = get_le
+  return ctx
+end
+
+local function create_r6(code, addr, out)
+  local ctx = create(code, addr, out)
+  ctx.map_pri = map_pri_r6
+  return ctx
+end
+
+local function create_r6_el(code, addr, out)
+  local ctx = create(code, addr, out)
+  ctx.get = get_le
+  ctx.map_pri = map_pri_r6
+  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
+
+local function disass_r6(code, addr, out)
+  create_r6(code, addr, out):disass()
+end
+
+local function disass_r6_el(code, addr, out)
+  create_r6_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,
+  create_r6 = create_r6,
+  create_r6_el = create_r6_el,
+  disass = disass,
+  disass_el = disass_el,
+  disass_r6 = disass_r6,
+  disass_r6_el = disass_r6_el,
+  regname = regname
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_mips64.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64 disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_mips64el.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64EL disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_mips64r6.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64R6 disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This module just exports the r6 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_r6,
+  disass = dis_mips.disass_r6,
+  regname = dis_mips.regname
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_mips64r6el.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64R6EL disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This module just exports the r6 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_r6_el,
+  disass = dis_mips.disass_r6_el,
+  regname = dis_mips.regname
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_mipsel.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPSEL disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 591 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_ppc.lua

@@ -0,0 +1,591 @@
+----------------------------------------------------------------------------
+-- LuaJIT PPC disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_x64.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT x64 disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 953 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dis_x86.lua

@@ -0,0 +1,953 @@
+----------------------------------------------------------------------------
+-- LuaJIT x86/x64 disassembler module.
+--
+-- Copyright (C) 2005-2021 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",
+--9x
+[0x96] = "||fmaddsub132pHXrvm",[0x97] = "||fmsubadd132pHXrvm",
+[0x98] = "||fmadd132pHXrvm",[0x99] = "||fmadd132sHXrvm",
+[0x9a] = "||fmsub132pHXrvm",[0x9b] = "||fmsub132sHXrvm",
+[0x9c] = "||fnmadd132pHXrvm",[0x9d] = "||fnmadd132sHXrvm",
+[0x9e] = "||fnmsub132pHXrvm",[0x9f] = "||fnmsub132sHXrvm",
+--Ax
+[0xa6] = "||fmaddsub213pHXrvm",[0xa7] = "||fmsubadd213pHXrvm",
+[0xa8] = "||fmadd213pHXrvm",[0xa9] = "||fmadd213sHXrvm",
+[0xaa] = "||fmsub213pHXrvm",[0xab] = "||fmsub213sHXrvm",
+[0xac] = "||fnmadd213pHXrvm",[0xad] = "||fnmadd213sHXrvm",
+[0xae] = "||fnmsub213pHXrvm",[0xaf] = "||fnmsub213sHXrvm",
+--Bx
+[0xb6] = "||fmaddsub231pHXrvm",[0xb7] = "||fmsubadd231pHXrvm",
+[0xb8] = "||fmadd231pHXrvm",[0xb9] = "||fmadd231sHXrvm",
+[0xba] = "||fmsub231pHXrvm",[0xbb] = "||fmsub231sHXrvm",
+[0xbc] = "||fnmadd231pHXrvm",[0xbd] = "||fnmadd231sHXrvm",
+[0xbe] = "||fnmsub231pHXrvm",[0xbf] = "||fnmsub231sHXrvm",
+--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: 1DFGHIMPQRSTUVWXYabcdfgijlmoprstuvwxyz
+  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 == "H" then
+      name = name..(ctx.rexw and "d" or "s")
+      ctx.rexw = false
+    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,
+  H = 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
+}
+

+ 726 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/dump.lua

@@ -0,0 +1,726 @@
+----------------------------------------------------------------------------
+-- LuaJIT compiler dump module.
+--
+-- Copyright (C) 2005-2021 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 maskaddr = jit.arch == "arm" and -2
+    local ircall = vmdef.ircall
+    for i=0,#ircall do
+      local addr = ircalladdr(i)
+      if addr ~= 0 then
+	if maskaddr then addr = band(addr, maskaddr) end
+	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, extra)
+  local out = format(colortype_ansi[t], s)
+  if extra then out = "\027[3m"..out end
+  return out
+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 = { ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;", }
+
+local function colorize_html(s, t, extra)
+  s = gsub(s, "[<>&]", html_escape)
+  return format('<span class="irt_%s%s">%s</span>',
+		irtype_text[t], extra and " irt_extra" or "", 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 = [[
+<style type="text/css">
+background { background: #ffffff; color: #000000; }
+pre.ljdump {
+font-size: 10pt;
+background: #f0f4ff;
+color: #000000;
+border: 1px solid #bfcfff;
+padding: 0.5em;
+margin-left: 2em;
+margin-right: 2em;
+}
+span.irt_str { color: #00a000; }
+span.irt_thr, span.irt_fun { color: #404040; font-weight: bold; }
+span.irt_tab { color: #c00000; }
+span.irt_udt, span.irt_lud { color: #00c0c0; }
+span.irt_num { color: #4040c0; }
+span.irt_int, span.irt_i8, span.irt_u8, span.irt_i16, span.irt_u16 { color: #b040b0; }
+span.irt_extra { font-style: italic; }
+</style>
+]]
+
+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
+    if band(mode, 64) ~= 0 then s = s.."K" 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, 12)
+    if c == 1 then s = s.." none"
+    elseif 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,
+  ["TMPREF"] = { [0] = "", "IN", "OUT", "INOUT", "", "", "OUT2", "INOUT2" },
+  ["BUFHDR"] = { [0] = "RESET", "APPEND", "WRITE" },
+  ["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 t < 12 then
+      s = k == 0 and "NULL" or format("[0x%08x]", k)
+    elseif 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, band(sn or 0, 0x100000) ~= 0)
+  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), band(sn, 0x100000) ~= 0))
+      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('<pre class="ljdump">\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("</pre>\n\n") else out:write("\n") end
+  else
+    if what == "flush" then symtab, nexitsym = {}, 0 end
+    out:write("---- TRACE ", what, "\n\n")
+  end
+  out:flush()
+end
+
+-- Dump recorded bytecode.
+local function dump_record(tr, func, pc, depth)
+  if depth ~= recdepth then
+    recdepth = depth
+    recprefix = rep(" .", depth)
+  end
+  local line
+  if pc >= 0 then
+    line = bcline(func, pc, recprefix)
+    if dumpmode.H then line = gsub(line, "[<>&]", html_escape) end
+  else
+    line = "0000 "..recprefix.." FUNCC      \n"
+  end
+  if pc <= 0 then
+    out:write(sub(line, 1, -2), "         ; ", fmtfunc(func), "\n")
+  else
+    out:write(line)
+  end
+  if pc >= 0 and band(funcbc(func, pc), 0xff) < 16 then -- ORDER BC
+    out:write(bcline(func, pc+1, recprefix)) -- Write JMP for cond.
+  end
+end
+
+------------------------------------------------------------------------------
+
+local gpr64 = jit.arch:match("64")
+local fprmips32 = jit.arch == "mips" or jit.arch == "mipsel"
+
+-- Dump taken trace exits.
+local function dump_texit(tr, ex, ngpr, nfpr, ...)
+  out:write("---- TRACE ", tr, " exit ", ex, "\n")
+  if dumpmode.X then
+    local regs = {...}
+    if gpr64 then
+      for i=1,ngpr do
+	out:write(format(" %016x", regs[i]))
+	if i % 4 == 0 then out:write("\n") end
+      end
+    else
+      for i=1,ngpr do
+	out:write(" ", tohex(regs[i]))
+	if i % 8 == 0 then out:write("\n") end
+      end
+    end
+    if fprmips32 then
+      for i=1,nfpr,2 do
+	out:write(format(" %+17.14g", regs[ngpr+i]))
+	if i % 8 == 7 then out:write("\n") end
+      end
+    else
+      for i=1,nfpr do
+	out:write(format(" %+17.14g", regs[ngpr+i]))
+	if i % 4 == 0 then out:write("\n") end
+      end
+    end
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Detach dump handlers.
+local function dumpoff()
+  if active then
+    active = false
+    jit.attach(dump_texit)
+    jit.attach(dump_record)
+    jit.attach(dump_trace)
+    if out and out ~= stdout and out ~= stderr then out:close() end
+    out = nil
+  end
+end
+
+-- Open the output file and attach dump handlers.
+local function dumpon(opt, outfile)
+  if active then dumpoff() end
+
+  local term = os.getenv("TERM")
+  local colormode = (term and term:match("color") or os.getenv("COLORTERM")) and "A" or "T"
+  if opt then
+    opt = gsub(opt, "[TAH]", function(mode) colormode = mode; return ""; end)
+  end
+
+  local m = { t=true, b=true, i=true, m=true, }
+  if opt and opt ~= "" then
+    local o = sub(opt, 1, 1)
+    if o ~= "+" and o ~= "-" then m = {} end
+    for i=1,#opt do m[sub(opt, i, i)] = (o ~= "-") end
+  end
+  dumpmode = m
+
+  if m.t or m.b or m.i or m.s or m.m then
+    jit.attach(dump_trace, "trace")
+  end
+  if m.b then
+    jit.attach(dump_record, "record")
+    if not bcline then bcline = require("jit.bc").line end
+  end
+  if m.x or m.X then
+    jit.attach(dump_texit, "texit")
+  end
+
+  if not outfile then outfile = os.getenv("LUAJIT_DUMPFILE") end
+  if outfile then
+    out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
+  else
+    out = stdout
+  end
+
+  m[colormode] = true
+  if colormode == "A" then
+    colorize = colorize_ansi
+    irtype = irtype_ansi
+  elseif colormode == "H" then
+    colorize = colorize_html
+    irtype = irtype_html
+    out:write(header_html)
+  else
+    colorize = colorize_text
+    irtype = irtype_text
+  end
+
+  active = true
+end
+
+-- Public module functions.
+return {
+  on = dumpon,
+  off = dumpoff,
+  start = dumpon -- For -j command line option.
+}
+

+ 312 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/p.lua

@@ -0,0 +1,312 @@
+----------------------------------------------------------------------------
+-- LuaJIT profiler.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module is a simple command line interface to the built-in
+-- low-overhead profiler of LuaJIT.
+--
+-- The lower-level API of the profiler is accessible via the "jit.profile"
+-- module or the luaJIT_profile_* C API.
+--
+-- Example usage:
+--
+--   luajit -jp myapp.lua
+--   luajit -jp=s myapp.lua
+--   luajit -jp=-s myapp.lua
+--   luajit -jp=vl myapp.lua
+--   luajit -jp=G,profile.txt myapp.lua
+--
+-- The following dump features are available:
+--
+--   f  Stack dump: function name, otherwise module:line. Default mode.
+--   F  Stack dump: ditto, but always prepend module.
+--   l  Stack dump: module:line.
+--   <number> stack dump depth (callee < caller). Default: 1.
+--   -<number> Inverse stack dump depth (caller > callee).
+--   s  Split stack dump after first stack level. Implies abs(depth) >= 2.
+--   p  Show full path for module names.
+--   v  Show VM states. Can be combined with stack dumps, e.g. vf or fv.
+--   z  Show zones. Can be combined with stack dumps, e.g. zf or fz.
+--   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 (e.g. flame graphs).
+--   m<number> Minimum sample percentage to be shown. Default: 3.
+--   i<number> Sampling interval in milliseconds. Default: 10.
+--
+----------------------------------------------------------------------------
+
+-- Cache some library functions and objects.
+local jit = require("jit")
+assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
+local profile = require("jit.profile")
+local vmdef = require("jit.vmdef")
+local math = math
+local pairs, ipairs, tonumber, floor = pairs, ipairs, tonumber, math.floor
+local sort, format = table.sort, string.format
+local stdout = io.stdout
+local zone -- Load jit.zone module on demand.
+
+-- Output file handle.
+local out
+
+------------------------------------------------------------------------------
+
+local prof_ud
+local prof_states, prof_split, prof_min, prof_raw, prof_fmt, prof_depth
+local prof_ann, prof_count1, prof_count2, prof_samples
+
+local map_vmmode = {
+  N = "Compiled",
+  I = "Interpreted",
+  C = "C code",
+  G = "Garbage Collector",
+  J = "JIT Compiler",
+}
+
+-- Profiler callback.
+local function prof_cb(th, samples, vmmode)
+  prof_samples = prof_samples + samples
+  local key_stack, key_stack2, key_state
+  -- Collect keys for sample.
+  if prof_states then
+    if prof_states == "v" then
+      key_state = map_vmmode[vmmode] or vmmode
+    else
+      key_state = zone:get() or "(none)"
+    end
+  end
+  if prof_fmt then
+    key_stack = profile.dumpstack(th, prof_fmt, prof_depth)
+    key_stack = key_stack:gsub("%[builtin#(%d+)%]", function(x)
+      return vmdef.ffnames[tonumber(x)]
+    end)
+    if prof_split == 2 then
+      local k1, k2 = key_stack:match("(.-) [<>] (.*)")
+      if k2 then key_stack, key_stack2 = k1, k2 end
+    elseif prof_split == 3 then
+      key_stack2 = profile.dumpstack(th, "l", 1)
+    end
+  end
+  -- Order keys.
+  local k1, k2
+  if prof_split == 1 then
+    if key_state then
+      k1 = key_state
+      if key_stack then k2 = key_stack end
+    end
+  elseif key_stack then
+    k1 = key_stack
+    if key_stack2 then k2 = key_stack2 elseif key_state then k2 = key_state end
+  end
+  -- Coalesce samples in one or two levels.
+  if k1 then
+    local t1 = prof_count1
+    t1[k1] = (t1[k1] or 0) + samples
+    if k2 then
+      local t2 = prof_count2
+      local t3 = t2[k1]
+      if not t3 then t3 = {}; t2[k1] = t3 end
+      t3[k2] = (t3[k2] or 0) + samples
+    end
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Show top N list.
+local function prof_top(count1, count2, samples, indent)
+  local t, n = {}, 0
+  for k in pairs(count1) do
+    n = n + 1
+    t[n] = k
+  end
+  sort(t, function(a, b) return count1[a] > count1[b] end)
+  for i=1,n do
+    local k = t[i]
+    local v = count1[k]
+    local pct = floor(v*100/samples + 0.5)
+    if pct < prof_min then break end
+    if not prof_raw then
+      out:write(format("%s%2d%%  %s\n", indent, pct, k))
+    elseif prof_raw == "r" then
+      out:write(format("%s%5d  %s\n", indent, v, k))
+    else
+      out:write(format("%s %d\n", k, v))
+    end
+    if count2 then
+      local r = count2[k]
+      if r then
+	prof_top(r, nil, v, (prof_split == 3 or prof_split == 1) and "  -- " or
+			    (prof_depth < 0 and "  -> " or "  <- "))
+      end
+    end
+  end
+end
+
+-- Annotate source code
+local function prof_annotate(count1, samples)
+  local files = {}
+  local ms = 0
+  for k, v in pairs(count1) do
+    local pct = floor(v*100/samples + 0.5)
+    ms = math.max(ms, v)
+    if pct >= prof_min then
+      local file, line = k:match("^(.*):(%d+)$")
+      if not file then file = k; line = 0 end
+      local fl = files[file]
+      if not fl then fl = {}; files[file] = fl; files[#files+1] = file end
+      line = tonumber(line)
+      fl[line] = prof_raw and v or pct
+    end
+  end
+  sort(files)
+  local fmtv, fmtn = " %3d%% | %s\n", "      | %s\n"
+  if prof_raw then
+    local n = math.max(5, math.ceil(math.log10(ms)))
+    fmtv = "%"..n.."d | %s\n"
+    fmtn = (" "):rep(n).." | %s\n"
+  end
+  local ann = prof_ann
+  for _, file in ipairs(files) do
+    local f0 = file:byte()
+    if f0 == 40 or f0 == 91 then
+      out:write(format("\n====== %s ======\n[Cannot annotate non-file]\n", file))
+      break
+    end
+    local fp, err = io.open(file)
+    if not fp then
+      out:write(format("====== ERROR: %s: %s\n", file, err))
+      break
+    end
+    out:write(format("\n====== %s ======\n", file))
+    local fl = files[file]
+    local n, show = 1, false
+    if ann ~= 0 then
+      for i=1,ann do
+	if fl[i] then show = true; out:write("@@ 1 @@\n"); break end
+      end
+    end
+    for line in fp:lines() do
+      if line:byte() == 27 then
+	out:write("[Cannot annotate bytecode file]\n")
+	break
+      end
+      local v = fl[n]
+      if ann ~= 0 then
+	local v2 = fl[n+ann]
+	if show then
+	  if v2 then show = n+ann elseif v then show = n
+	  elseif show+ann < n then show = false end
+	elseif v2 then
+	  show = n+ann
+	  out:write(format("@@ %d @@\n", n))
+	end
+	if not show then goto next end
+      end
+      if v then
+	out:write(format(fmtv, v, line))
+      else
+	out:write(format(fmtn, line))
+      end
+    ::next::
+      n = n + 1
+    end
+    fp:close()
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Finish profiling and dump result.
+local function prof_finish()
+  if prof_ud then
+    profile.stop()
+    local samples = prof_samples
+    if samples == 0 then
+      if prof_raw ~= true then out:write("[No samples collected]\n") end
+      return
+    end
+    if prof_ann then
+      prof_annotate(prof_count1, samples)
+    else
+      prof_top(prof_count1, prof_count2, samples, "")
+    end
+    prof_count1 = nil
+    prof_count2 = nil
+    prof_ud = nil
+    if out ~= stdout then out:close() end
+  end
+end
+
+-- Start profiling.
+local function prof_start(mode)
+  local interval = ""
+  mode = mode:gsub("i%d*", function(s) interval = s; return "" end)
+  prof_min = 3
+  mode = mode:gsub("m(%d+)", function(s) prof_min = tonumber(s); return "" end)
+  prof_depth = 1
+  mode = mode:gsub("%-?%d+", function(s) prof_depth = tonumber(s); return "" end)
+  local m = {}
+  for c in mode:gmatch(".") do m[c] = c end
+  prof_states = m.z or m.v
+  if prof_states == "z" then zone = require("jit.zone") end
+  local scope = m.l or m.f or m.F or (prof_states and "" or "f")
+  local flags = (m.p or "")
+  prof_raw = m.r
+  if m.s then
+    prof_split = 2
+    if prof_depth == -1 or m["-"] then prof_depth = -2
+    elseif prof_depth == 1 then prof_depth = 2 end
+  elseif mode:find("[fF].*l") then
+    scope = "l"
+    prof_split = 3
+  else
+    prof_split = (scope == "" or mode:find("[zv].*[lfF]")) and 1 or 0
+  end
+  prof_ann = m.A and 0 or (m.a and 3)
+  if prof_ann then
+    scope = "l"
+    prof_fmt = "pl"
+    prof_split = 0
+    prof_depth = 1
+  elseif m.G and scope ~= "" then
+    prof_fmt = flags..scope.."Z;"
+    prof_depth = -100
+    prof_raw = true
+    prof_min = 0
+  elseif scope == "" then
+    prof_fmt = false
+  else
+    local sc = prof_split == 3 and m.f or m.F or scope
+    prof_fmt = flags..sc..(prof_depth >= 0 and "Z < " or "Z > ")
+  end
+  prof_count1 = {}
+  prof_count2 = {}
+  prof_samples = 0
+  profile.start(scope:lower()..interval, prof_cb)
+  prof_ud = newproxy(true)
+  getmetatable(prof_ud).__gc = prof_finish
+end
+
+------------------------------------------------------------------------------
+
+local function start(mode, outfile)
+  if not outfile then outfile = os.getenv("LUAJIT_PROFILEFILE") end
+  if outfile then
+    out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
+  else
+    out = stdout
+  end
+  prof_start(mode or "f")
+end
+
+-- Public module functions.
+return {
+  start = start, -- For -j command line option.
+  stop = prof_finish
+}
+

+ 170 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/v.lua

@@ -0,0 +1,170 @@
+----------------------------------------------------------------------------
+-- Verbose mode of the LuaJIT compiler.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module shows verbose information about the progress of the
+-- JIT compiler. It prints one line for each generated trace. This module
+-- is useful to see which code has been compiled or where the compiler
+-- punts and falls back to the interpreter.
+--
+-- Example usage:
+--
+--   luajit -jv -e "for i=1,1000 do for j=1,1000 do end end"
+--   luajit -jv=myapp.out myapp.lua
+--
+-- Default output is to stderr. To redirect the output to a file, pass a
+-- filename as an argument (use '-' for stdout) or set the environment
+-- variable LUAJIT_VERBOSEFILE. The file is overwritten every time the
+-- module is started.
+--
+-- The output from the first example should look like this:
+--
+-- [TRACE   1 (command line):1 loop]
+-- [TRACE   2 (1/3) (command line):1 -> 1]
+--
+-- The first number in each line is the internal trace number. Next are
+-- the file name ('(command line)') and the line number (':1') where the
+-- trace has started. Side traces also show the parent trace number and
+-- the exit number where they are attached to in parentheses ('(1/3)').
+-- An arrow at the end shows where the trace links to ('-> 1'), unless
+-- it loops to itself.
+--
+-- In this case the inner loop gets hot and is traced first, generating
+-- a root trace. Then the last exit from the 1st trace gets hot, too,
+-- and triggers generation of the 2nd trace. The side trace follows the
+-- path along the outer loop and *around* the inner loop, back to its
+-- start, and then links to the 1st trace. Yes, this may seem unusual,
+-- if you know how traditional compilers work. Trace compilers are full
+-- of surprises like this -- have fun! :-)
+--
+-- Aborted traces are shown like this:
+--
+-- [TRACE --- foo.lua:44 -- leaving loop in root trace at foo:lua:50]
+--
+-- Don't worry -- trace aborts are quite common, even in programs which
+-- can be fully compiled. The compiler may retry several times until it
+-- finds a suitable trace.
+--
+-- Of course this doesn't work with features that are not-yet-implemented
+-- (NYI error messages). The VM simply falls back to the interpreter. This
+-- may not matter at all if the particular trace is not very high up in
+-- the CPU usage profile. Oh, and the interpreter is quite fast, too.
+--
+-- Also check out the -jdump module, which prints all the gory details.
+--
+------------------------------------------------------------------------------
+
+-- 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, traceinfo = jutil.funcinfo, jutil.traceinfo
+local type, format = type, string.format
+local stdout, stderr = io.stdout, io.stderr
+
+-- Active flag and output file handle.
+local active, out
+
+------------------------------------------------------------------------------
+
+local startloc, startex
+
+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
+
+-- 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 == "start" then
+    startloc = fmtfunc(func, pc)
+    startex = otr and "("..otr.."/"..(oex == -1 and "stitch" or oex)..") " or ""
+  else
+    if what == "abort" then
+      local loc = fmtfunc(func, pc)
+      if loc ~= startloc then
+	out:write(format("[TRACE --- %s%s -- %s at %s]\n",
+	  startex, startloc, fmterr(otr, oex), loc))
+      else
+	out:write(format("[TRACE --- %s%s -- %s]\n",
+	  startex, startloc, fmterr(otr, oex)))
+      end
+    elseif what == "stop" then
+      local info = traceinfo(tr)
+      local link, ltype = info.link, info.linktype
+      if ltype == "interpreter" then
+	out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n",
+	  tr, startex, startloc))
+      elseif ltype == "stitch" then
+	out:write(format("[TRACE %3s %s%s %s %s]\n",
+	  tr, startex, startloc, ltype, fmtfunc(func, pc)))
+      elseif link == tr or link == 0 then
+	out:write(format("[TRACE %3s %s%s %s]\n",
+	  tr, startex, startloc, ltype))
+      elseif ltype == "root" then
+	out:write(format("[TRACE %3s %s%s -> %d]\n",
+	  tr, startex, startloc, link))
+      else
+	out:write(format("[TRACE %3s %s%s -> %d %s]\n",
+	  tr, startex, startloc, link, ltype))
+      end
+    else
+      out:write(format("[TRACE %s]\n", what))
+    end
+    out:flush()
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Detach dump handlers.
+local function dumpoff()
+  if active then
+    active = false
+    jit.attach(dump_trace)
+    if out and out ~= stdout and out ~= stderr then out:close() end
+    out = nil
+  end
+end
+
+-- Open the output file and attach dump handlers.
+local function dumpon(outfile)
+  if active then dumpoff() end
+  if not outfile then outfile = os.getenv("LUAJIT_VERBOSEFILE") end
+  if outfile then
+    out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
+  else
+    out = stderr
+  end
+  jit.attach(dump_trace, "trace")
+  active = true
+end
+
+-- Public module functions.
+return {
+  on = dumpon,
+  off = dumpoff,
+  start = dumpon -- For -j command line option.
+}
+

+ 395 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/vmdef.lua

@@ -0,0 +1,395 @@
+-- This is a generated file. DO NOT EDIT!
+
+return {
+
+bcnames = "ISLT  ISGE  ISLE  ISGT  ISEQV ISNEV ISEQS ISNES ISEQN ISNEN ISEQP ISNEP ISTC  ISFC  IST   ISF   ISTYPEISNUM MOV   NOT   UNM   LEN   ADDVN SUBVN MULVN DIVVN MODVN ADDNV SUBNV MULNV DIVNV MODNV ADDVV SUBVV MULVV DIVVV MODVV POW   CAT   KSTR  KCDATAKSHORTKNUM  KPRI  KNIL  UGET  USETV USETS USETN USETP UCLO  FNEW  TNEW  TDUP  GGET  GSET  TGETV TGETS TGETB TGETR TSETV TSETS TSETB TSETM TSETR CALLM CALL  CALLMTCALLT ITERC ITERN VARG  ISNEXTRETM  RET   RET0  RET1  FORI  JFORI FORL  IFORL JFORL ITERL IITERLJITERLLOOP  ILOOP JLOOP JMP   FUNCF IFUNCFJFUNCFFUNCV IFUNCVJFUNCVFUNCC FUNCCW",
+
+irnames = "LT    GE    LE    GT    ULT   UGE   ULE   UGT   EQ    NE    ABC   RETF  NOP   BASE  PVAL  GCSTEPHIOP  LOOP  USE   PHI   RENAMEPROF  KPRI  KINT  KGC   KPTR  KKPTR KNULL KNUM  KINT64KSLOT BNOT  BSWAP BAND  BOR   BXOR  BSHL  BSHR  BSAR  BROL  BROR  ADD   SUB   MUL   DIV   MOD   POW   NEG   ABS   LDEXP MIN   MAX   FPMATHADDOV SUBOV MULOV AREF  HREFK HREF  NEWREFUREFO UREFC FREF  TMPREFSTRREFLREF  ALOAD HLOAD ULOAD FLOAD XLOAD SLOAD VLOAD ALEN  ASTOREHSTOREUSTOREFSTOREXSTORESNEW  XSNEW TNEW  TDUP  CNEW  CNEWI BUFHDRBUFPUTBUFSTRTBAR  OBAR  XBAR  CONV  TOBIT TOSTR STRTO CALLN CALLA CALLL CALLS CALLXSCARG  ",
+
+irfpm = { [0]="floor", "ceil", "trunc", "sqrt", "log", "log2", "other", },
+
+irfield = { [0]="str.len", "func.env", "func.pc", "func.ffid", "thread.env", "tab.meta", "tab.array", "tab.node", "tab.asize", "tab.hmask", "tab.nomm", "udata.meta", "udata.udtype", "udata.file", "sbuf.w", "sbuf.e", "sbuf.b", "sbuf.l", "sbuf.ref", "sbuf.r", "cdata.ctypeid", "cdata.ptr", "cdata.int", "cdata.int64", "cdata.int64_4", },
+
+ircall = {
+[0]="lj_str_cmp",
+"lj_str_find",
+"lj_str_new",
+"lj_strscan_num",
+"lj_strfmt_int",
+"lj_strfmt_num",
+"lj_strfmt_char",
+"lj_strfmt_putint",
+"lj_strfmt_putnum",
+"lj_strfmt_putquoted",
+"lj_strfmt_putfxint",
+"lj_strfmt_putfnum_int",
+"lj_strfmt_putfnum_uint",
+"lj_strfmt_putfnum",
+"lj_strfmt_putfstr",
+"lj_strfmt_putfchar",
+"lj_buf_putmem",
+"lj_buf_putstr",
+"lj_buf_putchar",
+"lj_buf_putstr_reverse",
+"lj_buf_putstr_lower",
+"lj_buf_putstr_upper",
+"lj_buf_putstr_rep",
+"lj_buf_puttab",
+"lj_bufx_set",
+"lj_bufx_more",
+"lj_serialize_put",
+"lj_serialize_get",
+"lj_serialize_encode",
+"lj_serialize_decode",
+"lj_buf_tostr",
+"lj_tab_new_ah",
+"lj_tab_new1",
+"lj_tab_dup",
+"lj_tab_clear",
+"lj_tab_newkey",
+"lj_tab_keyindex",
+"lj_vm_next",
+"lj_tab_len",
+"lj_tab_len_hint",
+"lj_gc_step_jit",
+"lj_gc_barrieruv",
+"lj_mem_newgco",
+"lj_prng_u64d",
+"lj_vm_modi",
+"log10",
+"exp",
+"sin",
+"cos",
+"tan",
+"asin",
+"acos",
+"atan",
+"sinh",
+"cosh",
+"tanh",
+"fputc",
+"fwrite",
+"fflush",
+"lj_vm_floor",
+"lj_vm_ceil",
+"lj_vm_trunc",
+"sqrt",
+"log",
+"lj_vm_log2",
+"lj_vm_powi",
+"pow",
+"atan2",
+"ldexp",
+"lj_vm_tobit",
+"softfp_add",
+"softfp_sub",
+"softfp_mul",
+"softfp_div",
+"softfp_cmp",
+"softfp_i2d",
+"softfp_d2i",
+"lj_vm_sfmin",
+"lj_vm_sfmax",
+"lj_vm_tointg",
+"softfp_ui2d",
+"softfp_f2d",
+"softfp_d2ui",
+"softfp_d2f",
+"softfp_i2f",
+"softfp_ui2f",
+"softfp_f2i",
+"softfp_f2ui",
+"fp64_l2d",
+"fp64_ul2d",
+"fp64_l2f",
+"fp64_ul2f",
+"fp64_d2l",
+"fp64_d2ul",
+"fp64_f2l",
+"fp64_f2ul",
+"lj_carith_divi64",
+"lj_carith_divu64",
+"lj_carith_modi64",
+"lj_carith_modu64",
+"lj_carith_powi64",
+"lj_carith_powu64",
+"lj_cdata_newv",
+"lj_cdata_setfin",
+"strlen",
+"memcpy",
+"memset",
+"lj_vm_errno",
+"lj_carith_mul64",
+"lj_carith_shl64",
+"lj_carith_shr64",
+"lj_carith_sar64",
+"lj_carith_rol64",
+"lj_carith_ror64",
+},
+
+traceerr = {
+[0]="error thrown or hook called during recording",
+"trace too short",
+"trace too long",
+"trace too deep",
+"too many snapshots",
+"blacklisted",
+"retry recording",
+"NYI: bytecode %d",
+"leaving loop in root trace",
+"inner loop in root trace",
+"loop unroll limit reached",
+"bad argument type",
+"JIT compilation disabled for function",
+"call unroll limit reached",
+"down-recursion, restarting",
+"NYI: unsupported variant of FastFunc %s",
+"NYI: return to lower frame",
+"store with nil or NaN key",
+"missing metamethod",
+"looping index lookup",
+"NYI: mixed sparse/dense table",
+"symbol not in cache",
+"NYI: unsupported C type conversion",
+"NYI: unsupported C function type",
+"guard would always fail",
+"too many PHIs",
+"persistent type instability",
+"failed to allocate mcode memory",
+"machine code too long",
+"hit mcode limit (retrying)",
+"too many spill slots",
+"inconsistent register allocation",
+"NYI: cannot assemble IR instruction %d",
+"NYI: PHI shuffling too complex",
+"NYI: register coalescing too complex",
+},
+
+ffnames = {
+[0]="Lua",
+"C",
+"assert",
+"type",
+"next",
+"pairs",
+"ipairs_aux",
+"ipairs",
+"getmetatable",
+"setmetatable",
+"getfenv",
+"setfenv",
+"rawget",
+"rawset",
+"rawequal",
+"unpack",
+"select",
+"tonumber",
+"tostring",
+"error",
+"pcall",
+"xpcall",
+"loadfile",
+"load",
+"loadstring",
+"dofile",
+"gcinfo",
+"collectgarbage",
+"newproxy",
+"print",
+"coroutine.status",
+"coroutine.running",
+"coroutine.isyieldable",
+"coroutine.create",
+"coroutine.yield",
+"coroutine.resume",
+"coroutine.wrap_aux",
+"coroutine.wrap",
+"math.abs",
+"math.floor",
+"math.ceil",
+"math.sqrt",
+"math.log10",
+"math.exp",
+"math.sin",
+"math.cos",
+"math.tan",
+"math.asin",
+"math.acos",
+"math.atan",
+"math.sinh",
+"math.cosh",
+"math.tanh",
+"math.frexp",
+"math.modf",
+"math.log",
+"math.atan2",
+"math.pow",
+"math.fmod",
+"math.ldexp",
+"math.min",
+"math.max",
+"math.random",
+"math.randomseed",
+"bit.tobit",
+"bit.bnot",
+"bit.bswap",
+"bit.lshift",
+"bit.rshift",
+"bit.arshift",
+"bit.rol",
+"bit.ror",
+"bit.band",
+"bit.bor",
+"bit.bxor",
+"bit.tohex",
+"string.byte",
+"string.char",
+"string.sub",
+"string.rep",
+"string.reverse",
+"string.lower",
+"string.upper",
+"string.dump",
+"string.find",
+"string.match",
+"string.gmatch_aux",
+"string.gmatch",
+"string.gsub",
+"string.format",
+"table.maxn",
+"table.insert",
+"table.concat",
+"table.sort",
+"table.new",
+"table.clear",
+"io.method.close",
+"io.method.read",
+"io.method.write",
+"io.method.flush",
+"io.method.seek",
+"io.method.setvbuf",
+"io.method.lines",
+"io.method.__gc",
+"io.method.__tostring",
+"io.open",
+"io.popen",
+"io.tmpfile",
+"io.close",
+"io.read",
+"io.write",
+"io.flush",
+"io.input",
+"io.output",
+"io.lines",
+"io.type",
+"os.execute",
+"os.remove",
+"os.rename",
+"os.tmpname",
+"os.getenv",
+"os.exit",
+"os.clock",
+"os.date",
+"os.time",
+"os.difftime",
+"os.setlocale",
+"debug.getregistry",
+"debug.getmetatable",
+"debug.setmetatable",
+"debug.getfenv",
+"debug.setfenv",
+"debug.getinfo",
+"debug.getlocal",
+"debug.setlocal",
+"debug.getupvalue",
+"debug.setupvalue",
+"debug.upvalueid",
+"debug.upvaluejoin",
+"debug.sethook",
+"debug.gethook",
+"debug.debug",
+"debug.traceback",
+"jit.on",
+"jit.off",
+"jit.flush",
+"jit.status",
+"jit.security",
+"jit.attach",
+"jit.util.funcinfo",
+"jit.util.funcbc",
+"jit.util.funck",
+"jit.util.funcuvname",
+"jit.util.traceinfo",
+"jit.util.traceir",
+"jit.util.tracek",
+"jit.util.tracesnap",
+"jit.util.tracemc",
+"jit.util.traceexitstub",
+"jit.util.ircalladdr",
+"jit.opt.start",
+"jit.profile.start",
+"jit.profile.stop",
+"jit.profile.dumpstack",
+"ffi.meta.__index",
+"ffi.meta.__newindex",
+"ffi.meta.__eq",
+"ffi.meta.__len",
+"ffi.meta.__lt",
+"ffi.meta.__le",
+"ffi.meta.__concat",
+"ffi.meta.__call",
+"ffi.meta.__add",
+"ffi.meta.__sub",
+"ffi.meta.__mul",
+"ffi.meta.__div",
+"ffi.meta.__mod",
+"ffi.meta.__pow",
+"ffi.meta.__unm",
+"ffi.meta.__tostring",
+"ffi.meta.__pairs",
+"ffi.meta.__ipairs",
+"ffi.clib.__index",
+"ffi.clib.__newindex",
+"ffi.clib.__gc",
+"ffi.callback.free",
+"ffi.callback.set",
+"ffi.cdef",
+"ffi.new",
+"ffi.cast",
+"ffi.typeof",
+"ffi.typeinfo",
+"ffi.istype",
+"ffi.sizeof",
+"ffi.alignof",
+"ffi.offsetof",
+"ffi.errno",
+"ffi.string",
+"ffi.copy",
+"ffi.fill",
+"ffi.abi",
+"ffi.metatype",
+"ffi.gc",
+"ffi.load",
+"buffer.method.free",
+"buffer.method.reset",
+"buffer.method.skip",
+"buffer.method.set",
+"buffer.method.put",
+"buffer.method.putf",
+"buffer.method.get",
+"buffer.method.putcdata",
+"buffer.method.reserve",
+"buffer.method.commit",
+"buffer.method.ref",
+"buffer.method.encode",
+"buffer.method.decode",
+"buffer.method.__gc",
+"buffer.method.__tostring",
+"buffer.method.__len",
+"buffer.new",
+"buffer.encode",
+"buffer.decode",
+},
+
+}
+

+ 45 - 0
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/jit/zone.lua

@@ -0,0 +1,45 @@
+----------------------------------------------------------------------------
+-- LuaJIT profiler zones.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module implements a simple hierarchical zone model.
+--
+-- Example usage:
+--
+--   local zone = require("jit.zone")
+--   zone("AI")
+--   ...
+--     zone("A*")
+--     ...
+--     print(zone:get()) --> "A*"
+--     ...
+--     zone()
+--   ...
+--   print(zone:get()) --> "AI"
+--   ...
+--   zone()
+--
+----------------------------------------------------------------------------
+
+local remove = table.remove
+
+return setmetatable({
+  flush = function(t)
+    for i=#t,1,-1 do t[i] = nil end
+  end,
+  get = function(t)
+    return t[#t]
+  end
+}, {
+  __call = function(t, zone)
+    if zone then
+      t[#t+1] = zone
+    else
+      return (assert(remove(t), "empty zone stack"))
+    end
+  end
+})
+

BIN
love/src/jni/LuaJIT-2.1/android/armeabi-v7a/libluajit.a


+ 190 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/bc.lua

@@ -0,0 +1,190 @@
+----------------------------------------------------------------------------
+-- LuaJIT bytecode listing module.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module lists the bytecode of a Lua function. If it's loaded by -jbc
+-- it hooks into the parser and lists all functions of a chunk as they
+-- are parsed.
+--
+-- Example usage:
+--
+--   luajit -jbc -e 'local x=0; for i=1,1e6 do x=x+i end; print(x)'
+--   luajit -jbc=- foo.lua
+--   luajit -jbc=foo.list foo.lua
+--
+-- Default output is to stderr. To redirect the output to a file, pass a
+-- filename as an argument (use '-' for stdout) or set the environment
+-- variable LUAJIT_LISTFILE. The file is overwritten every time the module
+-- is started.
+--
+-- This module can also be used programmatically:
+--
+--   local bc = require("jit.bc")
+--
+--   local function foo() print("hello") end
+--
+--   bc.dump(foo)           --> -- 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.
+}
+

+ 665 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/bcsave.lua

@@ -0,0 +1,665 @@
+----------------------------------------------------------------------------
+-- LuaJIT module to save/list bytecode.
+--
+-- Copyright (C) 2005-2021 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 type, assert = type, assert
+local format = string.format
+local tremove, tconcat = table.remove, table.concat
+
+------------------------------------------------------------------------------
+
+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 =		{ e = "le", b = 32, m = 3, p = 0x14c, },
+  x64 =		{ e = "le", b = 64, m = 62, p = 0x8664, },
+  arm =		{ e = "le", b = 32, m = 40, p = 0x1c0, },
+  arm64 =	{ e = "le", b = 64, m = 183, p = 0xaa64, },
+  arm64be =	{ e = "be", b = 64, m = 183, },
+  ppc =		{ e = "be", b = 32, m = 20, },
+  mips =	{ e = "be", b = 32, m = 8, f = 0x50001006, },
+  mipsel =	{ e = "le", b = 32, m = 8, f = 0x50001006, },
+  mips64 =	{ e = "be", b = 64, m = 8, f = 0x80000007, },
+  mips64el =	{ e = "le", b = 64, m = 8, f = 0x80000007, },
+  mips64r6 =	{ e = "be", b = 64, m = 8, f = 0xa0000407, },
+  mips64r6el =	{ e = "le", b = 64, m = 8, f = 0xa0000407, },
+}
+
+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 = str:lower()
+  local s = check(map[str], "unknown ", err)
+  return type(s) == "string" and s or str
+end
+
+local function detecttype(str)
+  local ext = str:lower():match("%.(%a+)$")
+  return map_type[ext] or "raw"
+end
+
+local function checkmodname(str)
+  check(str:match("^[%w_.%-]+$"), "bad module name")
+  return str:gsub("[%.%-]", "_")
+end
+
+local function detectmodname(str)
+  if type(str) == "string" then
+    local tail = str:match("[^/\\]+$")
+    if tail then str = tail end
+    local head = str:match("^(.*)%.[^.]*$")
+    if head then str = head end
+    str = str:match("^[%w_.%-]+")
+  else
+    str = nil
+  end
+  check(str, "cannot derive module name, use -n name")
+  return str:gsub("[%.%-]", "_")
+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(format([[
+#ifdef __cplusplus
+extern "C"
+#endif
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+const unsigned char %s%s[] = {
+]], LJBC_PREFIX, ctx.modname))
+  else
+    fp:write(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(tconcat(t, ",", 1, n), ",\n")
+      n, m = 0, #b + 1
+    end
+    n = n + 1
+    t[n] = b
+  end
+  bcsave_tail(fp, output, tconcat(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 ai = assert(map_arch[ctx.arch])
+  local is64, isbe = ai.b == 64, ai.e == "be"
+
+  -- 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(ai.m)
+  hdr.flags = f32(ai.f or 0)
+  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+2)
+  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 ai = assert(map_arch[ctx.arch])
+  local is64 = ai.b == 64
+  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(assert(ai.p))
+  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 = jit.os:lower(),
+    type = false, modname = false,
+  }
+  while n <= #arg do
+    local a = arg[n]
+    if type(a) == "string" and a:sub(1, 1) == "-" and a ~= "-" then
+      tremove(arg, n)
+      if a == "--" then break end
+      for m=2,#a do
+	local opt = a:sub(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(tremove(arg, n))
+	  elseif opt == "t" then
+	    ctx.type = checkarg(tremove(arg, n), map_type, "file type")
+	  elseif opt == "a" then
+	    ctx.arch = checkarg(tremove(arg, n), map_arch, "architecture")
+	  elseif opt == "o" then
+	    ctx.os = checkarg(tremove(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.
+}
+

+ 689 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/dis_arm.lua

@@ -0,0 +1,689 @@
+----------------------------------------------------------------------------
+-- LuaJIT ARM disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 1216 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/dis_arm64.lua

@@ -0,0 +1,1216 @@
+----------------------------------------------------------------------------
+-- LuaJIT ARM64 disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+	else
+	  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 <R>.
+      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
+}
+

+ 12 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/dis_arm64be.lua

@@ -0,0 +1,12 @@
+----------------------------------------------------------------------------
+-- LuaJIT ARM64BE disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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")
+

+ 694 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/dis_mips.lua

@@ -0,0 +1,694 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+
+------------------------------------------------------------------------------
+-- Extended opcode maps common to all MIPS releases
+------------------------------------------------------------------------------
+
+local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", }
+local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", }
+
+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",
+  },
+}
+
+------------------------------------------------------------------------------
+-- Primary and extended opcode maps for MIPS R1-R5
+------------------------------------------------------------------------------
+
+local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", }
+
+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_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",
+}
+
+------------------------------------------------------------------------------
+-- Primary and extended opcode maps for MIPS R6
+------------------------------------------------------------------------------
+
+local map_mul_r6 =   { shift = 6, mask = 3, [2] = "mulDST",   [3] = "muhDST" }
+local map_mulu_r6 =  { shift = 6, mask = 3, [2] = "muluDST",  [3] = "muhuDST" }
+local map_div_r6 =   { shift = 6, mask = 3, [2] = "divDST",   [3] = "modDST" }
+local map_divu_r6 =  { shift = 6, mask = 3, [2] = "divuDST",  [3] = "moduDST" }
+local map_dmul_r6 =  { shift = 6, mask = 3, [2] = "dmulDST",  [3] = "dmuhDST" }
+local map_dmulu_r6 = { shift = 6, mask = 3, [2] = "dmuluDST", [3] = "dmuhuDST" }
+local map_ddiv_r6 =  { shift = 6, mask = 3, [2] = "ddivDST",  [3] = "dmodDST" }
+local map_ddivu_r6 = { shift = 6, mask = 3, [2] = "ddivuDST", [3] = "dmoduDST" }
+
+local map_special_r6 = {
+  shift = 0, mask = 63,
+  [0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
+  false,	map_srl,	"sraDTA",
+  "sllvDTS",	false,		map_srlv,	"sravDTS",
+  "jrS",	"jalrD1S",	false,		false,
+  "syscallY",	"breakY",	false,		"sync",
+  "clzDS",	"cloDS",	"dclzDS",	"dcloDS",
+  "dsllvDST",	"dlsaDSTA",	"dsrlvDST",	"dsravDST",
+  map_mul_r6,	map_mulu_r6,	map_div_r6,	map_divu_r6,
+  map_dmul_r6,	map_dmulu_r6,	map_ddiv_r6,	map_ddivu_r6,
+  "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",	"seleqzDST",	"tneSTZ",	"selnezDST",
+  "dsllDTA",	false,		"dsrlDTA",	"dsraDTA",
+  "dsll32DTA",	false,		"dsrl32DTA",	"dsra32DTA",
+}
+
+local map_bshfl_r6 = {
+  shift = 9, mask = 3,
+  [1] = "alignDSTa",
+  _ = {
+    shift = 6, mask = 31,
+    [0] = "bitswapDT",
+    [2] = "wsbhDT",
+    [16] = "sebDT",
+    [24] = "sehDT",
+  }
+}
+
+local map_dbshfl_r6 = {
+  shift = 9, mask = 3,
+  [1] = "dalignDSTa",
+  _ = {
+    shift = 6, mask = 31,
+    [0] = "dbitswapDT",
+    [2] = "dsbhDT",
+    [5] = "dshdDT",
+  }
+}
+
+local map_special3_r6 = {
+  shift = 0, mask = 63,
+  [0]  = "extTSAK", [1]  = "dextmTSAP", [3]  = "dextTSAK",
+  [4]  = "insTSAL", [6]  = "dinsuTSEQ", [7]  = "dinsTSAL",
+  [32] = map_bshfl_r6, [36] = map_dbshfl_r6,  [59] = "rdhwrTD",
+}
+
+local map_regimm_r6 = {
+  shift = 16, mask = 31,
+  [0] = "bltzSB", [1] = "bgezSB",
+  [6] = "dahiSI", [30] = "datiSI",
+  [23] = "sigrieI", [31] = "synciSO",
+}
+
+local map_pcrel_r6 = {
+  shift = 19, mask = 3,
+  [0] = "addiupcS2", "lwpcS2", "lwupcS2", {
+    shift = 18, mask = 1,
+    [0] = "ldpcS3", { shift = 16, mask = 3, [2] = "auipcSI", [3] = "aluipcSI" }
+  }
+}
+
+local map_cop1s_r6 = {
+  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",
+  "sel.sFGH",		false,		false,		false,
+  "seleqz.sFGH",	"recip.sFG",	"rsqrt.sFG",	"selnez.sFGH",
+  "maddf.sFGH",		"msubf.sFGH",	"rint.sFG",	"class.sFG",
+  "min.sFGH",		"mina.sFGH",	"max.sFGH",	"maxa.sFGH",
+  false,		"cvt.d.sFG",	false,		false,
+  "cvt.w.sFG",		"cvt.l.sFG",
+}
+
+local map_cop1d_r6 = {
+  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",
+  "sel.dFGH",		false,		false,		false,
+  "seleqz.dFGH",	"recip.dFG",	"rsqrt.dFG",	"selnez.dFGH",
+  "maddf.dFGH",		"msubf.dFGH",	"rint.dFG",	"class.dFG",
+  "min.dFGH",		"mina.dFGH",	"max.dFGH",	"maxa.dFGH",
+  "cvt.s.dFG",		false,		false,		false,
+  "cvt.w.dFG",		"cvt.l.dFG",
+}
+
+local map_cop1w_r6 = {
+  shift = 0, mask = 63,
+  [0] = "cmp.af.sFGH",	"cmp.un.sFGH",	"cmp.eq.sFGH",	"cmp.ueq.sFGH",
+  "cmp.lt.sFGH",	"cmp.ult.sFGH",	"cmp.le.sFGH",	"cmp.ule.sFGH",
+  "cmp.saf.sFGH",	"cmp.sun.sFGH",	"cmp.seq.sFGH",	"cmp.sueq.sFGH",
+  "cmp.slt.sFGH",	"cmp.sult.sFGH",	"cmp.sle.sFGH",	"cmp.sule.sFGH",
+  false,		"cmp.or.sFGH",	"cmp.une.sFGH",	"cmp.ne.sFGH",
+  false,		false,		false,		false,
+  false,		"cmp.sor.sFGH",	"cmp.sune.sFGH",	"cmp.sne.sFGH",
+  false,		false,		false,		false,
+  "cvt.s.wFG", "cvt.d.wFG",
+}
+
+local map_cop1l_r6 = {
+  shift = 0, mask = 63,
+  [0] = "cmp.af.dFGH",	"cmp.un.dFGH",	"cmp.eq.dFGH",	"cmp.ueq.dFGH",
+  "cmp.lt.dFGH",	"cmp.ult.dFGH",	"cmp.le.dFGH",	"cmp.ule.dFGH",
+  "cmp.saf.dFGH",	"cmp.sun.dFGH",	"cmp.seq.dFGH",	"cmp.sueq.dFGH",
+  "cmp.slt.dFGH",	"cmp.sult.dFGH",	"cmp.sle.dFGH",	"cmp.sule.dFGH",
+  false,		"cmp.or.dFGH",	"cmp.une.dFGH",	"cmp.ne.dFGH",
+  false,		false,		false,		false,
+  false,		"cmp.sor.dFGH",	"cmp.sune.dFGH",	"cmp.sne.dFGH",
+  false,		false,		false,		false,
+  "cvt.s.lFG", "cvt.d.lFG",
+}
+
+local map_cop1_r6 = {
+  shift = 21, mask = 31,
+  [0] = "mfc1TG", "dmfc1TG",	"cfc1TG",	"mfhc1TG",
+  "mtc1TG",	"dmtc1TG",	"ctc1TG",	"mthc1TG",
+  false,	"bc1eqzHB",	false,		false,
+  false,	"bc1nezHB",	false,		false,
+  map_cop1s_r6,	map_cop1d_r6,	false,		false,
+  map_cop1w_r6,	map_cop1l_r6,
+}
+
+local function maprs_popTS(rs, rt)
+  if rt == 0 then return 0 elseif rs == 0 then return 1
+  elseif rs == rt then return 2 else return 3 end
+end
+
+local map_pop06_r6 = {
+  maprs = maprs_popTS, [0] = "blezSB", "blezalcTB", "bgezalcTB", "bgeucSTB"
+}
+local map_pop07_r6 = {
+  maprs = maprs_popTS, [0] = "bgtzSB", "bgtzalcTB", "bltzalcTB", "bltucSTB"
+}
+local map_pop26_r6 = {
+  maprs = maprs_popTS, "blezcTB", "bgezcTB", "bgecSTB"
+}
+local map_pop27_r6 = {
+  maprs = maprs_popTS, "bgtzcTB", "bltzcTB", "bltcSTB"
+}
+
+local function maprs_popS(rs, rt)
+  if rs == 0 then return 0 else return 1 end
+end
+
+local map_pop66_r6 = {
+  maprs = maprs_popS, [0] = "jicTI", "beqzcSb"
+}
+local map_pop76_r6 = {
+  maprs = maprs_popS, [0] = "jialcTI", "bnezcSb"
+}
+
+local function maprs_popST(rs, rt)
+  if rs >= rt then return 0 elseif rs == 0 then return 1 else return 2 end
+end
+
+local map_pop10_r6 = {
+  maprs = maprs_popST, [0] = "bovcSTB", "beqzalcTB", "beqcSTB"
+}
+local map_pop30_r6 = {
+  maprs = maprs_popST, [0] = "bnvcSTB", "bnezalcTB", "bnecSTB"
+}
+
+local map_pri_r6 = {
+  [0] = map_special_r6,	map_regimm_r6,	"jJ",	"jalJ",
+  "beq|beqz|bST00B",	"bne|bnezST0B",		map_pop06_r6,	map_pop07_r6,
+  map_pop10_r6,	"addiu|liTS0I",	"sltiTSI",	"sltiuTSI",
+  "andiTSU",	"ori|liTS0U",	"xoriTSU",	"aui|luiTS0U",
+  map_cop0,	map_cop1_r6,	false,		false,
+  false,	false,		map_pop26_r6,	map_pop27_r6,
+  map_pop30_r6,	"daddiuTSI",	false,		false,
+  false,	"dauiTSI",	false,		map_special3_r6,
+  "lbTSO",	"lhTSO",	false,		"lwTSO",
+  "lbuTSO",	"lhuTSO",	false,		false,
+  "sbTSO",	"shTSO",	false,		"swTSO",
+  false,	false,		false,		false,
+  false,	"lwc1HSO",	"bc#",		false,
+  false,	"ldc1HSO",	map_pop66_r6,	"ldTSO",
+  false,	"swc1HSO",	"balc#",	map_pcrel_r6,
+  false,	"sdc1HSO",	map_pop76_r6,	"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 = ctx.map_pri[rshift(op, 26)]
+  while type(opat) ~= "string" do
+    if not opat then return unknown(ctx) end
+    if opat.maprs then
+      opat = opat[opat.maprs(band(rshift(op,21),31), band(rshift(op,16),31))]
+    else
+      opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
+    end
+  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 == "a" then
+      x = band(rshift(op, 6), 7)
+    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 == "2" then
+      x = arshift(lshift(op, 13), 11)
+    elseif p == "3" then
+      x = arshift(lshift(op, 14), 11)
+    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), 14) + 4
+      ctx.rel = x
+      x = format("0x%08x", x)
+    elseif p == "b" then
+      x = ctx.addr + ctx.pos + arshift(lshift(op, 11), 9) + 4
+      ctx.rel = x
+      x = format("0x%08x", x)
+    elseif p == "#" then
+      x = ctx.addr + ctx.pos + arshift(lshift(op, 6), 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
+  ctx.map_pri = map_pri
+  return ctx
+end
+
+local function create_el(code, addr, out)
+  local ctx = create(code, addr, out)
+  ctx.get = get_le
+  return ctx
+end
+
+local function create_r6(code, addr, out)
+  local ctx = create(code, addr, out)
+  ctx.map_pri = map_pri_r6
+  return ctx
+end
+
+local function create_r6_el(code, addr, out)
+  local ctx = create(code, addr, out)
+  ctx.get = get_le
+  ctx.map_pri = map_pri_r6
+  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
+
+local function disass_r6(code, addr, out)
+  create_r6(code, addr, out):disass()
+end
+
+local function disass_r6_el(code, addr, out)
+  create_r6_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,
+  create_r6 = create_r6,
+  create_r6_el = create_r6_el,
+  disass = disass,
+  disass_el = disass_el,
+  disass_r6 = disass_r6,
+  disass_r6_el = disass_r6_el,
+  regname = regname
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/dis_mips64.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64 disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/dis_mips64el.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64EL disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/dis_mips64r6.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64R6 disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This module just exports the r6 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_r6,
+  disass = dis_mips.disass_r6,
+  regname = dis_mips.regname
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/dis_mips64r6el.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64R6EL disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This module just exports the r6 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_r6_el,
+  disass = dis_mips.disass_r6_el,
+  regname = dis_mips.regname
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/dis_mipsel.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPSEL disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 591 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/dis_ppc.lua

@@ -0,0 +1,591 @@
+----------------------------------------------------------------------------
+-- LuaJIT PPC disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/dis_x64.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT x64 disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 953 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/dis_x86.lua

@@ -0,0 +1,953 @@
+----------------------------------------------------------------------------
+-- LuaJIT x86/x64 disassembler module.
+--
+-- Copyright (C) 2005-2021 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",
+--9x
+[0x96] = "||fmaddsub132pHXrvm",[0x97] = "||fmsubadd132pHXrvm",
+[0x98] = "||fmadd132pHXrvm",[0x99] = "||fmadd132sHXrvm",
+[0x9a] = "||fmsub132pHXrvm",[0x9b] = "||fmsub132sHXrvm",
+[0x9c] = "||fnmadd132pHXrvm",[0x9d] = "||fnmadd132sHXrvm",
+[0x9e] = "||fnmsub132pHXrvm",[0x9f] = "||fnmsub132sHXrvm",
+--Ax
+[0xa6] = "||fmaddsub213pHXrvm",[0xa7] = "||fmsubadd213pHXrvm",
+[0xa8] = "||fmadd213pHXrvm",[0xa9] = "||fmadd213sHXrvm",
+[0xaa] = "||fmsub213pHXrvm",[0xab] = "||fmsub213sHXrvm",
+[0xac] = "||fnmadd213pHXrvm",[0xad] = "||fnmadd213sHXrvm",
+[0xae] = "||fnmsub213pHXrvm",[0xaf] = "||fnmsub213sHXrvm",
+--Bx
+[0xb6] = "||fmaddsub231pHXrvm",[0xb7] = "||fmsubadd231pHXrvm",
+[0xb8] = "||fmadd231pHXrvm",[0xb9] = "||fmadd231sHXrvm",
+[0xba] = "||fmsub231pHXrvm",[0xbb] = "||fmsub231sHXrvm",
+[0xbc] = "||fnmadd231pHXrvm",[0xbd] = "||fnmadd231sHXrvm",
+[0xbe] = "||fnmsub231pHXrvm",[0xbf] = "||fnmsub231sHXrvm",
+--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: 1DFGHIMPQRSTUVWXYabcdfgijlmoprstuvwxyz
+  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 == "H" then
+      name = name..(ctx.rexw and "d" or "s")
+      ctx.rexw = false
+    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,
+  H = 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
+}
+

+ 726 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/dump.lua

@@ -0,0 +1,726 @@
+----------------------------------------------------------------------------
+-- LuaJIT compiler dump module.
+--
+-- Copyright (C) 2005-2021 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 maskaddr = jit.arch == "arm" and -2
+    local ircall = vmdef.ircall
+    for i=0,#ircall do
+      local addr = ircalladdr(i)
+      if addr ~= 0 then
+	if maskaddr then addr = band(addr, maskaddr) end
+	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, extra)
+  local out = format(colortype_ansi[t], s)
+  if extra then out = "\027[3m"..out end
+  return out
+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 = { ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;", }
+
+local function colorize_html(s, t, extra)
+  s = gsub(s, "[<>&]", html_escape)
+  return format('<span class="irt_%s%s">%s</span>',
+		irtype_text[t], extra and " irt_extra" or "", 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 = [[
+<style type="text/css">
+background { background: #ffffff; color: #000000; }
+pre.ljdump {
+font-size: 10pt;
+background: #f0f4ff;
+color: #000000;
+border: 1px solid #bfcfff;
+padding: 0.5em;
+margin-left: 2em;
+margin-right: 2em;
+}
+span.irt_str { color: #00a000; }
+span.irt_thr, span.irt_fun { color: #404040; font-weight: bold; }
+span.irt_tab { color: #c00000; }
+span.irt_udt, span.irt_lud { color: #00c0c0; }
+span.irt_num { color: #4040c0; }
+span.irt_int, span.irt_i8, span.irt_u8, span.irt_i16, span.irt_u16 { color: #b040b0; }
+span.irt_extra { font-style: italic; }
+</style>
+]]
+
+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
+    if band(mode, 64) ~= 0 then s = s.."K" 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, 12)
+    if c == 1 then s = s.." none"
+    elseif 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,
+  ["TMPREF"] = { [0] = "", "IN", "OUT", "INOUT", "", "", "OUT2", "INOUT2" },
+  ["BUFHDR"] = { [0] = "RESET", "APPEND", "WRITE" },
+  ["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 t < 12 then
+      s = k == 0 and "NULL" or format("[0x%08x]", k)
+    elseif 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, band(sn or 0, 0x100000) ~= 0)
+  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), band(sn, 0x100000) ~= 0))
+      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('<pre class="ljdump">\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("</pre>\n\n") else out:write("\n") end
+  else
+    if what == "flush" then symtab, nexitsym = {}, 0 end
+    out:write("---- TRACE ", what, "\n\n")
+  end
+  out:flush()
+end
+
+-- Dump recorded bytecode.
+local function dump_record(tr, func, pc, depth)
+  if depth ~= recdepth then
+    recdepth = depth
+    recprefix = rep(" .", depth)
+  end
+  local line
+  if pc >= 0 then
+    line = bcline(func, pc, recprefix)
+    if dumpmode.H then line = gsub(line, "[<>&]", html_escape) end
+  else
+    line = "0000 "..recprefix.." FUNCC      \n"
+  end
+  if pc <= 0 then
+    out:write(sub(line, 1, -2), "         ; ", fmtfunc(func), "\n")
+  else
+    out:write(line)
+  end
+  if pc >= 0 and band(funcbc(func, pc), 0xff) < 16 then -- ORDER BC
+    out:write(bcline(func, pc+1, recprefix)) -- Write JMP for cond.
+  end
+end
+
+------------------------------------------------------------------------------
+
+local gpr64 = jit.arch:match("64")
+local fprmips32 = jit.arch == "mips" or jit.arch == "mipsel"
+
+-- Dump taken trace exits.
+local function dump_texit(tr, ex, ngpr, nfpr, ...)
+  out:write("---- TRACE ", tr, " exit ", ex, "\n")
+  if dumpmode.X then
+    local regs = {...}
+    if gpr64 then
+      for i=1,ngpr do
+	out:write(format(" %016x", regs[i]))
+	if i % 4 == 0 then out:write("\n") end
+      end
+    else
+      for i=1,ngpr do
+	out:write(" ", tohex(regs[i]))
+	if i % 8 == 0 then out:write("\n") end
+      end
+    end
+    if fprmips32 then
+      for i=1,nfpr,2 do
+	out:write(format(" %+17.14g", regs[ngpr+i]))
+	if i % 8 == 7 then out:write("\n") end
+      end
+    else
+      for i=1,nfpr do
+	out:write(format(" %+17.14g", regs[ngpr+i]))
+	if i % 4 == 0 then out:write("\n") end
+      end
+    end
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Detach dump handlers.
+local function dumpoff()
+  if active then
+    active = false
+    jit.attach(dump_texit)
+    jit.attach(dump_record)
+    jit.attach(dump_trace)
+    if out and out ~= stdout and out ~= stderr then out:close() end
+    out = nil
+  end
+end
+
+-- Open the output file and attach dump handlers.
+local function dumpon(opt, outfile)
+  if active then dumpoff() end
+
+  local term = os.getenv("TERM")
+  local colormode = (term and term:match("color") or os.getenv("COLORTERM")) and "A" or "T"
+  if opt then
+    opt = gsub(opt, "[TAH]", function(mode) colormode = mode; return ""; end)
+  end
+
+  local m = { t=true, b=true, i=true, m=true, }
+  if opt and opt ~= "" then
+    local o = sub(opt, 1, 1)
+    if o ~= "+" and o ~= "-" then m = {} end
+    for i=1,#opt do m[sub(opt, i, i)] = (o ~= "-") end
+  end
+  dumpmode = m
+
+  if m.t or m.b or m.i or m.s or m.m then
+    jit.attach(dump_trace, "trace")
+  end
+  if m.b then
+    jit.attach(dump_record, "record")
+    if not bcline then bcline = require("jit.bc").line end
+  end
+  if m.x or m.X then
+    jit.attach(dump_texit, "texit")
+  end
+
+  if not outfile then outfile = os.getenv("LUAJIT_DUMPFILE") end
+  if outfile then
+    out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
+  else
+    out = stdout
+  end
+
+  m[colormode] = true
+  if colormode == "A" then
+    colorize = colorize_ansi
+    irtype = irtype_ansi
+  elseif colormode == "H" then
+    colorize = colorize_html
+    irtype = irtype_html
+    out:write(header_html)
+  else
+    colorize = colorize_text
+    irtype = irtype_text
+  end
+
+  active = true
+end
+
+-- Public module functions.
+return {
+  on = dumpon,
+  off = dumpoff,
+  start = dumpon -- For -j command line option.
+}
+

+ 312 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/p.lua

@@ -0,0 +1,312 @@
+----------------------------------------------------------------------------
+-- LuaJIT profiler.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module is a simple command line interface to the built-in
+-- low-overhead profiler of LuaJIT.
+--
+-- The lower-level API of the profiler is accessible via the "jit.profile"
+-- module or the luaJIT_profile_* C API.
+--
+-- Example usage:
+--
+--   luajit -jp myapp.lua
+--   luajit -jp=s myapp.lua
+--   luajit -jp=-s myapp.lua
+--   luajit -jp=vl myapp.lua
+--   luajit -jp=G,profile.txt myapp.lua
+--
+-- The following dump features are available:
+--
+--   f  Stack dump: function name, otherwise module:line. Default mode.
+--   F  Stack dump: ditto, but always prepend module.
+--   l  Stack dump: module:line.
+--   <number> stack dump depth (callee < caller). Default: 1.
+--   -<number> Inverse stack dump depth (caller > callee).
+--   s  Split stack dump after first stack level. Implies abs(depth) >= 2.
+--   p  Show full path for module names.
+--   v  Show VM states. Can be combined with stack dumps, e.g. vf or fv.
+--   z  Show zones. Can be combined with stack dumps, e.g. zf or fz.
+--   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 (e.g. flame graphs).
+--   m<number> Minimum sample percentage to be shown. Default: 3.
+--   i<number> Sampling interval in milliseconds. Default: 10.
+--
+----------------------------------------------------------------------------
+
+-- Cache some library functions and objects.
+local jit = require("jit")
+assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
+local profile = require("jit.profile")
+local vmdef = require("jit.vmdef")
+local math = math
+local pairs, ipairs, tonumber, floor = pairs, ipairs, tonumber, math.floor
+local sort, format = table.sort, string.format
+local stdout = io.stdout
+local zone -- Load jit.zone module on demand.
+
+-- Output file handle.
+local out
+
+------------------------------------------------------------------------------
+
+local prof_ud
+local prof_states, prof_split, prof_min, prof_raw, prof_fmt, prof_depth
+local prof_ann, prof_count1, prof_count2, prof_samples
+
+local map_vmmode = {
+  N = "Compiled",
+  I = "Interpreted",
+  C = "C code",
+  G = "Garbage Collector",
+  J = "JIT Compiler",
+}
+
+-- Profiler callback.
+local function prof_cb(th, samples, vmmode)
+  prof_samples = prof_samples + samples
+  local key_stack, key_stack2, key_state
+  -- Collect keys for sample.
+  if prof_states then
+    if prof_states == "v" then
+      key_state = map_vmmode[vmmode] or vmmode
+    else
+      key_state = zone:get() or "(none)"
+    end
+  end
+  if prof_fmt then
+    key_stack = profile.dumpstack(th, prof_fmt, prof_depth)
+    key_stack = key_stack:gsub("%[builtin#(%d+)%]", function(x)
+      return vmdef.ffnames[tonumber(x)]
+    end)
+    if prof_split == 2 then
+      local k1, k2 = key_stack:match("(.-) [<>] (.*)")
+      if k2 then key_stack, key_stack2 = k1, k2 end
+    elseif prof_split == 3 then
+      key_stack2 = profile.dumpstack(th, "l", 1)
+    end
+  end
+  -- Order keys.
+  local k1, k2
+  if prof_split == 1 then
+    if key_state then
+      k1 = key_state
+      if key_stack then k2 = key_stack end
+    end
+  elseif key_stack then
+    k1 = key_stack
+    if key_stack2 then k2 = key_stack2 elseif key_state then k2 = key_state end
+  end
+  -- Coalesce samples in one or two levels.
+  if k1 then
+    local t1 = prof_count1
+    t1[k1] = (t1[k1] or 0) + samples
+    if k2 then
+      local t2 = prof_count2
+      local t3 = t2[k1]
+      if not t3 then t3 = {}; t2[k1] = t3 end
+      t3[k2] = (t3[k2] or 0) + samples
+    end
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Show top N list.
+local function prof_top(count1, count2, samples, indent)
+  local t, n = {}, 0
+  for k in pairs(count1) do
+    n = n + 1
+    t[n] = k
+  end
+  sort(t, function(a, b) return count1[a] > count1[b] end)
+  for i=1,n do
+    local k = t[i]
+    local v = count1[k]
+    local pct = floor(v*100/samples + 0.5)
+    if pct < prof_min then break end
+    if not prof_raw then
+      out:write(format("%s%2d%%  %s\n", indent, pct, k))
+    elseif prof_raw == "r" then
+      out:write(format("%s%5d  %s\n", indent, v, k))
+    else
+      out:write(format("%s %d\n", k, v))
+    end
+    if count2 then
+      local r = count2[k]
+      if r then
+	prof_top(r, nil, v, (prof_split == 3 or prof_split == 1) and "  -- " or
+			    (prof_depth < 0 and "  -> " or "  <- "))
+      end
+    end
+  end
+end
+
+-- Annotate source code
+local function prof_annotate(count1, samples)
+  local files = {}
+  local ms = 0
+  for k, v in pairs(count1) do
+    local pct = floor(v*100/samples + 0.5)
+    ms = math.max(ms, v)
+    if pct >= prof_min then
+      local file, line = k:match("^(.*):(%d+)$")
+      if not file then file = k; line = 0 end
+      local fl = files[file]
+      if not fl then fl = {}; files[file] = fl; files[#files+1] = file end
+      line = tonumber(line)
+      fl[line] = prof_raw and v or pct
+    end
+  end
+  sort(files)
+  local fmtv, fmtn = " %3d%% | %s\n", "      | %s\n"
+  if prof_raw then
+    local n = math.max(5, math.ceil(math.log10(ms)))
+    fmtv = "%"..n.."d | %s\n"
+    fmtn = (" "):rep(n).." | %s\n"
+  end
+  local ann = prof_ann
+  for _, file in ipairs(files) do
+    local f0 = file:byte()
+    if f0 == 40 or f0 == 91 then
+      out:write(format("\n====== %s ======\n[Cannot annotate non-file]\n", file))
+      break
+    end
+    local fp, err = io.open(file)
+    if not fp then
+      out:write(format("====== ERROR: %s: %s\n", file, err))
+      break
+    end
+    out:write(format("\n====== %s ======\n", file))
+    local fl = files[file]
+    local n, show = 1, false
+    if ann ~= 0 then
+      for i=1,ann do
+	if fl[i] then show = true; out:write("@@ 1 @@\n"); break end
+      end
+    end
+    for line in fp:lines() do
+      if line:byte() == 27 then
+	out:write("[Cannot annotate bytecode file]\n")
+	break
+      end
+      local v = fl[n]
+      if ann ~= 0 then
+	local v2 = fl[n+ann]
+	if show then
+	  if v2 then show = n+ann elseif v then show = n
+	  elseif show+ann < n then show = false end
+	elseif v2 then
+	  show = n+ann
+	  out:write(format("@@ %d @@\n", n))
+	end
+	if not show then goto next end
+      end
+      if v then
+	out:write(format(fmtv, v, line))
+      else
+	out:write(format(fmtn, line))
+      end
+    ::next::
+      n = n + 1
+    end
+    fp:close()
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Finish profiling and dump result.
+local function prof_finish()
+  if prof_ud then
+    profile.stop()
+    local samples = prof_samples
+    if samples == 0 then
+      if prof_raw ~= true then out:write("[No samples collected]\n") end
+      return
+    end
+    if prof_ann then
+      prof_annotate(prof_count1, samples)
+    else
+      prof_top(prof_count1, prof_count2, samples, "")
+    end
+    prof_count1 = nil
+    prof_count2 = nil
+    prof_ud = nil
+    if out ~= stdout then out:close() end
+  end
+end
+
+-- Start profiling.
+local function prof_start(mode)
+  local interval = ""
+  mode = mode:gsub("i%d*", function(s) interval = s; return "" end)
+  prof_min = 3
+  mode = mode:gsub("m(%d+)", function(s) prof_min = tonumber(s); return "" end)
+  prof_depth = 1
+  mode = mode:gsub("%-?%d+", function(s) prof_depth = tonumber(s); return "" end)
+  local m = {}
+  for c in mode:gmatch(".") do m[c] = c end
+  prof_states = m.z or m.v
+  if prof_states == "z" then zone = require("jit.zone") end
+  local scope = m.l or m.f or m.F or (prof_states and "" or "f")
+  local flags = (m.p or "")
+  prof_raw = m.r
+  if m.s then
+    prof_split = 2
+    if prof_depth == -1 or m["-"] then prof_depth = -2
+    elseif prof_depth == 1 then prof_depth = 2 end
+  elseif mode:find("[fF].*l") then
+    scope = "l"
+    prof_split = 3
+  else
+    prof_split = (scope == "" or mode:find("[zv].*[lfF]")) and 1 or 0
+  end
+  prof_ann = m.A and 0 or (m.a and 3)
+  if prof_ann then
+    scope = "l"
+    prof_fmt = "pl"
+    prof_split = 0
+    prof_depth = 1
+  elseif m.G and scope ~= "" then
+    prof_fmt = flags..scope.."Z;"
+    prof_depth = -100
+    prof_raw = true
+    prof_min = 0
+  elseif scope == "" then
+    prof_fmt = false
+  else
+    local sc = prof_split == 3 and m.f or m.F or scope
+    prof_fmt = flags..sc..(prof_depth >= 0 and "Z < " or "Z > ")
+  end
+  prof_count1 = {}
+  prof_count2 = {}
+  prof_samples = 0
+  profile.start(scope:lower()..interval, prof_cb)
+  prof_ud = newproxy(true)
+  getmetatable(prof_ud).__gc = prof_finish
+end
+
+------------------------------------------------------------------------------
+
+local function start(mode, outfile)
+  if not outfile then outfile = os.getenv("LUAJIT_PROFILEFILE") end
+  if outfile then
+    out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
+  else
+    out = stdout
+  end
+  prof_start(mode or "f")
+end
+
+-- Public module functions.
+return {
+  start = start, -- For -j command line option.
+  stop = prof_finish
+}
+

+ 170 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/v.lua

@@ -0,0 +1,170 @@
+----------------------------------------------------------------------------
+-- Verbose mode of the LuaJIT compiler.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module shows verbose information about the progress of the
+-- JIT compiler. It prints one line for each generated trace. This module
+-- is useful to see which code has been compiled or where the compiler
+-- punts and falls back to the interpreter.
+--
+-- Example usage:
+--
+--   luajit -jv -e "for i=1,1000 do for j=1,1000 do end end"
+--   luajit -jv=myapp.out myapp.lua
+--
+-- Default output is to stderr. To redirect the output to a file, pass a
+-- filename as an argument (use '-' for stdout) or set the environment
+-- variable LUAJIT_VERBOSEFILE. The file is overwritten every time the
+-- module is started.
+--
+-- The output from the first example should look like this:
+--
+-- [TRACE   1 (command line):1 loop]
+-- [TRACE   2 (1/3) (command line):1 -> 1]
+--
+-- The first number in each line is the internal trace number. Next are
+-- the file name ('(command line)') and the line number (':1') where the
+-- trace has started. Side traces also show the parent trace number and
+-- the exit number where they are attached to in parentheses ('(1/3)').
+-- An arrow at the end shows where the trace links to ('-> 1'), unless
+-- it loops to itself.
+--
+-- In this case the inner loop gets hot and is traced first, generating
+-- a root trace. Then the last exit from the 1st trace gets hot, too,
+-- and triggers generation of the 2nd trace. The side trace follows the
+-- path along the outer loop and *around* the inner loop, back to its
+-- start, and then links to the 1st trace. Yes, this may seem unusual,
+-- if you know how traditional compilers work. Trace compilers are full
+-- of surprises like this -- have fun! :-)
+--
+-- Aborted traces are shown like this:
+--
+-- [TRACE --- foo.lua:44 -- leaving loop in root trace at foo:lua:50]
+--
+-- Don't worry -- trace aborts are quite common, even in programs which
+-- can be fully compiled. The compiler may retry several times until it
+-- finds a suitable trace.
+--
+-- Of course this doesn't work with features that are not-yet-implemented
+-- (NYI error messages). The VM simply falls back to the interpreter. This
+-- may not matter at all if the particular trace is not very high up in
+-- the CPU usage profile. Oh, and the interpreter is quite fast, too.
+--
+-- Also check out the -jdump module, which prints all the gory details.
+--
+------------------------------------------------------------------------------
+
+-- 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, traceinfo = jutil.funcinfo, jutil.traceinfo
+local type, format = type, string.format
+local stdout, stderr = io.stdout, io.stderr
+
+-- Active flag and output file handle.
+local active, out
+
+------------------------------------------------------------------------------
+
+local startloc, startex
+
+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
+
+-- 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 == "start" then
+    startloc = fmtfunc(func, pc)
+    startex = otr and "("..otr.."/"..(oex == -1 and "stitch" or oex)..") " or ""
+  else
+    if what == "abort" then
+      local loc = fmtfunc(func, pc)
+      if loc ~= startloc then
+	out:write(format("[TRACE --- %s%s -- %s at %s]\n",
+	  startex, startloc, fmterr(otr, oex), loc))
+      else
+	out:write(format("[TRACE --- %s%s -- %s]\n",
+	  startex, startloc, fmterr(otr, oex)))
+      end
+    elseif what == "stop" then
+      local info = traceinfo(tr)
+      local link, ltype = info.link, info.linktype
+      if ltype == "interpreter" then
+	out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n",
+	  tr, startex, startloc))
+      elseif ltype == "stitch" then
+	out:write(format("[TRACE %3s %s%s %s %s]\n",
+	  tr, startex, startloc, ltype, fmtfunc(func, pc)))
+      elseif link == tr or link == 0 then
+	out:write(format("[TRACE %3s %s%s %s]\n",
+	  tr, startex, startloc, ltype))
+      elseif ltype == "root" then
+	out:write(format("[TRACE %3s %s%s -> %d]\n",
+	  tr, startex, startloc, link))
+      else
+	out:write(format("[TRACE %3s %s%s -> %d %s]\n",
+	  tr, startex, startloc, link, ltype))
+      end
+    else
+      out:write(format("[TRACE %s]\n", what))
+    end
+    out:flush()
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Detach dump handlers.
+local function dumpoff()
+  if active then
+    active = false
+    jit.attach(dump_trace)
+    if out and out ~= stdout and out ~= stderr then out:close() end
+    out = nil
+  end
+end
+
+-- Open the output file and attach dump handlers.
+local function dumpon(outfile)
+  if active then dumpoff() end
+  if not outfile then outfile = os.getenv("LUAJIT_VERBOSEFILE") end
+  if outfile then
+    out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
+  else
+    out = stderr
+  end
+  jit.attach(dump_trace, "trace")
+  active = true
+end
+
+-- Public module functions.
+return {
+  on = dumpon,
+  off = dumpoff,
+  start = dumpon -- For -j command line option.
+}
+

+ 395 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/vmdef.lua

@@ -0,0 +1,395 @@
+-- This is a generated file. DO NOT EDIT!
+
+return {
+
+bcnames = "ISLT  ISGE  ISLE  ISGT  ISEQV ISNEV ISEQS ISNES ISEQN ISNEN ISEQP ISNEP ISTC  ISFC  IST   ISF   ISTYPEISNUM MOV   NOT   UNM   LEN   ADDVN SUBVN MULVN DIVVN MODVN ADDNV SUBNV MULNV DIVNV MODNV ADDVV SUBVV MULVV DIVVV MODVV POW   CAT   KSTR  KCDATAKSHORTKNUM  KPRI  KNIL  UGET  USETV USETS USETN USETP UCLO  FNEW  TNEW  TDUP  GGET  GSET  TGETV TGETS TGETB TGETR TSETV TSETS TSETB TSETM TSETR CALLM CALL  CALLMTCALLT ITERC ITERN VARG  ISNEXTRETM  RET   RET0  RET1  FORI  JFORI FORL  IFORL JFORL ITERL IITERLJITERLLOOP  ILOOP JLOOP JMP   FUNCF IFUNCFJFUNCFFUNCV IFUNCVJFUNCVFUNCC FUNCCW",
+
+irnames = "LT    GE    LE    GT    ULT   UGE   ULE   UGT   EQ    NE    ABC   RETF  NOP   BASE  PVAL  GCSTEPHIOP  LOOP  USE   PHI   RENAMEPROF  KPRI  KINT  KGC   KPTR  KKPTR KNULL KNUM  KINT64KSLOT BNOT  BSWAP BAND  BOR   BXOR  BSHL  BSHR  BSAR  BROL  BROR  ADD   SUB   MUL   DIV   MOD   POW   NEG   ABS   LDEXP MIN   MAX   FPMATHADDOV SUBOV MULOV AREF  HREFK HREF  NEWREFUREFO UREFC FREF  TMPREFSTRREFLREF  ALOAD HLOAD ULOAD FLOAD XLOAD SLOAD VLOAD ALEN  ASTOREHSTOREUSTOREFSTOREXSTORESNEW  XSNEW TNEW  TDUP  CNEW  CNEWI BUFHDRBUFPUTBUFSTRTBAR  OBAR  XBAR  CONV  TOBIT TOSTR STRTO CALLN CALLA CALLL CALLS CALLXSCARG  ",
+
+irfpm = { [0]="floor", "ceil", "trunc", "sqrt", "log", "log2", "other", },
+
+irfield = { [0]="str.len", "func.env", "func.pc", "func.ffid", "thread.env", "tab.meta", "tab.array", "tab.node", "tab.asize", "tab.hmask", "tab.nomm", "udata.meta", "udata.udtype", "udata.file", "sbuf.w", "sbuf.e", "sbuf.b", "sbuf.l", "sbuf.ref", "sbuf.r", "cdata.ctypeid", "cdata.ptr", "cdata.int", "cdata.int64", "cdata.int64_4", },
+
+ircall = {
+[0]="lj_str_cmp",
+"lj_str_find",
+"lj_str_new",
+"lj_strscan_num",
+"lj_strfmt_int",
+"lj_strfmt_num",
+"lj_strfmt_char",
+"lj_strfmt_putint",
+"lj_strfmt_putnum",
+"lj_strfmt_putquoted",
+"lj_strfmt_putfxint",
+"lj_strfmt_putfnum_int",
+"lj_strfmt_putfnum_uint",
+"lj_strfmt_putfnum",
+"lj_strfmt_putfstr",
+"lj_strfmt_putfchar",
+"lj_buf_putmem",
+"lj_buf_putstr",
+"lj_buf_putchar",
+"lj_buf_putstr_reverse",
+"lj_buf_putstr_lower",
+"lj_buf_putstr_upper",
+"lj_buf_putstr_rep",
+"lj_buf_puttab",
+"lj_bufx_set",
+"lj_bufx_more",
+"lj_serialize_put",
+"lj_serialize_get",
+"lj_serialize_encode",
+"lj_serialize_decode",
+"lj_buf_tostr",
+"lj_tab_new_ah",
+"lj_tab_new1",
+"lj_tab_dup",
+"lj_tab_clear",
+"lj_tab_newkey",
+"lj_tab_keyindex",
+"lj_vm_next",
+"lj_tab_len",
+"lj_tab_len_hint",
+"lj_gc_step_jit",
+"lj_gc_barrieruv",
+"lj_mem_newgco",
+"lj_prng_u64d",
+"lj_vm_modi",
+"log10",
+"exp",
+"sin",
+"cos",
+"tan",
+"asin",
+"acos",
+"atan",
+"sinh",
+"cosh",
+"tanh",
+"fputc",
+"fwrite",
+"fflush",
+"lj_vm_floor",
+"lj_vm_ceil",
+"lj_vm_trunc",
+"sqrt",
+"log",
+"lj_vm_log2",
+"lj_vm_powi",
+"pow",
+"atan2",
+"ldexp",
+"lj_vm_tobit",
+"softfp_add",
+"softfp_sub",
+"softfp_mul",
+"softfp_div",
+"softfp_cmp",
+"softfp_i2d",
+"softfp_d2i",
+"lj_vm_sfmin",
+"lj_vm_sfmax",
+"lj_vm_tointg",
+"softfp_ui2d",
+"softfp_f2d",
+"softfp_d2ui",
+"softfp_d2f",
+"softfp_i2f",
+"softfp_ui2f",
+"softfp_f2i",
+"softfp_f2ui",
+"fp64_l2d",
+"fp64_ul2d",
+"fp64_l2f",
+"fp64_ul2f",
+"fp64_d2l",
+"fp64_d2ul",
+"fp64_f2l",
+"fp64_f2ul",
+"lj_carith_divi64",
+"lj_carith_divu64",
+"lj_carith_modi64",
+"lj_carith_modu64",
+"lj_carith_powi64",
+"lj_carith_powu64",
+"lj_cdata_newv",
+"lj_cdata_setfin",
+"strlen",
+"memcpy",
+"memset",
+"lj_vm_errno",
+"lj_carith_mul64",
+"lj_carith_shl64",
+"lj_carith_shr64",
+"lj_carith_sar64",
+"lj_carith_rol64",
+"lj_carith_ror64",
+},
+
+traceerr = {
+[0]="error thrown or hook called during recording",
+"trace too short",
+"trace too long",
+"trace too deep",
+"too many snapshots",
+"blacklisted",
+"retry recording",
+"NYI: bytecode %d",
+"leaving loop in root trace",
+"inner loop in root trace",
+"loop unroll limit reached",
+"bad argument type",
+"JIT compilation disabled for function",
+"call unroll limit reached",
+"down-recursion, restarting",
+"NYI: unsupported variant of FastFunc %s",
+"NYI: return to lower frame",
+"store with nil or NaN key",
+"missing metamethod",
+"looping index lookup",
+"NYI: mixed sparse/dense table",
+"symbol not in cache",
+"NYI: unsupported C type conversion",
+"NYI: unsupported C function type",
+"guard would always fail",
+"too many PHIs",
+"persistent type instability",
+"failed to allocate mcode memory",
+"machine code too long",
+"hit mcode limit (retrying)",
+"too many spill slots",
+"inconsistent register allocation",
+"NYI: cannot assemble IR instruction %d",
+"NYI: PHI shuffling too complex",
+"NYI: register coalescing too complex",
+},
+
+ffnames = {
+[0]="Lua",
+"C",
+"assert",
+"type",
+"next",
+"pairs",
+"ipairs_aux",
+"ipairs",
+"getmetatable",
+"setmetatable",
+"getfenv",
+"setfenv",
+"rawget",
+"rawset",
+"rawequal",
+"unpack",
+"select",
+"tonumber",
+"tostring",
+"error",
+"pcall",
+"xpcall",
+"loadfile",
+"load",
+"loadstring",
+"dofile",
+"gcinfo",
+"collectgarbage",
+"newproxy",
+"print",
+"coroutine.status",
+"coroutine.running",
+"coroutine.isyieldable",
+"coroutine.create",
+"coroutine.yield",
+"coroutine.resume",
+"coroutine.wrap_aux",
+"coroutine.wrap",
+"math.abs",
+"math.floor",
+"math.ceil",
+"math.sqrt",
+"math.log10",
+"math.exp",
+"math.sin",
+"math.cos",
+"math.tan",
+"math.asin",
+"math.acos",
+"math.atan",
+"math.sinh",
+"math.cosh",
+"math.tanh",
+"math.frexp",
+"math.modf",
+"math.log",
+"math.atan2",
+"math.pow",
+"math.fmod",
+"math.ldexp",
+"math.min",
+"math.max",
+"math.random",
+"math.randomseed",
+"bit.tobit",
+"bit.bnot",
+"bit.bswap",
+"bit.lshift",
+"bit.rshift",
+"bit.arshift",
+"bit.rol",
+"bit.ror",
+"bit.band",
+"bit.bor",
+"bit.bxor",
+"bit.tohex",
+"string.byte",
+"string.char",
+"string.sub",
+"string.rep",
+"string.reverse",
+"string.lower",
+"string.upper",
+"string.dump",
+"string.find",
+"string.match",
+"string.gmatch_aux",
+"string.gmatch",
+"string.gsub",
+"string.format",
+"table.maxn",
+"table.insert",
+"table.concat",
+"table.sort",
+"table.new",
+"table.clear",
+"io.method.close",
+"io.method.read",
+"io.method.write",
+"io.method.flush",
+"io.method.seek",
+"io.method.setvbuf",
+"io.method.lines",
+"io.method.__gc",
+"io.method.__tostring",
+"io.open",
+"io.popen",
+"io.tmpfile",
+"io.close",
+"io.read",
+"io.write",
+"io.flush",
+"io.input",
+"io.output",
+"io.lines",
+"io.type",
+"os.execute",
+"os.remove",
+"os.rename",
+"os.tmpname",
+"os.getenv",
+"os.exit",
+"os.clock",
+"os.date",
+"os.time",
+"os.difftime",
+"os.setlocale",
+"debug.getregistry",
+"debug.getmetatable",
+"debug.setmetatable",
+"debug.getfenv",
+"debug.setfenv",
+"debug.getinfo",
+"debug.getlocal",
+"debug.setlocal",
+"debug.getupvalue",
+"debug.setupvalue",
+"debug.upvalueid",
+"debug.upvaluejoin",
+"debug.sethook",
+"debug.gethook",
+"debug.debug",
+"debug.traceback",
+"jit.on",
+"jit.off",
+"jit.flush",
+"jit.status",
+"jit.security",
+"jit.attach",
+"jit.util.funcinfo",
+"jit.util.funcbc",
+"jit.util.funck",
+"jit.util.funcuvname",
+"jit.util.traceinfo",
+"jit.util.traceir",
+"jit.util.tracek",
+"jit.util.tracesnap",
+"jit.util.tracemc",
+"jit.util.traceexitstub",
+"jit.util.ircalladdr",
+"jit.opt.start",
+"jit.profile.start",
+"jit.profile.stop",
+"jit.profile.dumpstack",
+"ffi.meta.__index",
+"ffi.meta.__newindex",
+"ffi.meta.__eq",
+"ffi.meta.__len",
+"ffi.meta.__lt",
+"ffi.meta.__le",
+"ffi.meta.__concat",
+"ffi.meta.__call",
+"ffi.meta.__add",
+"ffi.meta.__sub",
+"ffi.meta.__mul",
+"ffi.meta.__div",
+"ffi.meta.__mod",
+"ffi.meta.__pow",
+"ffi.meta.__unm",
+"ffi.meta.__tostring",
+"ffi.meta.__pairs",
+"ffi.meta.__ipairs",
+"ffi.clib.__index",
+"ffi.clib.__newindex",
+"ffi.clib.__gc",
+"ffi.callback.free",
+"ffi.callback.set",
+"ffi.cdef",
+"ffi.new",
+"ffi.cast",
+"ffi.typeof",
+"ffi.typeinfo",
+"ffi.istype",
+"ffi.sizeof",
+"ffi.alignof",
+"ffi.offsetof",
+"ffi.errno",
+"ffi.string",
+"ffi.copy",
+"ffi.fill",
+"ffi.abi",
+"ffi.metatype",
+"ffi.gc",
+"ffi.load",
+"buffer.method.free",
+"buffer.method.reset",
+"buffer.method.skip",
+"buffer.method.set",
+"buffer.method.put",
+"buffer.method.putf",
+"buffer.method.get",
+"buffer.method.putcdata",
+"buffer.method.reserve",
+"buffer.method.commit",
+"buffer.method.ref",
+"buffer.method.encode",
+"buffer.method.decode",
+"buffer.method.__gc",
+"buffer.method.__tostring",
+"buffer.method.__len",
+"buffer.new",
+"buffer.encode",
+"buffer.decode",
+},
+
+}
+

+ 45 - 0
love/src/jni/LuaJIT-2.1/android/x86/jit/zone.lua

@@ -0,0 +1,45 @@
+----------------------------------------------------------------------------
+-- LuaJIT profiler zones.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module implements a simple hierarchical zone model.
+--
+-- Example usage:
+--
+--   local zone = require("jit.zone")
+--   zone("AI")
+--   ...
+--     zone("A*")
+--     ...
+--     print(zone:get()) --> "A*"
+--     ...
+--     zone()
+--   ...
+--   print(zone:get()) --> "AI"
+--   ...
+--   zone()
+--
+----------------------------------------------------------------------------
+
+local remove = table.remove
+
+return setmetatable({
+  flush = function(t)
+    for i=#t,1,-1 do t[i] = nil end
+  end,
+  get = function(t)
+    return t[#t]
+  end
+}, {
+  __call = function(t, zone)
+    if zone then
+      t[#t+1] = zone
+    else
+      return (assert(remove(t), "empty zone stack"))
+    end
+  end
+})
+

BIN
love/src/jni/LuaJIT-2.1/android/x86/libluajit.a


+ 190 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/bc.lua

@@ -0,0 +1,190 @@
+----------------------------------------------------------------------------
+-- LuaJIT bytecode listing module.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module lists the bytecode of a Lua function. If it's loaded by -jbc
+-- it hooks into the parser and lists all functions of a chunk as they
+-- are parsed.
+--
+-- Example usage:
+--
+--   luajit -jbc -e 'local x=0; for i=1,1e6 do x=x+i end; print(x)'
+--   luajit -jbc=- foo.lua
+--   luajit -jbc=foo.list foo.lua
+--
+-- Default output is to stderr. To redirect the output to a file, pass a
+-- filename as an argument (use '-' for stdout) or set the environment
+-- variable LUAJIT_LISTFILE. The file is overwritten every time the module
+-- is started.
+--
+-- This module can also be used programmatically:
+--
+--   local bc = require("jit.bc")
+--
+--   local function foo() print("hello") end
+--
+--   bc.dump(foo)           --> -- 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.
+}
+

+ 665 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/bcsave.lua

@@ -0,0 +1,665 @@
+----------------------------------------------------------------------------
+-- LuaJIT module to save/list bytecode.
+--
+-- Copyright (C) 2005-2021 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 type, assert = type, assert
+local format = string.format
+local tremove, tconcat = table.remove, table.concat
+
+------------------------------------------------------------------------------
+
+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 =		{ e = "le", b = 32, m = 3, p = 0x14c, },
+  x64 =		{ e = "le", b = 64, m = 62, p = 0x8664, },
+  arm =		{ e = "le", b = 32, m = 40, p = 0x1c0, },
+  arm64 =	{ e = "le", b = 64, m = 183, p = 0xaa64, },
+  arm64be =	{ e = "be", b = 64, m = 183, },
+  ppc =		{ e = "be", b = 32, m = 20, },
+  mips =	{ e = "be", b = 32, m = 8, f = 0x50001006, },
+  mipsel =	{ e = "le", b = 32, m = 8, f = 0x50001006, },
+  mips64 =	{ e = "be", b = 64, m = 8, f = 0x80000007, },
+  mips64el =	{ e = "le", b = 64, m = 8, f = 0x80000007, },
+  mips64r6 =	{ e = "be", b = 64, m = 8, f = 0xa0000407, },
+  mips64r6el =	{ e = "le", b = 64, m = 8, f = 0xa0000407, },
+}
+
+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 = str:lower()
+  local s = check(map[str], "unknown ", err)
+  return type(s) == "string" and s or str
+end
+
+local function detecttype(str)
+  local ext = str:lower():match("%.(%a+)$")
+  return map_type[ext] or "raw"
+end
+
+local function checkmodname(str)
+  check(str:match("^[%w_.%-]+$"), "bad module name")
+  return str:gsub("[%.%-]", "_")
+end
+
+local function detectmodname(str)
+  if type(str) == "string" then
+    local tail = str:match("[^/\\]+$")
+    if tail then str = tail end
+    local head = str:match("^(.*)%.[^.]*$")
+    if head then str = head end
+    str = str:match("^[%w_.%-]+")
+  else
+    str = nil
+  end
+  check(str, "cannot derive module name, use -n name")
+  return str:gsub("[%.%-]", "_")
+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(format([[
+#ifdef __cplusplus
+extern "C"
+#endif
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+const unsigned char %s%s[] = {
+]], LJBC_PREFIX, ctx.modname))
+  else
+    fp:write(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(tconcat(t, ",", 1, n), ",\n")
+      n, m = 0, #b + 1
+    end
+    n = n + 1
+    t[n] = b
+  end
+  bcsave_tail(fp, output, tconcat(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 ai = assert(map_arch[ctx.arch])
+  local is64, isbe = ai.b == 64, ai.e == "be"
+
+  -- 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(ai.m)
+  hdr.flags = f32(ai.f or 0)
+  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+2)
+  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 ai = assert(map_arch[ctx.arch])
+  local is64 = ai.b == 64
+  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(assert(ai.p))
+  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 = jit.os:lower(),
+    type = false, modname = false,
+  }
+  while n <= #arg do
+    local a = arg[n]
+    if type(a) == "string" and a:sub(1, 1) == "-" and a ~= "-" then
+      tremove(arg, n)
+      if a == "--" then break end
+      for m=2,#a do
+	local opt = a:sub(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(tremove(arg, n))
+	  elseif opt == "t" then
+	    ctx.type = checkarg(tremove(arg, n), map_type, "file type")
+	  elseif opt == "a" then
+	    ctx.arch = checkarg(tremove(arg, n), map_arch, "architecture")
+	  elseif opt == "o" then
+	    ctx.os = checkarg(tremove(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.
+}
+

+ 689 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_arm.lua

@@ -0,0 +1,689 @@
+----------------------------------------------------------------------------
+-- LuaJIT ARM disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 1216 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_arm64.lua

@@ -0,0 +1,1216 @@
+----------------------------------------------------------------------------
+-- LuaJIT ARM64 disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+	else
+	  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 <R>.
+      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
+}
+

+ 12 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_arm64be.lua

@@ -0,0 +1,12 @@
+----------------------------------------------------------------------------
+-- LuaJIT ARM64BE disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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")
+

+ 694 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_mips.lua

@@ -0,0 +1,694 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+
+------------------------------------------------------------------------------
+-- Extended opcode maps common to all MIPS releases
+------------------------------------------------------------------------------
+
+local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", }
+local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", }
+
+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",
+  },
+}
+
+------------------------------------------------------------------------------
+-- Primary and extended opcode maps for MIPS R1-R5
+------------------------------------------------------------------------------
+
+local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", }
+
+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_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",
+}
+
+------------------------------------------------------------------------------
+-- Primary and extended opcode maps for MIPS R6
+------------------------------------------------------------------------------
+
+local map_mul_r6 =   { shift = 6, mask = 3, [2] = "mulDST",   [3] = "muhDST" }
+local map_mulu_r6 =  { shift = 6, mask = 3, [2] = "muluDST",  [3] = "muhuDST" }
+local map_div_r6 =   { shift = 6, mask = 3, [2] = "divDST",   [3] = "modDST" }
+local map_divu_r6 =  { shift = 6, mask = 3, [2] = "divuDST",  [3] = "moduDST" }
+local map_dmul_r6 =  { shift = 6, mask = 3, [2] = "dmulDST",  [3] = "dmuhDST" }
+local map_dmulu_r6 = { shift = 6, mask = 3, [2] = "dmuluDST", [3] = "dmuhuDST" }
+local map_ddiv_r6 =  { shift = 6, mask = 3, [2] = "ddivDST",  [3] = "dmodDST" }
+local map_ddivu_r6 = { shift = 6, mask = 3, [2] = "ddivuDST", [3] = "dmoduDST" }
+
+local map_special_r6 = {
+  shift = 0, mask = 63,
+  [0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
+  false,	map_srl,	"sraDTA",
+  "sllvDTS",	false,		map_srlv,	"sravDTS",
+  "jrS",	"jalrD1S",	false,		false,
+  "syscallY",	"breakY",	false,		"sync",
+  "clzDS",	"cloDS",	"dclzDS",	"dcloDS",
+  "dsllvDST",	"dlsaDSTA",	"dsrlvDST",	"dsravDST",
+  map_mul_r6,	map_mulu_r6,	map_div_r6,	map_divu_r6,
+  map_dmul_r6,	map_dmulu_r6,	map_ddiv_r6,	map_ddivu_r6,
+  "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",	"seleqzDST",	"tneSTZ",	"selnezDST",
+  "dsllDTA",	false,		"dsrlDTA",	"dsraDTA",
+  "dsll32DTA",	false,		"dsrl32DTA",	"dsra32DTA",
+}
+
+local map_bshfl_r6 = {
+  shift = 9, mask = 3,
+  [1] = "alignDSTa",
+  _ = {
+    shift = 6, mask = 31,
+    [0] = "bitswapDT",
+    [2] = "wsbhDT",
+    [16] = "sebDT",
+    [24] = "sehDT",
+  }
+}
+
+local map_dbshfl_r6 = {
+  shift = 9, mask = 3,
+  [1] = "dalignDSTa",
+  _ = {
+    shift = 6, mask = 31,
+    [0] = "dbitswapDT",
+    [2] = "dsbhDT",
+    [5] = "dshdDT",
+  }
+}
+
+local map_special3_r6 = {
+  shift = 0, mask = 63,
+  [0]  = "extTSAK", [1]  = "dextmTSAP", [3]  = "dextTSAK",
+  [4]  = "insTSAL", [6]  = "dinsuTSEQ", [7]  = "dinsTSAL",
+  [32] = map_bshfl_r6, [36] = map_dbshfl_r6,  [59] = "rdhwrTD",
+}
+
+local map_regimm_r6 = {
+  shift = 16, mask = 31,
+  [0] = "bltzSB", [1] = "bgezSB",
+  [6] = "dahiSI", [30] = "datiSI",
+  [23] = "sigrieI", [31] = "synciSO",
+}
+
+local map_pcrel_r6 = {
+  shift = 19, mask = 3,
+  [0] = "addiupcS2", "lwpcS2", "lwupcS2", {
+    shift = 18, mask = 1,
+    [0] = "ldpcS3", { shift = 16, mask = 3, [2] = "auipcSI", [3] = "aluipcSI" }
+  }
+}
+
+local map_cop1s_r6 = {
+  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",
+  "sel.sFGH",		false,		false,		false,
+  "seleqz.sFGH",	"recip.sFG",	"rsqrt.sFG",	"selnez.sFGH",
+  "maddf.sFGH",		"msubf.sFGH",	"rint.sFG",	"class.sFG",
+  "min.sFGH",		"mina.sFGH",	"max.sFGH",	"maxa.sFGH",
+  false,		"cvt.d.sFG",	false,		false,
+  "cvt.w.sFG",		"cvt.l.sFG",
+}
+
+local map_cop1d_r6 = {
+  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",
+  "sel.dFGH",		false,		false,		false,
+  "seleqz.dFGH",	"recip.dFG",	"rsqrt.dFG",	"selnez.dFGH",
+  "maddf.dFGH",		"msubf.dFGH",	"rint.dFG",	"class.dFG",
+  "min.dFGH",		"mina.dFGH",	"max.dFGH",	"maxa.dFGH",
+  "cvt.s.dFG",		false,		false,		false,
+  "cvt.w.dFG",		"cvt.l.dFG",
+}
+
+local map_cop1w_r6 = {
+  shift = 0, mask = 63,
+  [0] = "cmp.af.sFGH",	"cmp.un.sFGH",	"cmp.eq.sFGH",	"cmp.ueq.sFGH",
+  "cmp.lt.sFGH",	"cmp.ult.sFGH",	"cmp.le.sFGH",	"cmp.ule.sFGH",
+  "cmp.saf.sFGH",	"cmp.sun.sFGH",	"cmp.seq.sFGH",	"cmp.sueq.sFGH",
+  "cmp.slt.sFGH",	"cmp.sult.sFGH",	"cmp.sle.sFGH",	"cmp.sule.sFGH",
+  false,		"cmp.or.sFGH",	"cmp.une.sFGH",	"cmp.ne.sFGH",
+  false,		false,		false,		false,
+  false,		"cmp.sor.sFGH",	"cmp.sune.sFGH",	"cmp.sne.sFGH",
+  false,		false,		false,		false,
+  "cvt.s.wFG", "cvt.d.wFG",
+}
+
+local map_cop1l_r6 = {
+  shift = 0, mask = 63,
+  [0] = "cmp.af.dFGH",	"cmp.un.dFGH",	"cmp.eq.dFGH",	"cmp.ueq.dFGH",
+  "cmp.lt.dFGH",	"cmp.ult.dFGH",	"cmp.le.dFGH",	"cmp.ule.dFGH",
+  "cmp.saf.dFGH",	"cmp.sun.dFGH",	"cmp.seq.dFGH",	"cmp.sueq.dFGH",
+  "cmp.slt.dFGH",	"cmp.sult.dFGH",	"cmp.sle.dFGH",	"cmp.sule.dFGH",
+  false,		"cmp.or.dFGH",	"cmp.une.dFGH",	"cmp.ne.dFGH",
+  false,		false,		false,		false,
+  false,		"cmp.sor.dFGH",	"cmp.sune.dFGH",	"cmp.sne.dFGH",
+  false,		false,		false,		false,
+  "cvt.s.lFG", "cvt.d.lFG",
+}
+
+local map_cop1_r6 = {
+  shift = 21, mask = 31,
+  [0] = "mfc1TG", "dmfc1TG",	"cfc1TG",	"mfhc1TG",
+  "mtc1TG",	"dmtc1TG",	"ctc1TG",	"mthc1TG",
+  false,	"bc1eqzHB",	false,		false,
+  false,	"bc1nezHB",	false,		false,
+  map_cop1s_r6,	map_cop1d_r6,	false,		false,
+  map_cop1w_r6,	map_cop1l_r6,
+}
+
+local function maprs_popTS(rs, rt)
+  if rt == 0 then return 0 elseif rs == 0 then return 1
+  elseif rs == rt then return 2 else return 3 end
+end
+
+local map_pop06_r6 = {
+  maprs = maprs_popTS, [0] = "blezSB", "blezalcTB", "bgezalcTB", "bgeucSTB"
+}
+local map_pop07_r6 = {
+  maprs = maprs_popTS, [0] = "bgtzSB", "bgtzalcTB", "bltzalcTB", "bltucSTB"
+}
+local map_pop26_r6 = {
+  maprs = maprs_popTS, "blezcTB", "bgezcTB", "bgecSTB"
+}
+local map_pop27_r6 = {
+  maprs = maprs_popTS, "bgtzcTB", "bltzcTB", "bltcSTB"
+}
+
+local function maprs_popS(rs, rt)
+  if rs == 0 then return 0 else return 1 end
+end
+
+local map_pop66_r6 = {
+  maprs = maprs_popS, [0] = "jicTI", "beqzcSb"
+}
+local map_pop76_r6 = {
+  maprs = maprs_popS, [0] = "jialcTI", "bnezcSb"
+}
+
+local function maprs_popST(rs, rt)
+  if rs >= rt then return 0 elseif rs == 0 then return 1 else return 2 end
+end
+
+local map_pop10_r6 = {
+  maprs = maprs_popST, [0] = "bovcSTB", "beqzalcTB", "beqcSTB"
+}
+local map_pop30_r6 = {
+  maprs = maprs_popST, [0] = "bnvcSTB", "bnezalcTB", "bnecSTB"
+}
+
+local map_pri_r6 = {
+  [0] = map_special_r6,	map_regimm_r6,	"jJ",	"jalJ",
+  "beq|beqz|bST00B",	"bne|bnezST0B",		map_pop06_r6,	map_pop07_r6,
+  map_pop10_r6,	"addiu|liTS0I",	"sltiTSI",	"sltiuTSI",
+  "andiTSU",	"ori|liTS0U",	"xoriTSU",	"aui|luiTS0U",
+  map_cop0,	map_cop1_r6,	false,		false,
+  false,	false,		map_pop26_r6,	map_pop27_r6,
+  map_pop30_r6,	"daddiuTSI",	false,		false,
+  false,	"dauiTSI",	false,		map_special3_r6,
+  "lbTSO",	"lhTSO",	false,		"lwTSO",
+  "lbuTSO",	"lhuTSO",	false,		false,
+  "sbTSO",	"shTSO",	false,		"swTSO",
+  false,	false,		false,		false,
+  false,	"lwc1HSO",	"bc#",		false,
+  false,	"ldc1HSO",	map_pop66_r6,	"ldTSO",
+  false,	"swc1HSO",	"balc#",	map_pcrel_r6,
+  false,	"sdc1HSO",	map_pop76_r6,	"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 = ctx.map_pri[rshift(op, 26)]
+  while type(opat) ~= "string" do
+    if not opat then return unknown(ctx) end
+    if opat.maprs then
+      opat = opat[opat.maprs(band(rshift(op,21),31), band(rshift(op,16),31))]
+    else
+      opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
+    end
+  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 == "a" then
+      x = band(rshift(op, 6), 7)
+    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 == "2" then
+      x = arshift(lshift(op, 13), 11)
+    elseif p == "3" then
+      x = arshift(lshift(op, 14), 11)
+    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), 14) + 4
+      ctx.rel = x
+      x = format("0x%08x", x)
+    elseif p == "b" then
+      x = ctx.addr + ctx.pos + arshift(lshift(op, 11), 9) + 4
+      ctx.rel = x
+      x = format("0x%08x", x)
+    elseif p == "#" then
+      x = ctx.addr + ctx.pos + arshift(lshift(op, 6), 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
+  ctx.map_pri = map_pri
+  return ctx
+end
+
+local function create_el(code, addr, out)
+  local ctx = create(code, addr, out)
+  ctx.get = get_le
+  return ctx
+end
+
+local function create_r6(code, addr, out)
+  local ctx = create(code, addr, out)
+  ctx.map_pri = map_pri_r6
+  return ctx
+end
+
+local function create_r6_el(code, addr, out)
+  local ctx = create(code, addr, out)
+  ctx.get = get_le
+  ctx.map_pri = map_pri_r6
+  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
+
+local function disass_r6(code, addr, out)
+  create_r6(code, addr, out):disass()
+end
+
+local function disass_r6_el(code, addr, out)
+  create_r6_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,
+  create_r6 = create_r6,
+  create_r6_el = create_r6_el,
+  disass = disass,
+  disass_el = disass_el,
+  disass_r6 = disass_r6,
+  disass_r6_el = disass_r6_el,
+  regname = regname
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_mips64.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64 disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_mips64el.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64EL disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_mips64r6.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64R6 disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This module just exports the r6 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_r6,
+  disass = dis_mips.disass_r6,
+  regname = dis_mips.regname
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_mips64r6el.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPS64R6EL disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+-- This module just exports the r6 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_r6_el,
+  disass = dis_mips.disass_r6_el,
+  regname = dis_mips.regname
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_mipsel.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT MIPSEL disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 591 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_ppc.lua

@@ -0,0 +1,591 @@
+----------------------------------------------------------------------------
+-- LuaJIT PPC disassembler module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 17 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_x64.lua

@@ -0,0 +1,17 @@
+----------------------------------------------------------------------------
+-- LuaJIT x64 disassembler wrapper module.
+--
+-- Copyright (C) 2005-2021 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
+}
+

+ 953 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/dis_x86.lua

@@ -0,0 +1,953 @@
+----------------------------------------------------------------------------
+-- LuaJIT x86/x64 disassembler module.
+--
+-- Copyright (C) 2005-2021 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",
+--9x
+[0x96] = "||fmaddsub132pHXrvm",[0x97] = "||fmsubadd132pHXrvm",
+[0x98] = "||fmadd132pHXrvm",[0x99] = "||fmadd132sHXrvm",
+[0x9a] = "||fmsub132pHXrvm",[0x9b] = "||fmsub132sHXrvm",
+[0x9c] = "||fnmadd132pHXrvm",[0x9d] = "||fnmadd132sHXrvm",
+[0x9e] = "||fnmsub132pHXrvm",[0x9f] = "||fnmsub132sHXrvm",
+--Ax
+[0xa6] = "||fmaddsub213pHXrvm",[0xa7] = "||fmsubadd213pHXrvm",
+[0xa8] = "||fmadd213pHXrvm",[0xa9] = "||fmadd213sHXrvm",
+[0xaa] = "||fmsub213pHXrvm",[0xab] = "||fmsub213sHXrvm",
+[0xac] = "||fnmadd213pHXrvm",[0xad] = "||fnmadd213sHXrvm",
+[0xae] = "||fnmsub213pHXrvm",[0xaf] = "||fnmsub213sHXrvm",
+--Bx
+[0xb6] = "||fmaddsub231pHXrvm",[0xb7] = "||fmsubadd231pHXrvm",
+[0xb8] = "||fmadd231pHXrvm",[0xb9] = "||fmadd231sHXrvm",
+[0xba] = "||fmsub231pHXrvm",[0xbb] = "||fmsub231sHXrvm",
+[0xbc] = "||fnmadd231pHXrvm",[0xbd] = "||fnmadd231sHXrvm",
+[0xbe] = "||fnmsub231pHXrvm",[0xbf] = "||fnmsub231sHXrvm",
+--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: 1DFGHIMPQRSTUVWXYabcdfgijlmoprstuvwxyz
+  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 == "H" then
+      name = name..(ctx.rexw and "d" or "s")
+      ctx.rexw = false
+    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,
+  H = 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
+}
+

+ 726 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/dump.lua

@@ -0,0 +1,726 @@
+----------------------------------------------------------------------------
+-- LuaJIT compiler dump module.
+--
+-- Copyright (C) 2005-2021 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 maskaddr = jit.arch == "arm" and -2
+    local ircall = vmdef.ircall
+    for i=0,#ircall do
+      local addr = ircalladdr(i)
+      if addr ~= 0 then
+	if maskaddr then addr = band(addr, maskaddr) end
+	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, extra)
+  local out = format(colortype_ansi[t], s)
+  if extra then out = "\027[3m"..out end
+  return out
+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 = { ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;", }
+
+local function colorize_html(s, t, extra)
+  s = gsub(s, "[<>&]", html_escape)
+  return format('<span class="irt_%s%s">%s</span>',
+		irtype_text[t], extra and " irt_extra" or "", 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 = [[
+<style type="text/css">
+background { background: #ffffff; color: #000000; }
+pre.ljdump {
+font-size: 10pt;
+background: #f0f4ff;
+color: #000000;
+border: 1px solid #bfcfff;
+padding: 0.5em;
+margin-left: 2em;
+margin-right: 2em;
+}
+span.irt_str { color: #00a000; }
+span.irt_thr, span.irt_fun { color: #404040; font-weight: bold; }
+span.irt_tab { color: #c00000; }
+span.irt_udt, span.irt_lud { color: #00c0c0; }
+span.irt_num { color: #4040c0; }
+span.irt_int, span.irt_i8, span.irt_u8, span.irt_i16, span.irt_u16 { color: #b040b0; }
+span.irt_extra { font-style: italic; }
+</style>
+]]
+
+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
+    if band(mode, 64) ~= 0 then s = s.."K" 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, 12)
+    if c == 1 then s = s.." none"
+    elseif 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,
+  ["TMPREF"] = { [0] = "", "IN", "OUT", "INOUT", "", "", "OUT2", "INOUT2" },
+  ["BUFHDR"] = { [0] = "RESET", "APPEND", "WRITE" },
+  ["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 t < 12 then
+      s = k == 0 and "NULL" or format("[0x%08x]", k)
+    elseif 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, band(sn or 0, 0x100000) ~= 0)
+  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), band(sn, 0x100000) ~= 0))
+      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('<pre class="ljdump">\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("</pre>\n\n") else out:write("\n") end
+  else
+    if what == "flush" then symtab, nexitsym = {}, 0 end
+    out:write("---- TRACE ", what, "\n\n")
+  end
+  out:flush()
+end
+
+-- Dump recorded bytecode.
+local function dump_record(tr, func, pc, depth)
+  if depth ~= recdepth then
+    recdepth = depth
+    recprefix = rep(" .", depth)
+  end
+  local line
+  if pc >= 0 then
+    line = bcline(func, pc, recprefix)
+    if dumpmode.H then line = gsub(line, "[<>&]", html_escape) end
+  else
+    line = "0000 "..recprefix.." FUNCC      \n"
+  end
+  if pc <= 0 then
+    out:write(sub(line, 1, -2), "         ; ", fmtfunc(func), "\n")
+  else
+    out:write(line)
+  end
+  if pc >= 0 and band(funcbc(func, pc), 0xff) < 16 then -- ORDER BC
+    out:write(bcline(func, pc+1, recprefix)) -- Write JMP for cond.
+  end
+end
+
+------------------------------------------------------------------------------
+
+local gpr64 = jit.arch:match("64")
+local fprmips32 = jit.arch == "mips" or jit.arch == "mipsel"
+
+-- Dump taken trace exits.
+local function dump_texit(tr, ex, ngpr, nfpr, ...)
+  out:write("---- TRACE ", tr, " exit ", ex, "\n")
+  if dumpmode.X then
+    local regs = {...}
+    if gpr64 then
+      for i=1,ngpr do
+	out:write(format(" %016x", regs[i]))
+	if i % 4 == 0 then out:write("\n") end
+      end
+    else
+      for i=1,ngpr do
+	out:write(" ", tohex(regs[i]))
+	if i % 8 == 0 then out:write("\n") end
+      end
+    end
+    if fprmips32 then
+      for i=1,nfpr,2 do
+	out:write(format(" %+17.14g", regs[ngpr+i]))
+	if i % 8 == 7 then out:write("\n") end
+      end
+    else
+      for i=1,nfpr do
+	out:write(format(" %+17.14g", regs[ngpr+i]))
+	if i % 4 == 0 then out:write("\n") end
+      end
+    end
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Detach dump handlers.
+local function dumpoff()
+  if active then
+    active = false
+    jit.attach(dump_texit)
+    jit.attach(dump_record)
+    jit.attach(dump_trace)
+    if out and out ~= stdout and out ~= stderr then out:close() end
+    out = nil
+  end
+end
+
+-- Open the output file and attach dump handlers.
+local function dumpon(opt, outfile)
+  if active then dumpoff() end
+
+  local term = os.getenv("TERM")
+  local colormode = (term and term:match("color") or os.getenv("COLORTERM")) and "A" or "T"
+  if opt then
+    opt = gsub(opt, "[TAH]", function(mode) colormode = mode; return ""; end)
+  end
+
+  local m = { t=true, b=true, i=true, m=true, }
+  if opt and opt ~= "" then
+    local o = sub(opt, 1, 1)
+    if o ~= "+" and o ~= "-" then m = {} end
+    for i=1,#opt do m[sub(opt, i, i)] = (o ~= "-") end
+  end
+  dumpmode = m
+
+  if m.t or m.b or m.i or m.s or m.m then
+    jit.attach(dump_trace, "trace")
+  end
+  if m.b then
+    jit.attach(dump_record, "record")
+    if not bcline then bcline = require("jit.bc").line end
+  end
+  if m.x or m.X then
+    jit.attach(dump_texit, "texit")
+  end
+
+  if not outfile then outfile = os.getenv("LUAJIT_DUMPFILE") end
+  if outfile then
+    out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
+  else
+    out = stdout
+  end
+
+  m[colormode] = true
+  if colormode == "A" then
+    colorize = colorize_ansi
+    irtype = irtype_ansi
+  elseif colormode == "H" then
+    colorize = colorize_html
+    irtype = irtype_html
+    out:write(header_html)
+  else
+    colorize = colorize_text
+    irtype = irtype_text
+  end
+
+  active = true
+end
+
+-- Public module functions.
+return {
+  on = dumpon,
+  off = dumpoff,
+  start = dumpon -- For -j command line option.
+}
+

+ 312 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/p.lua

@@ -0,0 +1,312 @@
+----------------------------------------------------------------------------
+-- LuaJIT profiler.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module is a simple command line interface to the built-in
+-- low-overhead profiler of LuaJIT.
+--
+-- The lower-level API of the profiler is accessible via the "jit.profile"
+-- module or the luaJIT_profile_* C API.
+--
+-- Example usage:
+--
+--   luajit -jp myapp.lua
+--   luajit -jp=s myapp.lua
+--   luajit -jp=-s myapp.lua
+--   luajit -jp=vl myapp.lua
+--   luajit -jp=G,profile.txt myapp.lua
+--
+-- The following dump features are available:
+--
+--   f  Stack dump: function name, otherwise module:line. Default mode.
+--   F  Stack dump: ditto, but always prepend module.
+--   l  Stack dump: module:line.
+--   <number> stack dump depth (callee < caller). Default: 1.
+--   -<number> Inverse stack dump depth (caller > callee).
+--   s  Split stack dump after first stack level. Implies abs(depth) >= 2.
+--   p  Show full path for module names.
+--   v  Show VM states. Can be combined with stack dumps, e.g. vf or fv.
+--   z  Show zones. Can be combined with stack dumps, e.g. zf or fz.
+--   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 (e.g. flame graphs).
+--   m<number> Minimum sample percentage to be shown. Default: 3.
+--   i<number> Sampling interval in milliseconds. Default: 10.
+--
+----------------------------------------------------------------------------
+
+-- Cache some library functions and objects.
+local jit = require("jit")
+assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
+local profile = require("jit.profile")
+local vmdef = require("jit.vmdef")
+local math = math
+local pairs, ipairs, tonumber, floor = pairs, ipairs, tonumber, math.floor
+local sort, format = table.sort, string.format
+local stdout = io.stdout
+local zone -- Load jit.zone module on demand.
+
+-- Output file handle.
+local out
+
+------------------------------------------------------------------------------
+
+local prof_ud
+local prof_states, prof_split, prof_min, prof_raw, prof_fmt, prof_depth
+local prof_ann, prof_count1, prof_count2, prof_samples
+
+local map_vmmode = {
+  N = "Compiled",
+  I = "Interpreted",
+  C = "C code",
+  G = "Garbage Collector",
+  J = "JIT Compiler",
+}
+
+-- Profiler callback.
+local function prof_cb(th, samples, vmmode)
+  prof_samples = prof_samples + samples
+  local key_stack, key_stack2, key_state
+  -- Collect keys for sample.
+  if prof_states then
+    if prof_states == "v" then
+      key_state = map_vmmode[vmmode] or vmmode
+    else
+      key_state = zone:get() or "(none)"
+    end
+  end
+  if prof_fmt then
+    key_stack = profile.dumpstack(th, prof_fmt, prof_depth)
+    key_stack = key_stack:gsub("%[builtin#(%d+)%]", function(x)
+      return vmdef.ffnames[tonumber(x)]
+    end)
+    if prof_split == 2 then
+      local k1, k2 = key_stack:match("(.-) [<>] (.*)")
+      if k2 then key_stack, key_stack2 = k1, k2 end
+    elseif prof_split == 3 then
+      key_stack2 = profile.dumpstack(th, "l", 1)
+    end
+  end
+  -- Order keys.
+  local k1, k2
+  if prof_split == 1 then
+    if key_state then
+      k1 = key_state
+      if key_stack then k2 = key_stack end
+    end
+  elseif key_stack then
+    k1 = key_stack
+    if key_stack2 then k2 = key_stack2 elseif key_state then k2 = key_state end
+  end
+  -- Coalesce samples in one or two levels.
+  if k1 then
+    local t1 = prof_count1
+    t1[k1] = (t1[k1] or 0) + samples
+    if k2 then
+      local t2 = prof_count2
+      local t3 = t2[k1]
+      if not t3 then t3 = {}; t2[k1] = t3 end
+      t3[k2] = (t3[k2] or 0) + samples
+    end
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Show top N list.
+local function prof_top(count1, count2, samples, indent)
+  local t, n = {}, 0
+  for k in pairs(count1) do
+    n = n + 1
+    t[n] = k
+  end
+  sort(t, function(a, b) return count1[a] > count1[b] end)
+  for i=1,n do
+    local k = t[i]
+    local v = count1[k]
+    local pct = floor(v*100/samples + 0.5)
+    if pct < prof_min then break end
+    if not prof_raw then
+      out:write(format("%s%2d%%  %s\n", indent, pct, k))
+    elseif prof_raw == "r" then
+      out:write(format("%s%5d  %s\n", indent, v, k))
+    else
+      out:write(format("%s %d\n", k, v))
+    end
+    if count2 then
+      local r = count2[k]
+      if r then
+	prof_top(r, nil, v, (prof_split == 3 or prof_split == 1) and "  -- " or
+			    (prof_depth < 0 and "  -> " or "  <- "))
+      end
+    end
+  end
+end
+
+-- Annotate source code
+local function prof_annotate(count1, samples)
+  local files = {}
+  local ms = 0
+  for k, v in pairs(count1) do
+    local pct = floor(v*100/samples + 0.5)
+    ms = math.max(ms, v)
+    if pct >= prof_min then
+      local file, line = k:match("^(.*):(%d+)$")
+      if not file then file = k; line = 0 end
+      local fl = files[file]
+      if not fl then fl = {}; files[file] = fl; files[#files+1] = file end
+      line = tonumber(line)
+      fl[line] = prof_raw and v or pct
+    end
+  end
+  sort(files)
+  local fmtv, fmtn = " %3d%% | %s\n", "      | %s\n"
+  if prof_raw then
+    local n = math.max(5, math.ceil(math.log10(ms)))
+    fmtv = "%"..n.."d | %s\n"
+    fmtn = (" "):rep(n).." | %s\n"
+  end
+  local ann = prof_ann
+  for _, file in ipairs(files) do
+    local f0 = file:byte()
+    if f0 == 40 or f0 == 91 then
+      out:write(format("\n====== %s ======\n[Cannot annotate non-file]\n", file))
+      break
+    end
+    local fp, err = io.open(file)
+    if not fp then
+      out:write(format("====== ERROR: %s: %s\n", file, err))
+      break
+    end
+    out:write(format("\n====== %s ======\n", file))
+    local fl = files[file]
+    local n, show = 1, false
+    if ann ~= 0 then
+      for i=1,ann do
+	if fl[i] then show = true; out:write("@@ 1 @@\n"); break end
+      end
+    end
+    for line in fp:lines() do
+      if line:byte() == 27 then
+	out:write("[Cannot annotate bytecode file]\n")
+	break
+      end
+      local v = fl[n]
+      if ann ~= 0 then
+	local v2 = fl[n+ann]
+	if show then
+	  if v2 then show = n+ann elseif v then show = n
+	  elseif show+ann < n then show = false end
+	elseif v2 then
+	  show = n+ann
+	  out:write(format("@@ %d @@\n", n))
+	end
+	if not show then goto next end
+      end
+      if v then
+	out:write(format(fmtv, v, line))
+      else
+	out:write(format(fmtn, line))
+      end
+    ::next::
+      n = n + 1
+    end
+    fp:close()
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Finish profiling and dump result.
+local function prof_finish()
+  if prof_ud then
+    profile.stop()
+    local samples = prof_samples
+    if samples == 0 then
+      if prof_raw ~= true then out:write("[No samples collected]\n") end
+      return
+    end
+    if prof_ann then
+      prof_annotate(prof_count1, samples)
+    else
+      prof_top(prof_count1, prof_count2, samples, "")
+    end
+    prof_count1 = nil
+    prof_count2 = nil
+    prof_ud = nil
+    if out ~= stdout then out:close() end
+  end
+end
+
+-- Start profiling.
+local function prof_start(mode)
+  local interval = ""
+  mode = mode:gsub("i%d*", function(s) interval = s; return "" end)
+  prof_min = 3
+  mode = mode:gsub("m(%d+)", function(s) prof_min = tonumber(s); return "" end)
+  prof_depth = 1
+  mode = mode:gsub("%-?%d+", function(s) prof_depth = tonumber(s); return "" end)
+  local m = {}
+  for c in mode:gmatch(".") do m[c] = c end
+  prof_states = m.z or m.v
+  if prof_states == "z" then zone = require("jit.zone") end
+  local scope = m.l or m.f or m.F or (prof_states and "" or "f")
+  local flags = (m.p or "")
+  prof_raw = m.r
+  if m.s then
+    prof_split = 2
+    if prof_depth == -1 or m["-"] then prof_depth = -2
+    elseif prof_depth == 1 then prof_depth = 2 end
+  elseif mode:find("[fF].*l") then
+    scope = "l"
+    prof_split = 3
+  else
+    prof_split = (scope == "" or mode:find("[zv].*[lfF]")) and 1 or 0
+  end
+  prof_ann = m.A and 0 or (m.a and 3)
+  if prof_ann then
+    scope = "l"
+    prof_fmt = "pl"
+    prof_split = 0
+    prof_depth = 1
+  elseif m.G and scope ~= "" then
+    prof_fmt = flags..scope.."Z;"
+    prof_depth = -100
+    prof_raw = true
+    prof_min = 0
+  elseif scope == "" then
+    prof_fmt = false
+  else
+    local sc = prof_split == 3 and m.f or m.F or scope
+    prof_fmt = flags..sc..(prof_depth >= 0 and "Z < " or "Z > ")
+  end
+  prof_count1 = {}
+  prof_count2 = {}
+  prof_samples = 0
+  profile.start(scope:lower()..interval, prof_cb)
+  prof_ud = newproxy(true)
+  getmetatable(prof_ud).__gc = prof_finish
+end
+
+------------------------------------------------------------------------------
+
+local function start(mode, outfile)
+  if not outfile then outfile = os.getenv("LUAJIT_PROFILEFILE") end
+  if outfile then
+    out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
+  else
+    out = stdout
+  end
+  prof_start(mode or "f")
+end
+
+-- Public module functions.
+return {
+  start = start, -- For -j command line option.
+  stop = prof_finish
+}
+

+ 170 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/v.lua

@@ -0,0 +1,170 @@
+----------------------------------------------------------------------------
+-- Verbose mode of the LuaJIT compiler.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module shows verbose information about the progress of the
+-- JIT compiler. It prints one line for each generated trace. This module
+-- is useful to see which code has been compiled or where the compiler
+-- punts and falls back to the interpreter.
+--
+-- Example usage:
+--
+--   luajit -jv -e "for i=1,1000 do for j=1,1000 do end end"
+--   luajit -jv=myapp.out myapp.lua
+--
+-- Default output is to stderr. To redirect the output to a file, pass a
+-- filename as an argument (use '-' for stdout) or set the environment
+-- variable LUAJIT_VERBOSEFILE. The file is overwritten every time the
+-- module is started.
+--
+-- The output from the first example should look like this:
+--
+-- [TRACE   1 (command line):1 loop]
+-- [TRACE   2 (1/3) (command line):1 -> 1]
+--
+-- The first number in each line is the internal trace number. Next are
+-- the file name ('(command line)') and the line number (':1') where the
+-- trace has started. Side traces also show the parent trace number and
+-- the exit number where they are attached to in parentheses ('(1/3)').
+-- An arrow at the end shows where the trace links to ('-> 1'), unless
+-- it loops to itself.
+--
+-- In this case the inner loop gets hot and is traced first, generating
+-- a root trace. Then the last exit from the 1st trace gets hot, too,
+-- and triggers generation of the 2nd trace. The side trace follows the
+-- path along the outer loop and *around* the inner loop, back to its
+-- start, and then links to the 1st trace. Yes, this may seem unusual,
+-- if you know how traditional compilers work. Trace compilers are full
+-- of surprises like this -- have fun! :-)
+--
+-- Aborted traces are shown like this:
+--
+-- [TRACE --- foo.lua:44 -- leaving loop in root trace at foo:lua:50]
+--
+-- Don't worry -- trace aborts are quite common, even in programs which
+-- can be fully compiled. The compiler may retry several times until it
+-- finds a suitable trace.
+--
+-- Of course this doesn't work with features that are not-yet-implemented
+-- (NYI error messages). The VM simply falls back to the interpreter. This
+-- may not matter at all if the particular trace is not very high up in
+-- the CPU usage profile. Oh, and the interpreter is quite fast, too.
+--
+-- Also check out the -jdump module, which prints all the gory details.
+--
+------------------------------------------------------------------------------
+
+-- 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, traceinfo = jutil.funcinfo, jutil.traceinfo
+local type, format = type, string.format
+local stdout, stderr = io.stdout, io.stderr
+
+-- Active flag and output file handle.
+local active, out
+
+------------------------------------------------------------------------------
+
+local startloc, startex
+
+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
+
+-- 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 == "start" then
+    startloc = fmtfunc(func, pc)
+    startex = otr and "("..otr.."/"..(oex == -1 and "stitch" or oex)..") " or ""
+  else
+    if what == "abort" then
+      local loc = fmtfunc(func, pc)
+      if loc ~= startloc then
+	out:write(format("[TRACE --- %s%s -- %s at %s]\n",
+	  startex, startloc, fmterr(otr, oex), loc))
+      else
+	out:write(format("[TRACE --- %s%s -- %s]\n",
+	  startex, startloc, fmterr(otr, oex)))
+      end
+    elseif what == "stop" then
+      local info = traceinfo(tr)
+      local link, ltype = info.link, info.linktype
+      if ltype == "interpreter" then
+	out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n",
+	  tr, startex, startloc))
+      elseif ltype == "stitch" then
+	out:write(format("[TRACE %3s %s%s %s %s]\n",
+	  tr, startex, startloc, ltype, fmtfunc(func, pc)))
+      elseif link == tr or link == 0 then
+	out:write(format("[TRACE %3s %s%s %s]\n",
+	  tr, startex, startloc, ltype))
+      elseif ltype == "root" then
+	out:write(format("[TRACE %3s %s%s -> %d]\n",
+	  tr, startex, startloc, link))
+      else
+	out:write(format("[TRACE %3s %s%s -> %d %s]\n",
+	  tr, startex, startloc, link, ltype))
+      end
+    else
+      out:write(format("[TRACE %s]\n", what))
+    end
+    out:flush()
+  end
+end
+
+------------------------------------------------------------------------------
+
+-- Detach dump handlers.
+local function dumpoff()
+  if active then
+    active = false
+    jit.attach(dump_trace)
+    if out and out ~= stdout and out ~= stderr then out:close() end
+    out = nil
+  end
+end
+
+-- Open the output file and attach dump handlers.
+local function dumpon(outfile)
+  if active then dumpoff() end
+  if not outfile then outfile = os.getenv("LUAJIT_VERBOSEFILE") end
+  if outfile then
+    out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
+  else
+    out = stderr
+  end
+  jit.attach(dump_trace, "trace")
+  active = true
+end
+
+-- Public module functions.
+return {
+  on = dumpon,
+  off = dumpoff,
+  start = dumpon -- For -j command line option.
+}
+

+ 395 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/vmdef.lua

@@ -0,0 +1,395 @@
+-- This is a generated file. DO NOT EDIT!
+
+return {
+
+bcnames = "ISLT  ISGE  ISLE  ISGT  ISEQV ISNEV ISEQS ISNES ISEQN ISNEN ISEQP ISNEP ISTC  ISFC  IST   ISF   ISTYPEISNUM MOV   NOT   UNM   LEN   ADDVN SUBVN MULVN DIVVN MODVN ADDNV SUBNV MULNV DIVNV MODNV ADDVV SUBVV MULVV DIVVV MODVV POW   CAT   KSTR  KCDATAKSHORTKNUM  KPRI  KNIL  UGET  USETV USETS USETN USETP UCLO  FNEW  TNEW  TDUP  GGET  GSET  TGETV TGETS TGETB TGETR TSETV TSETS TSETB TSETM TSETR CALLM CALL  CALLMTCALLT ITERC ITERN VARG  ISNEXTRETM  RET   RET0  RET1  FORI  JFORI FORL  IFORL JFORL ITERL IITERLJITERLLOOP  ILOOP JLOOP JMP   FUNCF IFUNCFJFUNCFFUNCV IFUNCVJFUNCVFUNCC FUNCCW",
+
+irnames = "LT    GE    LE    GT    ULT   UGE   ULE   UGT   EQ    NE    ABC   RETF  NOP   BASE  PVAL  GCSTEPHIOP  LOOP  USE   PHI   RENAMEPROF  KPRI  KINT  KGC   KPTR  KKPTR KNULL KNUM  KINT64KSLOT BNOT  BSWAP BAND  BOR   BXOR  BSHL  BSHR  BSAR  BROL  BROR  ADD   SUB   MUL   DIV   MOD   POW   NEG   ABS   LDEXP MIN   MAX   FPMATHADDOV SUBOV MULOV AREF  HREFK HREF  NEWREFUREFO UREFC FREF  TMPREFSTRREFLREF  ALOAD HLOAD ULOAD FLOAD XLOAD SLOAD VLOAD ALEN  ASTOREHSTOREUSTOREFSTOREXSTORESNEW  XSNEW TNEW  TDUP  CNEW  CNEWI BUFHDRBUFPUTBUFSTRTBAR  OBAR  XBAR  CONV  TOBIT TOSTR STRTO CALLN CALLA CALLL CALLS CALLXSCARG  ",
+
+irfpm = { [0]="floor", "ceil", "trunc", "sqrt", "log", "log2", "other", },
+
+irfield = { [0]="str.len", "func.env", "func.pc", "func.ffid", "thread.env", "tab.meta", "tab.array", "tab.node", "tab.asize", "tab.hmask", "tab.nomm", "udata.meta", "udata.udtype", "udata.file", "sbuf.w", "sbuf.e", "sbuf.b", "sbuf.l", "sbuf.ref", "sbuf.r", "cdata.ctypeid", "cdata.ptr", "cdata.int", "cdata.int64", "cdata.int64_4", },
+
+ircall = {
+[0]="lj_str_cmp",
+"lj_str_find",
+"lj_str_new",
+"lj_strscan_num",
+"lj_strfmt_int",
+"lj_strfmt_num",
+"lj_strfmt_char",
+"lj_strfmt_putint",
+"lj_strfmt_putnum",
+"lj_strfmt_putquoted",
+"lj_strfmt_putfxint",
+"lj_strfmt_putfnum_int",
+"lj_strfmt_putfnum_uint",
+"lj_strfmt_putfnum",
+"lj_strfmt_putfstr",
+"lj_strfmt_putfchar",
+"lj_buf_putmem",
+"lj_buf_putstr",
+"lj_buf_putchar",
+"lj_buf_putstr_reverse",
+"lj_buf_putstr_lower",
+"lj_buf_putstr_upper",
+"lj_buf_putstr_rep",
+"lj_buf_puttab",
+"lj_bufx_set",
+"lj_bufx_more",
+"lj_serialize_put",
+"lj_serialize_get",
+"lj_serialize_encode",
+"lj_serialize_decode",
+"lj_buf_tostr",
+"lj_tab_new_ah",
+"lj_tab_new1",
+"lj_tab_dup",
+"lj_tab_clear",
+"lj_tab_newkey",
+"lj_tab_keyindex",
+"lj_vm_next",
+"lj_tab_len",
+"lj_tab_len_hint",
+"lj_gc_step_jit",
+"lj_gc_barrieruv",
+"lj_mem_newgco",
+"lj_prng_u64d",
+"lj_vm_modi",
+"log10",
+"exp",
+"sin",
+"cos",
+"tan",
+"asin",
+"acos",
+"atan",
+"sinh",
+"cosh",
+"tanh",
+"fputc",
+"fwrite",
+"fflush",
+"lj_vm_floor",
+"lj_vm_ceil",
+"lj_vm_trunc",
+"sqrt",
+"log",
+"lj_vm_log2",
+"lj_vm_powi",
+"pow",
+"atan2",
+"ldexp",
+"lj_vm_tobit",
+"softfp_add",
+"softfp_sub",
+"softfp_mul",
+"softfp_div",
+"softfp_cmp",
+"softfp_i2d",
+"softfp_d2i",
+"lj_vm_sfmin",
+"lj_vm_sfmax",
+"lj_vm_tointg",
+"softfp_ui2d",
+"softfp_f2d",
+"softfp_d2ui",
+"softfp_d2f",
+"softfp_i2f",
+"softfp_ui2f",
+"softfp_f2i",
+"softfp_f2ui",
+"fp64_l2d",
+"fp64_ul2d",
+"fp64_l2f",
+"fp64_ul2f",
+"fp64_d2l",
+"fp64_d2ul",
+"fp64_f2l",
+"fp64_f2ul",
+"lj_carith_divi64",
+"lj_carith_divu64",
+"lj_carith_modi64",
+"lj_carith_modu64",
+"lj_carith_powi64",
+"lj_carith_powu64",
+"lj_cdata_newv",
+"lj_cdata_setfin",
+"strlen",
+"memcpy",
+"memset",
+"lj_vm_errno",
+"lj_carith_mul64",
+"lj_carith_shl64",
+"lj_carith_shr64",
+"lj_carith_sar64",
+"lj_carith_rol64",
+"lj_carith_ror64",
+},
+
+traceerr = {
+[0]="error thrown or hook called during recording",
+"trace too short",
+"trace too long",
+"trace too deep",
+"too many snapshots",
+"blacklisted",
+"retry recording",
+"NYI: bytecode %d",
+"leaving loop in root trace",
+"inner loop in root trace",
+"loop unroll limit reached",
+"bad argument type",
+"JIT compilation disabled for function",
+"call unroll limit reached",
+"down-recursion, restarting",
+"NYI: unsupported variant of FastFunc %s",
+"NYI: return to lower frame",
+"store with nil or NaN key",
+"missing metamethod",
+"looping index lookup",
+"NYI: mixed sparse/dense table",
+"symbol not in cache",
+"NYI: unsupported C type conversion",
+"NYI: unsupported C function type",
+"guard would always fail",
+"too many PHIs",
+"persistent type instability",
+"failed to allocate mcode memory",
+"machine code too long",
+"hit mcode limit (retrying)",
+"too many spill slots",
+"inconsistent register allocation",
+"NYI: cannot assemble IR instruction %d",
+"NYI: PHI shuffling too complex",
+"NYI: register coalescing too complex",
+},
+
+ffnames = {
+[0]="Lua",
+"C",
+"assert",
+"type",
+"next",
+"pairs",
+"ipairs_aux",
+"ipairs",
+"getmetatable",
+"setmetatable",
+"getfenv",
+"setfenv",
+"rawget",
+"rawset",
+"rawequal",
+"unpack",
+"select",
+"tonumber",
+"tostring",
+"error",
+"pcall",
+"xpcall",
+"loadfile",
+"load",
+"loadstring",
+"dofile",
+"gcinfo",
+"collectgarbage",
+"newproxy",
+"print",
+"coroutine.status",
+"coroutine.running",
+"coroutine.isyieldable",
+"coroutine.create",
+"coroutine.yield",
+"coroutine.resume",
+"coroutine.wrap_aux",
+"coroutine.wrap",
+"math.abs",
+"math.floor",
+"math.ceil",
+"math.sqrt",
+"math.log10",
+"math.exp",
+"math.sin",
+"math.cos",
+"math.tan",
+"math.asin",
+"math.acos",
+"math.atan",
+"math.sinh",
+"math.cosh",
+"math.tanh",
+"math.frexp",
+"math.modf",
+"math.log",
+"math.atan2",
+"math.pow",
+"math.fmod",
+"math.ldexp",
+"math.min",
+"math.max",
+"math.random",
+"math.randomseed",
+"bit.tobit",
+"bit.bnot",
+"bit.bswap",
+"bit.lshift",
+"bit.rshift",
+"bit.arshift",
+"bit.rol",
+"bit.ror",
+"bit.band",
+"bit.bor",
+"bit.bxor",
+"bit.tohex",
+"string.byte",
+"string.char",
+"string.sub",
+"string.rep",
+"string.reverse",
+"string.lower",
+"string.upper",
+"string.dump",
+"string.find",
+"string.match",
+"string.gmatch_aux",
+"string.gmatch",
+"string.gsub",
+"string.format",
+"table.maxn",
+"table.insert",
+"table.concat",
+"table.sort",
+"table.new",
+"table.clear",
+"io.method.close",
+"io.method.read",
+"io.method.write",
+"io.method.flush",
+"io.method.seek",
+"io.method.setvbuf",
+"io.method.lines",
+"io.method.__gc",
+"io.method.__tostring",
+"io.open",
+"io.popen",
+"io.tmpfile",
+"io.close",
+"io.read",
+"io.write",
+"io.flush",
+"io.input",
+"io.output",
+"io.lines",
+"io.type",
+"os.execute",
+"os.remove",
+"os.rename",
+"os.tmpname",
+"os.getenv",
+"os.exit",
+"os.clock",
+"os.date",
+"os.time",
+"os.difftime",
+"os.setlocale",
+"debug.getregistry",
+"debug.getmetatable",
+"debug.setmetatable",
+"debug.getfenv",
+"debug.setfenv",
+"debug.getinfo",
+"debug.getlocal",
+"debug.setlocal",
+"debug.getupvalue",
+"debug.setupvalue",
+"debug.upvalueid",
+"debug.upvaluejoin",
+"debug.sethook",
+"debug.gethook",
+"debug.debug",
+"debug.traceback",
+"jit.on",
+"jit.off",
+"jit.flush",
+"jit.status",
+"jit.security",
+"jit.attach",
+"jit.util.funcinfo",
+"jit.util.funcbc",
+"jit.util.funck",
+"jit.util.funcuvname",
+"jit.util.traceinfo",
+"jit.util.traceir",
+"jit.util.tracek",
+"jit.util.tracesnap",
+"jit.util.tracemc",
+"jit.util.traceexitstub",
+"jit.util.ircalladdr",
+"jit.opt.start",
+"jit.profile.start",
+"jit.profile.stop",
+"jit.profile.dumpstack",
+"ffi.meta.__index",
+"ffi.meta.__newindex",
+"ffi.meta.__eq",
+"ffi.meta.__len",
+"ffi.meta.__lt",
+"ffi.meta.__le",
+"ffi.meta.__concat",
+"ffi.meta.__call",
+"ffi.meta.__add",
+"ffi.meta.__sub",
+"ffi.meta.__mul",
+"ffi.meta.__div",
+"ffi.meta.__mod",
+"ffi.meta.__pow",
+"ffi.meta.__unm",
+"ffi.meta.__tostring",
+"ffi.meta.__pairs",
+"ffi.meta.__ipairs",
+"ffi.clib.__index",
+"ffi.clib.__newindex",
+"ffi.clib.__gc",
+"ffi.callback.free",
+"ffi.callback.set",
+"ffi.cdef",
+"ffi.new",
+"ffi.cast",
+"ffi.typeof",
+"ffi.typeinfo",
+"ffi.istype",
+"ffi.sizeof",
+"ffi.alignof",
+"ffi.offsetof",
+"ffi.errno",
+"ffi.string",
+"ffi.copy",
+"ffi.fill",
+"ffi.abi",
+"ffi.metatype",
+"ffi.gc",
+"ffi.load",
+"buffer.method.free",
+"buffer.method.reset",
+"buffer.method.skip",
+"buffer.method.set",
+"buffer.method.put",
+"buffer.method.putf",
+"buffer.method.get",
+"buffer.method.putcdata",
+"buffer.method.reserve",
+"buffer.method.commit",
+"buffer.method.ref",
+"buffer.method.encode",
+"buffer.method.decode",
+"buffer.method.__gc",
+"buffer.method.__tostring",
+"buffer.method.__len",
+"buffer.new",
+"buffer.encode",
+"buffer.decode",
+},
+
+}
+

+ 45 - 0
love/src/jni/LuaJIT-2.1/android/x86_64/jit/zone.lua

@@ -0,0 +1,45 @@
+----------------------------------------------------------------------------
+-- LuaJIT profiler zones.
+--
+-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
+-- Released under the MIT license. See Copyright Notice in luajit.h
+----------------------------------------------------------------------------
+--
+-- This module implements a simple hierarchical zone model.
+--
+-- Example usage:
+--
+--   local zone = require("jit.zone")
+--   zone("AI")
+--   ...
+--     zone("A*")
+--     ...
+--     print(zone:get()) --> "A*"
+--     ...
+--     zone()
+--   ...
+--   print(zone:get()) --> "AI"
+--   ...
+--   zone()
+--
+----------------------------------------------------------------------------
+
+local remove = table.remove
+
+return setmetatable({
+  flush = function(t)
+    for i=#t,1,-1 do t[i] = nil end
+  end,
+  get = function(t)
+    return t[#t]
+  end
+}, {
+  __call = function(t, zone)
+    if zone then
+      t[#t+1] = zone
+    else
+      return (assert(remove(t), "empty zone stack"))
+    end
+  end
+})
+

BIN
love/src/jni/LuaJIT-2.1/android/x86_64/libluajit.a


+ 4 - 0
love/src/jni/LuaJIT-2.1/build_instructions.bat

@@ -28,6 +28,8 @@ wsl make HOST_LUA=luajit.exe "HOST_CC=clang.exe -m32" HOST_CFLAGS=-D_CRT_SECURE_
 if not "%ERRORLEVEL%" == "0" goto :error
 copy src\libluajit.a android\armeabi-v7a\libluajit.a
 if not "%ERRORLEVEL%" == "0" goto :error
+xcopy src\jit android\armeabi-v7a\jit /I
+del android\armeabi-v7a\jit\.gitignore
 
 :x86
 rem x86
@@ -48,6 +50,8 @@ wsl make HOST_LUA=luajit.exe "HOST_CC=clang.exe %4" HOST_CFLAGS=-D_CRT_SECURE_NO
 if not "%ERRORLEVEL%" == "0" goto :error
 copy src\libluajit.a android\%1\libluajit.a
 if not "%ERRORLEVEL%" == "0" goto :error
+xcopy src\jit android\%1\jit /I
+del android\%1\jit\.gitignore
 goto :done
 
 :error

+ 4 - 2
love/src/jni/LuaJIT-2.1/doc/contact.html

@@ -1,8 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!DOCTYPE html>
 <html>
 <head>
 <title>Contact</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta charset="utf-8">
 <meta name="Copyright" content="Copyright (C) 2005-2021">
 <meta name="Language" content="en">
 <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
@@ -37,6 +37,8 @@
 <a href="ext_ffi_semantics.html">FFI Semantics</a>
 </li></ul>
 </li><li>
+<a href="ext_buffer.html">String Buffers</a>
+</li><li>
 <a href="ext_jit.html">jit.* Library</a>
 </li><li>
 <a href="ext_c_api.html">Lua/C API</a>

+ 693 - 0
love/src/jni/LuaJIT-2.1/doc/ext_buffer.html

@@ -0,0 +1,693 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>String Buffer Library</title>
+<meta charset="utf-8">
+<meta name="Copyright" content="Copyright (C) 2005-2021">
+<meta name="Language" content="en">
+<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
+<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
+<style type="text/css">
+.lib {
+  vertical-align: middle;
+  margin-left: 5px;
+  padding: 0 5px;
+  font-size: 60%;
+  border-radius: 5px;
+  background: #c5d5ff;
+  color: #000;
+}
+</style>
+</head>
+<body>
+<div id="site">
+<a href="https://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
+</div>
+<div id="head">
+<h1>String Buffer Library</h1>
+</div>
+<div id="nav">
+<ul><li>
+<a href="luajit.html">LuaJIT</a>
+<ul><li>
+<a href="https://luajit.org/download.html">Download <span class="ext">&raquo;</span></a>
+</li><li>
+<a href="install.html">Installation</a>
+</li><li>
+<a href="running.html">Running</a>
+</li></ul>
+</li><li>
+<a href="extensions.html">Extensions</a>
+<ul><li>
+<a href="ext_ffi.html">FFI Library</a>
+<ul><li>
+<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
+</li><li>
+<a href="ext_ffi_api.html">ffi.* API</a>
+</li><li>
+<a href="ext_ffi_semantics.html">FFI Semantics</a>
+</li></ul>
+</li><li>
+<a class="current" href="ext_buffer.html">String Buffers</a>
+</li><li>
+<a href="ext_jit.html">jit.* Library</a>
+</li><li>
+<a href="ext_c_api.html">Lua/C API</a>
+</li><li>
+<a href="ext_profiler.html">Profiler</a>
+</li></ul>
+</li><li>
+<a href="status.html">Status</a>
+</li><li>
+<a href="faq.html">FAQ</a>
+</li><li>
+<a href="http://wiki.luajit.org/">Wiki <span class="ext">&raquo;</span></a>
+</li><li>
+<a href="https://luajit.org/list.html">Mailing List <span class="ext">&raquo;</span></a>
+</li></ul>
+</div>
+<div id="main">
+<p>
+The string buffer library allows <b>high-performance manipulation of
+string-like data</b>.
+</p>
+<p>
+Unlike Lua strings, which are constants, string buffers are
+<b>mutable</b> sequences of 8-bit (binary-transparent) characters. Data
+can be stored, formatted and encoded into a string buffer and later
+converted, extracted or decoded.
+</p>
+<p>
+The convenient string buffer API simplifies common string manipulation
+tasks, that would otherwise require creating many intermediate strings.
+String buffers improve performance by eliminating redundant memory
+copies, object creation, string interning and garbage collection
+overhead. In conjunction with the FFI library, they allow zero-copy
+operations.
+</p>
+<p>
+The string buffer libary also includes a high-performance
+<a href="serialize">serializer</a> for Lua objects.
+</p>
+
+<h2 id="wip" style="color:#ff0000">Work in Progress</h2>
+<p>
+<b style="color:#ff0000">This library is a work in progress. More
+functionality will be added soon.</b>
+</p>
+
+<h2 id="use">Using the String Buffer Library</h2>
+<p>
+The string buffer library is built into LuaJIT by default, but it's not
+loaded by default. Add this to the start of every Lua file that needs
+one of its functions:
+</p>
+<pre class="code">
+local buffer = require("string.buffer")
+</pre>
+<p>
+The convention for the syntax shown on this page is that <tt>buffer</tt>
+refers to the buffer library and <tt>buf</tt> refers to an individual
+buffer object.
+</p>
+<p>
+Please note the difference between a Lua function call, e.g.
+<tt>buffer.new()</tt> (with a dot) and a Lua method call, e.g.
+<tt>buf:reset()</tt> (with a colon).
+</p>
+
+<h3 id="buffer_object">Buffer Objects</h3>
+<p>
+A buffer object is a garbage-collected Lua object. After creation with
+<tt>buffer.new()</tt>, it can (and should) be reused for many operations.
+When the last reference to a buffer object is gone, it will eventually
+be freed by the garbage collector, along with the allocated buffer
+space.
+</p>
+<p>
+Buffers operate like a FIFO (first-in first-out) data structure. Data
+can be appended (written) to the end of the buffer and consumed (read)
+from the front of the buffer. These operations may be freely mixed.
+</p>
+<p>
+The buffer space that holds the characters is managed automatically
+&mdash; it grows as needed and already consumed space is recycled. Use
+<tt>buffer.new(size)</tt> and <tt>buf:free()</tt>, if you need more
+control.
+</p>
+<p>
+The maximum size of a single buffer is the same as the maximum size of a
+Lua string, which is slightly below two gigabytes. For huge data sizes,
+neither strings nor buffers are the right data structure &mdash; use the
+FFI library to directly map memory or files up to the virtual memory
+limit of your OS.
+</p>
+
+<h3 id="buffer_overview">Buffer Method Overview</h3>
+<ul>
+<li>
+The <tt>buf:put*()</tt>-like methods append (write) characters to the
+end of the buffer.
+</li>
+<li>
+The <tt>buf:get*()</tt>-like methods consume (read) characters from the
+front of the buffer.
+</li>
+<li>
+Other methods, like <tt>buf:tostring()</tt> only read the buffer
+contents, but don't change the buffer.
+</li>
+<li>
+The <tt>buf:set()</tt> method allows zero-copy consumption of a string
+or an FFI cdata object as a buffer.
+</li>
+<li>
+The FFI-specific methods allow zero-copy read/write-style operations or
+modifying the buffer contents in-place. Please check the
+<a href="#ffi_caveats">FFI caveats</a> below, too.
+</li>
+<li>
+Methods that don't need to return anything specific, return the buffer
+object itself as a convenience. This allows method chaining, e.g.:
+<tt>buf:reset():encode(obj)</tt> or <tt>buf:skip(len):get()</tt>
+</li>
+</ul>
+
+<h2 id="create">Buffer Creation and Management</h2>
+
+<h3 id="buffer_new"><tt>local buf = buffer.new([size [,options]])<br>
+local buf = buffer.new([options])</tt></h3>
+<p>
+Creates a new buffer object.
+</p>
+<p>
+The optional <tt>size</tt> argument ensures a minimum initial buffer
+size. This is strictly an optimization when the required buffer size is
+known beforehand. The buffer space will grow as needed, in any case.
+</p>
+<p>
+The optional table <tt>options</tt> sets various
+<a href="#serialize_options">serialization options</a>.
+</p>
+
+<h3 id="buffer_reset"><tt>buf = buf:reset()</tt></h3>
+<p>
+Reset (empty) the buffer. The allocated buffer space is not freed and
+may be reused.
+</p>
+
+<h3 id="buffer_free"><tt>buf = buf:free()</tt></h3>
+<p>
+The buffer space of the buffer object is freed. The object itself
+remains intact, empty and may be reused.
+</p>
+<p>
+Note: you normally don't need to use this method. The garbage collector
+automatically frees the buffer space, when the buffer object is
+collected. Use this method, if you need to free the associated memory
+immediately.
+</p>
+
+<h2 id="write">Buffer Writers</h2>
+
+<h3 id="buffer_put"><tt>buf = buf:put([str|num|obj] [,…])</tt></h3>
+<p>
+Appends a string <tt>str</tt>, a number <tt>num</tt> or any object
+<tt>obj</tt> with a <tt>__tostring</tt> metamethod to the buffer.
+Multiple arguments are appended in the given order.
+</p>
+<p>
+Appending a buffer to a buffer is possible and short-circuited
+internally. But it still involves a copy. Better combine the buffer
+writes to use a single buffer.
+</p>
+
+<h3 id="buffer_putf"><tt>buf = buf:putf(format, …)</tt></h3>
+<p>
+Appends the formatted arguments to the buffer. The <tt>format</tt>
+string supports the same options as <tt>string.format()</tt>.
+</p>
+
+<h3 id="buffer_putcdata"><tt>buf = buf:putcdata(cdata, len)</tt><span class="lib">FFI</span></h3>
+<p>
+Appends the given <tt>len</tt> number of bytes from the memory pointed
+to by the FFI <tt>cdata</tt> object to the buffer. The object needs to
+be convertible to a (constant) pointer.
+</p>
+
+<h3 id="buffer_set"><tt>buf = buf:set(str)<br>
+buf = buf:set(cdata, len)</tt><span class="lib">FFI</span></h3>
+<p>
+This method allows zero-copy consumption of a string or an FFI cdata
+object as a buffer. It stores a reference to the passed string
+<tt>str</tt> or the FFI <tt>cdata</tt> object in the buffer. Any buffer
+space originally allocated is freed. This is <i>not</i> an append
+operation, unlike the <tt>buf:put*()</tt> methods.
+</p>
+<p>
+After calling this method, the buffer behaves as if
+<tt>buf:free():put(str)</tt> or <tt>buf:free():put(cdata,&nbsp;len)</tt>
+had been called. However, the data is only referenced and not copied, as
+long as the buffer is only consumed.
+</p>
+<p>
+In case the buffer is written to later on, the referenced data is copied
+and the object reference is removed (copy-on-write semantics).
+</p>
+<p>
+The stored reference is an anchor for the garbage collector and keeps the
+originally passed string or FFI cdata object alive.
+</p>
+
+<h3 id="buffer_reserve"><tt>ptr, len = buf:reserve(size)</tt><span class="lib">FFI</span><br>
+<tt>buf = buf:commit(used)</tt><span class="lib">FFI</span></h3>
+<p>
+The <tt>reserve</tt> method reserves at least <tt>size</tt> bytes of
+write space in the buffer. It returns an <tt>uint8_t&nbsp;*</tt> FFI
+cdata pointer <tt>ptr</tt> that points to this space.
+</p>
+<p>
+The available length in bytes is returned in <tt>len</tt>. This is at
+least <tt>size</tt> bytes, but may be more to facilitate efficient
+buffer growth. You can either make use of the additional space or ignore
+<tt>len</tt> and only use <tt>size</tt> bytes.
+</p>
+<p>
+The <tt>commit</tt> method appends the <tt>used</tt> bytes of the
+previously returned write space to the buffer data.
+</p>
+<p>
+This pair of methods allows zero-copy use of C read-style APIs:
+</p>
+<pre class="code">
+local MIN_SIZE = 65536
+repeat
+  local ptr, len = buf:reserve(MIN_SIZE)
+  local n = C.read(fd, ptr, len)
+  if n == 0 then break end -- EOF.
+  if n &lt; 0 then error("read error") end
+  buf:commit(n)
+until false
+</pre>
+<p>
+The reserved write space is <i>not</i> initialized. At least the
+<tt>used</tt> bytes <b>must</b> be written to before calling the
+<tt>commit</tt> method. There's no need to call the <tt>commit</tt>
+method, if nothing is added to the buffer (e.g. on error).
+</p>
+
+<h2 id="read">Buffer Readers</h2>
+
+<h3 id="buffer_length"><tt>len = #buf</tt></h3>
+<p>
+Returns the current length of the buffer data in bytes.
+</p>
+
+<h3 id="buffer_concat"><tt>res = str|num|buf .. str|num|buf […]</tt></h3>
+<p>
+The Lua concatenation operator <tt>..</tt> also accepts buffers, just
+like strings or numbers. It always returns a string and not a buffer.
+</p>
+<p>
+Note that although this is supported for convenience, this thwarts one
+of the main reasons to use buffers, which is to avoid string
+allocations. Rewrite it with <tt>buf:put()</tt> and <tt>buf:get()</tt>.
+</p>
+<p>
+Mixing this with unrelated objects that have a <tt>__concat</tt>
+metamethod may not work, since these probably only expect strings.
+</p>
+
+<h3 id="buffer_skip"><tt>buf = buf:skip(len)</tt></h3>
+<p>
+Skips (consumes) <tt>len</tt> bytes from the buffer up to the current
+length of the buffer data.
+</p>
+
+<h3 id="buffer_get"><tt>str, … = buf:get([len|nil] [,…])</tt></h3>
+<p>
+Consumes the buffer data and returns one or more strings. If called
+without arguments, the whole buffer data is consumed. If called with a
+number, up to <tt>len</tt> bytes are consumed. A <tt>nil</tt> argument
+consumes the remaining buffer space (this only makes sense as the last
+argument). Multiple arguments consume the buffer data in the given
+order.
+</p>
+<p>
+Note: a zero length or no remaining buffer data returns an empty string
+and not <tt>nil</tt>.
+</p>
+
+<h3 id="buffer_tostring"><tt>str = buf:tostring()<br>
+str = tostring(buf)</tt></h3>
+<p>
+Creates a string from the buffer data, but doesn't consume it. The
+buffer remains unchanged.
+</p>
+<p>
+Buffer objects also define a <tt>__tostring</tt> metamethod. This means
+buffers can be passed to the global <tt>tostring()</tt> function and
+many other functions that accept this in place of strings. The important
+internal uses in functions like <tt>io.write()</tt> are short-circuited
+to avoid the creation of an intermediate string object.
+</p>
+
+<h3 id="buffer_ref"><tt>ptr, len = buf:ref()</tt><span class="lib">FFI</span></h3>
+<p>
+Returns an <tt>uint8_t&nbsp;*</tt> FFI cdata pointer <tt>ptr</tt> that
+points to the buffer data. The length of the buffer data in bytes is
+returned in <tt>len</tt>.
+</p>
+<p>
+The returned pointer can be directly passed to C functions that expect a
+buffer and a length. You can also do bytewise reads
+(<tt>local&nbsp;x&nbsp;=&nbsp;ptr[i]</tt>) or writes
+(<tt>ptr[i]&nbsp;=&nbsp;0x40</tt>) of the buffer data.
+</p>
+<p>
+In conjunction with the <tt>skip</tt> method, this allows zero-copy use
+of C write-style APIs:
+</p>
+<pre class="code">
+repeat
+  local ptr, len = buf:ref()
+  if len == 0 then break end
+  local n = C.write(fd, ptr, len)
+  if n &lt; 0 then error("write error") end
+  buf:skip(n)
+until n >= len
+</pre>
+<p>
+Unlike Lua strings, buffer data is <i>not</i> implicitly
+zero-terminated. It's not safe to pass <tt>ptr</tt> to C functions that
+expect zero-terminated strings. If you're not using <tt>len</tt>, then
+you're doing something wrong.
+</p>
+
+<h2 id="serialize">Serialization of Lua Objects</h2>
+<p>
+The following functions and methods allow <b>high-speed serialization</b>
+(encoding) of a Lua object into a string and decoding it back to a Lua
+object. This allows convenient storage and transport of <b>structured
+data</b>.
+</p>
+<p>
+The encoded data is in an <a href="#serialize_format">internal binary
+format</a>. The data can be stored in files, binary-transparent
+databases or transmitted to other LuaJIT instances across threads,
+processes or networks.
+</p>
+<p>
+Encoding speed can reach up to 1 Gigabyte/second on a modern desktop- or
+server-class system, even when serializing many small objects. Decoding
+speed is mostly constrained by object creation cost.
+</p>
+<p>
+The serializer handles most Lua types, common FFI number types and
+nested structures. Functions, thread objects, other FFI cdata and full
+userdata cannot be serialized (yet).
+</p>
+<p>
+The encoder serializes nested structures as trees. Multiple references
+to a single object will be stored separately and create distinct objects
+after decoding. Circular references cause an error.
+</p>
+
+<h3 id="serialize_methods">Serialization Functions and Methods</h3>
+
+<h3 id="buffer_encode"><tt>str = buffer.encode(obj)<br>
+buf = buf:encode(obj)</tt></h3>
+<p>
+Serializes (encodes) the Lua object <tt>obj</tt>. The stand-alone
+function returns a string <tt>str</tt>. The buffer method appends the
+encoding to the buffer.
+</p>
+<p>
+<tt>obj</tt> can be any of the supported Lua types &mdash; it doesn't
+need to be a Lua table.
+</p>
+<p>
+This function may throw an error when attempting to serialize
+unsupported object types, circular references or deeply nested tables.
+</p>
+
+<h3 id="buffer_decode"><tt>obj = buffer.decode(str)<br>
+obj = buf:decode()</tt></h3>
+<p>
+The stand-alone function de-serializes (decodes) the string
+<tt>str</tt>, the buffer method de-serializes one object from the
+buffer. Both return a Lua object <tt>obj</tt>.
+</p>
+<p>
+The returned object may be any of the supported Lua types &mdash;
+even <tt>nil</tt>.
+</p>
+<p>
+This function may throw an error when fed with malformed or incomplete
+encoded data. The stand-alone function throws when there's left-over
+data after decoding a single top-level object. The buffer method leaves
+any left-over data in the buffer.
+</p>
+
+<h3 id="serialize_options">Serialization Options</h3>
+<p>
+The <tt>options</tt> table passed to <tt>buffer.new()</tt> may contain
+the following members (all optional):
+</p>
+<ul>
+<li>
+<tt>dict</tt> is a Lua table holding a <b>dictionary of strings</b> that
+commonly occur as table keys of objects you are serializing. These keys
+are compactly encoded as indexes during serialization. A well chosen
+dictionary saves space and improves serialization performance.
+</li>
+<li>
+<tt>metatable</tt> is a Lua table holding a <b>dictionary of metatables</b>
+for the table objects you are serializing.
+</li>
+</ul>
+<p>
+<tt>dict</tt> needs to be an array of strings and <tt>metatable</tt> needs
+to be an array of tables. Both starting at index 1 and without holes (no
+<tt>nil</tt> inbetween). The tables are anchored in the buffer object and
+internally modified into a two-way index (don't do this yourself, just pass
+a plain array). The tables must not be modified after they have been passed
+to <tt>buffer.new()</tt>.
+</p>
+<p>
+The <tt>dict</tt> and <tt>metatable</tt> tables used by the encoder and
+decoder must be the same. Put the most common entries at the front. Extend
+at the end to ensure backwards-compatibility &mdash; older encodings can
+then still be read. You may also set some indexes to <tt>false</tt> to
+explicitly drop backwards-compatibility. Old encodings that use these
+indexes will throw an error when decoded.
+</p>
+<p>
+Metatables that are not found in the <tt>metatable</tt> dictionary are
+ignored when encoding. Decoding returns a table with a <tt>nil</tt>
+metatable.
+</p>
+<p>
+Note: parsing and preparation of the options table is somewhat
+expensive. Create a buffer object only once and recycle it for multiple
+uses. Avoid mixing encoder and decoder buffers, since the
+<tt>buf:set()</tt> method frees the already allocated buffer space:
+</p>
+<pre class="code">
+local options = {
+  dict = { "commonly", "used", "string", "keys" },
+}
+local buf_enc = buffer.new(options)
+local buf_dec = buffer.new(options)
+
+local function encode(obj)
+  return buf_enc:reset():encode(obj):get()
+end
+
+local function decode(str)
+  return buf_dec:set(str):decode()
+end
+</pre>
+
+<h3 id="serialize_stream">Streaming Serialization</h3>
+<p>
+In some contexts, it's desirable to do piecewise serialization of large
+datasets, also known as <i>streaming</i>.
+</p>
+<p>
+This serialization format can be safely concatenated and supports streaming.
+Multiple encodings can simply be appended to a buffer and later decoded
+individually:
+</p>
+<pre class="code">
+local buf = buffer.new()
+buf:encode(obj1)
+buf:encode(obj2)
+local copy1 = buf:decode()
+local copy2 = buf:decode()
+</pre>
+<p>
+Here's how to iterate over a stream:
+</p>
+<pre class="code">
+while #buf ~= 0 do
+  local obj = buf:decode()
+  -- Do something with obj.
+end
+</pre>
+<p>
+Since the serialization format doesn't prepend a length to its encoding,
+network applications may need to transmit the length, too.
+</p>
+
+<h3 id="serialize_format">Serialization Format Specification</h3>
+<p>
+This serialization format is designed for <b>internal use</b> by LuaJIT
+applications. Serialized data is upwards-compatible and portable across
+all supported LuaJIT platforms.
+</p>
+<p>
+It's an <b>8-bit binary format</b> and not human-readable. It uses e.g.
+embedded zeroes and stores embedded Lua string objects unmodified, which
+are 8-bit-clean, too. Encoded data can be safely concatenated for
+streaming and later decoded one top-level object at a time.
+</p>
+<p>
+The encoding is reasonably compact, but tuned for maximum performance,
+not for minimum space usage. It compresses well with any of the common
+byte-oriented data compression algorithms.
+</p>
+<p>
+Although documented here for reference, this format is explicitly
+<b>not</b> intended to be a 'public standard' for structured data
+interchange across computer languages (like JSON or MessagePack). Please
+do not use it as such.
+</p>
+<p>
+The specification is given below as a context-free grammar with a
+top-level <tt>object</tt> as the starting point. Alternatives are
+separated by the <tt>|</tt> symbol and <tt>*</tt> indicates repeats.
+Grouping is implicit or indicated by <tt>{…}</tt>. Terminals are
+either plain hex numbers, encoded as bytes, or have a <tt>.format</tt>
+suffix.
+</p>
+<pre>
+object    → nil | false | true
+          | null | lightud32 | lightud64
+          | int | num | tab | tab_mt
+          | int64 | uint64 | complex
+          | string
+
+nil       → 0x00
+false     → 0x01
+true      → 0x02
+
+null      → 0x03                            // NULL lightuserdata
+lightud32 → 0x04 data.I                   // 32 bit lightuserdata
+lightud64 → 0x05 data.L                   // 64 bit lightuserdata
+
+int       → 0x06 int.I                                 // int32_t
+num       → 0x07 double.L
+
+tab       → 0x08                                   // Empty table
+          | 0x09 h.U h*{object object}          // Key/value hash
+          | 0x0a a.U a*object                    // 0-based array
+          | 0x0b a.U a*object h.U h*{object object}      // Mixed
+          | 0x0c a.U (a-1)*object                // 1-based array
+          | 0x0d a.U (a-1)*object h.U h*{object object}  // Mixed
+tab_mt    → 0x0e (index-1).U tab          // Metatable dict entry
+
+int64     → 0x10 int.L                             // FFI int64_t
+uint64    → 0x11 uint.L                           // FFI uint64_t
+complex   → 0x12 re.L im.L                         // FFI complex
+
+string    → (0x20+len).U len*char.B
+          | 0x0f (index-1).U                 // String dict entry
+
+.B = 8 bit
+.I = 32 bit little-endian
+.L = 64 bit little-endian
+.U = prefix-encoded 32 bit unsigned number n:
+     0x00..0xdf   → n.B
+     0xe0..0x1fdf → (0xe0|(((n-0xe0)>>8)&0x1f)).B ((n-0xe0)&0xff).B
+   0x1fe0..       → 0xff n.I
+</pre>
+
+<h2 id="error">Error handling</h2>
+<p>
+Many of the buffer methods can throw an error. Out-of-memory or usage
+errors are best caught with an outer wrapper for larger parts of code.
+There's not much one can do after that, anyway.
+</p>
+<p>
+OTOH you may want to catch some errors individually. Buffer methods need
+to receive the buffer object as the first argument. The Lua colon-syntax
+<tt>obj:method()</tt> does that implicitly. But to wrap a method with
+<tt>pcall()</tt>, the arguments need to be passed like this:
+</p>
+<pre class="code">
+local ok, err = pcall(buf.encode, buf, obj)
+if not ok then
+  -- Handle error in err.
+end
+</pre>
+
+<h2 id="ffi_caveats">FFI caveats</h2>
+<p>
+The string buffer library has been designed to work well together with
+the FFI library. But due to the low-level nature of the FFI library,
+some care needs to be taken:
+</p>
+<p>
+First, please remember that FFI pointers are zero-indexed. The space
+returned by <tt>buf:reserve()</tt> and <tt>buf:ref()</tt> starts at the
+returned pointer and ends before <tt>len</tt> bytes after that.
+</p>
+<p>
+I.e. the first valid index is <tt>ptr[0]</tt> and the last valid index
+is <tt>ptr[len-1]</tt>. If the returned length is zero, there's no valid
+index at all. The returned pointer may even be <tt>NULL</tt>.
+</p>
+<p>
+The space pointed to by the returned pointer is only valid as long as
+the buffer is not modified in any way (neither append, nor consume, nor
+reset, etc.). The pointer is also not a GC anchor for the buffer object
+itself.
+</p>
+<p>
+Buffer data is only guaranteed to be byte-aligned. Casting the returned
+pointer to a data type with higher alignment may cause unaligned
+accesses. It depends on the CPU architecture whether this is allowed or
+not (it's always OK on x86/x64 and mostly OK on other modern
+architectures).
+</p>
+<p>
+FFI pointers or references do not count as GC anchors for an underlying
+object. E.g. an <tt>array</tt> allocated with <tt>ffi.new()</tt> is
+anchored by <tt>buf:set(array,&nbsp;len)</tt>, but not by
+<tt>buf:set(array+offset,&nbsp;len)</tt>. The addition of the offset
+creates a new pointer, even when the offset is zero. In this case, you
+need to make sure there's still a reference to the original array as
+long as its contents are in use by the buffer.
+</p>
+<p>
+Even though each LuaJIT VM instance is single-threaded (but you can
+create multiple VMs), FFI data structures can be accessed concurrently.
+Be careful when reading/writing FFI cdata from/to buffers to avoid
+concurrent accesses or modifications. In particular, the memory
+referenced by <tt>buf:set(cdata,&nbsp;len)</tt> must not be modified
+while buffer readers are working on it. Shared, but read-only memory
+mappings of files are OK, but only if the file does not change.
+</p>
+<br class="flush">
+</div>
+<div id="foot">
+<hr class="hide">
+Copyright &copy; 2005-2021
+<span class="noprint">
+&middot;
+<a href="contact.html">Contact</a>
+</span>
+</div>
+</body>
+</html>

+ 4 - 2
love/src/jni/LuaJIT-2.1/doc/ext_c_api.html

@@ -1,8 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!DOCTYPE html>
 <html>
 <head>
 <title>Lua/C API Extensions</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta charset="utf-8">
 <meta name="Copyright" content="Copyright (C) 2005-2021">
 <meta name="Language" content="en">
 <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
@@ -37,6 +37,8 @@
 <a href="ext_ffi_semantics.html">FFI Semantics</a>
 </li></ul>
 </li><li>
+<a href="ext_buffer.html">String Buffers</a>
+</li><li>
 <a href="ext_jit.html">jit.* Library</a>
 </li><li>
 <a class="current" href="ext_c_api.html">Lua/C API</a>

+ 4 - 2
love/src/jni/LuaJIT-2.1/doc/ext_ffi.html

@@ -1,8 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!DOCTYPE html>
 <html>
 <head>
 <title>FFI Library</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta charset="utf-8">
 <meta name="Copyright" content="Copyright (C) 2005-2021">
 <meta name="Language" content="en">
 <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
@@ -37,6 +37,8 @@
 <a href="ext_ffi_semantics.html">FFI Semantics</a>
 </li></ul>
 </li><li>
+<a href="ext_buffer.html">String Buffers</a>
+</li><li>
 <a href="ext_jit.html">jit.* Library</a>
 </li><li>
 <a href="ext_c_api.html">Lua/C API</a>

+ 4 - 2
love/src/jni/LuaJIT-2.1/doc/ext_ffi_api.html

@@ -1,8 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!DOCTYPE html>
 <html>
 <head>
 <title>ffi.* API Functions</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta charset="utf-8">
 <meta name="Copyright" content="Copyright (C) 2005-2021">
 <meta name="Language" content="en">
 <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
@@ -42,6 +42,8 @@ td.abiparam { font-weight: bold; width: 6em; }
 <a href="ext_ffi_semantics.html">FFI Semantics</a>
 </li></ul>
 </li><li>
+<a href="ext_buffer.html">String Buffers</a>
+</li><li>
 <a href="ext_jit.html">jit.* Library</a>
 </li><li>
 <a href="ext_c_api.html">Lua/C API</a>

+ 4 - 2
love/src/jni/LuaJIT-2.1/doc/ext_ffi_semantics.html

@@ -1,8 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!DOCTYPE html>
 <html>
 <head>
 <title>FFI Semantics</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta charset="utf-8">
 <meta name="Copyright" content="Copyright (C) 2005-2021">
 <meta name="Language" content="en">
 <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
@@ -42,6 +42,8 @@ td.convop { font-style: italic; width: 40%; }
 <a class="current" href="ext_ffi_semantics.html">FFI Semantics</a>
 </li></ul>
 </li><li>
+<a href="ext_buffer.html">String Buffers</a>
+</li><li>
 <a href="ext_jit.html">jit.* Library</a>
 </li><li>
 <a href="ext_c_api.html">Lua/C API</a>

+ 4 - 2
love/src/jni/LuaJIT-2.1/doc/ext_ffi_tutorial.html

@@ -1,8 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!DOCTYPE html>
 <html>
 <head>
 <title>FFI Tutorial</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta charset="utf-8">
 <meta name="Copyright" content="Copyright (C) 2005-2021">
 <meta name="Language" content="en">
 <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
@@ -44,6 +44,8 @@ td.idiomlua b { font-weight: normal; color: #2142bf; }
 <a href="ext_ffi_semantics.html">FFI Semantics</a>
 </li></ul>
 </li><li>
+<a href="ext_buffer.html">String Buffers</a>
+</li><li>
 <a href="ext_jit.html">jit.* Library</a>
 </li><li>
 <a href="ext_c_api.html">Lua/C API</a>

+ 4 - 2
love/src/jni/LuaJIT-2.1/doc/ext_jit.html

@@ -1,8 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!DOCTYPE html>
 <html>
 <head>
 <title>jit.* Library</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta charset="utf-8">
 <meta name="Copyright" content="Copyright (C) 2005-2021">
 <meta name="Language" content="en">
 <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
@@ -37,6 +37,8 @@
 <a href="ext_ffi_semantics.html">FFI Semantics</a>
 </li></ul>
 </li><li>
+<a href="ext_buffer.html">String Buffers</a>
+</li><li>
 <a class="current" href="ext_jit.html">jit.* Library</a>
 </li><li>
 <a href="ext_c_api.html">Lua/C API</a>

+ 4 - 2
love/src/jni/LuaJIT-2.1/doc/ext_profiler.html

@@ -1,8 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!DOCTYPE html>
 <html>
 <head>
 <title>Profiler</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta charset="utf-8">
 <meta name="Copyright" content="Copyright (C) 2005-2021">
 <meta name="Language" content="en">
 <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
@@ -37,6 +37,8 @@
 <a href="ext_ffi_semantics.html">FFI Semantics</a>
 </li></ul>
 </li><li>
+<a href="ext_buffer.html">String Buffers</a>
+</li><li>
 <a href="ext_jit.html">jit.* Library</a>
 </li><li>
 <a href="ext_c_api.html">Lua/C API</a>

+ 13 - 19
love/src/jni/LuaJIT-2.1/doc/extensions.html

@@ -1,8 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!DOCTYPE html>
 <html>
 <head>
 <title>Extensions</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta charset="utf-8">
 <meta name="Copyright" content="Copyright (C) 2005-2021">
 <meta name="Language" content="en">
 <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
@@ -54,6 +54,8 @@ td.excinterop {
 <a href="ext_ffi_semantics.html">FFI Semantics</a>
 </li></ul>
 </li><li>
+<a href="ext_buffer.html">String Buffers</a>
+</li><li>
 <a href="ext_jit.html">jit.* Library</a>
 </li><li>
 <a href="ext_c_api.html">Lua/C API</a>
@@ -392,29 +394,19 @@ the toolchain used to compile LuaJIT:
 <td class="excinterop">Interoperability</td>
 </tr>
 <tr class="odd separate">
-<td class="excplatform">POSIX/x64, DWARF2 unwinding</td>
-<td class="exccompiler">GCC 4.3+, Clang</td>
+<td class="excplatform">External frame unwinding</td>
+<td class="exccompiler">GCC, Clang, MSVC</td>
 <td class="excinterop"><b style="color: #00a000;">Full</b></td>
 </tr>
 <tr class="even">
-<td class="excplatform">ARM <tt>-DLUAJIT_UNWIND_EXTERNAL</tt></td>
-<td class="exccompiler">GCC, Clang</td>
-<td class="excinterop"><b style="color: #00a000;">Full</b></td>
-</tr>
-<tr class="odd">
-<td class="excplatform">Other platforms, DWARF2 unwinding</td>
+<td class="excplatform">Internal frame unwinding + DWARF2</td>
 <td class="exccompiler">GCC, Clang</td>
 <td class="excinterop"><b style="color: #c06000;">Limited</b></td>
 </tr>
-<tr class="even">
-<td class="excplatform">Windows/x64</td>
-<td class="exccompiler">MSVC</td>
-<td class="excinterop"><b style="color: #00a000;">Full</b></td>
-</tr>
 <tr class="odd">
-<td class="excplatform">Windows/x86</td>
-<td class="exccompiler">Any</td>
-<td class="excinterop"><b style="color: #00a000;">Full</b></td>
+<td class="excplatform">Windows 64 bit</td>
+<td class="exccompiler">non-MSVC</td>
+<td class="excinterop"><b style="color: #c06000;">Limited</b></td>
 </tr>
 <tr class="even">
 <td class="excplatform">Other platforms</td>
@@ -435,7 +427,9 @@ the toolchain used to compile LuaJIT:
 on the C&nbsp;stack. The contents of the C++&nbsp;exception object
 pass through unmodified.</li>
 <li>Lua errors can be caught on the C++ side with <tt>catch(...)</tt>.
-The corresponding Lua error message can be retrieved from the Lua stack.</li>
+The corresponding Lua error message can be retrieved from the Lua stack.<br>
+For MSVC for Windows 64 bit this requires compilation of your C++ code
+with <tt>/EHa</tt>.</li>
 <li>Throwing Lua errors across C++ frames is safe. C++ destructors
 will be called.</li>
 </ul>

+ 19 - 5
love/src/jni/LuaJIT-2.1/doc/faq.html

@@ -1,8 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!DOCTYPE html>
 <html>
 <head>
 <title>Frequently Asked Questions (FAQ)</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta charset="utf-8">
 <meta name="Copyright" content="Copyright (C) 2005-2021">
 <meta name="Language" content="en">
 <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
@@ -40,6 +40,8 @@ dd { margin-left: 1.5em; }
 <a href="ext_ffi_semantics.html">FFI Semantics</a>
 </li></ul>
 </li><li>
+<a href="ext_buffer.html">String Buffers</a>
+</li><li>
 <a href="ext_jit.html">jit.* Library</a>
 </li><li>
 <a href="ext_c_api.html">Lua/C API</a>
@@ -74,7 +76,7 @@ about LuaJIT.</li>
 and links to books and papers about Lua.</li>
 <li>The community-managed <a href="http://lua-users.org/wiki/"><span class="ext">&raquo;</span>&nbsp;Lua Wiki</a>
 has information about diverse topics.</li>
-</ul>
+</ul></dd>
 </dl>
 
 <dl id="tech">
@@ -119,8 +121,7 @@ Consider testing your application with older versions, too.<br>
 
 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.
-
+Please check the Delphi docs for the Set8087CW method.</dd>
 </dl>
 
 <dl id="ctrlc">
@@ -133,6 +134,19 @@ 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.</dd>
 </dl>
 
+<dl id="order">
+<dt>Q: Table iteration with <tt>pairs()</tt> does not result in the same order?</dt>
+<dd>The order of table iteration is explicitly <b>undefined</b> by
+the Lua language standard.<br>
+Different Lua implementations or versions may use different orders for
+otherwise identical tables. Different ways of constructing a table may
+result in different orders, too.<br>
+Due to improved VM security, LuaJIT 2.1 may even use a different order
+on separate VM invocations or when string keys are newly interned.<br><br>
+If your program relies on a deterministic order, it has a bug. Rewrite it,
+so it doesn't rely on the key order. Or sort the table keys, if you must.</dd>
+</dl>
+
 <dl id="sandbox">
 <dt>Q: Can Lua code be safely sandboxed?</dt>
 <dd>

+ 19 - 10
love/src/jni/LuaJIT-2.1/doc/install.html

@@ -1,8 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!DOCTYPE html>
 <html>
 <head>
 <title>Installation</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta charset="utf-8">
 <meta name="Copyright" content="Copyright (C) 2005-2021">
 <meta name="Language" content="en">
 <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
@@ -65,6 +65,8 @@ td.compatno {
 <a href="ext_ffi_semantics.html">FFI Semantics</a>
 </li></ul>
 </li><li>
+<a href="ext_buffer.html">String Buffers</a>
+</li><li>
 <a href="ext_jit.html">jit.* Library</a>
 </li><li>
 <a href="ext_c_api.html">Lua/C API</a>
@@ -186,14 +188,18 @@ Debian/Ubuntu, install <tt>libc6-dev</tt> with the package manager.
 </p>
 <p>
 The recommended way to fetch the latest version is to do a pull from
-the git repository. Alternatively download the latest source package of
-LuaJIT (pick the .tar.gz). 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:
+the git repository.
+</p>
+<p>
+Alternatively download the latest source package of LuaJIT (pick the .tar.gz).
+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 (replace XX.YY.ZZ with the version you downloaded):
 </p>
 <pre class="code">
-tar zxf LuaJIT-2.1.0-beta3.tar.gz
-cd LuaJIT-2.1.0-beta3</pre>
+tar zxf LuaJIT-XX.YY.ZZ.tar.gz
+cd LuaJIT-XX.YY.ZZ
+</pre>
 <h3>Building LuaJIT</h3>
 <p>
 The supplied Makefiles try to auto-detect the settings needed for your
@@ -217,9 +223,12 @@ You can add an extra prefix to the search paths by appending the
 make PREFIX=/home/myself/lj2
 </pre>
 <p>
-Note for macOS: you must set the <tt>MACOSX_DEPLOYMENT_TARGET</tt>
-environment variable to a value supported by your toolchain.
+Note for macOS: you <b>must</b> set the <tt>MACOSX_DEPLOYMENT_TARGET</tt>
+environment variable to a value supported by your toolchain:
 </p>
+<pre class="code">
+MACOSX_DEPLOYMENT_TARGET=XX.YY make
+</pre>
 <h3>Installing LuaJIT</h3>
 <p>
 The top-level Makefile installs LuaJIT by default under

+ 4 - 2
love/src/jni/LuaJIT-2.1/doc/luajit.html

@@ -1,8 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!DOCTYPE html>
 <html>
 <head>
 <title>LuaJIT</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta charset="utf-8">
 <meta name="Copyright" content="Copyright (C) 2005-2021">
 <meta name="Language" content="en">
 <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
@@ -122,6 +122,8 @@ table.feature small {
 <a href="ext_ffi_semantics.html">FFI Semantics</a>
 </li></ul>
 </li><li>
+<a href="ext_buffer.html">String Buffers</a>
+</li><li>
 <a href="ext_jit.html">jit.* Library</a>
 </li><li>
 <a href="ext_c_api.html">Lua/C API</a>

+ 6 - 4
love/src/jni/LuaJIT-2.1/doc/running.html

@@ -1,8 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!DOCTYPE html>
 <html>
 <head>
 <title>Running LuaJIT</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta charset="utf-8">
 <meta name="Copyright" content="Copyright (C) 2005-2021">
 <meta name="Language" content="en">
 <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
@@ -59,6 +59,8 @@ td.param_default {
 <a href="ext_ffi_semantics.html">FFI Semantics</a>
 </li></ul>
 </li><li>
+<a href="ext_buffer.html">String Buffers</a>
+</li><li>
 <a href="ext_jit.html">jit.* Library</a>
 </li><li>
 <a href="ext_c_api.html">Lua/C API</a>
@@ -183,8 +185,8 @@ 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 <tt>lib</tt> directory of the source
 distribution or installed under the <tt>jit</tt> directory. By default
-this is <tt>/usr/local/share/luajit-2.1.0-beta3/jit</tt> on POSIX
-systems.
+this is <tt>/usr/local/share/luajit-XX.YY.ZZ>/jit</tt> on POSIX
+systems (replace XX.YY.ZZ by the installed version).
 </p>
 
 <h3 id="opt_O"><tt>-O[level]</tt><br>

+ 4 - 8
love/src/jni/LuaJIT-2.1/doc/status.html

@@ -1,8 +1,8 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!DOCTYPE html>
 <html>
 <head>
 <title>Status</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta charset="utf-8">
 <meta name="Copyright" content="Copyright (C) 2005-2021">
 <meta name="Language" content="en">
 <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
@@ -40,6 +40,8 @@ ul li { padding-bottom: 0.3em; }
 <a href="ext_ffi_semantics.html">FFI Semantics</a>
 </li></ul>
 </li><li>
+<a href="ext_buffer.html">String Buffers</a>
+</li><li>
 <a href="ext_jit.html">jit.* Library</a>
 </li><li>
 <a href="ext_c_api.html">Lua/C API</a>
@@ -90,12 +92,6 @@ The Lua <b>debug API</b> 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).
 </li>
-<li>
-Currently some <b>out-of-memory</b> errors from <b>on-trace code</b> are not
-handled correctly. The error may fall through an on-trace
-<tt>pcall</tt> or it may be passed on to the function set with
-<tt>lua_atpanic</tt> on x64.
-</li>
 </ul>
 <br class="flush">
 </div>

+ 5 - 2
love/src/jni/LuaJIT-2.1/dynasm/dasm_arm.h

@@ -294,7 +294,7 @@ int dasm_link(Dst_DECL, size_t *szp)
 
   { /* Handle globals not defined in this translation unit. */
     int idx;
-    for (idx = 20; idx*sizeof(int) < D->lgsize; 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; }
@@ -371,7 +371,10 @@ int dasm_encode(Dst_DECL, void *buffer)
 	  ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000;
 	  break;
 	case DASM_REL_LG:
-	  CK(n >= 0, UNDEF_LG);
+	  if (n < 0) {
+	    n = (int)((ptrdiff_t)D->globals[-n] - (ptrdiff_t)cp - 4);
+	    goto patchrel;
+	  }
 	  /* fallthrough */
 	case DASM_REL_PC:
 	  CK(n >= 0, UNDEF_PC);

+ 3 - 3
love/src/jni/LuaJIT-2.1/dynasm/dasm_arm.lua

@@ -9,9 +9,9 @@
 local _info = {
   arch =	"arm",
   description =	"DynASM ARM module",
-  version =	"1.4.0",
-  vernum =	 10400,
-  release =	"2015-10-18",
+  version =	"1.5.0",
+  vernum =	 10500,
+  release =	"2021-05-02",
   author =	"Mike Pall",
   license =	"MIT",
 }

+ 50 - 8
love/src/jni/LuaJIT-2.1/dynasm/dasm_arm64.h

@@ -21,8 +21,9 @@ enum {
   /* 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_REL_PC, DASM_LABEL_PC, DASM_REL_A,
   DASM_IMM, DASM_IMM6, DASM_IMM12, DASM_IMM13W, DASM_IMM13X, DASM_IMML,
+  DASM_IMMV, DASM_VREG,
   DASM__MAX
 };
 
@@ -39,6 +40,7 @@ enum {
 #define DASM_S_RANGE_LG		0x13000000
 #define DASM_S_RANGE_PC		0x14000000
 #define DASM_S_RANGE_REL	0x15000000
+#define DASM_S_RANGE_VREG	0x16000000
 #define DASM_S_UNDEF_LG		0x21000000
 #define DASM_S_UNDEF_PC		0x22000000
 
@@ -247,7 +249,7 @@ void dasm_put(Dst_DECL, int start, ...)
 	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_REL_EXT: if ((ins & 0x8000)) ofs += 8; break;
       case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
       case DASM_REL_LG:
 	n = (ins & 2047) - 10; pl = D->lglabels + n;
@@ -268,6 +270,11 @@ void dasm_put(Dst_DECL, int start, ...)
 	  *pl = pos;
 	}
 	pos++;
+	if ((ins & 0x8000)) ofs += 8;
+	break;
+      case DASM_REL_A:
+	b[pos++] = n;
+	b[pos++] = va_arg(ap, int);
 	break;
       case DASM_LABEL_LG:
 	pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
@@ -312,13 +319,21 @@ void dasm_put(Dst_DECL, int start, ...)
 	}
       case DASM_IMML: {
 #ifdef DASM_CHECKS
-	int scale = (p[-2] >> 30);
+	int scale = (ins & 3);
 	CK((!(n & ((1<<scale)-1)) && (unsigned int)(n>>scale) < 4096) ||
 	   (unsigned int)(n+256) < 512, RANGE_I);
 #endif
 	b[pos++] = n;
 	break;
 	}
+      case DASM_IMMV:
+	ofs += 4;
+	b[pos++] = n;
+	break;
+      case DASM_VREG:
+	CK(n < 32, RANGE_VREG);
+	b[pos++] = n;
+	break;
       }
     }
   }
@@ -348,7 +363,7 @@ int dasm_link(Dst_DECL, size_t *szp)
 
   { /* Handle globals not defined in this translation unit. */
     int idx;
-    for (idx = 20; idx*sizeof(int) < D->lgsize; 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; }
@@ -375,8 +390,8 @@ int dasm_link(Dst_DECL, size_t *szp)
 	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;
+	case DASM_IMML: case DASM_IMMV: case DASM_VREG: pos++; break;
+	case DASM_IMM13X: case DASM_REL_A: pos += 2; break;
 	}
       }
       stop: (void)0;
@@ -426,7 +441,12 @@ int dasm_encode(Dst_DECL, void *buffer)
 	  ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000;
 	  break;
 	case DASM_REL_LG:
-	  CK(n >= 0, UNDEF_LG);
+	  if (n < 0) {
+	    ptrdiff_t na = (ptrdiff_t)D->globals[-n] - (ptrdiff_t)cp + 4;
+	    n = (int)na;
+	    CK((ptrdiff_t)n == na, RANGE_REL);
+	    goto patchrel;
+	  }
 	  /* fallthrough */
 	case DASM_REL_PC:
 	  CK(n >= 0, UNDEF_PC);
@@ -446,8 +466,24 @@ int dasm_encode(Dst_DECL, void *buffer)
 	  } else if ((ins & 0x1000)) {  /* TBZ, TBNZ */
 	    CK((n & 3) == 0 && ((n+0x00008000) >> 16) == 0, RANGE_REL);
 	    cp[-1] |= ((n << 3) & 0x0007ffe0);
+	  } else if ((ins & 0x8000)) {  /* absolute */
+	    cp[0] = (unsigned int)((ptrdiff_t)cp - 4 + n);
+	    cp[1] = (unsigned int)(((ptrdiff_t)cp - 4 + n) >> 32);
+	    cp += 2;
 	  }
 	  break;
+	case DASM_REL_A: {
+	  ptrdiff_t na = (((ptrdiff_t)(*b++) << 32) | (unsigned int)n);
+	  if ((ins & 0x3000) == 0x3000) {  /* ADRP */
+	    ins &= ~0x1000;
+	    na = (na >> 12) - (((ptrdiff_t)cp - 4) >> 12);
+	  } else {
+	    na = na - (ptrdiff_t)cp + 4;
+	  }
+	  n = (int)na;
+	  CK((ptrdiff_t)n == na, RANGE_REL);
+	  goto patchrel;
+	}
 	case DASM_LABEL_LG:
 	  ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
 	  break;
@@ -468,11 +504,17 @@ int dasm_encode(Dst_DECL, void *buffer)
 	  cp[-1] |= (dasm_imm13(n, *b++) << 10);
 	  break;
 	case DASM_IMML: {
-	  int scale = (p[-2] >> 30);
+	  int scale = (ins & 3);
 	  cp[-1] |= (!(n & ((1<<scale)-1)) && (unsigned int)(n>>scale) < 4096) ?
 	    ((n << (10-scale)) | 0x01000000) : ((n & 511) << 12);
 	  break;
 	  }
+	case DASM_IMMV:
+	  *cp++ = n;
+	  break;
+	case DASM_VREG:
+	  cp[-1] |= (n & 0x1f) << (ins & 0x1f);
+	  break;
 	default: *cp++ = ins; break;
 	}
       }

+ 94 - 41
love/src/jni/LuaJIT-2.1/dynasm/dasm_arm64.lua

@@ -9,9 +9,9 @@
 local _info = {
   arch =	"arm",
   description =	"DynASM ARM64 module",
-  version =	"1.4.0",
-  vernum =	 10400,
-  release =	"2015-10-18",
+  version =	"1.5.0",
+  vernum =	 10500,
+  release =	"2021-05-02",
   author =	"Mike Pall",
   license =	"MIT",
 }
@@ -23,12 +23,12 @@ local _M = { _info = _info }
 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 format, byte, char = _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
+local ror, tohex, tobit = bit.ror, bit.tohex, bit.tobit
 
 -- Inherited tables and callbacks.
 local g_opt, g_arch
@@ -39,7 +39,9 @@ local wline, werror, wfatal, wwarn
 local action_names = {
   "STOP", "SECTION", "ESC", "REL_EXT",
   "ALIGN", "REL_LG", "LABEL_LG",
-  "REL_PC", "LABEL_PC", "IMM", "IMM6", "IMM12", "IMM13W", "IMM13X", "IMML",
+  "REL_PC", "LABEL_PC", "REL_A",
+  "IMM", "IMM6", "IMM12", "IMM13W", "IMM13X", "IMML", "IMMV",
+  "VREG",
 }
 
 -- Maximum number of section buffer positions for dasm_put().
@@ -246,9 +248,12 @@ local map_cond = {
 
 local parse_reg_type
 
-local function parse_reg(expr)
+local function parse_reg(expr, shift)
   if not expr then werror("expected register name") end
   local tname, ovreg = match(expr, "^([%w_]+):(@?%l%d+)$")
+  if not tname then
+    tname, ovreg = match(expr, "^([%w_]+):(R[xwqdshb]%b())$")
+  end
   local tp = map_type[tname or expr]
   if tp then
     local reg = ovreg or tp.reg
@@ -266,18 +271,28 @@ local function parse_reg(expr)
       elseif parse_reg_type ~= rt then
 	werror("register size mismatch")
       end
-      return r, tp
+      return shl(r, shift), tp
+    end
+  end
+  local vrt, vreg = match(expr, "^R([xwqdshb])(%b())$")
+  if vreg then
+    if not parse_reg_type then
+      parse_reg_type = vrt
+    elseif parse_reg_type ~= vrt then
+      werror("register size mismatch")
     end
+    if shift then waction("VREG", shift, vreg) end
+    return 0
   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)
+  local base, tp = parse_reg(expr, 5)
   if parse_reg_type ~= "x" then werror("bad register type") end
   parse_reg_type = false
-  return shl(base, 5), tp
+  return base, tp
 end
 
 local parse_ctx = {}
@@ -297,7 +312,7 @@ local function parse_number(n)
   local code = loadenv("return "..n)
   if code then
     local ok, y = pcall(code)
-    if ok then return y end
+    if ok and type(y) == "number" then return y end
   end
   return nil
 end
@@ -403,7 +418,7 @@ local function parse_imm_load(imm, scale)
     end
     werror("out of range immediate `"..imm.."'")
   else
-    waction("IMML", 0, imm)
+    waction("IMML", scale, imm)
     return 0
   end
 end
@@ -462,6 +477,7 @@ end
 
 local function parse_load(params, nparams, n, op)
   if params[n+2] then werror("too many operands") end
+  local scale = shr(op, 30)
   local pn, p2 = params[n], params[n+1]
   local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$")
   if not p1 then
@@ -470,14 +486,13 @@ local function parse_load(params, nparams, n, op)
       if reg and tailr ~= "" then
 	local base, tp = parse_reg_base(reg)
 	if tp then
-	  waction("IMML", 0, format(tp.ctypefmt, tailr))
+	  waction("IMML", scale, 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
@@ -494,7 +509,7 @@ local function parse_load(params, nparams, n, op)
 	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
+	op = op + parse_reg(p2b, 16) + 0x00200800
 	if parse_reg_type ~= "x" and parse_reg_type ~= "w" then
 	  werror("bad index register type")
 	end
@@ -561,14 +576,14 @@ local function parse_load_pair(params, nparams, n, op)
 end
 
 local function parse_label(label, def)
-  local prefix = sub(label, 1, 2)
+  local prefix = label:sub(1, 2)
   -- =>label (pc label reference)
   if prefix == "=>" then
-    return "PC", 0, sub(label, 3)
+    return "PC", 0, label:sub(3)
   end
   -- ->name (global label reference)
   if prefix == "->" then
-    return "LG", map_global[sub(label, 3)]
+    return "LG", map_global[label:sub(3)]
   end
   if def then
     -- [1-9] (local label definition)
@@ -586,8 +601,11 @@ local function parse_label(label, def)
     if extname then
       return "EXT", map_extern[extname]
     end
+    -- &expr (pointer)
+    if label:sub(1, 1) == "&" then
+      return "A", 0, format("(ptrdiff_t)(%s)", label:sub(2))
+    end
   end
-  werror("bad label `"..label.."'")
 end
 
 local function branch_type(op)
@@ -620,24 +638,24 @@ local function alias_bfx(p)
 end
 
 local function alias_bfiz(p)
-  parse_reg(p[1])
+  parse_reg(p[1], 0)
   if parse_reg_type == "w" then
-    p[3] = "#-("..p[3]:sub(2)..")%32"
+    p[3] = "#(32-("..p[3]:sub(2).."))%32"
     p[4] = "#("..p[4]:sub(2)..")-1"
   else
-    p[3] = "#-("..p[3]:sub(2)..")%64"
+    p[3] = "#(64-("..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])
+  parse_reg(p[1], 0)
   local sh = p[3]:sub(2)
   if parse_reg_type == "w" then
-    p[3] = "#-("..sh..")%32"
+    p[3] = "#(32-("..sh.."))%32"
     p[4] = "#31-("..sh..")"
   else
-    p[3] = "#-("..sh..")%64"
+    p[3] = "#(64-("..sh.."))%64"
     p[4] = "#63-("..sh..")"
   end
 end)
@@ -881,25 +899,25 @@ end
 
 -- Handle opcodes defined with template strings.
 local function parse_template(params, template, nparams, pos)
-  local op = tonumber(sub(template, 1, 8), 16)
+  local op = tonumber(template:sub(1, 8), 16)
   local n = 1
   local rtt = {}
 
   parse_reg_type = false
 
   -- Process each character.
-  for p in gmatch(sub(template, 9), ".") do
+  for p in gmatch(template:sub(9), ".") do
     local q = params[n]
     if p == "D" then
-      op = op + parse_reg(q); n = n + 1
+      op = op + parse_reg(q, 0); n = n + 1
     elseif p == "N" then
-      op = op + shl(parse_reg(q), 5); n = n + 1
+      op = op + parse_reg(q, 5); n = n + 1
     elseif p == "M" then
-      op = op + shl(parse_reg(q), 16); n = n + 1
+      op = op + parse_reg(q, 16); n = n + 1
     elseif p == "A" then
-      op = op + shl(parse_reg(q), 10); n = n + 1
+      op = op + parse_reg(q, 10); n = n + 1
     elseif p == "m" then
-      op = op + shl(parse_reg(params[n-1]), 16)
+      op = op + parse_reg(params[n-1], 16)
 
     elseif p == "p" then
       if q == "sp" then params[n] = "@x31" end
@@ -930,8 +948,14 @@ local function parse_template(params, template, nparams, pos)
 
     elseif p == "B" then
       local mode, v, s = parse_label(q, false); n = n + 1
+      if not mode then werror("bad label `"..q.."'") end
       local m = branch_type(op)
-      waction("REL_"..mode, v+m, s, 1)
+      if mode == "A" then
+	waction("REL_"..mode, v+m, format("(unsigned int)(%s)", s))
+	actargs[#actargs+1] = format("(unsigned int)((%s)>>32)", s)
+      else
+	waction("REL_"..mode, v+m, s, 1)
+      end
 
     elseif p == "I" then
       op = op + parse_imm12(q); n = n + 1
@@ -977,8 +1001,8 @@ 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
+  -- A single opcode needs a maximum of 4 positions.
+  if secpos+4 > maxsecpos then wflush() end
   local pos = wpos()
   local lpos, apos, spos = #actlist, #actargs, secpos
 
@@ -990,9 +1014,11 @@ function op_template(params, template, nparams)
     actlist[lpos+1] = nil
     actlist[lpos+2] = nil
     actlist[lpos+3] = nil
+    actlist[lpos+4] = nil
     actargs[apos+1] = nil
     actargs[apos+2] = nil
     actargs[apos+3] = nil
+    actargs[apos+4] = nil
   end
   error(err, 0)
 end
@@ -1036,23 +1062,50 @@ 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
+  if not mode or 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)
+local function op_data(params)
   if not params then return "imm..." end
+  local sz = params.op == ".long" and 4 or 8
   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)
+    local imm = parse_number(p)
+    if imm then
+      local n = tobit(imm)
+      if n == imm or (n < 0 and n + 2^32 == imm) then
+	wputw(n < 0 and n + 2^32 or n)
+	if sz == 8 then
+	  wputw(imm < 0 and 0xffffffff or 0)
+	end
+      elseif sz == 4 then
+	werror("bad immediate `"..p.."'")
+      else
+	imm = nil
+      end
+    end
+    if not imm then
+      local mode, v, s = parse_label(p, false)
+      if sz == 4 then
+	if mode then werror("label does not fit into .long") end
+	waction("IMMV", 0, p)
+      elseif mode and mode ~= "A" then
+	waction("REL_"..mode, v+0x8000, s, 1)
+      else
+	if mode == "A" then p = s end
+	waction("IMMV", 0, format("(unsigned int)(%s)", p))
+	waction("IMMV", 0, format("(unsigned int)((unsigned long long)(%s)>>32)", p))
+      end
+    end
     if secpos+2 > maxsecpos then wflush() end
   end
 end
+map_op[".long_*"] = op_data
+map_op[".quad_*"] = op_data
+map_op[".addr_*"] = op_data
 
 -- Alignment pseudo-opcode.
 map_op[".align_1"] = function(params)

Some files were not shown because too many files changed in this diff