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-55b16959717084884fd4a0cbae6d19e3786c20c7.tar.gz luajit-55b16959717084884fd4a0cbae6d19e3786c20c7.tar.bz2 luajit-55b16959717084884fd4a0cbae6d19e3786c20c7.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 | |||
