diff options
author | Mike Pall <mike> | 2009-12-08 19:46:35 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2009-12-08 19:46:35 +0100 |
commit | 55b16959717084884fd4a0cbae6d19e3786c20c7 (patch) | |
tree | c8a07a43c13679751ed25a9d06796e9e7b2134a6 /lib/bc.lua | |
download | luajit-2.0.0-beta1.tar.gz luajit-2.0.0-beta1.tar.bz2 luajit-2.0.0-beta1.zip |
RELEASE LuaJIT-2.0.0-beta1v2.0.0-beta1
Diffstat (limited to 'lib/bc.lua')
-rw-r--r-- | lib/bc.lua | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/lib/bc.lua b/lib/bc.lua new file mode 100644 index 00000000..532f2493 --- /dev/null +++ b/lib/bc.lua | |||
@@ -0,0 +1,182 @@ | |||
1 | ---------------------------------------------------------------------------- | ||
2 | -- LuaJIT bytecode listing module. | ||
3 | -- | ||
4 | -- Copyright (C) 2005-2009 Mike Pall. All rights reserved. | ||
5 | -- Released under the MIT/X 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. | ||
11 | -- | ||
12 | -- Example usage: | ||
13 | -- | ||
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 | ||
17 | -- | ||
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. | ||
22 | -- | ||
23 | -- This module can also be used programmatically: | ||
24 | -- | ||
25 | -- local bc = require("jit.bc") | ||
26 | -- | ||
27 | -- local function foo() print("hello") end | ||
28 | -- | ||
29 | -- bc.dump(foo) --> -- BYTECODE -- [...] | ||
30 | -- print(bc.line(foo, 2)) --> 0002 KSTR 1 1 ; "hello" | ||
31 | -- | ||
32 | -- local out = { | ||
33 | -- -- Do something wich 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) | ||
39 | -- | ||
40 | ------------------------------------------------------------------------------ | ||
41 | |||
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 | ||
54 | |||
55 | ------------------------------------------------------------------------------ | ||
56 | |||
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)) | ||
63 | end | ||
64 | end | ||
65 | |||
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 s = format("%04d %s %-6s %3s ", | ||
74 | pc, prefix or " ", sub(bcnames, oidx+1, oidx+6), ma == 0 and "" or a) | ||
75 | local d = shr(ins, 16) | ||
76 | if mc == 13*128 then -- BCMjump | ||
77 | if ma == 0 then | ||
78 | return format("%s=> %04d\n", sub(s, 1, -3), pc+d-0x7fff) | ||
79 | end | ||
80 | return format("%s=> %04d\n", s, pc+d-0x7fff) | ||
81 | end | ||
82 | if mb ~= 0 then d = band(d, 0xff) end | ||
83 | local kc | ||
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 | ||
88 | kc = funck(func, d) | ||
89 | elseif mc == 12*128 then -- BCMfunc | ||
90 | local fi = funcinfo(funck(func, -d-1)) | ||
91 | if fi.ffid then | ||
92 | kc = vmdef.ffnames[fi.ffid] | ||
93 | else | ||
94 | kc = fi.loc | ||
95 | end | ||
96 | elseif mc == 5*128 then -- BCMuv | ||
97 | kc = funcuvname(func, d) | ||
98 | end | ||
99 | if ma == 5 then -- BCMuv | ||
100 | local ka = funcuvname(func, a) | ||
101 | if kc then kc = ka.." ; "..kc else kc = ka end | ||
102 | end | ||
103 | if mb ~= 0 then | ||
104 | local b = shr(ins, 24) | ||
105 | if kc then return format("%s%3d %3d ; %s\n", s, b, d, kc) end | ||
106 | return format("%s%3d %3d\n", s, b, d) | ||
107 | end | ||
108 | if kc then return format("%s%3d ; %s\n", s, d, kc) end | ||
109 | if mc == 7*128 and d > 32767 then d = d - 65536 end -- BCMlits | ||
110 | return format("%s%3d\n", s, d) | ||
111 | end | ||
112 | |||
113 | -- Collect branch targets of a function. | ||
114 | local function bctargets(func) | ||
115 | local target = {} | ||
116 | for pc=1,1000000000 do | ||
117 | local ins, m = funcbc(func, pc) | ||
118 | if not ins then break end | ||
119 | if band(m, 15*128) == 13*128 then target[pc+shr(ins, 16)-0x7fff] = true end | ||
120 | end | ||
121 | return target | ||
122 | end | ||
123 | |||
124 | -- Dump bytecode instructions of a function. | ||
125 | local function bcdump(func, out) | ||
126 | if not out then out = stdout end | ||
127 | local fi = funcinfo(func) | ||
128 | out:write(format("-- BYTECODE -- %s-%d\n", fi.loc, fi.lastlinedefined)) | ||
129 | local target = bctargets(func) | ||
130 | for pc=1,1000000000 do | ||
131 | local s = bcline(func, pc, target[pc] and "=>") | ||
132 | if not s then break end | ||
133 | out:write(s) | ||
134 | end | ||
135 | out:write("\n") | ||
136 | out:flush() | ||
137 | end | ||
138 | |||
139 | ------------------------------------------------------------------------------ | ||
140 | |||
141 | -- Active flag and output file handle. | ||
142 | local active, out | ||
143 | |||
144 | -- List handler. | ||
145 | local function h_list(func) | ||
146 | return bcdump(func, out) | ||
147 | end | ||
148 | |||
149 | -- Detach list handler. | ||
150 | local function bclistoff() | ||
151 | if active then | ||
152 | active = false | ||
153 | jit.attach(h_list) | ||
154 | if out and out ~= stdout and out ~= stderr then out:close() end | ||
155 | out = nil | ||
156 | end | ||
157 | end | ||
158 | |||
159 | -- Open the output file and attach list handler. | ||
160 | local function bcliston(outfile) | ||
161 | if active then bclistoff() end | ||
162 | if not outfile then outfile = os.getenv("LUAJIT_LISTFILE") end | ||
163 | if outfile then | ||
164 | out = outfile == "-" and stdout or assert(io.open(outfile, "w")) | ||
165 | else | ||
166 | out = stderr | ||
167 | end | ||
168 | jit.attach(h_list, "bc") | ||
169 | active = true | ||
170 | end | ||
171 | |||
172 | -- Public module functions. | ||
173 | module(...) | ||
174 | |||
175 | line = bcline | ||
176 | dump = bcdump | ||
177 | targets = bctargets | ||
178 | |||
179 | on = bcliston | ||
180 | off = bclistoff | ||
181 | start = bcliston -- For -j command line option. | ||
182 | |||