ARM: Don't evict ASMREF_L in ra_evictk().
[luajit-2.0.git] / lib / dump.lua
blob6ada21bc01a6631e4a1cf84c1e1da594e7c7aecc
1 ----------------------------------------------------------------------------
2 -- LuaJIT compiler dump module.
3 --
4 -- Copyright (C) 2005-2011 Mike Pall. All rights reserved.
5 -- Released under the MIT/X license. See Copyright Notice in luajit.h
6 ----------------------------------------------------------------------------
7 --
8 -- This module can be used to debug the JIT compiler itself. It dumps the
9 -- code representations and structures used in various compiler stages.
11 -- Example usage:
13 -- luajit -jdump -e "local x=0; for i=1,1e6 do x=x+i end; print(x)"
14 -- luajit -jdump=im -e "for i=1,1000 do for j=1,1000 do end end" | less -R
15 -- luajit -jdump=is myapp.lua | less -R
16 -- luajit -jdump=-b myapp.lua
17 -- luajit -jdump=+aH,myapp.html myapp.lua
18 -- luajit -jdump=ixT,myapp.dump myapp.lua
20 -- The first argument specifies the dump mode. The second argument gives
21 -- the output file name. Default output is to stdout, unless the environment
22 -- variable LUAJIT_DUMPFILE is set. The file is overwritten every time the
23 -- module is started.
25 -- Different features can be turned on or off with the dump mode. If the
26 -- mode starts with a '+', the following features are added to the default
27 -- set of features; a '-' removes them. Otherwise the features are replaced.
29 -- The following dump features are available (* marks the default):
31 -- * t Print a line for each started, ended or aborted trace (see also -jv).
32 -- * b Dump the traced bytecode.
33 -- * i Dump the IR (intermediate representation).
34 -- r Augment the IR with register/stack slots.
35 -- s Dump the snapshot map.
36 -- * m Dump the generated machine code.
37 -- x Print each taken trace exit.
38 -- X Print each taken trace exit and the contents of all registers.
40 -- The output format can be set with the following characters:
42 -- T Plain text output.
43 -- A ANSI-colored text output
44 -- H Colorized HTML + CSS output.
46 -- The default output format is plain text. It's set to ANSI-colored text
47 -- if the COLORTERM variable is set. Note: this is independent of any output
48 -- redirection, which is actually considered a feature.
50 -- You probably want to use less -R to enjoy viewing ANSI-colored text from
51 -- a pipe or a file. Add this to your ~/.bashrc: export LESS="-R"
53 ------------------------------------------------------------------------------
55 -- Cache some library functions and objects.
56 local jit = require("jit")
57 assert(jit.version_num == 20000, "LuaJIT core/library version mismatch")
58 local jutil = require("jit.util")
59 local vmdef = require("jit.vmdef")
60 local funcinfo, funcbc = jutil.funcinfo, jutil.funcbc
61 local traceinfo, traceir, tracek = jutil.traceinfo, jutil.traceir, jutil.tracek
62 local tracemc, tracesnap = jutil.tracemc, jutil.tracesnap
63 local traceexitstub, ircalladdr = jutil.traceexitstub, jutil.ircalladdr
64 local bit = require("bit")
65 local band, shl, shr = bit.band, bit.lshift, bit.rshift
66 local sub, gsub, format = string.sub, string.gsub, string.format
67 local byte, char, rep = string.byte, string.char, string.rep
68 local type, tostring = type, tostring
69 local stdout, stderr = io.stdout, io.stderr
71 -- Load other modules on-demand.
72 local bcline, disass
74 -- Active flag, output file handle and dump mode.
75 local active, out, dumpmode
77 ------------------------------------------------------------------------------
79 local symtab = {}
80 local nexitsym = 0
82 -- Fill symbol table with trace exit addresses.
83 local function fillsymtab(nexit)
84 local t = symtab
85 if nexitsym == 0 then
86 local ircall = vmdef.ircall
87 for i=0,#ircall do t[ircalladdr(i)] = ircall[i] end
88 end
89 if nexit > nexitsym then
90 for i=nexitsym,nexit-1 do
91 local addr = traceexitstub(i)
92 if addr == nil then nexit = 1000000; break end
93 t[addr] = tostring(i)
94 end
95 nexitsym = nexit
96 end
97 return t
98 end
100 local function dumpwrite(s)
101 out:write(s)
104 -- Disassemble machine code.
105 local function dump_mcode(tr)
106 local info = traceinfo(tr)
107 if not info then return end
108 local mcode, addr, loop = tracemc(tr)
109 if not mcode then return end
110 if not disass then disass = require("jit.dis_"..jit.arch) end
111 out:write("---- TRACE ", tr, " mcode ", #mcode, "\n")
112 local ctx = disass.create(mcode, addr, dumpwrite)
113 ctx.hexdump = 0
114 ctx.symtab = fillsymtab(info.nexit)
115 if loop ~= 0 then
116 symtab[addr+loop] = "LOOP"
117 ctx:disass(0, loop)
118 out:write("->LOOP:\n")
119 ctx:disass(loop, #mcode-loop)
120 symtab[addr+loop] = nil
121 else
122 ctx:disass(0, #mcode)
126 ------------------------------------------------------------------------------
128 local irtype_text = {
129 [0] = "nil",
130 "fal",
131 "tru",
132 "lud",
133 "str",
134 "p32",
135 "thr",
136 "pro",
137 "fun",
138 "p64",
139 "cdt",
140 "tab",
141 "udt",
142 "flt",
143 "num",
144 "i8 ",
145 "u8 ",
146 "i16",
147 "u16",
148 "int",
149 "u32",
150 "i64",
151 "u64",
152 "sfp",
155 local colortype_ansi = {
156 [0] = "%s",
157 "%s",
158 "%s",
159 "\027[36m%s\027[m",
160 "\027[32m%s\027[m",
161 "%s",
162 "\027[1m%s\027[m",
163 "%s",
164 "\027[1m%s\027[m",
165 "%s",
166 "\027[33m%s\027[m",
167 "\027[31m%s\027[m",
168 "\027[36m%s\027[m",
169 "\027[34m%s\027[m",
170 "\027[34m%s\027[m",
171 "\027[35m%s\027[m",
172 "\027[35m%s\027[m",
173 "\027[35m%s\027[m",
174 "\027[35m%s\027[m",
175 "\027[35m%s\027[m",
176 "\027[35m%s\027[m",
177 "\027[35m%s\027[m",
178 "\027[35m%s\027[m",
179 "\027[35m%s\027[m",
182 local function colorize_text(s, t)
183 return s
186 local function colorize_ansi(s, t)
187 return format(colortype_ansi[t], s)
190 local irtype_ansi = setmetatable({},
191 { __index = function(tab, t)
192 local s = colorize_ansi(irtype_text[t], t); tab[t] = s; return s; end })
194 local html_escape = { ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;", }
196 local function colorize_html(s, t)
197 s = gsub(s, "[<>&]", html_escape)
198 return format('<span class="irt_%s">%s</span>', irtype_text[t], s)
201 local irtype_html = setmetatable({},
202 { __index = function(tab, t)
203 local s = colorize_html(irtype_text[t], t); tab[t] = s; return s; end })
205 local header_html = [[
206 <style type="text/css">
207 background { background: #ffffff; color: #000000; }
208 pre.ljdump {
209 font-size: 10pt;
210 background: #f0f4ff;
211 color: #000000;
212 border: 1px solid #bfcfff;
213 padding: 0.5em;
214 margin-left: 2em;
215 margin-right: 2em;
217 span.irt_str { color: #00a000; }
218 span.irt_thr, span.irt_fun { color: #404040; font-weight: bold; }
219 span.irt_tab { color: #c00000; }
220 span.irt_udt, span.irt_lud { color: #00c0c0; }
221 span.irt_num { color: #4040c0; }
222 span.irt_int, span.irt_i8, span.irt_u8, span.irt_i16, span.irt_u16 { color: #b040b0; }
223 </style>
226 local colorize, irtype
228 -- Lookup tables to convert some literals into names.
229 local litname = {
230 ["SLOAD "] = setmetatable({}, { __index = function(t, mode)
231 local s = ""
232 if band(mode, 1) ~= 0 then s = s.."P" end
233 if band(mode, 2) ~= 0 then s = s.."F" end
234 if band(mode, 4) ~= 0 then s = s.."T" end
235 if band(mode, 8) ~= 0 then s = s.."C" end
236 if band(mode, 16) ~= 0 then s = s.."R" end
237 if band(mode, 32) ~= 0 then s = s.."I" end
238 t[mode] = s
239 return s
240 end}),
241 ["XLOAD "] = { [0] = "", "R", "V", "RV", "U", "RU", "VU", "RVU", },
242 ["CONV "] = setmetatable({}, { __index = function(t, mode)
243 local s = irtype[band(mode, 31)]
244 s = irtype[band(shr(mode, 5), 31)].."."..s
245 if band(mode, 0x400) ~= 0 then s = s.." trunc"
246 elseif band(mode, 0x800) ~= 0 then s = s.." sext" end
247 local c = shr(mode, 14)
248 if c == 2 then s = s.." index" elseif c == 3 then s = s.." check" end
249 t[mode] = s
250 return s
251 end}),
252 ["FLOAD "] = vmdef.irfield,
253 ["FREF "] = vmdef.irfield,
254 ["FPMATH"] = vmdef.irfpm,
257 local function ctlsub(c)
258 if c == "\n" then return "\\n"
259 elseif c == "\r" then return "\\r"
260 elseif c == "\t" then return "\\t"
261 elseif c == "\r" then return "\\r"
262 else return format("\\%03d", byte(c))
266 local function fmtfunc(func, pc)
267 local fi = funcinfo(func, pc)
268 if fi.loc then
269 return fi.loc
270 elseif fi.ffid then
271 return vmdef.ffnames[fi.ffid]
272 elseif fi.addr then
273 return format("C:%x", fi.addr)
274 else
275 return "(?)"
279 local function formatk(tr, idx)
280 local k, t, slot = tracek(tr, idx)
281 local tn = type(k)
282 local s
283 if tn == "number" then
284 if k == 2^52+2^51 then
285 s = "bias"
286 else
287 s = format("%+.14g", k)
289 elseif tn == "string" then
290 s = format(#k > 20 and '"%.20s"~' or '"%s"', gsub(k, "%c", ctlsub))
291 elseif tn == "function" then
292 s = fmtfunc(k)
293 elseif tn == "table" then
294 s = format("{%p}", k)
295 elseif tn == "userdata" then
296 if t == 12 then
297 s = format("userdata:%p", k)
298 else
299 s = format("[%p]", k)
300 if s == "[0x00000000]" then s = "NULL" end
302 elseif t == 21 then -- int64_t
303 s = sub(tostring(k), 1, -3)
304 if sub(s, 1, 1) ~= "-" then s = "+"..s end
305 else
306 s = tostring(k) -- For primitives.
308 s = colorize(format("%-4s", s), t)
309 if slot then
310 s = format("%s @%d", s, slot)
312 return s
315 local function printsnap(tr, snap)
316 local n = 2
317 for s=0,snap[1]-1 do
318 local sn = snap[n]
319 if shr(sn, 24) == s then
320 n = n + 1
321 local ref = band(sn, 0xffff) - 0x8000 -- REF_BIAS
322 if ref < 0 then
323 out:write(formatk(tr, ref))
324 elseif band(sn, 0x80000) ~= 0 then -- SNAP_SOFTFPNUM
325 out:write(colorize(format("%04d/%04d", ref, ref+1), 14))
326 else
327 local m, ot, op1, op2 = traceir(tr, ref)
328 out:write(colorize(format("%04d", ref), band(ot, 31)))
330 out:write(band(sn, 0x10000) == 0 and " " or "|") -- SNAP_FRAME
331 else
332 out:write("---- ")
335 out:write("]\n")
338 -- Dump snapshots (not interleaved with IR).
339 local function dump_snap(tr)
340 out:write("---- TRACE ", tr, " snapshots\n")
341 for i=0,1000000000 do
342 local snap = tracesnap(tr, i)
343 if not snap then break end
344 out:write(format("#%-3d %04d [ ", i, snap[0]))
345 printsnap(tr, snap)
349 -- Return a register name or stack slot for a rid/sp location.
350 local function ridsp_name(ridsp)
351 if not disass then disass = require("jit.dis_"..jit.arch) end
352 local rid = band(ridsp, 0xff)
353 if ridsp > 255 then return format("[%x]", shr(ridsp, 8)*4) end
354 if rid < 128 then return disass.regname(rid) end
355 return ""
358 -- Recursively gather CALL* args and dump them.
359 local function dumpcallargs(tr, ins)
360 if ins < 0 then
361 out:write(formatk(tr, ins))
362 else
363 local m, ot, op1, op2 = traceir(tr, ins)
364 local oidx = 6*shr(ot, 8)
365 local op = sub(vmdef.irnames, oidx+1, oidx+6)
366 if op == "CARG " then
367 dumpcallargs(tr, op1)
368 if op2 < 0 then
369 out:write(" ", formatk(tr, op2))
370 else
371 out:write(" ", format("%04d", op2))
373 else
374 out:write(format("%04d", ins))
379 -- Dump IR and interleaved snapshots.
380 local function dump_ir(tr, dumpsnap, dumpreg)
381 local info = traceinfo(tr)
382 if not info then return end
383 local nins = info.nins
384 out:write("---- TRACE ", tr, " IR\n")
385 local irnames = vmdef.irnames
386 local snapref = 65536
387 local snap, snapno
388 if dumpsnap then
389 snap = tracesnap(tr, 0)
390 snapref = snap[0]
391 snapno = 0
393 for ins=1,nins do
394 if ins >= snapref then
395 if dumpreg then
396 out:write(format(".... SNAP #%-3d [ ", snapno))
397 else
398 out:write(format(".... SNAP #%-3d [ ", snapno))
400 printsnap(tr, snap)
401 snapno = snapno + 1
402 snap = tracesnap(tr, snapno)
403 snapref = snap and snap[0] or 65536
405 local m, ot, op1, op2, ridsp = traceir(tr, ins)
406 local oidx, t = 6*shr(ot, 8), band(ot, 31)
407 local op = sub(irnames, oidx+1, oidx+6)
408 if op == "LOOP " then
409 if dumpreg then
410 out:write(format("%04d ------------ LOOP ------------\n", ins))
411 else
412 out:write(format("%04d ------ LOOP ------------\n", ins))
414 elseif op ~= "NOP " and op ~= "CARG " and
415 (dumpreg or op ~= "RENAME") then
416 if dumpreg then
417 out:write(format("%04d %-5s ", ins, ridsp_name(ridsp)))
418 else
419 out:write(format("%04d ", ins))
421 out:write(format("%s%s %s %s ",
422 band(ot, 128) == 0 and " " or ">",
423 band(ot, 64) == 0 and " " or "+",
424 irtype[t], op))
425 local m1, m2 = band(m, 3), band(m, 3*4)
426 if sub(op, 1, 4) == "CALL" then
427 if m2 == 1*4 then -- op2 == IRMlit
428 out:write(format("%-10s (", vmdef.ircall[op2]))
429 elseif op2 < 0 then
430 out:write(format("[0x%x](", tonumber((tracek(tr, op2)))))
431 else
432 out:write(format("%04d (", op2))
434 if op1 ~= -1 then dumpcallargs(tr, op1) end
435 out:write(")")
436 elseif op == "CNEW " and op2 == -1 then
437 out:write(formatk(tr, op1))
438 elseif m1 ~= 3 then -- op1 != IRMnone
439 if op1 < 0 then
440 out:write(formatk(tr, op1))
441 else
442 out:write(format(m1 == 0 and "%04d" or "#%-3d", op1))
444 if m2 ~= 3*4 then -- op2 != IRMnone
445 if m2 == 1*4 then -- op2 == IRMlit
446 local litn = litname[op]
447 if litn and litn[op2] then
448 out:write(" ", litn[op2])
449 elseif op == "UREFO " or op == "UREFC " then
450 out:write(format(" #%-3d", shr(op2, 8)))
451 else
452 out:write(format(" #%-3d", op2))
454 elseif op2 < 0 then
455 out:write(" ", formatk(tr, op2))
456 else
457 out:write(format(" %04d", op2))
461 out:write("\n")
464 if snap then
465 if dumpreg then
466 out:write(format(".... SNAP #%-3d [ ", snapno))
467 else
468 out:write(format(".... SNAP #%-3d [ ", snapno))
470 printsnap(tr, snap)
474 ------------------------------------------------------------------------------
476 local recprefix = ""
477 local recdepth = 0
479 -- Format trace error message.
480 local function fmterr(err, info)
481 if type(err) == "number" then
482 if type(info) == "function" then info = fmtfunc(info) end
483 err = format(vmdef.traceerr[err], info)
485 return err
488 -- Dump trace states.
489 local function dump_trace(what, tr, func, pc, otr, oex)
490 if what == "stop" or (what == "abort" and dumpmode.a) then
491 if dumpmode.i then dump_ir(tr, dumpmode.s, dumpmode.r and what == "stop")
492 elseif dumpmode.s then dump_snap(tr) end
493 if dumpmode.m then dump_mcode(tr) end
495 if what == "start" then
496 if dumpmode.H then out:write('<pre class="ljdump">\n') end
497 out:write("---- TRACE ", tr, " ", what)
498 if otr then out:write(" ", otr, "/", oex) end
499 out:write(" ", fmtfunc(func, pc), "\n")
500 recprefix = ""
501 elseif what == "stop" or what == "abort" then
502 out:write("---- TRACE ", tr, " ", what)
503 recprefix = nil
504 if what == "abort" then
505 out:write(" ", fmtfunc(func, pc), " -- ", fmterr(otr, oex), "\n")
506 else
507 local info = traceinfo(tr)
508 local link, ltype = info.link, info.linktype
509 if link == tr or link == 0 then
510 out:write(" -> ", ltype, "\n")
511 elseif ltype == "root" then
512 out:write(" -> ", link, "\n")
513 else
514 out:write(" -> ", link, " ", ltype, "\n")
517 if dumpmode.H then out:write("</pre>\n\n") else out:write("\n") end
518 else
519 out:write("---- TRACE ", what, "\n\n")
521 out:flush()
524 -- Dump recorded bytecode.
525 local function dump_record(tr, func, pc, depth, callee)
526 if depth ~= recdepth then
527 recdepth = depth
528 recprefix = rep(" .", depth)
530 local line
531 if pc >= 0 then
532 line = bcline(func, pc, recprefix)
533 if dumpmode.H then line = gsub(line, "[<>&]", html_escape) end
534 else
535 line = "0000 "..recprefix.." FUNCC \n"
536 callee = func
538 if pc <= 0 then
539 out:write(sub(line, 1, -2), " ; ", fmtfunc(func), "\n")
540 else
541 out:write(line)
543 if pc >= 0 and band(funcbc(func, pc), 0xff) < 16 then -- ORDER BC
544 out:write(bcline(func, pc+1, recprefix)) -- Write JMP for cond.
548 ------------------------------------------------------------------------------
550 -- Dump taken trace exits.
551 local function dump_texit(tr, ex, ngpr, nfpr, ...)
552 out:write("---- TRACE ", tr, " exit ", ex, "\n")
553 if dumpmode.X then
554 local regs = {...}
555 if jit.arch == "x64" then
556 for i=1,ngpr do
557 out:write(format(" %016x", regs[i]))
558 if i % 4 == 0 then out:write("\n") end
560 else
561 for i=1,ngpr do
562 out:write(format(" %08x", regs[i]))
563 if i % 8 == 0 then out:write("\n") end
566 for i=1,nfpr do
567 out:write(format(" %+17.14g", regs[ngpr+i]))
568 if i % 4 == 0 then out:write("\n") end
573 ------------------------------------------------------------------------------
575 -- Detach dump handlers.
576 local function dumpoff()
577 if active then
578 active = false
579 jit.attach(dump_texit)
580 jit.attach(dump_record)
581 jit.attach(dump_trace)
582 if out and out ~= stdout and out ~= stderr then out:close() end
583 out = nil
587 -- Open the output file and attach dump handlers.
588 local function dumpon(opt, outfile)
589 if active then dumpoff() end
591 local colormode = os.getenv("COLORTERM") and "A" or "T"
592 if opt then
593 opt = gsub(opt, "[TAH]", function(mode) colormode = mode; return ""; end)
596 local m = { t=true, b=true, i=true, m=true, }
597 if opt and opt ~= "" then
598 local o = sub(opt, 1, 1)
599 if o ~= "+" and o ~= "-" then m = {} end
600 for i=1,#opt do m[sub(opt, i, i)] = (o ~= "-") end
602 dumpmode = m
604 if m.t or m.b or m.i or m.s or m.m then
605 jit.attach(dump_trace, "trace")
607 if m.b then
608 jit.attach(dump_record, "record")
609 if not bcline then bcline = require("jit.bc").line end
611 if m.x or m.X then
612 jit.attach(dump_texit, "texit")
615 if not outfile then outfile = os.getenv("LUAJIT_DUMPFILE") end
616 if outfile then
617 out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
618 else
619 out = stdout
622 m[colormode] = true
623 if colormode == "A" then
624 colorize = colorize_ansi
625 irtype = irtype_ansi
626 elseif colormode == "H" then
627 colorize = colorize_html
628 irtype = irtype_html
629 out:write(header_html)
630 else
631 colorize = colorize_text
632 irtype = irtype_text
635 active = true
638 -- Public module functions.
639 module(...)
641 on = dumpon
642 off = dumpoff
643 start = dumpon -- For -j command line option.