Mercurial
comparison third_party/luajit/src/host/buildvm_lib.c @ 178:94705b5986b3
[ThirdParty] Added WRK and luajit for load testing.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Thu, 22 Jan 2026 20:10:30 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 177:24fe8ff94056 | 178:94705b5986b3 |
|---|---|
| 1 /* | |
| 2 ** LuaJIT VM builder: library definition compiler. | |
| 3 ** Copyright (C) 2005-2023 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 size_t len = strlen(buf); | |
| 383 if (buf[len-1] == '\n') { | |
| 384 buf[len-1] = 0; | |
| 385 if (buf[len-2] == '\r') { | |
| 386 buf[len-2] = 0; | |
| 387 } | |
| 388 } | |
| 389 if (!strcmp(buf, "#if LJ_52")) | |
| 390 ok = LJ_52; | |
| 391 else if (!strcmp(buf, "#if LJ_HASJIT")) | |
| 392 ok = LJ_HASJIT; | |
| 393 else if (!strcmp(buf, "#if LJ_HASFFI")) | |
| 394 ok = LJ_HASFFI; | |
| 395 else if (!strcmp(buf, "#if LJ_HASBUFFER")) | |
| 396 ok = LJ_HASBUFFER; | |
| 397 if (!ok) { | |
| 398 int lvl = 1; | |
| 399 while (fgets(buf, sizeof(buf), fp) != NULL) { | |
| 400 if (buf[0] == '#' && buf[1] == 'e' && buf[2] == 'n') { | |
| 401 if (--lvl == 0) break; | |
| 402 } else if (buf[0] == '#' && buf[1] == 'i' && buf[2] == 'f') { | |
| 403 lvl++; | |
| 404 } | |
| 405 } | |
| 406 continue; | |
| 407 } | |
| 408 } | |
| 409 for (p = buf; (p = strstr(p, LIBDEF_PREFIX)) != NULL; ) { | |
| 410 const LibDefHandler *ldh; | |
| 411 p += sizeof(LIBDEF_PREFIX)-1; | |
| 412 for (ldh = libdef_handlers; ldh->suffix != NULL; ldh++) { | |
| 413 size_t n, len = strlen(ldh->suffix); | |
| 414 if (!strncmp(p, ldh->suffix, len)) { | |
| 415 p += len; | |
| 416 n = ldh->stop ? strcspn(p, ldh->stop) : 0; | |
| 417 if (!p[n]) break; | |
| 418 p[n] = '\0'; | |
| 419 ldh->func(ctx, p, ldh->arg); | |
| 420 p += n+1; | |
| 421 break; | |
| 422 } | |
| 423 } | |
| 424 if (ldh->suffix == NULL) { | |
| 425 buf[strlen(buf)-1] = '\0'; | |
| 426 fprintf(stderr, "Error: unknown library definition tag %s%s\n", | |
| 427 LIBDEF_PREFIX, p); | |
| 428 exit(1); | |
| 429 } | |
| 430 } | |
| 431 } | |
| 432 fclose(fp); | |
| 433 if (ctx->mode == BUILD_libdef) { | |
| 434 libdef_endmodule(ctx); | |
| 435 } | |
| 436 } | |
| 437 | |
| 438 if (ctx->mode == BUILD_ffdef) { | |
| 439 fprintf(ctx->fp, "\n#undef FFDEF\n\n"); | |
| 440 fprintf(ctx->fp, | |
| 441 "#ifndef FF_NUM_ASMFUNC\n#define FF_NUM_ASMFUNC %d\n#endif\n\n", | |
| 442 ffasmfunc); | |
| 443 } else if (ctx->mode == BUILD_vmdef) { | |
| 444 fprintf(ctx->fp, "},\n\n"); | |
| 445 } else if (ctx->mode == BUILD_bcdef) { | |
| 446 int i; | |
| 447 fprintf(ctx->fp, "\n};\n\n"); | |
| 448 fprintf(ctx->fp, "LJ_DATADEF const uint16_t lj_bc_mode[] = {\n"); | |
| 449 fprintf(ctx->fp, "BCDEF(BCMODE)\n"); | |
| 450 for (i = ffasmfunc-1; i > 0; i--) | |
| 451 fprintf(ctx->fp, "BCMODE_FF,\n"); | |
| 452 fprintf(ctx->fp, "BCMODE_FF\n};\n\n"); | |
| 453 } else if (ctx->mode == BUILD_recdef) { | |
| 454 char *p = (char *)obuf; | |
| 455 fprintf(ctx->fp, "\n};\n\n"); | |
| 456 fprintf(ctx->fp, "static const RecordFunc recff_func[] = {\n" | |
| 457 "recff_nyi,\n" | |
| 458 "recff_c"); | |
| 459 while (*p) { | |
| 460 fprintf(ctx->fp, ",\nrecff_%s", p); | |
| 461 p += strlen(p)+1; | |
| 462 } | |
| 463 fprintf(ctx->fp, "\n};\n\n"); | |
| 464 } | |
| 465 } | |
| 466 |