const char dump_lua[] =
"----------------------------------------------------------------------------\n"
"-- LuaJIT compiler dump module.\n"
"--\n"
"-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.\n"
"-- Released under the MIT license. See Copyright Notice in luajit.h\n"
"----------------------------------------------------------------------------\n"
"--\n"
"-- This module can be used to debug the JIT compiler itself. It dumps the\n"
"-- code representations and structures used in various compiler stages.\n"
"--\n"
"-- Example usage:\n"
"--\n"
"--   luajit -jdump -e \"local x=0; for i=1,1e6 do x=x+i end; print(x)\"\n"
"--   luajit -jdump=im -e \"for i=1,1000 do for j=1,1000 do end end\" | less -R\n"
"--   luajit -jdump=is myapp.lua | less -R\n"
"--   luajit -jdump=-b myapp.lua\n"
"--   luajit -jdump=+aH,myapp.html myapp.lua\n"
"--   luajit -jdump=ixT,myapp.dump myapp.lua\n"
"--\n"
"-- The first argument specifies the dump mode. The second argument gives\n"
"-- the output file name. Default output is to stdout, unless the environment\n"
"-- variable LUAJIT_DUMPFILE is set. The file is overwritten every time the\n"
"-- module is started.\n"
"--\n"
"-- Different features can be turned on or off with the dump mode. If the\n"
"-- mode starts with a '+', the following features are added to the default\n"
"-- set of features; a '-' removes them. Otherwise the features are replaced.\n"
"--\n"
"-- The following dump features are available (* marks the default):\n"
"--\n"
"--  * t  Print a line for each started, ended or aborted trace (see also -jv).\n"
"--  * b  Dump the traced bytecode.\n"
"--  * i  Dump the IR (intermediate representation).\n"
"--    r  Augment the IR with register/stack slots.\n"
"--    s  Dump the snapshot map.\n"
"--  * m  Dump the generated machine code.\n"
"--    x  Print each taken trace exit.\n"
"--    X  Print each taken trace exit and the contents of all registers.\n"
"--    a  Print the IR of aborted traces, too.\n"
"--\n"
"-- The output format can be set with the following characters:\n"
"--\n"
"--    T  Plain text output.\n"
"--    A  ANSI-colored text output\n"
"--    H  Colorized HTML + CSS output.\n"
"--\n"
"-- The default output format is plain text. It's set to ANSI-colored text\n"
"-- if the COLORTERM variable is set. Note: this is independent of any output\n"
"-- redirection, which is actually considered a feature.\n"
"--\n"
"-- You probably want to use less -R to enjoy viewing ANSI-colored text from\n"
"-- a pipe or a file. Add this to your ~/.bashrc: export LESS=\"-R\"\n"
"--\n"
"------------------------------------------------------------------------------\n"
"\n"
"-- Cache some library functions and objects.\n"
"local jit = require(\"jit\")\n"
"assert(jit.version_num == 20100, \"LuaJIT core/library version mismatch\")\n"
"local jutil = require(\"jit.util\")\n"
"local vmdef = require(\"jit.vmdef\")\n"
"local funcinfo, funcbc = jutil.funcinfo, jutil.funcbc\n"
"local traceinfo, traceir, tracek = jutil.traceinfo, jutil.traceir, jutil.tracek\n"
"local tracemc, tracesnap = jutil.tracemc, jutil.tracesnap\n"
"local traceexitstub, ircalladdr = jutil.traceexitstub, jutil.ircalladdr\n"
"local bit = require(\"bit\")\n"
"local band, shr, tohex = bit.band, bit.rshift, bit.tohex\n"
"local sub, gsub, format = string.sub, string.gsub, string.format\n"
"local byte, rep = string.byte, string.rep\n"
"local type, tostring = type, tostring\n"
"local stdout, stderr = io.stdout, io.stderr\n"
"\n"
"-- Load other modules on-demand.\n"
"local bcline, disass\n"
"\n"
"-- Active flag, output file handle and dump mode.\n"
"local active, out, dumpmode\n"
"\n"
"------------------------------------------------------------------------------\n"
"\n"
"local symtabmt = { __index = false }\n"
"local symtab = {}\n"
"local nexitsym = 0\n"
"\n"
"-- Fill nested symbol table with per-trace exit stub addresses.\n"
"local function fillsymtab_tr(tr, nexit)\n"
"  local t = {}\n"
"  symtabmt.__index = t\n"
"  if jit.arch:sub(1, 4) == \"mips\" then\n"
"    t[traceexitstub(tr, 0)] = \"exit\"\n"
"    return\n"
"  end\n"
"  for i=0,nexit-1 do\n"
"    local addr = traceexitstub(tr, i)\n"
"    if addr < 0 then addr = addr + 2^32 end\n"
"    t[addr] = tostring(i)\n"
"  end\n"
"  local addr = traceexitstub(tr, nexit)\n"
"  if addr then t[addr] = \"stack_check\" end\n"
"end\n"
"\n"
"-- Fill symbol table with trace exit stub addresses.\n"
"local function fillsymtab(tr, nexit)\n"
"  local t = symtab\n"
"  if nexitsym == 0 then\n"
"    local ircall = vmdef.ircall\n"
"    for i=0,#ircall do\n"
"      local addr = ircalladdr(i)\n"
"      if addr ~= 0 then\n"
"\tif addr < 0 then addr = addr + 2^32 end\n"
"\tt[addr] = ircall[i]\n"
"      end\n"
"    end\n"
"  end\n"
"  if nexitsym == 1000000 then -- Per-trace exit stubs.\n"
"    fillsymtab_tr(tr, nexit)\n"
"  elseif nexit > nexitsym then -- Shared exit stubs.\n"
"    for i=nexitsym,nexit-1 do\n"
"      local addr = traceexitstub(i)\n"
"      if addr == nil then -- Fall back to per-trace exit stubs.\n"
"\tfillsymtab_tr(tr, nexit)\n"
"\tsetmetatable(symtab, symtabmt)\n"
"\tnexit = 1000000\n"
"\tbreak\n"
"      end\n"
"      if addr < 0 then addr = addr + 2^32 end\n"
"      t[addr] = tostring(i)\n"
"    end\n"
"    nexitsym = nexit\n"
"  end\n"
"  return t\n"
"end\n"
"\n"
"local function dumpwrite(s)\n"
"  out:write(s)\n"
"end\n"
"\n"
"-- Disassemble machine code.\n"
"local function dump_mcode(tr)\n"
"  local info = traceinfo(tr)\n"
"  if not info then return end\n"
"  local mcode, addr, loop = tracemc(tr)\n"
"  if not mcode then return end\n"
"  if not disass then disass = require(\"jit.dis_\"..jit.arch) end\n"
"  if addr < 0 then addr = addr + 2^32 end\n"
"  out:write(\"---- TRACE \", tr, \" mcode \", #mcode, \"\\n\")\n"
"  local ctx = disass.create(mcode, addr, dumpwrite)\n"
"  ctx.hexdump = 0\n"
"  ctx.symtab = fillsymtab(tr, info.nexit)\n"
"  if loop ~= 0 then\n"
"    symtab[addr+loop] = \"LOOP\"\n"
"    ctx:disass(0, loop)\n"
"    out:write(\"->LOOP:\\n\")\n"
"    ctx:disass(loop, #mcode-loop)\n"
"    symtab[addr+loop] = nil\n"
"  else\n"
"    ctx:disass(0, #mcode)\n"
"  end\n"
"end\n"
"\n"
"------------------------------------------------------------------------------\n"
"\n"
"local irtype_text = {\n"
"  [0] = \"nil\",\n"
"  \"fal\",\n"
"  \"tru\",\n"
"  \"lud\",\n"
"  \"str\",\n"
"  \"p32\",\n"
"  \"thr\",\n"
"  \"pro\",\n"
"  \"fun\",\n"
"  \"p64\",\n"
"  \"cdt\",\n"
"  \"tab\",\n"
"  \"udt\",\n"
"  \"flt\",\n"
"  \"num\",\n"
"  \"i8 \",\n"
"  \"u8 \",\n"
"  \"i16\",\n"
"  \"u16\",\n"
"  \"int\",\n"
"  \"u32\",\n"
"  \"i64\",\n"
"  \"u64\",\n"
"  \"sfp\",\n"
"}\n"
"\n"
"local colortype_ansi = {\n"
"  [0] = \"%s\",\n"
"  \"%s\",\n"
"  \"%s\",\n"
"  \"\\027[36m%s\\027[m\",\n"
"  \"\\027[32m%s\\027[m\",\n"
"  \"%s\",\n"
"  \"\\027[1m%s\\027[m\",\n"
"  \"%s\",\n"
"  \"\\027[1m%s\\027[m\",\n"
"  \"%s\",\n"
"  \"\\027[33m%s\\027[m\",\n"
"  \"\\027[31m%s\\027[m\",\n"
"  \"\\027[36m%s\\027[m\",\n"
"  \"\\027[34m%s\\027[m\",\n"
"  \"\\027[34m%s\\027[m\",\n"
"  \"\\027[35m%s\\027[m\",\n"
"  \"\\027[35m%s\\027[m\",\n"
"  \"\\027[35m%s\\027[m\",\n"
"  \"\\027[35m%s\\027[m\",\n"
"  \"\\027[35m%s\\027[m\",\n"
"  \"\\027[35m%s\\027[m\",\n"
"  \"\\027[35m%s\\027[m\",\n"
"  \"\\027[35m%s\\027[m\",\n"
"  \"\\027[35m%s\\027[m\",\n"
"}\n"
"\n"
"local function colorize_text(s)\n"
"  return s\n"
"end\n"
"\n"
"local function colorize_ansi(s, t)\n"
"  return format(colortype_ansi[t], s)\n"
"end\n"
"\n"
"local irtype_ansi = setmetatable({},\n"
"  { __index = function(tab, t)\n"
"      local s = colorize_ansi(irtype_text[t], t); tab[t] = s; return s; end })\n"
"\n"
"local html_escape = { [\"<\"] = \"&lt;\", [\">\"] = \"&gt;\", [\"&\"] = \"&amp;\", }\n"
"\n"
"local function colorize_html(s, t)\n"
"  s = gsub(s, \"[<>&]\", html_escape)\n"
"  return format('<span class=\"irt_%s\">%s</span>', irtype_text[t], s)\n"
"end\n"
"\n"
"local irtype_html = setmetatable({},\n"
"  { __index = function(tab, t)\n"
"      local s = colorize_html(irtype_text[t], t); tab[t] = s; return s; end })\n"
"\n"
"local header_html = [[\n"
"<style type=\"text/css\">\n"
"background { background: #ffffff; color: #000000; }\n"
"pre.ljdump {\n"
"font-size: 10pt;\n"
"background: #f0f4ff;\n"
"color: #000000;\n"
"border: 1px solid #bfcfff;\n"
"padding: 0.5em;\n"
"margin-left: 2em;\n"
"margin-right: 2em;\n"
"}\n"
"span.irt_str { color: #00a000; }\n"
"span.irt_thr, span.irt_fun { color: #404040; font-weight: bold; }\n"
"span.irt_tab { color: #c00000; }\n"
"span.irt_udt, span.irt_lud { color: #00c0c0; }\n"
"span.irt_num { color: #4040c0; }\n"
"span.irt_int, span.irt_i8, span.irt_u8, span.irt_i16, span.irt_u16 { color: #b040b0; }\n"
"</style>\n"
"]]\n"
"\n"
"local colorize, irtype\n"
"\n"
"-- Lookup tables to convert some literals into names.\n"
"local litname = {\n"
"  [\"SLOAD \"] = setmetatable({}, { __index = function(t, mode)\n"
"    local s = \"\"\n"
"    if band(mode, 1) ~= 0 then s = s..\"P\" end\n"
"    if band(mode, 2) ~= 0 then s = s..\"F\" end\n"
"    if band(mode, 4) ~= 0 then s = s..\"T\" end\n"
"    if band(mode, 8) ~= 0 then s = s..\"C\" end\n"
"    if band(mode, 16) ~= 0 then s = s..\"R\" end\n"
"    if band(mode, 32) ~= 0 then s = s..\"I\" end\n"
"    t[mode] = s\n"
"    return s\n"
"  end}),\n"
"  [\"XLOAD \"] = { [0] = \"\", \"R\", \"V\", \"RV\", \"U\", \"RU\", \"VU\", \"RVU\", },\n"
"  [\"CONV  \"] = setmetatable({}, { __index = function(t, mode)\n"
"    local s = irtype[band(mode, 31)]\n"
"    s = irtype[band(shr(mode, 5), 31)]..\".\"..s\n"
"    if band(mode, 0x800) ~= 0 then s = s..\" sext\" end\n"
"    local c = shr(mode, 14)\n"
"    if c == 2 then s = s..\" index\" elseif c == 3 then s = s..\" check\" end\n"
"    t[mode] = s\n"
"    return s\n"
"  end}),\n"
"  [\"FLOAD \"] = vmdef.irfield,\n"
"  [\"FREF  \"] = vmdef.irfield,\n"
"  [\"FPMATH\"] = vmdef.irfpm,\n"
"  [\"BUFHDR\"] = { [0] = \"RESET\", \"APPEND\" },\n"
"  [\"TOSTR \"] = { [0] = \"INT\", \"NUM\", \"CHAR\" },\n"
"}\n"
"\n"
"local function ctlsub(c)\n"
"  if c == \"\\n\" then return \"\\\\n\"\n"
"  elseif c == \"\\r\" then return \"\\\\r\"\n"
"  elseif c == \"\\t\" then return \"\\\\t\"\n"
"  else return format(\"\\\\%03d\", byte(c))\n"
"  end\n"
"end\n"
"\n"
"local function fmtfunc(func, pc)\n"
"  local fi = funcinfo(func, pc)\n"
"  if fi.loc then\n"
"    return fi.loc\n"
"  elseif fi.ffid then\n"
"    return vmdef.ffnames[fi.ffid]\n"
"  elseif fi.addr then\n"
"    return format(\"C:%x\", fi.addr)\n"
"  else\n"
"    return \"(\?)\"\n"
"  end\n"
"end\n"
"\n"
"local function formatk(tr, idx, sn)\n"
"  local k, t, slot = tracek(tr, idx)\n"
"  local tn = type(k)\n"
"  local s\n"
"  if tn == \"number\" then\n"
"    if band(sn or 0, 0x30000) ~= 0 then\n"
"      s = band(sn, 0x20000) ~= 0 and \"contpc\" or \"ftsz\"\n"
"    elseif k == 2^52+2^51 then\n"
"      s = \"bias\"\n"
"    else\n"
"      s = format(0 < k and k < 0x1p-1026 and \"%+a\" or \"%+.14g\", k)\n"
"    end\n"
"  elseif tn == \"string\" then\n"
"    s = format(#k > 20 and '\"%.20s\"~' or '\"%s\"', gsub(k, \"%c\", ctlsub))\n"
"  elseif tn == \"function\" then\n"
"    s = fmtfunc(k)\n"
"  elseif tn == \"table\" then\n"
"    s = format(\"{%p}\", k)\n"
"  elseif tn == \"userdata\" then\n"
"    if t == 12 then\n"
"      s = format(\"userdata:%p\", k)\n"
"    else\n"
"      s = format(\"[%p]\", k)\n"
"      if s == \"[NULL]\" then s = \"NULL\" end\n"
"    end\n"
"  elseif t == 21 then -- int64_t\n"
"    s = sub(tostring(k), 1, -3)\n"
"    if sub(s, 1, 1) ~= \"-\" then s = \"+\"..s end\n"
"  elseif sn == 0x1057fff then -- SNAP(1, SNAP_FRAME | SNAP_NORESTORE, REF_NIL)\n"
"    return \"----\" -- Special case for LJ_FR2 slot 1.\n"
"  else\n"
"    s = tostring(k) -- For primitives.\n"
"  end\n"
"  s = colorize(format(\"%-4s\", s), t)\n"
"  if slot then\n"
"    s = format(\"%s @%d\", s, slot)\n"
"  end\n"
"  return s\n"
"end\n"
"\n"
"local function printsnap(tr, snap)\n"
"  local n = 2\n"
"  for s=0,snap[1]-1 do\n"
"    local sn = snap[n]\n"
"    if shr(sn, 24) == s then\n"
"      n = n + 1\n"
"      local ref = band(sn, 0xffff) - 0x8000 -- REF_BIAS\n"
"      if ref < 0 then\n"
"\tout:write(formatk(tr, ref, sn))\n"
"      elseif band(sn, 0x80000) ~= 0 then -- SNAP_SOFTFPNUM\n"
"\tout:write(colorize(format(\"%04d/%04d\", ref, ref+1), 14))\n"
"      else\n"
"\tlocal m, ot, op1, op2 = traceir(tr, ref)\n"
"\tout:write(colorize(format(\"%04d\", ref), band(ot, 31)))\n"
"      end\n"
"      out:write(band(sn, 0x10000) == 0 and \" \" or \"|\") -- SNAP_FRAME\n"
"    else\n"
"      out:write(\"---- \")\n"
"    end\n"
"  end\n"
"  out:write(\"]\\n\")\n"
"end\n"
"\n"
"-- Dump snapshots (not interleaved with IR).\n"
"local function dump_snap(tr)\n"
"  out:write(\"---- TRACE \", tr, \" snapshots\\n\")\n"
"  for i=0,1000000000 do\n"
"    local snap = tracesnap(tr, i)\n"
"    if not snap then break end\n"
"    out:write(format(\"#%-3d %04d [ \", i, snap[0]))\n"
"    printsnap(tr, snap)\n"
"  end\n"
"end\n"
"\n"
"-- Return a register name or stack slot for a rid/sp location.\n"
"local function ridsp_name(ridsp, ins)\n"
"  if not disass then disass = require(\"jit.dis_\"..jit.arch) end\n"
"  local rid, slot = band(ridsp, 0xff), shr(ridsp, 8)\n"
"  if rid == 253 or rid == 254 then\n"
"    return (slot == 0 or slot == 255) and \" {sink\" or format(\" {%04d\", ins-slot)\n"
"  end\n"
"  if ridsp > 255 then return format(\"[%x]\", slot*4) end\n"
"  if rid < 128 then return disass.regname(rid) end\n"
"  return \"\"\n"
"end\n"
"\n"
"-- Dump CALL* function ref and return optional ctype.\n"
"local function dumpcallfunc(tr, ins)\n"
"  local ctype\n"
"  if ins > 0 then\n"
"    local m, ot, op1, op2 = traceir(tr, ins)\n"
"    if band(ot, 31) == 0 then -- nil type means CARG(func, ctype).\n"
"      ins = op1\n"
"      ctype = formatk(tr, op2)\n"
"    end\n"
"  end\n"
"  if ins < 0 then\n"
"    out:write(format(\"[0x%x](\", tonumber((tracek(tr, ins)))))\n"
"  else\n"
"    out:write(format(\"%04d (\", ins))\n"
"  end\n"
"  return ctype\n"
"end\n"
"\n"
"-- Recursively gather CALL* args and dump them.\n"
"local function dumpcallargs(tr, ins)\n"
"  if ins < 0 then\n"
"    out:write(formatk(tr, ins))\n"
"  else\n"
"    local m, ot, op1, op2 = traceir(tr, ins)\n"
"    local oidx = 6*shr(ot, 8)\n"
"    local op = sub(vmdef.irnames, oidx+1, oidx+6)\n"
"    if op == \"CARG  \" then\n"
"      dumpcallargs(tr, op1)\n"
"      if op2 < 0 then\n"
"\tout:write(\" \", formatk(tr, op2))\n"
"      else\n"
"\tout:write(\" \", format(\"%04d\", op2))\n"
"      end\n"
"    else\n"
"      out:write(format(\"%04d\", ins))\n"
"    end\n"
"  end\n"
"end\n"
"\n"
"-- Dump IR and interleaved snapshots.\n"
"local function dump_ir(tr, dumpsnap, dumpreg)\n"
"  local info = traceinfo(tr)\n"
"  if not info then return end\n"
"  local nins = info.nins\n"
"  out:write(\"---- TRACE \", tr, \" IR\\n\")\n"
"  local irnames = vmdef.irnames\n"
"  local snapref = 65536\n"
"  local snap, snapno\n"
"  if dumpsnap then\n"
"    snap = tracesnap(tr, 0)\n"
"    snapref = snap[0]\n"
"    snapno = 0\n"
"  end\n"
"  for ins=1,nins do\n"
"    if ins >= snapref then\n"
"      if dumpreg then\n"
"\tout:write(format(\"....              SNAP   #%-3d [ \", snapno))\n"
"      else\n"
"\tout:write(format(\"....        SNAP   #%-3d [ \", snapno))\n"
"      end\n"
"      printsnap(tr, snap)\n"
"      snapno = snapno + 1\n"
"      snap = tracesnap(tr, snapno)\n"
"      snapref = snap and snap[0] or 65536\n"
"    end\n"
"    local m, ot, op1, op2, ridsp = traceir(tr, ins)\n"
"    local oidx, t = 6*shr(ot, 8), band(ot, 31)\n"
"    local op = sub(irnames, oidx+1, oidx+6)\n"
"    if op == \"LOOP  \" then\n"
"      if dumpreg then\n"
"\tout:write(format(\"%04d ------------ LOOP ------------\\n\", ins))\n"
"      else\n"
"\tout:write(format(\"%04d ------ LOOP ------------\\n\", ins))\n"
"      end\n"
"    elseif op ~= \"NOP   \" and op ~= \"CARG  \" and\n"
"\t   (dumpreg or op ~= \"RENAME\") then\n"
"      local rid = band(ridsp, 255)\n"
"      if dumpreg then\n"
"\tout:write(format(\"%04d %-6s\", ins, ridsp_name(ridsp, ins)))\n"
"      else\n"
"\tout:write(format(\"%04d \", ins))\n"
"      end\n"
"      out:write(format(\"%s%s %s %s \",\n"
"\t\t       (rid == 254 or rid == 253) and \"}\" or\n"
"\t\t       (band(ot, 128) == 0 and \" \" or \">\"),\n"
"\t\t       band(ot, 64) == 0 and \" \" or \"+\",\n"
"\t\t       irtype[t], op))\n"
"      local m1, m2 = band(m, 3), band(m, 3*4)\n"
"      if sub(op, 1, 4) == \"CALL\" then\n"
"\tlocal ctype\n"
"\tif m2 == 1*4 then -- op2 == IRMlit\n"
"\t  out:write(format(\"%-10s  (\", vmdef.ircall[op2]))\n"
"\telse\n"
"\t  ctype = dumpcallfunc(tr, op2)\n"
"\tend\n"
"\tif op1 ~= -1 then dumpcallargs(tr, op1) end\n"
"\tout:write(\")\")\n"
"\tif ctype then out:write(\" ctype \", ctype) end\n"
"      elseif op == \"CNEW  \" and op2 == -1 then\n"
"\tout:write(formatk(tr, op1))\n"
"      elseif m1 ~= 3 then -- op1 != IRMnone\n"
"\tif op1 < 0 then\n"
"\t  out:write(formatk(tr, op1))\n"
"\telse\n"
"\t  out:write(format(m1 == 0 and \"%04d\" or \"#%-3d\", op1))\n"
"\tend\n"
"\tif m2 ~= 3*4 then -- op2 != IRMnone\n"
"\t  if m2 == 1*4 then -- op2 == IRMlit\n"
"\t    local litn = litname[op]\n"
"\t    if litn and litn[op2] then\n"
"\t      out:write(\"  \", litn[op2])\n"
"\t    elseif op == \"UREFO \" or op == \"UREFC \" then\n"
"\t      out:write(format(\"  #%-3d\", shr(op2, 8)))\n"
"\t    else\n"
"\t      out:write(format(\"  #%-3d\", op2))\n"
"\t    end\n"
"\t  elseif op2 < 0 then\n"
"\t    out:write(\"  \", formatk(tr, op2))\n"
"\t  else\n"
"\t    out:write(format(\"  %04d\", op2))\n"
"\t  end\n"
"\tend\n"
"      end\n"
"      out:write(\"\\n\")\n"
"    end\n"
"  end\n"
"  if snap then\n"
"    if dumpreg then\n"
"      out:write(format(\"....              SNAP   #%-3d [ \", snapno))\n"
"    else\n"
"      out:write(format(\"....        SNAP   #%-3d [ \", snapno))\n"
"    end\n"
"    printsnap(tr, snap)\n"
"  end\n"
"end\n"
"\n"
"------------------------------------------------------------------------------\n"
"\n"
"local recprefix = \"\"\n"
"local recdepth = 0\n"
"\n"
"-- Format trace error message.\n"
"local function fmterr(err, info)\n"
"  if type(err) == \"number\" then\n"
"    if type(info) == \"function\" then info = fmtfunc(info) end\n"
"    err = format(vmdef.traceerr[err], info)\n"
"  end\n"
"  return err\n"
"end\n"
"\n"
"-- Dump trace states.\n"
"local function dump_trace(what, tr, func, pc, otr, oex)\n"
"  if what == \"stop\" or (what == \"abort\" and dumpmode.a) then\n"
"    if dumpmode.i then dump_ir(tr, dumpmode.s, dumpmode.r and what == \"stop\")\n"
"    elseif dumpmode.s then dump_snap(tr) end\n"
"    if dumpmode.m then dump_mcode(tr) end\n"
"  end\n"
"  if what == \"start\" then\n"
"    if dumpmode.H then out:write('<pre class=\"ljdump\">\\n') end\n"
"    out:write(\"---- TRACE \", tr, \" \", what)\n"
"    if otr then out:write(\" \", otr, \"/\", oex == -1 and \"stitch\" or oex) end\n"
"    out:write(\" \", fmtfunc(func, pc), \"\\n\")\n"
"  elseif what == \"stop\" or what == \"abort\" then\n"
"    out:write(\"---- TRACE \", tr, \" \", what)\n"
"    if what == \"abort\" then\n"
"      out:write(\" \", fmtfunc(func, pc), \" -- \", fmterr(otr, oex), \"\\n\")\n"
"    else\n"
"      local info = traceinfo(tr)\n"
"      local link, ltype = info.link, info.linktype\n"
"      if link == tr or link == 0 then\n"
"\tout:write(\" -> \", ltype, \"\\n\")\n"
"      elseif ltype == \"root\" then\n"
"\tout:write(\" -> \", link, \"\\n\")\n"
"      else\n"
"\tout:write(\" -> \", link, \" \", ltype, \"\\n\")\n"
"      end\n"
"    end\n"
"    if dumpmode.H then out:write(\"</pre>\\n\\n\") else out:write(\"\\n\") end\n"
"  else\n"
"    if what == \"flush\" then symtab, nexitsym = {}, 0 end\n"
"    out:write(\"---- TRACE \", what, \"\\n\\n\")\n"
"  end\n"
"  out:flush()\n"
"end\n"
"\n"
"-- Dump recorded bytecode.\n"
"local function dump_record(tr, func, pc, depth, callee)\n"
"  if depth ~= recdepth then\n"
"    recdepth = depth\n"
"    recprefix = rep(\" .\", depth)\n"
"  end\n"
"  local line\n"
"  if pc >= 0 then\n"
"    line = bcline(func, pc, recprefix)\n"
"    if dumpmode.H then line = gsub(line, \"[<>&]\", html_escape) end\n"
"  else\n"
"    line = \"0000 \"..recprefix..\" FUNCC      \\n\"\n"
"    callee = func\n"
"  end\n"
"  if pc <= 0 then\n"
"    out:write(sub(line, 1, -2), \"         ; \", fmtfunc(func), \"\\n\")\n"
"  else\n"
"    out:write(line)\n"
"  end\n"
"  if pc >= 0 and band(funcbc(func, pc), 0xff) < 16 then -- ORDER BC\n"
"    out:write(bcline(func, pc+1, recprefix)) -- Write JMP for cond.\n"
"  end\n"
"end\n"
"\n"
"------------------------------------------------------------------------------\n"
"\n"
"-- Dump taken trace exits.\n"
"local function dump_texit(tr, ex, ngpr, nfpr, ...)\n"
"  out:write(\"---- TRACE \", tr, \" exit \", ex, \"\\n\")\n"
"  if dumpmode.X then\n"
"    local regs = {...}\n"
"    if jit.arch == \"x64\" then\n"
"      for i=1,ngpr do\n"
"\tout:write(format(\" %016x\", regs[i]))\n"
"\tif i % 4 == 0 then out:write(\"\\n\") end\n"
"      end\n"
"    else\n"
"      for i=1,ngpr do\n"
"\tout:write(\" \", tohex(regs[i]))\n"
"\tif i % 8 == 0 then out:write(\"\\n\") end\n"
"      end\n"
"    end\n"
"    if jit.arch == \"mips\" or jit.arch == \"mipsel\" then\n"
"      for i=1,nfpr,2 do\n"
"\tout:write(format(\" %+17.14g\", regs[ngpr+i]))\n"
"\tif i % 8 == 7 then out:write(\"\\n\") end\n"
"      end\n"
"    else\n"
"      for i=1,nfpr do\n"
"\tout:write(format(\" %+17.14g\", regs[ngpr+i]))\n"
"\tif i % 4 == 0 then out:write(\"\\n\") end\n"
"      end\n"
"    end\n"
"  end\n"
"end\n"
"\n"
"------------------------------------------------------------------------------\n"
"\n"
"-- Detach dump handlers.\n"
"local function dumpoff()\n"
"  if active then\n"
"    active = false\n"
"    jit.attach(dump_texit)\n"
"    jit.attach(dump_record)\n"
"    jit.attach(dump_trace)\n"
"    if out and out ~= stdout and out ~= stderr then out:close() end\n"
"    out = nil\n"
"  end\n"
"end\n"
"\n"
"-- Open the output file and attach dump handlers.\n"
"local function dumpon(opt, outfile)\n"
"  if active then dumpoff() end\n"
"\n"
"  local term = os.getenv(\"TERM\")\n"
"  local colormode = (term and term:match(\"color\") or os.getenv(\"COLORTERM\")) and \"A\" or \"T\"\n"
"  if opt then\n"
"    opt = gsub(opt, \"[TAH]\", function(mode) colormode = mode; return \"\"; end)\n"
"  end\n"
"\n"
"  local m = { t=true, b=true, i=true, m=true, }\n"
"  if opt and opt ~= \"\" then\n"
"    local o = sub(opt, 1, 1)\n"
"    if o ~= \"+\" and o ~= \"-\" then m = {} end\n"
"    for i=1,#opt do m[sub(opt, i, i)] = (o ~= \"-\") end\n"
"  end\n"
"  dumpmode = m\n"
"\n"
"  if m.t or m.b or m.i or m.s or m.m then\n"
"    jit.attach(dump_trace, \"trace\")\n"
"  end\n"
"  if m.b then\n"
"    jit.attach(dump_record, \"record\")\n"
"    if not bcline then bcline = require(\"jit.bc\").line end\n"
"  end\n"
"  if m.x or m.X then\n"
"    jit.attach(dump_texit, \"texit\")\n"
"  end\n"
"\n"
"  if not outfile then outfile = os.getenv(\"LUAJIT_DUMPFILE\") end\n"
"  if outfile then\n"
"    out = outfile == \"-\" and stdout or assert(io.open(outfile, \"w\"))\n"
"  else\n"
"    out = stdout\n"
"  end\n"
"\n"
"  m[colormode] = true\n"
"  if colormode == \"A\" then\n"
"    colorize = colorize_ansi\n"
"    irtype = irtype_ansi\n"
"  elseif colormode == \"H\" then\n"
"    colorize = colorize_html\n"
"    irtype = irtype_html\n"
"    out:write(header_html)\n"
"  else\n"
"    colorize = colorize_text\n"
"    irtype = irtype_text\n"
"  end\n"
"\n"
"  active = true\n"
"end\n"
"\n"
"-- Public module functions.\n"
"return {\n"
"  on = dumpon,\n"
"  off = dumpoff,\n"
"  start = dumpon -- For -j command line option.\n"
"}\n"
"\n"
""
;
