diff options
Diffstat (limited to '')
-rw-r--r-- | src/host/buildvm.c | 15 | ||||
-rw-r--r-- | src/host/buildvm_lib.c | 61 | ||||
-rw-r--r-- | src/host/buildvm_libbc.h | 30 | ||||
-rw-r--r-- | src/host/genlibbc.lua | 197 |
4 files changed, 295 insertions, 8 deletions
diff --git a/src/host/buildvm.c b/src/host/buildvm.c index 2ce3b638..ce892006 100644 --- a/src/host/buildvm.c +++ b/src/host/buildvm.c | |||
@@ -320,20 +320,20 @@ static void emit_vmdef(BuildCtx *ctx) | |||
320 | char buf[80]; | 320 | char buf[80]; |
321 | int i; | 321 | int i; |
322 | fprintf(ctx->fp, "-- This is a generated file. DO NOT EDIT!\n\n"); | 322 | fprintf(ctx->fp, "-- This is a generated file. DO NOT EDIT!\n\n"); |
323 | fprintf(ctx->fp, "module(...)\n\n"); | 323 | fprintf(ctx->fp, "return {\n\n"); |
324 | 324 | ||
325 | fprintf(ctx->fp, "bcnames = \""); | 325 | fprintf(ctx->fp, "bcnames = \""); |
326 | for (i = 0; bc_names[i]; i++) fprintf(ctx->fp, "%-6s", bc_names[i]); | 326 | for (i = 0; bc_names[i]; i++) fprintf(ctx->fp, "%-6s", bc_names[i]); |
327 | fprintf(ctx->fp, "\"\n\n"); | 327 | fprintf(ctx->fp, "\",\n\n"); |
328 | 328 | ||
329 | fprintf(ctx->fp, "irnames = \""); | 329 | fprintf(ctx->fp, "irnames = \""); |
330 | for (i = 0; ir_names[i]; i++) fprintf(ctx->fp, "%-6s", ir_names[i]); | 330 | for (i = 0; ir_names[i]; i++) fprintf(ctx->fp, "%-6s", ir_names[i]); |
331 | fprintf(ctx->fp, "\"\n\n"); | 331 | fprintf(ctx->fp, "\",\n\n"); |
332 | 332 | ||
333 | fprintf(ctx->fp, "irfpm = { [0]="); | 333 | fprintf(ctx->fp, "irfpm = { [0]="); |
334 | for (i = 0; irfpm_names[i]; i++) | 334 | for (i = 0; irfpm_names[i]; i++) |
335 | fprintf(ctx->fp, "\"%s\", ", lower(buf, irfpm_names[i])); | 335 | fprintf(ctx->fp, "\"%s\", ", lower(buf, irfpm_names[i])); |
336 | fprintf(ctx->fp, "}\n\n"); | 336 | fprintf(ctx->fp, "},\n\n"); |
337 | 337 | ||
338 | fprintf(ctx->fp, "irfield = { [0]="); | 338 | fprintf(ctx->fp, "irfield = { [0]="); |
339 | for (i = 0; irfield_names[i]; i++) { | 339 | for (i = 0; irfield_names[i]; i++) { |
@@ -343,17 +343,17 @@ static void emit_vmdef(BuildCtx *ctx) | |||
343 | if (p) *p = '.'; | 343 | if (p) *p = '.'; |
344 | fprintf(ctx->fp, "\"%s\", ", buf); | 344 | fprintf(ctx->fp, "\"%s\", ", buf); |
345 | } | 345 | } |
346 | fprintf(ctx->fp, "}\n\n"); | 346 | fprintf(ctx->fp, "},\n\n"); |
347 | 347 | ||
348 | fprintf(ctx->fp, "ircall = {\n[0]="); | 348 | fprintf(ctx->fp, "ircall = {\n[0]="); |
349 | for (i = 0; ircall_names[i]; i++) | 349 | for (i = 0; ircall_names[i]; i++) |
350 | fprintf(ctx->fp, "\"%s\",\n", ircall_names[i]); | 350 | fprintf(ctx->fp, "\"%s\",\n", ircall_names[i]); |
351 | fprintf(ctx->fp, "}\n\n"); | 351 | fprintf(ctx->fp, "},\n\n"); |
352 | 352 | ||
353 | fprintf(ctx->fp, "traceerr = {\n[0]="); | 353 | fprintf(ctx->fp, "traceerr = {\n[0]="); |
354 | for (i = 0; trace_errors[i]; i++) | 354 | for (i = 0; trace_errors[i]; i++) |
355 | fprintf(ctx->fp, "\"%s\",\n", trace_errors[i]); | 355 | fprintf(ctx->fp, "\"%s\",\n", trace_errors[i]); |
356 | fprintf(ctx->fp, "}\n\n"); | 356 | fprintf(ctx->fp, "},\n\n"); |
357 | } | 357 | } |
358 | 358 | ||
359 | /* -- Argument parsing ---------------------------------------------------- */ | 359 | /* -- Argument parsing ---------------------------------------------------- */ |
@@ -490,6 +490,7 @@ int main(int argc, char **argv) | |||
490 | case BUILD_vmdef: | 490 | case BUILD_vmdef: |
491 | emit_vmdef(ctx); | 491 | emit_vmdef(ctx); |
492 | emit_lib(ctx); | 492 | emit_lib(ctx); |
493 | fprintf(ctx->fp, "}\n\n"); | ||
493 | break; | 494 | break; |
494 | case BUILD_ffdef: | 495 | case BUILD_ffdef: |
495 | case BUILD_libdef: | 496 | case BUILD_libdef: |
diff --git a/src/host/buildvm_lib.c b/src/host/buildvm_lib.c index 40141dfb..f578bbc9 100644 --- a/src/host/buildvm_lib.c +++ b/src/host/buildvm_lib.c | |||
@@ -5,7 +5,9 @@ | |||
5 | 5 | ||
6 | #include "buildvm.h" | 6 | #include "buildvm.h" |
7 | #include "lj_obj.h" | 7 | #include "lj_obj.h" |
8 | #include "lj_bc.h" | ||
8 | #include "lj_lib.h" | 9 | #include "lj_lib.h" |
10 | #include "buildvm_libbc.h" | ||
9 | 11 | ||
10 | /* Context for library definitions. */ | 12 | /* Context for library definitions. */ |
11 | static uint8_t obuf[8192]; | 13 | static uint8_t obuf[8192]; |
@@ -151,6 +153,62 @@ static void libdef_func(BuildCtx *ctx, char *p, int arg) | |||
151 | regfunc = REGFUNC_OK; | 153 | regfunc = REGFUNC_OK; |
152 | } | 154 | } |
153 | 155 | ||
156 | static uint8_t *libdef_uleb128(uint8_t *p, uint32_t *vv) | ||
157 | { | ||
158 | uint32_t v = *p++; | ||
159 | if (v >= 0x80) { | ||
160 | int sh = 0; v &= 0x7f; | ||
161 | do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80); | ||
162 | } | ||
163 | *vv = v; | ||
164 | return p; | ||
165 | } | ||
166 | |||
167 | static void libdef_fixupbc(uint8_t *p) | ||
168 | { | ||
169 | uint32_t i, sizebc; | ||
170 | p += 4; | ||
171 | p = libdef_uleb128(p, &sizebc); | ||
172 | p = libdef_uleb128(p, &sizebc); | ||
173 | p = libdef_uleb128(p, &sizebc); | ||
174 | for (i = 0; i < sizebc; i++, p += 4) { | ||
175 | uint8_t op = p[libbc_endian ? 3 : 0]; | ||
176 | uint8_t ra = p[libbc_endian ? 2 : 1]; | ||
177 | uint8_t rc = p[libbc_endian ? 1 : 2]; | ||
178 | uint8_t rb = p[libbc_endian ? 0 : 3]; | ||
179 | if (!LJ_DUALNUM && op == BC_ISTYPE && rc == ~LJ_TNUMX+1) { | ||
180 | op = BC_ISNUM; rc++; | ||
181 | } | ||
182 | p[LJ_ENDIAN_SELECT(0, 3)] = op; | ||
183 | p[LJ_ENDIAN_SELECT(1, 2)] = ra; | ||
184 | p[LJ_ENDIAN_SELECT(2, 1)] = rc; | ||
185 | p[LJ_ENDIAN_SELECT(3, 0)] = rb; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | static void libdef_lua(BuildCtx *ctx, char *p, int arg) | ||
190 | { | ||
191 | UNUSED(arg); | ||
192 | if (ctx->mode == BUILD_libdef) { | ||
193 | int i; | ||
194 | for (i = 0; libbc_map[i].name != NULL; i++) { | ||
195 | if (!strcmp(libbc_map[i].name, p)) { | ||
196 | int ofs = libbc_map[i].ofs; | ||
197 | int len = libbc_map[i+1].ofs - ofs; | ||
198 | obuf[2]++; /* Bump hash table size. */ | ||
199 | *optr++ = LIBINIT_LUA; | ||
200 | libdef_name(p, 0); | ||
201 | memcpy(optr, libbc_code + ofs, len); | ||
202 | libdef_fixupbc(optr); | ||
203 | optr += len; | ||
204 | return; | ||
205 | } | ||
206 | } | ||
207 | fprintf(stderr, "Error: missing libbc definition for %s\n", p); | ||
208 | exit(1); | ||
209 | } | ||
210 | } | ||
211 | |||
154 | static uint32_t find_rec(char *name) | 212 | static uint32_t find_rec(char *name) |
155 | { | 213 | { |
156 | char *p = (char *)obuf; | 214 | char *p = (char *)obuf; |
@@ -277,6 +335,7 @@ static const LibDefHandler libdef_handlers[] = { | |||
277 | { "CF(", ")", libdef_func, LIBINIT_CF }, | 335 | { "CF(", ")", libdef_func, LIBINIT_CF }, |
278 | { "ASM(", ")", libdef_func, LIBINIT_ASM }, | 336 | { "ASM(", ")", libdef_func, LIBINIT_ASM }, |
279 | { "ASM_(", ")", libdef_func, LIBINIT_ASM_ }, | 337 | { "ASM_(", ")", libdef_func, LIBINIT_ASM_ }, |
338 | { "LUA(", ")", libdef_lua, 0 }, | ||
280 | { "REC(", ")", libdef_rec, 0 }, | 339 | { "REC(", ")", libdef_rec, 0 }, |
281 | { "PUSH(", ")", libdef_push, 0 }, | 340 | { "PUSH(", ")", libdef_push, 0 }, |
282 | { "SET(", ")", libdef_set, 0 }, | 341 | { "SET(", ")", libdef_set, 0 }, |
@@ -373,7 +432,7 @@ void emit_lib(BuildCtx *ctx) | |||
373 | "#ifndef FF_NUM_ASMFUNC\n#define FF_NUM_ASMFUNC %d\n#endif\n\n", | 432 | "#ifndef FF_NUM_ASMFUNC\n#define FF_NUM_ASMFUNC %d\n#endif\n\n", |
374 | ffasmfunc); | 433 | ffasmfunc); |
375 | } else if (ctx->mode == BUILD_vmdef) { | 434 | } else if (ctx->mode == BUILD_vmdef) { |
376 | fprintf(ctx->fp, "}\n\n"); | 435 | fprintf(ctx->fp, "},\n\n"); |
377 | } else if (ctx->mode == BUILD_bcdef) { | 436 | } else if (ctx->mode == BUILD_bcdef) { |
378 | int i; | 437 | int i; |
379 | fprintf(ctx->fp, "\n};\n\n"); | 438 | fprintf(ctx->fp, "\n};\n\n"); |
diff --git a/src/host/buildvm_libbc.h b/src/host/buildvm_libbc.h new file mode 100644 index 00000000..e96c8a53 --- /dev/null +++ b/src/host/buildvm_libbc.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* This is a generated file. DO NOT EDIT! */ | ||
2 | |||
3 | static const int libbc_endian = 0; | ||
4 | |||
5 | static const uint8_t libbc_code[] = { | ||
6 | 0,1,2,0,0,1,2,24,1,0,0,76,1,2,0,241,135,158,166,3,220,203,178,130,4,0,1,2,0, | ||
7 | 0,1,2,24,1,0,0,76,1,2,0,243,244,148,165,20,198,190,199,252,3,0,1,2,0,0,0,3, | ||
8 | 16,0,5,0,21,1,0,0,76,1,2,0,0,2,9,0,0,0,15,16,0,12,0,16,1,9,0,41,2,1,0,21,3, | ||
9 | 0,0,41,4,1,0,77,2,8,128,18,6,1,0,18,7,5,0,59,8,5,0,66,6,3,2,10,6,0,0,88,7,1, | ||
10 | 128,76,6,2,0,79,2,248,127,75,0,1,0,0,2,10,0,0,0,16,16,0,12,0,16,1,9,0,43,2, | ||
11 | 0,0,18,3,0,0,41,4,0,0,88,5,7,128,18,7,1,0,18,8,5,0,18,9,6,0,66,7,3,2,10,7,0, | ||
12 | 0,88,8,1,128,76,7,2,0,70,5,3,3,82,5,247,127,75,0,1,0,0,1,2,0,0,0,3,16,0,12, | ||
13 | 0,21,1,0,0,76,1,2,0,0,2,10,0,0,2,30,16,0,12,0,21,2,0,0,11,1,0,0,88,3,7,128, | ||
14 | 8,2,0,0,88,3,23,128,59,3,2,0,43,4,0,0,64,4,2,0,76,3,2,0,88,3,18,128,16,1,14, | ||
15 | 0,41,3,1,0,3,3,1,0,88,3,14,128,3,1,2,0,88,3,12,128,59,3,1,0,22,4,1,1,18,5,2, | ||
16 | 0,41,6,1,0,77,4,4,128,23,8,1,7,59,9,7,0,64,9,8,0,79,4,252,127,43,4,0,0,64,4, | ||
17 | 2,0,76,3,2,0,75,0,1,0,0,2,0 | ||
18 | }; | ||
19 | |||
20 | static const struct { const char *name; int ofs; } libbc_map[] = { | ||
21 | {"math_deg",0}, | ||
22 | {"math_rad",25}, | ||
23 | {"string_len",50}, | ||
24 | {"table_foreachi",69}, | ||
25 | {"table_foreach",136}, | ||
26 | {"table_getn",207}, | ||
27 | {"table_remove",226}, | ||
28 | {NULL,355} | ||
29 | }; | ||
30 | |||
diff --git a/src/host/genlibbc.lua b/src/host/genlibbc.lua new file mode 100644 index 00000000..16f0a0b6 --- /dev/null +++ b/src/host/genlibbc.lua | |||
@@ -0,0 +1,197 @@ | |||
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-2013 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, 0", 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 = {} | ||
83 | for i=0,#bcnames/6-1 do | ||
84 | BC[string.gsub(string.sub(bcnames, i*6+1, i*6+6), " ", "")] = i | ||
85 | end | ||
86 | local xop, xra = isbe and 3 or 0, isbe and 2 or 1 | ||
87 | local xrc, xrb = isbe and 1 or 2, isbe and 0 or 3 | ||
88 | |||
89 | local function fixup_dump(dump, fixup) | ||
90 | local buf = ffi.new("uint8_t[?]", #dump+1, dump) | ||
91 | local p = buf+5 | ||
92 | local n, sizebc | ||
93 | p, n = read_uleb128(p) | ||
94 | local start = p | ||
95 | p = p + 4 | ||
96 | p = read_uleb128(p) | ||
97 | p = read_uleb128(p) | ||
98 | p, sizebc = read_uleb128(p) | ||
99 | local rawtab = {} | ||
100 | for i=0,sizebc-1 do | ||
101 | local op = p[xop] | ||
102 | if op == BC.KSHORT then | ||
103 | local rd = p[xrc] + 256*p[xrb] | ||
104 | rd = bit.arshift(bit.lshift(rd, 16), 16) | ||
105 | local f = fixup[rd] | ||
106 | if f then | ||
107 | if f[1] == "CHECK" then | ||
108 | local tp = f[2] | ||
109 | if tp == "tab" then rawtab[p[xra]] = true end | ||
110 | p[xop] = tp == "num" and BC.ISNUM or BC.ISTYPE | ||
111 | p[xrb] = 0 | ||
112 | p[xrc] = name2itype[tp] | ||
113 | else | ||
114 | error("unhandled fixup type: "..f[1]) | ||
115 | end | ||
116 | end | ||
117 | elseif op == BC.TGETV then | ||
118 | if rawtab[p[xrb]] then | ||
119 | p[xop] = BC.TGETR | ||
120 | end | ||
121 | elseif op == BC.TSETV then | ||
122 | if rawtab[p[xrb]] then | ||
123 | p[xop] = BC.TSETR | ||
124 | end | ||
125 | elseif op == BC.ITERC then | ||
126 | if fixup.PAIRS then | ||
127 | p[xop] = BC.ITERN | ||
128 | end | ||
129 | end | ||
130 | p = p + 4 | ||
131 | end | ||
132 | return ffi.string(start, n) | ||
133 | end | ||
134 | |||
135 | local function find_defs(src) | ||
136 | local defs = {} | ||
137 | for name, code in string.gmatch(src, "LJLIB_LUA%(([^)]*)%)%s*/%*(.-)%*/") do | ||
138 | local env = {} | ||
139 | local tcode, fixup = transform_lua(code) | ||
140 | local func = assert(load(tcode, "", nil, env))() | ||
141 | defs[name] = fixup_dump(string.dump(func, true), fixup) | ||
142 | defs[#defs+1] = name | ||
143 | end | ||
144 | return defs | ||
145 | end | ||
146 | |||
147 | local function gen_header(defs) | ||
148 | local t = {} | ||
149 | local function w(x) t[#t+1] = x end | ||
150 | w("/* This is a generated file. DO NOT EDIT! */\n\n") | ||
151 | w("static const int libbc_endian = ") w(isbe and 1 or 0) w(";\n\n") | ||
152 | local s = "" | ||
153 | for _,name in ipairs(defs) do | ||
154 | s = s .. defs[name] | ||
155 | end | ||
156 | w("static const uint8_t libbc_code[] = {\n") | ||
157 | local n = 0 | ||
158 | for i=1,#s do | ||
159 | local x = string.byte(s, i) | ||
160 | w(x); w(",") | ||
161 | n = n + (x < 10 and 2 or (x < 100 and 3 or 4)) | ||
162 | if n >= 75 then n = 0; w("\n") end | ||
163 | end | ||
164 | w("0\n};\n\n") | ||
165 | w("static const struct { const char *name; int ofs; } libbc_map[] = {\n") | ||
166 | local m = 0 | ||
167 | for _,name in ipairs(defs) do | ||
168 | w('{"'); w(name); w('",'); w(m) w('},\n') | ||
169 | m = m + #defs[name] | ||
170 | end | ||
171 | w("{NULL,"); w(m); w("}\n};\n\n") | ||
172 | return table.concat(t) | ||
173 | end | ||
174 | |||
175 | local function write_file(name, data) | ||
176 | if name == "-" then | ||
177 | assert(io.write(data)) | ||
178 | assert(io.flush()) | ||
179 | else | ||
180 | local fp = io.open(name) | ||
181 | if fp then | ||
182 | local old = fp:read("*a") | ||
183 | fp:close() | ||
184 | if data == old then return end | ||
185 | end | ||
186 | fp = assert(io.open(name, "w")) | ||
187 | assert(fp:write(data)) | ||
188 | assert(fp:close()) | ||
189 | end | ||
190 | end | ||
191 | |||
192 | local outfile = 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 | |||