| 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 | |