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. */
13static uint8_t obuf[8192];
14static uint8_t *optr;
15static char modname[80];
16static size_t modnamelen;
17static char funcname[80];
18static int modstate, regfunc;
19static int ffid, recffid, ffasmfunc;
20
21enum {
22 REGFUNC_OK,
23 REGFUNC_NOREG,
24 REGFUNC_NOREGUV
25};
26
27static 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
50static 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
74static 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
97static 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
111static 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
156static 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
167static 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
189static 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
212static 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
229static 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
249static 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
262static 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
307static 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
318static void libdef_regfunc(BuildCtx *ctx, char *p, int arg)
319{
320 UNUSED(ctx); UNUSED(p);
321 regfunc = arg;
322}
323
324typedef void (*LibDefFunc)(BuildCtx *ctx, char *p, int arg);
325
326typedef struct LibDefHandler {
327 const char *suffix;
328 const char *stop;
329 const LibDefFunc func;
330 const int arg;
331} LibDefHandler;
332
333static 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. */
348void 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