Mercurial
comparison third_party/luajit/src/host/genlibbc.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 -- 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-2023 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 table.remove(arg, 1) | |
| 33 table.remove(arg, 1) | |
| 34 end | |
| 35 return outfile | |
| 36 end | |
| 37 | |
| 38 local function read_files(names) | |
| 39 local src = "" | |
| 40 for _,name in ipairs(names) do | |
| 41 local fp = assert(io.open(name)) | |
| 42 src = src .. fp:read("*a") | |
| 43 fp:close() | |
| 44 end | |
| 45 return src | |
| 46 end | |
| 47 | |
| 48 local function transform_lua(code) | |
| 49 local fixup = {} | |
| 50 local n = -30000 | |
| 51 code = string.gsub(code, "CHECK_(%w*)%((.-)%)", function(tp, var) | |
| 52 n = n + 1 | |
| 53 fixup[n] = { "CHECK", tp } | |
| 54 return format("%s=%d", var, n) | |
| 55 end) | |
| 56 code = string.gsub(code, "PAIRS%((.-)%)", function(var) | |
| 57 fixup.PAIRS = true | |
| 58 return format("nil, %s, 0x4dp80", var) | |
| 59 end) | |
| 60 return "return "..code, fixup | |
| 61 end | |
| 62 | |
| 63 local function read_uleb128(p) | |
| 64 local v = p[0]; p = p + 1 | |
| 65 if v >= 128 then | |
| 66 local sh = 7; v = v - 128 | |
| 67 repeat | |
| 68 local r = p[0] | |
| 69 v = v + bit.lshift(bit.band(r, 127), sh) | |
| 70 sh = sh + 7 | |
| 71 p = p + 1 | |
| 72 until r < 128 | |
| 73 end | |
| 74 return p, v | |
| 75 end | |
| 76 | |
| 77 -- ORDER LJ_T | |
| 78 local name2itype = { | |
| 79 str = 5, func = 9, tab = 12, int = 14, num = 15 | |
| 80 } | |
| 81 | |
| 82 local BC, BCN = {}, {} | |
| 83 for i=0,#bcnames/6-1 do | |
| 84 local name = bcnames:sub(i*6+1, i*6+6):gsub(" ", "") | |
| 85 BC[name] = i | |
| 86 BCN[i] = name | |
| 87 end | |
| 88 local xop, xra = isbe and 3 or 0, isbe and 2 or 1 | |
| 89 local xrc, xrb = isbe and 1 or 2, isbe and 0 or 3 | |
| 90 | |
| 91 local function fixup_dump(dump, fixup) | |
| 92 local buf = ffi.new("uint8_t[?]", #dump+1, dump) | |
| 93 local p = buf+5 | |
| 94 local n, sizebc | |
| 95 p, n = read_uleb128(p) | |
| 96 local start = p | |
| 97 p = p + 4 | |
| 98 p = read_uleb128(p) | |
| 99 p = read_uleb128(p) | |
| 100 p, sizebc = read_uleb128(p) | |
| 101 local startbc = tonumber(p - start) | |
| 102 local rawtab = {} | |
| 103 for i=0,sizebc-1 do | |
| 104 local op = p[xop] | |
| 105 if op == BC.KSHORT then | |
| 106 local rd = p[xrc] + 256*p[xrb] | |
| 107 rd = bit.arshift(bit.lshift(rd, 16), 16) | |
| 108 local f = fixup[rd] | |
| 109 if f then | |
| 110 if f[1] == "CHECK" then | |
| 111 local tp = f[2] | |
| 112 if tp == "tab" then rawtab[p[xra]] = true end | |
| 113 p[xop] = tp == "num" and BC.ISNUM or BC.ISTYPE | |
| 114 p[xrb] = 0 | |
| 115 p[xrc] = name2itype[tp] | |
| 116 else | |
| 117 error("unhandled fixup type: "..f[1]) | |
| 118 end | |
| 119 end | |
| 120 elseif op == BC.TGETV then | |
| 121 if rawtab[p[xrb]] then | |
| 122 p[xop] = BC.TGETR | |
| 123 end | |
| 124 elseif op == BC.TSETV then | |
| 125 if rawtab[p[xrb]] then | |
| 126 p[xop] = BC.TSETR | |
| 127 end | |
| 128 elseif op == BC.ITERC then | |
| 129 if fixup.PAIRS then | |
| 130 p[xop] = BC.ITERN | |
| 131 end | |
| 132 end | |
| 133 p = p + 4 | |
| 134 end | |
| 135 local ndump = ffi.string(start, n) | |
| 136 -- Fixup hi-part of 0x4dp80 to LJ_KEYINDEX. | |
| 137 ndump = ndump:gsub("\x80\x80\xcd\xaa\x04", "\xff\xff\xf9\xff\x0f") | |
| 138 return { dump = ndump, startbc = startbc, sizebc = sizebc } | |
| 139 end | |
| 140 | |
| 141 local function find_defs(src) | |
| 142 local defs = {} | |
| 143 for name, code in string.gmatch(src, "LJLIB_LUA%(([^)]*)%)%s*/%*(.-)%*/") do | |
| 144 local env = {} | |
| 145 local tcode, fixup = transform_lua(code) | |
| 146 local func = assert(load(tcode, "", nil, env))() | |
| 147 defs[name] = fixup_dump(string.dump(func, true), fixup) | |
| 148 defs[#defs+1] = name | |
| 149 end | |
| 150 return defs | |
| 151 end | |
| 152 | |
| 153 local function gen_header(defs) | |
| 154 local t = {} | |
| 155 local function w(x) t[#t+1] = x end | |
| 156 w("/* This is a generated file. DO NOT EDIT! */\n\n") | |
| 157 w("static const int libbc_endian = ") w(isbe and 1 or 0) w(";\n\n") | |
| 158 local s, sb = "", "" | |
| 159 for i,name in ipairs(defs) do | |
| 160 local d = defs[name] | |
| 161 s = s .. d.dump | |
| 162 sb = sb .. string.char(i) .. ("\0"):rep(d.startbc - 1) | |
| 163 .. (isbe and "\0\0\0\255" or "\255\0\0\0"):rep(d.sizebc) | |
| 164 .. ("\0"):rep(#d.dump - d.startbc - d.sizebc*4) | |
| 165 end | |
| 166 w("static const uint8_t libbc_code[] = {\n") | |
| 167 local n = 0 | |
| 168 for i=1,#s do | |
| 169 local x = string.byte(s, i) | |
| 170 local xb = string.byte(sb, i) | |
| 171 if xb == 255 then | |
| 172 local name = BCN[x] | |
| 173 local m = #name + 4 | |
| 174 if n + m > 78 then n = 0; w("\n") end | |
| 175 n = n + m | |
| 176 w("BC_"); w(name) | |
| 177 else | |
| 178 local m = x < 10 and 2 or (x < 100 and 3 or 4) | |
| 179 if xb == 0 then | |
| 180 if n + m > 78 then n = 0; w("\n") end | |
| 181 else | |
| 182 local name = defs[xb]:gsub("_", ".") | |
| 183 if n ~= 0 then w("\n") end | |
| 184 w("/* "); w(name); w(" */ ") | |
| 185 n = #name + 7 | |
| 186 end | |
| 187 n = n + m | |
| 188 w(x) | |
| 189 end | |
| 190 w(",") | |
| 191 end | |
| 192 w("\n0\n};\n\n") | |
| 193 w("static const struct { const char *name; int ofs; } libbc_map[] = {\n") | |
| 194 local m = 0 | |
| 195 for _,name in ipairs(defs) do | |
| 196 w('{"'); w(name); w('",'); w(m) w('},\n') | |
| 197 m = m + #defs[name].dump | |
| 198 end | |
| 199 w("{NULL,"); w(m); w("}\n};\n\n") | |
| 200 return table.concat(t) | |
| 201 end | |
| 202 | |
| 203 local function write_file(name, data) | |
| 204 if name == "-" then | |
| 205 assert(io.write(data)) | |
| 206 assert(io.flush()) | |
| 207 else | |
| 208 local fp = io.open(name) | |
| 209 if fp then | |
| 210 local old = fp:read("*a") | |
| 211 fp:close() | |
| 212 if data == old then return end | |
| 213 end | |
| 214 fp = assert(io.open(name, "w")) | |
| 215 assert(fp:write(data)) | |
| 216 assert(fp:close()) | |
| 217 end | |
| 218 end | |
| 219 | |
| 220 local outfile = parse_arg(arg) | |
| 221 local src = read_files(arg) | |
| 222 local defs = find_defs(src) | |
| 223 local hdr = gen_header(defs) | |
| 224 write_file(outfile, hdr) | |
| 225 |