1 ----------------------------------------------------------------------------
2 -- LuaJIT bytecode listing module.
4 -- Copyright (C) 2005-2011 Mike Pall. All rights reserved.
5 -- Released under the MIT/X license. See Copyright Notice in luajit.h
6 ----------------------------------------------------------------------------
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
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
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"
33 -- -- Do something with each line:
34 -- write = function(t, ...) io.write(...) end,
35 -- close = function(t) end,
36 -- flush = function(t) end,
40 ------------------------------------------------------------------------------
42 -- Cache some library functions and objects.
43 local jit
= require("jit")
44 assert(jit
.version_num
== 20000, "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 elseif c
== "\r" then return "\\r"
62 else return format("\\%03d", byte(c
))
66 -- Return one bytecode line.
67 local function bcline(func
, pc
, prefix
)
68 local ins
, m
= funcbc(func
, pc
)
69 if not ins
then return end
70 local ma
, mb
, mc
= band(m
, 7), band(m
, 15*8), band(m
, 15*128)
71 local a
= band(shr(ins
, 8), 0xff)
72 local oidx
= 6*band(ins
, 0xff)
73 local op
= sub(bcnames
, oidx
+1, oidx
+6)
74 local s
= format("%04d %s %-6s %3s ",
75 pc
, prefix
or " ", op
, ma
== 0 and "" or a
)
76 local d
= shr(ins
, 16)
77 if mc
== 13*128 then -- BCMjump
78 return format("%s=> %04d\n", s
, pc
+d
-0x7fff)
86 if mc
== 10*128 then -- BCMstr
87 kc
= funck(func
, -d
-1)
88 kc
= format(#kc
> 40 and '"%.40s"~' or '"%s"', gsub(kc
, "%c", ctlsub
))
89 elseif mc
== 9*128 then -- BCMnum
91 if op
== "TSETM " then kc
= kc
- 2^
52 end
92 elseif mc
== 12*128 then -- BCMfunc
93 local fi
= funcinfo(funck(func
, -d
-1))
95 kc
= vmdef
.ffnames
[fi
.ffid
]
99 elseif mc
== 5*128 then -- BCMuv
100 kc
= funcuvname(func
, d
)
102 if ma
== 5 then -- BCMuv
103 local ka
= funcuvname(func
, a
)
104 if kc
then kc
= ka
.." ; "..kc
else kc
= ka
end
107 local b
= shr(ins
, 24)
108 if kc
then return format("%s%3d %3d ; %s\n", s
, b
, d
, kc
) end
109 return format("%s%3d %3d\n", s
, b
, d
)
111 if kc
then return format("%s%3d ; %s\n", s
, d
, kc
) end
112 if mc
== 7*128 and d
> 32767 then d
= d
- 65536 end -- BCMlits
113 return format("%s%3d\n", s
, d
)
116 -- Collect branch targets of a function.
117 local function bctargets(func
)
119 for pc
=1,1000000000 do
120 local ins
, m
= funcbc(func
, pc
)
121 if not ins
then break end
122 if band(m
, 15*128) == 13*128 then target
[pc
+shr(ins
, 16)-0x7fff] = true end
127 -- Dump bytecode instructions of a function.
128 local function bcdump(func
, out
)
129 if not out
then out
= stdout
end
130 local fi
= funcinfo(func
)
131 out
:write(format("-- BYTECODE -- %s-%d\n", fi
.loc
, fi
.lastlinedefined
))
132 local target
= bctargets(func
)
133 for pc
=1,1000000000 do
134 local s
= bcline(func
, pc
, target
[pc
] and "=>")
135 if not s
then break end
142 ------------------------------------------------------------------------------
144 -- Active flag and output file handle.
148 local function h_list(func
)
149 return bcdump(func
, out
)
152 -- Detach list handler.
153 local function bclistoff()
157 if out
and out
~= stdout
and out
~= stderr
then out
:close() end
162 -- Open the output file and attach list handler.
163 local function bcliston(outfile
)
164 if active
then bclistoff() end
165 if not outfile
then outfile
= os
.getenv("LUAJIT_LISTFILE") end
167 out
= outfile
== "-" and stdout
or assert(io
.open(outfile
, "w"))
171 jit
.attach(h_list
, "bc")
175 -- Public module functions.
184 start
= bcliston
-- For -j command line option.