1 | /* |
2 | ** LuaJIT VM builder: library definition compiler. |
3 | ** Copyright (C) 2005-2021 Mike Pall. See Copyright Notice in luajit.h |
4 | */ |
5 | |
6 | #include "buildvm.h" |
7 | #include "lj_obj.h" |
8 | #include "lj_bc.h" |
9 | #include "lj_lib.h" |
10 | #include "buildvm_libbc.h" |
11 | |
12 | /* Context for library definitions. */ |
13 | static uint8_t obuf[8192]; |
14 | static uint8_t *optr; |
15 | static char modname[80]; |
16 | static size_t modnamelen; |
17 | static char funcname[80]; |
18 | static int modstate, regfunc; |
19 | static int ffid, recffid, ffasmfunc; |
20 | |
21 | enum { |
22 | REGFUNC_OK, |
23 | REGFUNC_NOREG, |
24 | REGFUNC_NOREGUV |
25 | }; |
26 | |
27 | static void libdef_name(const char *p, int kind) |
28 | { |
29 | size_t n = strlen(p); |
30 | if (kind != LIBINIT_STRING) { |
31 | if (n > modnamelen && p[modnamelen] == '_' && |
32 | !strncmp(p, modname, modnamelen)) { |
33 | p += modnamelen+1; |
34 | n -= modnamelen+1; |
35 | } |
36 | } |
37 | if (n > LIBINIT_MAXSTR) { |
38 | fprintf(stderr, "Error: string too long: '%s'\n" , p); |
39 | exit(1); |
40 | } |
41 | if (optr+1+n+2 > obuf+sizeof(obuf)) { /* +2 for caller. */ |
42 | fprintf(stderr, "Error: output buffer overflow\n" ); |
43 | exit(1); |
44 | } |
45 | *optr++ = (uint8_t)(n | kind); |
46 | memcpy(optr, p, n); |
47 | optr += n; |
48 | } |
49 | |
50 | static void libdef_endmodule(BuildCtx *ctx) |
51 | { |
52 | if (modstate != 0) { |
53 | char line[80]; |
54 | const uint8_t *p; |
55 | int n; |
56 | if (modstate == 1) |
57 | fprintf(ctx->fp, " (lua_CFunction)0" ); |
58 | fprintf(ctx->fp, "\n};\n" ); |
59 | fprintf(ctx->fp, "static const uint8_t %s%s[] = {\n" , |
60 | LABEL_PREFIX_LIBINIT, modname); |
61 | line[0] = '\0'; |
62 | for (n = 0, p = obuf; p < optr; p++) { |
63 | n += sprintf(line+n, "%d," , *p); |
64 | if (n >= 75) { |
65 | fprintf(ctx->fp, "%s\n" , line); |
66 | n = 0; |
67 | line[0] = '\0'; |
68 | } |
69 | } |
70 | fprintf(ctx->fp, "%s%d\n};\n#endif\n\n" , line, LIBINIT_END); |
71 | } |
72 | } |
73 | |
74 | static void libdef_module(BuildCtx *ctx, char *p, int arg) |
75 | { |
76 | UNUSED(arg); |
77 | if (ctx->mode == BUILD_libdef) { |
78 | libdef_endmodule(ctx); |
79 | optr = obuf; |
80 | *optr++ = (uint8_t)ffid; |
81 | *optr++ = (uint8_t)ffasmfunc; |
82 | *optr++ = 0; /* Hash table size. */ |
83 | modstate = 1; |
84 | fprintf(ctx->fp, "#ifdef %sMODULE_%s\n" , LIBDEF_PREFIX, p); |
85 | fprintf(ctx->fp, "#undef %sMODULE_%s\n" , LIBDEF_PREFIX, p); |
86 | fprintf(ctx->fp, "static const lua_CFunction %s%s[] = {\n" , |
87 | LABEL_PREFIX_LIBCF, p); |
88 | } |
89 | modnamelen = strlen(p); |
90 | if (modnamelen > sizeof(modname)-1) { |
91 | fprintf(stderr, "Error: module name too long: '%s'\n" , p); |
92 | exit(1); |
93 | } |
94 | strcpy(modname, p); |
95 | } |
96 | |
97 | static int find_ffofs(BuildCtx *ctx, const char *name) |
98 | { |
99 | int i; |
100 | for (i = 0; i < ctx->nglob; i++) { |
101 | const char *gl = ctx->globnames[i]; |
102 | if (gl[0] == 'f' && gl[1] == 'f' && gl[2] == '_' && !strcmp(gl+3, name)) { |
103 | return (int)((uint8_t *)ctx->glob[i] - ctx->code); |
104 | } |
105 | } |
106 | fprintf(stderr, "Error: undefined fast function %s%s\n" , |
107 | LABEL_PREFIX_FF, name); |
108 | exit(1); |
109 | } |
110 | |
111 | static void libdef_func(BuildCtx *ctx, char *p, int arg) |
112 | { |
113 | if (arg != LIBINIT_CF) |
114 | ffasmfunc++; |
115 | if (ctx->mode == BUILD_libdef) { |
116 | if (modstate == 0) { |
117 | fprintf(stderr, "Error: no module for function definition %s\n" , p); |
118 | exit(1); |
119 | } |
120 | if (regfunc == REGFUNC_NOREG) { |
121 | if (optr+1 > obuf+sizeof(obuf)) { |
122 | fprintf(stderr, "Error: output buffer overflow\n" ); |
123 | exit(1); |
124 | } |
125 | *optr++ = LIBINIT_FFID; |
126 | } else { |
127 | if (arg != LIBINIT_ASM_) { |
128 | if (modstate != 1) fprintf(ctx->fp, ",\n" ); |
129 | modstate = 2; |
130 | fprintf(ctx->fp, " %s%s" , arg ? LABEL_PREFIX_FFH : LABEL_PREFIX_CF, p); |
131 | } |
132 | if (regfunc != REGFUNC_NOREGUV) obuf[2]++; /* Bump hash table size. */ |
133 | libdef_name(regfunc == REGFUNC_NOREGUV ? "" : p, arg); |
134 | } |
135 | } else if (ctx->mode == BUILD_ffdef) { |
136 | fprintf(ctx->fp, "FFDEF(%s)\n" , p); |
137 | } else if (ctx->mode == BUILD_recdef) { |
138 | if (strlen(p) > sizeof(funcname)-1) { |
139 | fprintf(stderr, "Error: function name too long: '%s'\n" , p); |
140 | exit(1); |
141 | } |
142 | strcpy(funcname, p); |
143 | } else if (ctx->mode == BUILD_vmdef) { |
144 | int i; |
145 | for (i = 1; p[i] && modname[i-1]; i++) |
146 | if (p[i] == '_') p[i] = '.'; |
147 | fprintf(ctx->fp, "\"%s\",\n" , p); |
148 | } else if (ctx->mode == BUILD_bcdef) { |
149 | if (arg != LIBINIT_CF) |
150 | fprintf(ctx->fp, ",\n%d" , find_ffofs(ctx, p)); |
151 | } |
152 | ffid++; |
153 | regfunc = REGFUNC_OK; |
154 | } |
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 | |
212 | static uint32_t find_rec(char *name) |
213 | { |
214 | char *p = (char *)obuf; |
215 | uint32_t n; |
216 | for (n = 2; *p; n++) { |
217 | if (strcmp(p, name) == 0) |
218 | return n; |
219 | p += strlen(p)+1; |
220 | } |
221 | if (p+strlen(name)+1 >= (char *)obuf+sizeof(obuf)) { |
222 | fprintf(stderr, "Error: output buffer overflow\n" ); |
223 | exit(1); |
224 | } |
225 | strcpy(p, name); |
226 | return n; |
227 | } |
228 | |
229 | static void libdef_rec(BuildCtx *ctx, char *p, int arg) |
230 | { |
231 | UNUSED(arg); |
232 | if (ctx->mode == BUILD_recdef) { |
233 | char *q; |
234 | uint32_t n; |
235 | for (; recffid+1 < ffid; recffid++) |
236 | fprintf(ctx->fp, ",\n0" ); |
237 | recffid = ffid; |
238 | if (*p == '.') p = funcname; |
239 | q = strchr(p, ' '); |
240 | if (q) *q++ = '\0'; |
241 | n = find_rec(p); |
242 | if (q) |
243 | fprintf(ctx->fp, ",\n0x%02x00+(%s)" , n, q); |
244 | else |
245 | fprintf(ctx->fp, ",\n0x%02x00" , n); |
246 | } |
247 | } |
248 | |
249 | static void memcpy_endian(void *dst, void *src, size_t n) |
250 | { |
251 | union { uint8_t b; uint32_t u; } host_endian; |
252 | host_endian.u = 1; |
253 | if (host_endian.b == LJ_ENDIAN_SELECT(1, 0)) { |
254 | memcpy(dst, src, n); |
255 | } else { |
256 | size_t i; |
257 | for (i = 0; i < n; i++) |
258 | ((uint8_t *)dst)[i] = ((uint8_t *)src)[n-i-1]; |
259 | } |
260 | } |
261 | |
262 | static void libdef_push(BuildCtx *ctx, char *p, int arg) |
263 | { |
264 | UNUSED(arg); |
265 | if (ctx->mode == BUILD_libdef) { |
266 | int len = (int)strlen(p); |
267 | if (*p == '"') { |
268 | if (len > 1 && p[len-1] == '"') { |
269 | p[len-1] = '\0'; |
270 | libdef_name(p+1, LIBINIT_STRING); |
271 | return; |
272 | } |
273 | } else if (*p >= '0' && *p <= '9') { |
274 | char *ep; |
275 | double d = strtod(p, &ep); |
276 | if (*ep == '\0') { |
277 | if (optr+1+sizeof(double) > obuf+sizeof(obuf)) { |
278 | fprintf(stderr, "Error: output buffer overflow\n" ); |
279 | exit(1); |
280 | } |
281 | *optr++ = LIBINIT_NUMBER; |
282 | memcpy_endian(optr, &d, sizeof(double)); |
283 | optr += sizeof(double); |
284 | return; |
285 | } |
286 | } else if (!strcmp(p, "lastcl" )) { |
287 | if (optr+1 > obuf+sizeof(obuf)) { |
288 | fprintf(stderr, "Error: output buffer overflow\n" ); |
289 | exit(1); |
290 | } |
291 | *optr++ = LIBINIT_LASTCL; |
292 | return; |
293 | } else if (len > 4 && !strncmp(p, "top-" , 4)) { |
294 | if (optr+2 > obuf+sizeof(obuf)) { |
295 | fprintf(stderr, "Error: output buffer overflow\n" ); |
296 | exit(1); |
297 | } |
298 | *optr++ = LIBINIT_COPY; |
299 | *optr++ = (uint8_t)atoi(p+4); |
300 | return; |
301 | } |
302 | fprintf(stderr, "Error: bad value for %sPUSH(%s)\n" , LIBDEF_PREFIX, p); |
303 | exit(1); |
304 | } |
305 | } |
306 | |
307 | static void libdef_set(BuildCtx *ctx, char *p, int arg) |
308 | { |
309 | UNUSED(arg); |
310 | if (ctx->mode == BUILD_libdef) { |
311 | if (p[0] == '!' && p[1] == '\0') p[0] = '\0'; /* Set env. */ |
312 | libdef_name(p, LIBINIT_STRING); |
313 | *optr++ = LIBINIT_SET; |
314 | obuf[2]++; /* Bump hash table size. */ |
315 | } |
316 | } |
317 | |
318 | static void libdef_regfunc(BuildCtx *ctx, char *p, int arg) |
319 | { |
320 | UNUSED(ctx); UNUSED(p); |
321 | regfunc = arg; |
322 | } |
323 | |
324 | typedef void (*LibDefFunc)(BuildCtx *ctx, char *p, int arg); |
325 | |
326 | typedef struct LibDefHandler { |
327 | const char *suffix; |
328 | const char *stop; |
329 | const LibDefFunc func; |
330 | const int arg; |
331 | } LibDefHandler; |
332 | |
333 | static const LibDefHandler libdef_handlers[] = { |
334 | { "MODULE_" , " \t\r\n" , libdef_module, 0 }, |
335 | { "CF(" , ")" , libdef_func, LIBINIT_CF }, |
336 | { "ASM(" , ")" , libdef_func, LIBINIT_ASM }, |
337 | { "ASM_(" , ")" , libdef_func, LIBINIT_ASM_ }, |
338 | { "LUA(" , ")" , libdef_lua, 0 }, |
339 | { "REC(" , ")" , libdef_rec, 0 }, |
340 | { "PUSH(" , ")" , libdef_push, 0 }, |
341 | { "SET(" , ")" , libdef_set, 0 }, |
342 | { "NOREGUV" , NULL, libdef_regfunc, REGFUNC_NOREGUV }, |
343 | { "NOREG" , NULL, libdef_regfunc, REGFUNC_NOREG }, |
344 | { NULL, NULL, (LibDefFunc)0, 0 } |
345 | }; |
346 | |
347 | /* Emit C source code for library function definitions. */ |
348 | void emit_lib(BuildCtx *ctx) |
349 | { |
350 | const char *fname; |
351 | |
352 | if (ctx->mode == BUILD_ffdef || ctx->mode == BUILD_libdef || |
353 | ctx->mode == BUILD_recdef) |
354 | fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n" ); |
355 | else if (ctx->mode == BUILD_vmdef) |
356 | fprintf(ctx->fp, "ffnames = {\n[0]=\"Lua\",\n\"C\",\n" ); |
357 | if (ctx->mode == BUILD_recdef) |
358 | fprintf(ctx->fp, "static const uint16_t recff_idmap[] = {\n0,\n0x0100" ); |
359 | recffid = ffid = FF_C+1; |
360 | ffasmfunc = 0; |
361 | |
362 | while ((fname = *ctx->args++)) { |
363 | char buf[256]; /* We don't care about analyzing lines longer than that. */ |
364 | FILE *fp; |
365 | if (fname[0] == '-' && fname[1] == '\0') { |
366 | fp = stdin; |
367 | } else { |
368 | fp = fopen(fname, "r" ); |
369 | if (!fp) { |
370 | fprintf(stderr, "Error: cannot open input file '%s': %s\n" , |
371 | fname, strerror(errno)); |
372 | exit(1); |
373 | } |
374 | } |
375 | modstate = 0; |
376 | regfunc = REGFUNC_OK; |
377 | while (fgets(buf, sizeof(buf), fp) != NULL) { |
378 | char *p; |
379 | /* Simplistic pre-processor. Only handles top-level #if/#endif. */ |
380 | if (buf[0] == '#' && buf[1] == 'i' && buf[2] == 'f') { |
381 | int ok = 1; |
382 | if (!strcmp(buf, "#if LJ_52\n" )) |
383 | ok = LJ_52; |
384 | else if (!strcmp(buf, "#if LJ_HASJIT\n" )) |
385 | ok = LJ_HASJIT; |
386 | else if (!strcmp(buf, "#if LJ_HASFFI\n" )) |
387 | ok = LJ_HASFFI; |
388 | if (!ok) { |
389 | int lvl = 1; |
390 | while (fgets(buf, sizeof(buf), fp) != NULL) { |
391 | if (buf[0] == '#' && buf[1] == 'e' && buf[2] == 'n') { |
392 | if (--lvl == 0) break; |
393 | } else if (buf[0] == '#' && buf[1] == 'i' && buf[2] == 'f') { |
394 | lvl++; |
395 | } |
396 | } |
397 | continue; |
398 | } |
399 | } |
400 | for (p = buf; (p = strstr(p, LIBDEF_PREFIX)) != NULL; ) { |
401 | const LibDefHandler *ldh; |
402 | p += sizeof(LIBDEF_PREFIX)-1; |
403 | for (ldh = libdef_handlers; ldh->suffix != NULL; ldh++) { |
404 | size_t n, len = strlen(ldh->suffix); |
405 | if (!strncmp(p, ldh->suffix, len)) { |
406 | p += len; |
407 | n = ldh->stop ? strcspn(p, ldh->stop) : 0; |
408 | if (!p[n]) break; |
409 | p[n] = '\0'; |
410 | ldh->func(ctx, p, ldh->arg); |
411 | p += n+1; |
412 | break; |
413 | } |
414 | } |
415 | if (ldh->suffix == NULL) { |
416 | buf[strlen(buf)-1] = '\0'; |
417 | fprintf(stderr, "Error: unknown library definition tag %s%s\n" , |
418 | LIBDEF_PREFIX, p); |
419 | exit(1); |
420 | } |
421 | } |
422 | } |
423 | fclose(fp); |
424 | if (ctx->mode == BUILD_libdef) { |
425 | libdef_endmodule(ctx); |
426 | } |
427 | } |
428 | |
429 | if (ctx->mode == BUILD_ffdef) { |
430 | fprintf(ctx->fp, "\n#undef FFDEF\n\n" ); |
431 | fprintf(ctx->fp, |
432 | "#ifndef FF_NUM_ASMFUNC\n#define FF_NUM_ASMFUNC %d\n#endif\n\n" , |
433 | ffasmfunc); |
434 | } else if (ctx->mode == BUILD_vmdef) { |
435 | fprintf(ctx->fp, "},\n\n" ); |
436 | } else if (ctx->mode == BUILD_bcdef) { |
437 | int i; |
438 | fprintf(ctx->fp, "\n};\n\n" ); |
439 | fprintf(ctx->fp, "LJ_DATADEF const uint16_t lj_bc_mode[] = {\n" ); |
440 | fprintf(ctx->fp, "BCDEF(BCMODE)\n" ); |
441 | for (i = ffasmfunc-1; i > 0; i--) |
442 | fprintf(ctx->fp, "BCMODE_FF,\n" ); |
443 | fprintf(ctx->fp, "BCMODE_FF\n};\n\n" ); |
444 | } else if (ctx->mode == BUILD_recdef) { |
445 | char *p = (char *)obuf; |
446 | fprintf(ctx->fp, "\n};\n\n" ); |
447 | fprintf(ctx->fp, "static const RecordFunc recff_func[] = {\n" |
448 | "recff_nyi,\n" |
449 | "recff_c" ); |
450 | while (*p) { |
451 | fprintf(ctx->fp, ",\nrecff_%s" , p); |
452 | p += strlen(p)+1; |
453 | } |
454 | fprintf(ctx->fp, "\n};\n\n" ); |
455 | } |
456 | } |
457 | |
458 | |