1 ----------------------------------------------------------------------------
2 -- LuaJIT bytecode listing module.
4 -- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
5 -- Released under the MIT 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 local jutil
= require("jit.util")
45 local vmdef
= require("jit.vmdef")
46 local bit
= require("bit")
47 local sub
, gsub, format = string.sub
, string.gsub, string.format
48 local byte
, band
, shr
= string.byte
, bit
.band
, bit
.rshift
49 local funcinfo
, funcbc
, funck
= jutil
.funcinfo
, jutil
.funcbc
, jutil
.funck
50 local funcuvname
= jutil
.funcuvname
51 local bcnames
= vmdef
.bcnames
52 local stdout
, stderr
= io
.stdout
, io
.stderr
54 ------------------------------------------------------------------------------
56 local function ctlsub(c
)
57 if c
== "\n" then return "\\n"
58 elseif c
== "\r" then return "\\r"
59 elseif c
== "\t" then return "\\t"
60 else return format("\\%03d", byte(c
))
64 -- Return one bytecode line.
65 local function bcline(func
, pc
, prefix
)
66 local ins
, m
= funcbc(func
, pc
)
67 if not ins
then return end
68 local ma
, mb
, mc
= band(m
, 7), band(m
, 15*8), band(m
, 15*128)
69 local a
= band(shr(ins
, 8), 0xff)
70 local oidx
= 6*band(ins
, 0xff)
71 local op
= sub(bcnames
, oidx
+1, oidx
+6)
72 local s
= format("%04d %s %-6s %3s ",
73 pc
, prefix
or " ", op
, ma
== 0 and "" or a
)
74 local d
= shr(ins
, 16)
75 if mc
== 13*128 then -- BCMjump
76 return format("%s=> %04d\n", s
, pc
+d
-0x7fff)
84 if mc
== 10*128 then -- BCMstr
85 kc
= funck(func
, -d
-1)
86 kc
= format(#kc
> 40 and '"%.40s"~' or '"%s"', gsub(kc
, "%c", ctlsub
))
87 elseif mc
== 9*128 then -- BCMnum
89 if op
== "TSETM " then kc
= kc
- 2^
52 end
90 elseif mc
== 12*128 then -- BCMfunc
91 local fi
= funcinfo(funck(func
, -d
-1))
93 kc
= vmdef
.ffnames
[fi
.ffid
]
97 elseif mc
== 5*128 then -- BCMuv
98 kc
= funcuvname(func
, d
)
100 if ma
== 5 then -- BCMuv
101 local ka
= funcuvname(func
, a
)
102 if kc
then kc
= ka
.." ; "..kc
else kc
= ka
end
105 local b
= shr(ins
, 24)
106 if kc
then return format("%s%3d %3d ; %s\n", s
, b
, d
, kc
) end
107 return format("%s%3d %3d\n", s
, b
, d
)
109 if kc
then return format("%s%3d ; %s\n", s
, d
, kc
) end
110 if mc
== 7*128 and d
> 32767 then d
= d
- 65536 end -- BCMlits
111 return format("%s%3d\n", s
, d
)
114 -- Collect branch targets of a function.
115 local function bctargets(func
)
117 for pc
=1,1000000000 do
118 local ins
, m
= funcbc(func
, pc
)
119 if not ins
then break end
120 if band(m
, 15*128) == 13*128 then target
[pc
+shr(ins
, 16)-0x7fff] = true end
125 -- Dump bytecode instructions of a function.
126 local function bcdump(func
, out
, all
)
127 if not out
then out
= stdout
end
128 local fi
= funcinfo(func
)
129 if all
and fi
.children
then
130 for n
=-1,-1000000000,-1 do
131 local k
= funck(func
, n
)
132 if not k
then break end
133 if type(k
) == "proto" then bcdump(k
, out
, true) end
136 out
:write(format("-- BYTECODE -- %s-%d\n", fi
.loc
, fi
.lastlinedefined
))
137 local target
= bctargets(func
)
138 for pc
=1,1000000000 do
139 local s
= bcline(func
, pc
, target
[pc
] and "=>")
140 if not s
then break end
147 ------------------------------------------------------------------------------
149 -- Active flag and output file handle.
153 local function h_list(func
)
154 return bcdump(func
, out
)
157 -- Detach list handler.
158 local function bclistoff()
162 if out
and out
~= stdout
and out
~= stderr
then out
:close() end
167 -- Open the output file and attach list handler.
168 local function bcliston(outfile
)
169 if active
then bclistoff() end
170 if not outfile
then outfile
= os
.getenv("LUAJIT_LISTFILE") end
172 out
= outfile
== "-" and stdout
or assert(io
.open(outfile
, "w"))
176 jit
.attach(h_list
, "bc")
180 -- Public module functions.
187 start
= bcliston
-- For -j command line option.