beta-0.89.2
[luatex.git] / source / libs / luajit / LuaJIT-src / src / jit / bc.lua
blob320039ff3532c810538f94d1853fc7a30533d0bf
1 ----------------------------------------------------------------------------
2 -- LuaJIT bytecode listing module.
3 --
4 -- Copyright (C) 2005-2015 Mike Pall. All rights reserved.
5 -- Released under the MIT license. See Copyright Notice in luajit.h
6 ----------------------------------------------------------------------------
7 --
8 -- This module lists the bytecode of a Lua function. If it's loaded by -jbc
9 -- it hooks into the parser and lists all functions of a chunk as they
10 -- are parsed.
12 -- Example usage:
14 -- luajit -jbc -e 'local x=0; for i=1,1e6 do x=x+i end; print(x)'
15 -- luajit -jbc=- foo.lua
16 -- luajit -jbc=foo.list foo.lua
18 -- Default output is to stderr. To redirect the output to a file, pass a
19 -- filename as an argument (use '-' for stdout) or set the environment
20 -- variable LUAJIT_LISTFILE. The file is overwritten every time the module
21 -- is started.
23 -- This module can also be used programmatically:
25 -- local bc = require("jit.bc")
27 -- local function foo() print("hello") end
29 -- bc.dump(foo) --> -- BYTECODE -- [...]
30 -- print(bc.line(foo, 2)) --> 0002 KSTR 1 1 ; "hello"
32 -- local out = {
33 -- -- Do something with each line:
34 -- write = function(t, ...) io.write(...) end,
35 -- close = function(t) end,
36 -- flush = function(t) end,
37 -- }
38 -- bc.dump(foo, out)
40 ------------------------------------------------------------------------------
42 -- Cache some library functions and objects.
43 local jit = require("jit")
44 assert(jit.version_num == 20100, "LuaJIT core/library version mismatch")
45 local jutil = require("jit.util")
46 local vmdef = require("jit.vmdef")
47 local bit = require("bit")
48 local sub, gsub, format = string.sub, string.gsub, string.format
49 local byte, band, shr = string.byte, bit.band, bit.rshift
50 local funcinfo, funcbc, funck = jutil.funcinfo, jutil.funcbc, jutil.funck
51 local funcuvname = jutil.funcuvname
52 local bcnames = vmdef.bcnames
53 local stdout, stderr = io.stdout, io.stderr
55 ------------------------------------------------------------------------------
57 local function ctlsub(c)
58 if c == "\n" then return "\\n"
59 elseif c == "\r" then return "\\r"
60 elseif c == "\t" then return "\\t"
61 else return format("\\%03d", byte(c))
62 end
63 end
65 -- Return one bytecode line.
66 local function bcline(func, pc, prefix)
67 local ins, m = funcbc(func, pc)
68 if not ins then return end
69 local ma, mb, mc = band(m, 7), band(m, 15*8), band(m, 15*128)
70 local a = band(shr(ins, 8), 0xff)
71 local oidx = 6*band(ins, 0xff)
72 local op = sub(bcnames, oidx+1, oidx+6)
73 local s = format("%04d %s %-6s %3s ",
74 pc, prefix or " ", op, ma == 0 and "" or a)
75 local d = shr(ins, 16)
76 if mc == 13*128 then -- BCMjump
77 return format("%s=> %04d\n", s, pc+d-0x7fff)
78 end
79 if mb ~= 0 then
80 d = band(d, 0xff)
81 elseif mc == 0 then
82 return s.."\n"
83 end
84 local kc
85 if mc == 10*128 then -- BCMstr
86 kc = funck(func, -d-1)
87 kc = format(#kc > 40 and '"%.40s"~' or '"%s"', gsub(kc, "%c", ctlsub))
88 elseif mc == 9*128 then -- BCMnum
89 kc = funck(func, d)
90 if op == "TSETM " then kc = kc - 2^52 end
91 elseif mc == 12*128 then -- BCMfunc
92 local fi = funcinfo(funck(func, -d-1))
93 if fi.ffid then
94 kc = vmdef.ffnames[fi.ffid]
95 else
96 kc = fi.loc
97 end
98 elseif mc == 5*128 then -- BCMuv
99 kc = funcuvname(func, d)
101 if ma == 5 then -- BCMuv
102 local ka = funcuvname(func, a)
103 if kc then kc = ka.." ; "..kc else kc = ka end
105 if mb ~= 0 then
106 local b = shr(ins, 24)
107 if kc then return format("%s%3d %3d ; %s\n", s, b, d, kc) end
108 return format("%s%3d %3d\n", s, b, d)
110 if kc then return format("%s%3d ; %s\n", s, d, kc) end
111 if mc == 7*128 and d > 32767 then d = d - 65536 end -- BCMlits
112 return format("%s%3d\n", s, d)
115 -- Collect branch targets of a function.
116 local function bctargets(func)
117 local target = {}
118 for pc=1,1000000000 do
119 local ins, m = funcbc(func, pc)
120 if not ins then break end
121 if band(m, 15*128) == 13*128 then target[pc+shr(ins, 16)-0x7fff] = true end
123 return target
126 -- Dump bytecode instructions of a function.
127 local function bcdump(func, out, all)
128 if not out then out = stdout end
129 local fi = funcinfo(func)
130 if all and fi.children then
131 for n=-1,-1000000000,-1 do
132 local k = funck(func, n)
133 if not k then break end
134 if type(k) == "proto" then bcdump(k, out, true) end
137 out:write(format("-- BYTECODE -- %s-%d\n", fi.loc, fi.lastlinedefined))
138 local target = bctargets(func)
139 for pc=1,1000000000 do
140 local s = bcline(func, pc, target[pc] and "=>")
141 if not s then break end
142 out:write(s)
144 out:write("\n")
145 out:flush()
148 ------------------------------------------------------------------------------
150 -- Active flag and output file handle.
151 local active, out
153 -- List handler.
154 local function h_list(func)
155 return bcdump(func, out)
158 -- Detach list handler.
159 local function bclistoff()
160 if active then
161 active = false
162 jit.attach(h_list)
163 if out and out ~= stdout and out ~= stderr then out:close() end
164 out = nil
168 -- Open the output file and attach list handler.
169 local function bcliston(outfile)
170 if active then bclistoff() end
171 if not outfile then outfile = os.getenv("LUAJIT_LISTFILE") end
172 if outfile then
173 out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
174 else
175 out = stderr
177 jit.attach(h_list, "bc")
178 active = true
181 -- Public module functions.
182 return {
183 line = bcline,
184 dump = bcdump,
185 targets = bctargets,
186 on = bcliston,
187 off = bclistoff,
188 start = bcliston -- For -j command line option.