genlibbc.lua (4966B)
1 ---------------------------------------------------------------------------- 2 -- Lua script to dump the bytecode of the library functions written in Lua. 3 -- The resulting 'buildvm_libbc.h' is used for the build process of LuaJIT. 4 ---------------------------------------------------------------------------- 5 -- Copyright (C) 2005-2016 Mike Pall. All rights reserved. 6 -- Released under the MIT license. See Copyright Notice in luajit.h 7 ---------------------------------------------------------------------------- 8 9 local ffi = require("ffi") 10 local bit = require("bit") 11 local vmdef = require("jit.vmdef") 12 local bcnames = vmdef.bcnames 13 14 local format = string.format 15 16 local isbe = (string.byte(string.dump(function() end), 5) % 2 == 1) 17 18 local function usage(arg) 19 io.stderr:write("Usage: ", arg and arg[0] or "genlibbc", 20 " [-o buildvm_libbc.h] lib_*.c\n") 21 os.exit(1) 22 end 23 24 local function parse_arg(arg) 25 local outfile = "-" 26 if not (arg and arg[1]) then 27 usage(arg) 28 end 29 if arg[1] == "-o" then 30 outfile = arg[2] 31 if not outfile then usage(arg) end 32 arg = {table.unpack(arg, 3)} 33 end 34 return outfile, arg 35 end 36 37 local function read_files(names) 38 local src = "" 39 for _,name in ipairs(names) do 40 local fp = assert(io.open(name)) 41 src = src .. fp:read("*a") 42 fp:close() 43 end 44 return src 45 end 46 47 local function transform_lua(code) 48 local fixup = {} 49 local n = -30000 50 code = string.gsub(code, "CHECK_(%w*)%((.-)%)", function(tp, var) 51 n = n + 1 52 fixup[n] = { "CHECK", tp } 53 return format("%s=%d", var, n) 54 end) 55 code = string.gsub(code, "PAIRS%((.-)%)", function(var) 56 fixup.PAIRS = true 57 return format("nil, %s, 0", var) 58 end) 59 return "return "..code, fixup 60 end 61 62 local function read_uleb128(p) 63 local v = p[0]; p = p + 1 64 if v >= 128 then 65 local sh = 7; v = v - 128 66 repeat 67 local r = p[0] 68 v = v + bit.lshift(bit.band(r, 127), sh) 69 sh = sh + 7 70 p = p + 1 71 until r < 128 72 end 73 return p, v 74 end 75 76 -- ORDER LJ_T 77 local name2itype = { 78 str = 5, func = 9, tab = 12, int = 14, num = 15 79 } 80 81 local BC = {} 82 for i=0,#bcnames/6-1 do 83 BC[string.gsub(string.sub(bcnames, i*6+1, i*6+6), " ", "")] = i 84 end 85 local xop, xra = isbe and 3 or 0, isbe and 2 or 1 86 local xrc, xrb = isbe and 1 or 2, isbe and 0 or 3 87 88 local function fixup_dump(dump, fixup) 89 local buf = ffi.new("uint8_t[?]", #dump+1, dump) 90 local p = buf+5 91 local n, sizebc 92 p, n = read_uleb128(p) 93 local start = p 94 p = p + 4 95 p = read_uleb128(p) 96 p = read_uleb128(p) 97 p, sizebc = read_uleb128(p) 98 local rawtab = {} 99 for i=0,sizebc-1 do 100 local op = p[xop] 101 if op == BC.KSHORT then 102 local rd = p[xrc] + 256*p[xrb] 103 rd = bit.arshift(bit.lshift(rd, 16), 16) 104 local f = fixup[rd] 105 if f then 106 if f[1] == "CHECK" then 107 local tp = f[2] 108 if tp == "tab" then rawtab[p[xra]] = true end 109 p[xop] = tp == "num" and BC.ISNUM or BC.ISTYPE 110 p[xrb] = 0 111 p[xrc] = name2itype[tp] 112 else 113 error("unhandled fixup type: "..f[1]) 114 end 115 end 116 elseif op == BC.TGETV then 117 if rawtab[p[xrb]] then 118 p[xop] = BC.TGETR 119 end 120 elseif op == BC.TSETV then 121 if rawtab[p[xrb]] then 122 p[xop] = BC.TSETR 123 end 124 elseif op == BC.ITERC then 125 if fixup.PAIRS then 126 p[xop] = BC.ITERN 127 end 128 end 129 p = p + 4 130 end 131 return ffi.string(start, n) 132 end 133 134 local function find_defs(src) 135 local defs = {} 136 for name, code in string.gmatch(src, "LJLIB_LUA%(([^)]*)%)%s*/%*(.-)%*/") do 137 local env = {} 138 local tcode, fixup = transform_lua(code) 139 local func = assert(load(tcode, "", nil, env))() 140 defs[name] = fixup_dump(string.dump(func, true), fixup) 141 defs[#defs+1] = name 142 end 143 return defs 144 end 145 146 local function gen_header(defs) 147 local t = {} 148 local function w(x) t[#t+1] = x end 149 w("/* This is a generated file. DO NOT EDIT! */\n\n") 150 w("static const int libbc_endian = ") w(isbe and 1 or 0) w(";\n\n") 151 local s = "" 152 for _,name in ipairs(defs) do 153 s = s .. defs[name] 154 end 155 w("static const uint8_t libbc_code[] = {\n") 156 local n = 0 157 for i=1,#s do 158 local x = string.byte(s, i) 159 w(x); w(",") 160 n = n + (x < 10 and 2 or (x < 100 and 3 or 4)) 161 if n >= 75 then n = 0; w("\n") end 162 end 163 w("0\n};\n\n") 164 w("static const struct { const char *name; int ofs; } libbc_map[] = {\n") 165 local m = 0 166 for _,name in ipairs(defs) do 167 w('{"'); w(name); w('",'); w(m) w('},\n') 168 m = m + #defs[name] 169 end 170 w("{NULL,"); w(m); w("}\n};\n\n") 171 return table.concat(t) 172 end 173 174 local function write_file(name, data) 175 if name == "-" then 176 assert(io.write(data)) 177 assert(io.flush()) 178 else 179 local fp = io.open(name) 180 if fp then 181 local old = fp:read("*a") 182 fp:close() 183 if data == old then return end 184 end 185 fp = assert(io.open(name, "w")) 186 assert(fp:write(data)) 187 assert(fp:close()) 188 end 189 end 190 191 local outfile 192 outfile, arg = parse_arg(arg) 193 local src = read_files(arg) 194 local defs = find_defs(src) 195 local hdr = gen_header(defs) 196 write_file(outfile, hdr) 197