summaryrefslogtreecommitdiff
path: root/src/host/genlibbc.lua
diff options
context:
space:
mode:
Diffstat (limited to 'src/host/genlibbc.lua')
-rw-r--r--src/host/genlibbc.lua225
1 files changed, 225 insertions, 0 deletions
diff --git a/src/host/genlibbc.lua b/src/host/genlibbc.lua
new file mode 100644
index 00000000..3621c3f5
--- /dev/null
+++ b/src/host/genlibbc.lua
@@ -0,0 +1,225 @@
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
9local ffi = require("ffi")
10local bit = require("bit")
11local vmdef = require("jit.vmdef")
12local bcnames = vmdef.bcnames
13
14local format = string.format
15
16local isbe = (string.byte(string.dump(function() end), 5) % 2 == 1)
17
18local 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)
22end
23
24local 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
36end
37
38local 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
46end
47
48local 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
61end
62
63local 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
75end
76
77-- ORDER LJ_T
78local name2itype = {
79 str = 5, func = 9, tab = 12, int = 14, num = 15
80}
81
82local BC, BCN = {}, {}
83for 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
87end
88local xop, xra = isbe and 3 or 0, isbe and 2 or 1
89local xrc, xrb = isbe and 1 or 2, isbe and 0 or 3
90
91local 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 }
139end
140
141local 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
151end
152
153local 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)
201end
202
203local 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
218end
219
220local outfile = parse_arg(arg)
221local src = read_files(arg)
222local defs = find_defs(src)
223local hdr = gen_header(defs)
224write_file(outfile, hdr)
225