Mercurial
comparison third_party/luajit/src/jit/bc.lua @ 186:8cf4ec5e2191 hg-web
Fixed merge conflict.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 23 Jan 2026 22:38:59 -0800 |
| parents | 94705b5986b3 |
| children |
comparison
equal
deleted
inserted
replaced
| 176:fed99fc04e12 | 186:8cf4ec5e2191 |
|---|---|
| 1 ---------------------------------------------------------------------------- | |
| 2 -- LuaJIT bytecode listing module. | |
| 3 -- | |
| 4 -- Copyright (C) 2005-2023 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. | |
| 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 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) | |
| 39 -- | |
| 40 ------------------------------------------------------------------------------ | |
| 41 | |
| 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 | |
| 53 | |
| 54 ------------------------------------------------------------------------------ | |
| 55 | |
| 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)) | |
| 61 end | |
| 62 end | |
| 63 | |
| 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) | |
| 77 end | |
| 78 if mb ~= 0 then | |
| 79 d = band(d, 0xff) | |
| 80 elseif mc == 0 then | |
| 81 return s.."\n" | |
| 82 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 if op == "TSETM " then kc = kc - 2^52 end | |
| 90 elseif mc == 12*128 then -- BCMfunc | |
| 91 local fi = funcinfo(funck(func, -d-1)) | |
| 92 if fi.ffid then | |
| 93 kc = vmdef.ffnames[fi.ffid] | |
| 94 else | |
| 95 kc = fi.loc | |
| 96 end | |
| 97 elseif mc == 5*128 then -- BCMuv | |
| 98 kc = funcuvname(func, d) | |
| 99 end | |
| 100 if ma == 5 then -- BCMuv | |
| 101 local ka = funcuvname(func, a) | |
| 102 if kc then kc = ka.." ; "..kc else kc = ka end | |
| 103 end | |
| 104 if mb ~= 0 then | |
| 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) | |
| 108 end | |
| 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) | |
| 112 end | |
| 113 | |
| 114 -- Collect branch targets of a function. | |
| 115 local function bctargets(func) | |
| 116 local target = {} | |
| 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 | |
| 121 end | |
| 122 return target | |
| 123 end | |
| 124 | |
| 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 | |
| 134 end | |
| 135 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 | |
| 141 out:write(s) | |
| 142 end | |
| 143 out:write("\n") | |
| 144 out:flush() | |
| 145 end | |
| 146 | |
| 147 ------------------------------------------------------------------------------ | |
| 148 | |
| 149 -- Active flag and output file handle. | |
| 150 local active, out | |
| 151 | |
| 152 -- List handler. | |
| 153 local function h_list(func) | |
| 154 return bcdump(func, out) | |
| 155 end | |
| 156 | |
| 157 -- Detach list handler. | |
| 158 local function bclistoff() | |
| 159 if active then | |
| 160 active = false | |
| 161 jit.attach(h_list) | |
| 162 if out and out ~= stdout and out ~= stderr then out:close() end | |
| 163 out = nil | |
| 164 end | |
| 165 end | |
| 166 | |
| 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 | |
| 171 if outfile then | |
| 172 out = outfile == "-" and stdout or assert(io.open(outfile, "w")) | |
| 173 else | |
| 174 out = stderr | |
| 175 end | |
| 176 jit.attach(h_list, "bc") | |
| 177 active = true | |
| 178 end | |
| 179 | |
| 180 -- Public module functions. | |
| 181 return { | |
| 182 line = bcline, | |
| 183 dump = bcdump, | |
| 184 targets = bctargets, | |
| 185 on = bcliston, | |
| 186 off = bclistoff, | |
| 187 start = bcliston -- For -j command line option. | |
| 188 } | |
| 189 |