Mercurial
comparison third_party/luajit/src/lib_jit.c @ 186:8cf4ec5e2191 hg-web
Fixed merge conflict.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 23 Jan 2026 22:38:59 -0800 |
| parents | 94705b5986b3 |
| children |
comparison
equal
deleted
inserted
replaced
| 176:fed99fc04e12 | 186:8cf4ec5e2191 |
|---|---|
| 1 /* | |
| 2 ** JIT library. | |
| 3 ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h | |
| 4 */ | |
| 5 | |
| 6 #define lib_jit_c | |
| 7 #define LUA_LIB | |
| 8 | |
| 9 #include "lua.h" | |
| 10 #include "lauxlib.h" | |
| 11 #include "lualib.h" | |
| 12 | |
| 13 #include "lj_obj.h" | |
| 14 #include "lj_gc.h" | |
| 15 #include "lj_err.h" | |
| 16 #include "lj_debug.h" | |
| 17 #include "lj_str.h" | |
| 18 #include "lj_tab.h" | |
| 19 #include "lj_state.h" | |
| 20 #include "lj_bc.h" | |
| 21 #if LJ_HASFFI | |
| 22 #include "lj_ctype.h" | |
| 23 #endif | |
| 24 #if LJ_HASJIT | |
| 25 #include "lj_ir.h" | |
| 26 #include "lj_jit.h" | |
| 27 #include "lj_ircall.h" | |
| 28 #include "lj_iropt.h" | |
| 29 #include "lj_target.h" | |
| 30 #endif | |
| 31 #include "lj_trace.h" | |
| 32 #include "lj_dispatch.h" | |
| 33 #include "lj_vm.h" | |
| 34 #include "lj_vmevent.h" | |
| 35 #include "lj_lib.h" | |
| 36 | |
| 37 #include "luajit.h" | |
| 38 | |
| 39 /* -- jit.* functions ----------------------------------------------------- */ | |
| 40 | |
| 41 #define LJLIB_MODULE_jit | |
| 42 | |
| 43 static int setjitmode(lua_State *L, int mode) | |
| 44 { | |
| 45 int idx = 0; | |
| 46 if (L->base == L->top || tvisnil(L->base)) { /* jit.on/off/flush([nil]) */ | |
| 47 mode |= LUAJIT_MODE_ENGINE; | |
| 48 } else { | |
| 49 /* jit.on/off/flush(func|proto, nil|true|false) */ | |
| 50 if (tvisfunc(L->base) || tvisproto(L->base)) | |
| 51 idx = 1; | |
| 52 else if (!tvistrue(L->base)) /* jit.on/off/flush(true, nil|true|false) */ | |
| 53 goto err; | |
| 54 if (L->base+1 < L->top && tvisbool(L->base+1)) | |
| 55 mode |= boolV(L->base+1) ? LUAJIT_MODE_ALLFUNC : LUAJIT_MODE_ALLSUBFUNC; | |
| 56 else | |
| 57 mode |= LUAJIT_MODE_FUNC; | |
| 58 } | |
| 59 if (luaJIT_setmode(L, idx, mode) != 1) { | |
| 60 if ((mode & LUAJIT_MODE_MASK) == LUAJIT_MODE_ENGINE) | |
| 61 lj_err_caller(L, LJ_ERR_NOJIT); | |
| 62 err: | |
| 63 lj_err_argt(L, 1, LUA_TFUNCTION); | |
| 64 } | |
| 65 return 0; | |
| 66 } | |
| 67 | |
| 68 LJLIB_CF(jit_on) | |
| 69 { | |
| 70 return setjitmode(L, LUAJIT_MODE_ON); | |
| 71 } | |
| 72 | |
| 73 LJLIB_CF(jit_off) | |
| 74 { | |
| 75 return setjitmode(L, LUAJIT_MODE_OFF); | |
| 76 } | |
| 77 | |
| 78 LJLIB_CF(jit_flush) | |
| 79 { | |
| 80 #if LJ_HASJIT | |
| 81 if (L->base < L->top && tvisnumber(L->base)) { | |
| 82 int traceno = lj_lib_checkint(L, 1); | |
| 83 luaJIT_setmode(L, traceno, LUAJIT_MODE_FLUSH|LUAJIT_MODE_TRACE); | |
| 84 return 0; | |
| 85 } | |
| 86 #endif | |
| 87 return setjitmode(L, LUAJIT_MODE_FLUSH); | |
| 88 } | |
| 89 | |
| 90 #if LJ_HASJIT | |
| 91 /* Push a string for every flag bit that is set. */ | |
| 92 static void flagbits_to_strings(lua_State *L, uint32_t flags, uint32_t base, | |
| 93 const char *str) | |
| 94 { | |
| 95 for (; *str; base <<= 1, str += 1+*str) | |
| 96 if (flags & base) | |
| 97 setstrV(L, L->top++, lj_str_new(L, str+1, *(uint8_t *)str)); | |
| 98 } | |
| 99 #endif | |
| 100 | |
| 101 LJLIB_CF(jit_status) | |
| 102 { | |
| 103 #if LJ_HASJIT | |
| 104 jit_State *J = L2J(L); | |
| 105 L->top = L->base; | |
| 106 setboolV(L->top++, (J->flags & JIT_F_ON) ? 1 : 0); | |
| 107 flagbits_to_strings(L, J->flags, JIT_F_CPU, JIT_F_CPUSTRING); | |
| 108 flagbits_to_strings(L, J->flags, JIT_F_OPT, JIT_F_OPTSTRING); | |
| 109 return (int)(L->top - L->base); | |
| 110 #else | |
| 111 setboolV(L->top++, 0); | |
| 112 return 1; | |
| 113 #endif | |
| 114 } | |
| 115 | |
| 116 LJLIB_CF(jit_security) | |
| 117 { | |
| 118 int idx = lj_lib_checkopt(L, 1, -1, LJ_SECURITY_MODESTRING); | |
| 119 setintV(L->top++, ((LJ_SECURITY_MODE >> (2*idx)) & 3)); | |
| 120 return 1; | |
| 121 } | |
| 122 | |
| 123 LJLIB_CF(jit_attach) | |
| 124 { | |
| 125 #ifdef LUAJIT_DISABLE_VMEVENT | |
| 126 luaL_error(L, "vmevent API disabled"); | |
| 127 #else | |
| 128 GCfunc *fn = lj_lib_checkfunc(L, 1); | |
| 129 GCstr *s = lj_lib_optstr(L, 2); | |
| 130 luaL_findtable(L, LUA_REGISTRYINDEX, LJ_VMEVENTS_REGKEY, LJ_VMEVENTS_HSIZE); | |
| 131 if (s) { /* Attach to given event. */ | |
| 132 const uint8_t *p = (const uint8_t *)strdata(s); | |
| 133 uint32_t h = s->len; | |
| 134 while (*p) h = h ^ (lj_rol(h, 6) + *p++); | |
| 135 lua_pushvalue(L, 1); | |
| 136 lua_rawseti(L, -2, VMEVENT_HASHIDX(h)); | |
| 137 G(L)->vmevmask = VMEVENT_NOCACHE; /* Invalidate cache. */ | |
| 138 } else { /* Detach if no event given. */ | |
| 139 setnilV(L->top++); | |
| 140 while (lua_next(L, -2)) { | |
| 141 L->top--; | |
| 142 if (tvisfunc(L->top) && funcV(L->top) == fn) { | |
| 143 setnilV(lj_tab_set(L, tabV(L->top-2), L->top-1)); | |
| 144 } | |
| 145 } | |
| 146 } | |
| 147 #endif | |
| 148 return 0; | |
| 149 } | |
| 150 | |
| 151 LJLIB_PUSH(top-5) LJLIB_SET(os) | |
| 152 LJLIB_PUSH(top-4) LJLIB_SET(arch) | |
| 153 LJLIB_PUSH(top-3) LJLIB_SET(version_num) | |
| 154 LJLIB_PUSH(top-2) LJLIB_SET(version) | |
| 155 | |
| 156 #include "lj_libdef.h" | |
| 157 | |
| 158 /* -- jit.util.* functions ------------------------------------------------ */ | |
| 159 | |
| 160 #define LJLIB_MODULE_jit_util | |
| 161 | |
| 162 /* -- Reflection API for Lua functions ------------------------------------ */ | |
| 163 | |
| 164 /* Return prototype of first argument (Lua function or prototype object) */ | |
| 165 static GCproto *check_Lproto(lua_State *L, int nolua) | |
| 166 { | |
| 167 TValue *o = L->base; | |
| 168 if (L->top > o) { | |
| 169 if (tvisproto(o)) { | |
| 170 return protoV(o); | |
| 171 } else if (tvisfunc(o)) { | |
| 172 if (isluafunc(funcV(o))) | |
| 173 return funcproto(funcV(o)); | |
| 174 else if (nolua) | |
| 175 return NULL; | |
| 176 } | |
| 177 } | |
| 178 lj_err_argt(L, 1, LUA_TFUNCTION); | |
| 179 return NULL; /* unreachable */ | |
| 180 } | |
| 181 | |
| 182 static void setintfield(lua_State *L, GCtab *t, const char *name, int32_t val) | |
| 183 { | |
| 184 setintV(lj_tab_setstr(L, t, lj_str_newz(L, name)), val); | |
| 185 } | |
| 186 | |
| 187 /* local info = jit.util.funcinfo(func [,pc]) */ | |
| 188 LJLIB_CF(jit_util_funcinfo) | |
| 189 { | |
| 190 GCproto *pt = check_Lproto(L, 1); | |
| 191 if (pt) { | |
| 192 BCPos pc = (BCPos)lj_lib_optint(L, 2, 0); | |
| 193 GCtab *t; | |
| 194 lua_createtable(L, 0, 16); /* Increment hash size if fields are added. */ | |
| 195 t = tabV(L->top-1); | |
| 196 setintfield(L, t, "linedefined", pt->firstline); | |
| 197 setintfield(L, t, "lastlinedefined", pt->firstline + pt->numline); | |
| 198 setintfield(L, t, "stackslots", pt->framesize); | |
| 199 setintfield(L, t, "params", pt->numparams); | |
| 200 setintfield(L, t, "bytecodes", (int32_t)pt->sizebc); | |
| 201 setintfield(L, t, "gcconsts", (int32_t)pt->sizekgc); | |
| 202 setintfield(L, t, "nconsts", (int32_t)pt->sizekn); | |
| 203 setintfield(L, t, "upvalues", (int32_t)pt->sizeuv); | |
| 204 if (pc < pt->sizebc) | |
| 205 setintfield(L, t, "currentline", lj_debug_line(pt, pc)); | |
| 206 lua_pushboolean(L, (pt->flags & PROTO_VARARG)); | |
| 207 lua_setfield(L, -2, "isvararg"); | |
| 208 lua_pushboolean(L, (pt->flags & PROTO_CHILD)); | |
| 209 lua_setfield(L, -2, "children"); | |
| 210 setstrV(L, L->top++, proto_chunkname(pt)); | |
| 211 lua_setfield(L, -2, "source"); | |
| 212 lj_debug_pushloc(L, pt, pc); | |
| 213 lua_setfield(L, -2, "loc"); | |
| 214 setprotoV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "proto")), pt); | |
| 215 } else { | |
| 216 GCfunc *fn = funcV(L->base); | |
| 217 GCtab *t; | |
| 218 lua_createtable(L, 0, 4); /* Increment hash size if fields are added. */ | |
| 219 t = tabV(L->top-1); | |
| 220 if (!iscfunc(fn)) | |
| 221 setintfield(L, t, "ffid", fn->c.ffid); | |
| 222 setintptrV(lj_tab_setstr(L, t, lj_str_newlit(L, "addr")), | |
| 223 (intptr_t)(void *)fn->c.f); | |
| 224 setintfield(L, t, "upvalues", fn->c.nupvalues); | |
| 225 } | |
| 226 return 1; | |
| 227 } | |
| 228 | |
| 229 /* local ins, m = jit.util.funcbc(func, pc) */ | |
| 230 LJLIB_CF(jit_util_funcbc) | |
| 231 { | |
| 232 GCproto *pt = check_Lproto(L, 0); | |
| 233 BCPos pc = (BCPos)lj_lib_checkint(L, 2); | |
| 234 if (pc < pt->sizebc) { | |
| 235 BCIns ins = proto_bc(pt)[pc]; | |
| 236 BCOp op = bc_op(ins); | |
| 237 lj_assertL(op < BC__MAX, "bad bytecode op %d", op); | |
| 238 setintV(L->top, ins); | |
| 239 setintV(L->top+1, lj_bc_mode[op]); | |
| 240 L->top += 2; | |
| 241 return 2; | |
| 242 } | |
| 243 return 0; | |
| 244 } | |
| 245 | |
| 246 /* local k = jit.util.funck(func, idx) */ | |
| 247 LJLIB_CF(jit_util_funck) | |
| 248 { | |
| 249 GCproto *pt = check_Lproto(L, 0); | |
| 250 ptrdiff_t idx = (ptrdiff_t)lj_lib_checkint(L, 2); | |
| 251 if (idx >= 0) { | |
| 252 if (idx < (ptrdiff_t)pt->sizekn) { | |
| 253 copyTV(L, L->top-1, proto_knumtv(pt, idx)); | |
| 254 return 1; | |
| 255 } | |
| 256 } else { | |
| 257 if (~idx < (ptrdiff_t)pt->sizekgc) { | |
| 258 GCobj *gc = proto_kgc(pt, idx); | |
| 259 setgcV(L, L->top-1, gc, ~gc->gch.gct); | |
| 260 return 1; | |
| 261 } | |
| 262 } | |
| 263 return 0; | |
| 264 } | |
| 265 | |
| 266 /* local name = jit.util.funcuvname(func, idx) */ | |
| 267 LJLIB_CF(jit_util_funcuvname) | |
| 268 { | |
| 269 GCproto *pt = check_Lproto(L, 0); | |
| 270 uint32_t idx = (uint32_t)lj_lib_checkint(L, 2); | |
| 271 if (idx < pt->sizeuv) { | |
| 272 setstrV(L, L->top-1, lj_str_newz(L, lj_debug_uvname(pt, idx))); | |
| 273 return 1; | |
| 274 } | |
| 275 return 0; | |
| 276 } | |
| 277 | |
| 278 /* -- Reflection API for traces ------------------------------------------- */ | |
| 279 | |
| 280 #if LJ_HASJIT | |
| 281 | |
| 282 /* Check trace argument. Must not throw for non-existent trace numbers. */ | |
| 283 static GCtrace *jit_checktrace(lua_State *L) | |
| 284 { | |
| 285 TraceNo tr = (TraceNo)lj_lib_checkint(L, 1); | |
| 286 jit_State *J = L2J(L); | |
| 287 if (tr > 0 && tr < J->sizetrace) | |
| 288 return traceref(J, tr); | |
| 289 return NULL; | |
| 290 } | |
| 291 | |
| 292 /* Names of link types. ORDER LJ_TRLINK */ | |
| 293 static const char *const jit_trlinkname[] = { | |
| 294 "none", "root", "loop", "tail-recursion", "up-recursion", "down-recursion", | |
| 295 "interpreter", "return", "stitch" | |
| 296 }; | |
| 297 | |
| 298 /* local info = jit.util.traceinfo(tr) */ | |
| 299 LJLIB_CF(jit_util_traceinfo) | |
| 300 { | |
| 301 GCtrace *T = jit_checktrace(L); | |
| 302 if (T) { | |
| 303 GCtab *t; | |
| 304 lua_createtable(L, 0, 8); /* Increment hash size if fields are added. */ | |
| 305 t = tabV(L->top-1); | |
| 306 setintfield(L, t, "nins", (int32_t)T->nins - REF_BIAS - 1); | |
| 307 setintfield(L, t, "nk", REF_BIAS - (int32_t)T->nk); | |
| 308 setintfield(L, t, "link", T->link); | |
| 309 setintfield(L, t, "nexit", T->nsnap); | |
| 310 setstrV(L, L->top++, lj_str_newz(L, jit_trlinkname[T->linktype])); | |
| 311 lua_setfield(L, -2, "linktype"); | |
| 312 /* There are many more fields. Add them only when needed. */ | |
| 313 return 1; | |
| 314 } | |
| 315 return 0; | |
| 316 } | |
| 317 | |
| 318 /* local m, ot, op1, op2, prev = jit.util.traceir(tr, idx) */ | |
| 319 LJLIB_CF(jit_util_traceir) | |
| 320 { | |
| 321 GCtrace *T = jit_checktrace(L); | |
| 322 IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS; | |
| 323 if (T && ref >= REF_BIAS && ref < T->nins) { | |
| 324 IRIns *ir = &T->ir[ref]; | |
| 325 int32_t m = lj_ir_mode[ir->o]; | |
| 326 setintV(L->top-2, m); | |
| 327 setintV(L->top-1, ir->ot); | |
| 328 setintV(L->top++, (int32_t)ir->op1 - (irm_op1(m)==IRMref ? REF_BIAS : 0)); | |
| 329 setintV(L->top++, (int32_t)ir->op2 - (irm_op2(m)==IRMref ? REF_BIAS : 0)); | |
| 330 setintV(L->top++, ir->prev); | |
| 331 return 5; | |
| 332 } | |
| 333 return 0; | |
| 334 } | |
| 335 | |
| 336 /* local k, t [, slot] = jit.util.tracek(tr, idx) */ | |
| 337 LJLIB_CF(jit_util_tracek) | |
| 338 { | |
| 339 GCtrace *T = jit_checktrace(L); | |
| 340 IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS; | |
| 341 if (T && ref >= T->nk && ref < REF_BIAS) { | |
| 342 IRIns *ir = &T->ir[ref]; | |
| 343 int32_t slot = -1; | |
| 344 if (ir->o == IR_KSLOT) { | |
| 345 slot = ir->op2; | |
| 346 ir = &T->ir[ir->op1]; | |
| 347 } | |
| 348 #if LJ_HASFFI | |
| 349 if (ir->o == IR_KINT64) ctype_loadffi(L); | |
| 350 #endif | |
| 351 lj_ir_kvalue(L, L->top-2, ir); | |
| 352 setintV(L->top-1, (int32_t)irt_type(ir->t)); | |
| 353 if (slot == -1) | |
| 354 return 2; | |
| 355 setintV(L->top++, slot); | |
| 356 return 3; | |
| 357 } | |
| 358 return 0; | |
| 359 } | |
| 360 | |
| 361 /* local snap = jit.util.tracesnap(tr, sn) */ | |
| 362 LJLIB_CF(jit_util_tracesnap) | |
| 363 { | |
| 364 GCtrace *T = jit_checktrace(L); | |
| 365 SnapNo sn = (SnapNo)lj_lib_checkint(L, 2); | |
| 366 if (T && sn < T->nsnap) { | |
| 367 SnapShot *snap = &T->snap[sn]; | |
| 368 SnapEntry *map = &T->snapmap[snap->mapofs]; | |
| 369 MSize n, nent = snap->nent; | |
| 370 GCtab *t; | |
| 371 lua_createtable(L, nent+2, 0); | |
| 372 t = tabV(L->top-1); | |
| 373 setintV(lj_tab_setint(L, t, 0), (int32_t)snap->ref - REF_BIAS); | |
| 374 setintV(lj_tab_setint(L, t, 1), (int32_t)snap->nslots); | |
| 375 for (n = 0; n < nent; n++) | |
| 376 setintV(lj_tab_setint(L, t, (int32_t)(n+2)), (int32_t)map[n]); | |
| 377 setintV(lj_tab_setint(L, t, (int32_t)(nent+2)), (int32_t)SNAP(255, 0, 0)); | |
| 378 return 1; | |
| 379 } | |
| 380 return 0; | |
| 381 } | |
| 382 | |
| 383 /* local mcode, addr, loop = jit.util.tracemc(tr) */ | |
| 384 LJLIB_CF(jit_util_tracemc) | |
| 385 { | |
| 386 GCtrace *T = jit_checktrace(L); | |
| 387 if (T && T->mcode != NULL) { | |
| 388 setstrV(L, L->top-1, lj_str_new(L, (const char *)T->mcode, T->szmcode)); | |
| 389 setintptrV(L->top++, (intptr_t)(void *)T->mcode); | |
| 390 setintV(L->top++, T->mcloop); | |
| 391 return 3; | |
| 392 } | |
| 393 return 0; | |
| 394 } | |
| 395 | |
| 396 /* local addr = jit.util.traceexitstub([tr,] exitno) */ | |
| 397 LJLIB_CF(jit_util_traceexitstub) | |
| 398 { | |
| 399 #ifdef EXITSTUBS_PER_GROUP | |
| 400 ExitNo exitno = (ExitNo)lj_lib_checkint(L, 1); | |
| 401 jit_State *J = L2J(L); | |
| 402 if (exitno < EXITSTUBS_PER_GROUP*LJ_MAX_EXITSTUBGR) { | |
| 403 setintptrV(L->top-1, (intptr_t)(void *)exitstub_addr(J, exitno)); | |
| 404 return 1; | |
| 405 } | |
| 406 #else | |
| 407 if (L->top > L->base+1) { /* Don't throw for one-argument variant. */ | |
| 408 GCtrace *T = jit_checktrace(L); | |
| 409 ExitNo exitno = (ExitNo)lj_lib_checkint(L, 2); | |
| 410 ExitNo maxexit = T->root ? T->nsnap+1 : T->nsnap; | |
| 411 if (T && T->mcode != NULL && exitno < maxexit) { | |
| 412 setintptrV(L->top-1, (intptr_t)(void *)exitstub_trace_addr(T, exitno)); | |
| 413 return 1; | |
| 414 } | |
| 415 } | |
| 416 #endif | |
| 417 return 0; | |
| 418 } | |
| 419 | |
| 420 /* local addr = jit.util.ircalladdr(idx) */ | |
| 421 LJLIB_CF(jit_util_ircalladdr) | |
| 422 { | |
| 423 uint32_t idx = (uint32_t)lj_lib_checkint(L, 1); | |
| 424 if (idx < IRCALL__MAX) { | |
| 425 ASMFunction func = lj_ir_callinfo[idx].func; | |
| 426 setintptrV(L->top-1, (intptr_t)(void *)lj_ptr_strip(func)); | |
| 427 return 1; | |
| 428 } | |
| 429 return 0; | |
| 430 } | |
| 431 | |
| 432 #endif | |
| 433 | |
| 434 #include "lj_libdef.h" | |
| 435 | |
| 436 static int luaopen_jit_util(lua_State *L) | |
| 437 { | |
| 438 LJ_LIB_REG(L, NULL, jit_util); | |
| 439 return 1; | |
| 440 } | |
| 441 | |
| 442 /* -- jit.opt module ------------------------------------------------------ */ | |
| 443 | |
| 444 #if LJ_HASJIT | |
| 445 | |
| 446 #define LJLIB_MODULE_jit_opt | |
| 447 | |
| 448 /* Parse optimization level. */ | |
| 449 static int jitopt_level(jit_State *J, const char *str) | |
| 450 { | |
| 451 if (str[0] >= '0' && str[0] <= '9' && str[1] == '\0') { | |
| 452 uint32_t flags; | |
| 453 if (str[0] == '0') flags = JIT_F_OPT_0; | |
| 454 else if (str[0] == '1') flags = JIT_F_OPT_1; | |
| 455 else if (str[0] == '2') flags = JIT_F_OPT_2; | |
| 456 else flags = JIT_F_OPT_3; | |
| 457 J->flags = (J->flags & ~JIT_F_OPT_MASK) | flags; | |
| 458 return 1; /* Ok. */ | |
| 459 } | |
| 460 return 0; /* No match. */ | |
| 461 } | |
| 462 | |
| 463 /* Parse optimization flag. */ | |
| 464 static int jitopt_flag(jit_State *J, const char *str) | |
| 465 { | |
| 466 const char *lst = JIT_F_OPTSTRING; | |
| 467 uint32_t opt; | |
| 468 int set = 1; | |
| 469 if (str[0] == '+') { | |
| 470 str++; | |
| 471 } else if (str[0] == '-') { | |
| 472 str++; | |
| 473 set = 0; | |
| 474 } else if (str[0] == 'n' && str[1] == 'o') { | |
| 475 str += str[2] == '-' ? 3 : 2; | |
| 476 set = 0; | |
| 477 } | |
| 478 for (opt = JIT_F_OPT; ; opt <<= 1) { | |
| 479 size_t len = *(const uint8_t *)lst; | |
| 480 if (len == 0) | |
| 481 break; | |
| 482 if (strncmp(str, lst+1, len) == 0 && str[len] == '\0') { | |
| 483 if (set) J->flags |= opt; else J->flags &= ~opt; | |
| 484 return 1; /* Ok. */ | |
| 485 } | |
| 486 lst += 1+len; | |
| 487 } | |
| 488 return 0; /* No match. */ | |
| 489 } | |
| 490 | |
| 491 /* Parse optimization parameter. */ | |
| 492 static int jitopt_param(jit_State *J, const char *str) | |
| 493 { | |
| 494 const char *lst = JIT_P_STRING; | |
| 495 int i; | |
| 496 for (i = 0; i < JIT_P__MAX; i++) { | |
| 497 size_t len = *(const uint8_t *)lst; | |
| 498 lj_assertJ(len != 0, "bad JIT_P_STRING"); | |
| 499 if (strncmp(str, lst+1, len) == 0 && str[len] == '=') { | |
| 500 int32_t n = 0; | |
| 501 const char *p = &str[len+1]; | |
| 502 while (*p >= '0' && *p <= '9') | |
| 503 n = n*10 + (*p++ - '0'); | |
| 504 if (*p) return 0; /* Malformed number. */ | |
| 505 J->param[i] = n; | |
| 506 if (i == JIT_P_hotloop) | |
| 507 lj_dispatch_init_hotcount(J2G(J)); | |
| 508 return 1; /* Ok. */ | |
| 509 } | |
| 510 lst += 1+len; | |
| 511 } | |
| 512 return 0; /* No match. */ | |
| 513 } | |
| 514 | |
| 515 /* jit.opt.start(flags...) */ | |
| 516 LJLIB_CF(jit_opt_start) | |
| 517 { | |
| 518 jit_State *J = L2J(L); | |
| 519 int nargs = (int)(L->top - L->base); | |
| 520 if (nargs == 0) { | |
| 521 J->flags = (J->flags & ~JIT_F_OPT_MASK) | JIT_F_OPT_DEFAULT; | |
| 522 } else { | |
| 523 int i; | |
| 524 for (i = 1; i <= nargs; i++) { | |
| 525 const char *str = strdata(lj_lib_checkstr(L, i)); | |
| 526 if (!jitopt_level(J, str) && | |
| 527 !jitopt_flag(J, str) && | |
| 528 !jitopt_param(J, str)) | |
| 529 lj_err_callerv(L, LJ_ERR_JITOPT, str); | |
| 530 } | |
| 531 } | |
| 532 return 0; | |
| 533 } | |
| 534 | |
| 535 #include "lj_libdef.h" | |
| 536 | |
| 537 #endif | |
| 538 | |
| 539 /* -- jit.profile module -------------------------------------------------- */ | |
| 540 | |
| 541 #if LJ_HASPROFILE | |
| 542 | |
| 543 #define LJLIB_MODULE_jit_profile | |
| 544 | |
| 545 /* Not loaded by default, use: local profile = require("jit.profile") */ | |
| 546 | |
| 547 #define KEY_PROFILE_THREAD (U64x(80000000,00000000)|'t') | |
| 548 #define KEY_PROFILE_FUNC (U64x(80000000,00000000)|'f') | |
| 549 | |
| 550 static void jit_profile_callback(lua_State *L2, lua_State *L, int samples, | |
| 551 int vmstate) | |
| 552 { | |
| 553 TValue key; | |
| 554 cTValue *tv; | |
| 555 key.u64 = KEY_PROFILE_FUNC; | |
| 556 tv = lj_tab_get(L, tabV(registry(L)), &key); | |
| 557 if (tvisfunc(tv)) { | |
| 558 char vmst = (char)vmstate; | |
| 559 int status; | |
| 560 setfuncV(L2, L2->top++, funcV(tv)); | |
| 561 setthreadV(L2, L2->top++, L); | |
| 562 setintV(L2->top++, samples); | |
| 563 setstrV(L2, L2->top++, lj_str_new(L2, &vmst, 1)); | |
| 564 status = lua_pcall(L2, 3, 0, 0); /* callback(thread, samples, vmstate) */ | |
| 565 if (status) { | |
| 566 if (G(L2)->panic) G(L2)->panic(L2); | |
| 567 exit(EXIT_FAILURE); | |
| 568 } | |
| 569 lj_trace_abort(G(L2)); | |
| 570 } | |
| 571 } | |
| 572 | |
| 573 /* profile.start(mode, cb) */ | |
| 574 LJLIB_CF(jit_profile_start) | |
| 575 { | |
| 576 GCtab *registry = tabV(registry(L)); | |
| 577 GCstr *mode = lj_lib_optstr(L, 1); | |
| 578 GCfunc *func = lj_lib_checkfunc(L, 2); | |
| 579 lua_State *L2 = lua_newthread(L); /* Thread that runs profiler callback. */ | |
| 580 TValue key; | |
| 581 /* Anchor thread and function in registry. */ | |
| 582 key.u64 = KEY_PROFILE_THREAD; | |
| 583 setthreadV(L, lj_tab_set(L, registry, &key), L2); | |
| 584 key.u64 = KEY_PROFILE_FUNC; | |
| 585 setfuncV(L, lj_tab_set(L, registry, &key), func); | |
| 586 lj_gc_anybarriert(L, registry); | |
| 587 luaJIT_profile_start(L, mode ? strdata(mode) : "", | |
| 588 (luaJIT_profile_callback)jit_profile_callback, L2); | |
| 589 return 0; | |
| 590 } | |
| 591 | |
| 592 /* profile.stop() */ | |
| 593 LJLIB_CF(jit_profile_stop) | |
| 594 { | |
| 595 GCtab *registry; | |
| 596 TValue key; | |
| 597 luaJIT_profile_stop(L); | |
| 598 registry = tabV(registry(L)); | |
| 599 key.u64 = KEY_PROFILE_THREAD; | |
| 600 setnilV(lj_tab_set(L, registry, &key)); | |
| 601 key.u64 = KEY_PROFILE_FUNC; | |
| 602 setnilV(lj_tab_set(L, registry, &key)); | |
| 603 lj_gc_anybarriert(L, registry); | |
| 604 return 0; | |
| 605 } | |
| 606 | |
| 607 /* dump = profile.dumpstack([thread,] fmt, depth) */ | |
| 608 LJLIB_CF(jit_profile_dumpstack) | |
| 609 { | |
| 610 lua_State *L2 = L; | |
| 611 int arg = 0; | |
| 612 size_t len; | |
| 613 int depth; | |
| 614 GCstr *fmt; | |
| 615 const char *p; | |
| 616 if (L->top > L->base && tvisthread(L->base)) { | |
| 617 L2 = threadV(L->base); | |
| 618 arg = 1; | |
| 619 } | |
| 620 fmt = lj_lib_checkstr(L, arg+1); | |
| 621 depth = lj_lib_checkint(L, arg+2); | |
| 622 p = luaJIT_profile_dumpstack(L2, strdata(fmt), depth, &len); | |
| 623 lua_pushlstring(L, p, len); | |
| 624 return 1; | |
| 625 } | |
| 626 | |
| 627 #include "lj_libdef.h" | |
| 628 | |
| 629 static int luaopen_jit_profile(lua_State *L) | |
| 630 { | |
| 631 LJ_LIB_REG(L, NULL, jit_profile); | |
| 632 return 1; | |
| 633 } | |
| 634 | |
| 635 #endif | |
| 636 | |
| 637 /* -- JIT compiler initialization ----------------------------------------- */ | |
| 638 | |
| 639 #if LJ_HASJIT | |
| 640 /* Default values for JIT parameters. */ | |
| 641 static const int32_t jit_param_default[JIT_P__MAX+1] = { | |
| 642 #define JIT_PARAMINIT(len, name, value) (value), | |
| 643 JIT_PARAMDEF(JIT_PARAMINIT) | |
| 644 #undef JIT_PARAMINIT | |
| 645 0 | |
| 646 }; | |
| 647 | |
| 648 #if LJ_TARGET_ARM && LJ_TARGET_LINUX | |
| 649 #include <sys/utsname.h> | |
| 650 #endif | |
| 651 | |
| 652 /* Arch-dependent CPU feature detection. */ | |
| 653 static uint32_t jit_cpudetect(void) | |
| 654 { | |
| 655 uint32_t flags = 0; | |
| 656 #if LJ_TARGET_X86ORX64 | |
| 657 | |
| 658 uint32_t vendor[4]; | |
| 659 uint32_t features[4]; | |
| 660 if (lj_vm_cpuid(0, vendor) && lj_vm_cpuid(1, features)) { | |
| 661 flags |= ((features[2] >> 0)&1) * JIT_F_SSE3; | |
| 662 flags |= ((features[2] >> 19)&1) * JIT_F_SSE4_1; | |
| 663 if (vendor[0] >= 7) { | |
| 664 uint32_t xfeatures[4]; | |
| 665 lj_vm_cpuid(7, xfeatures); | |
| 666 flags |= ((xfeatures[1] >> 8)&1) * JIT_F_BMI2; | |
| 667 } | |
| 668 } | |
| 669 /* Don't bother checking for SSE2 -- the VM will crash before getting here. */ | |
| 670 | |
| 671 #elif LJ_TARGET_ARM | |
| 672 | |
| 673 int ver = LJ_ARCH_VERSION; /* Compile-time ARM CPU detection. */ | |
| 674 #if LJ_TARGET_LINUX | |
| 675 if (ver < 70) { /* Runtime ARM CPU detection. */ | |
| 676 struct utsname ut; | |
| 677 uname(&ut); | |
| 678 if (strncmp(ut.machine, "armv", 4) == 0) { | |
| 679 if (ut.machine[4] >= '8') ver = 80; | |
| 680 else if (ut.machine[4] == '7') ver = 70; | |
| 681 else if (ut.machine[4] == '6') ver = 60; | |
| 682 } | |
| 683 } | |
| 684 #endif | |
| 685 flags |= ver >= 70 ? JIT_F_ARMV7 : | |
| 686 ver >= 61 ? JIT_F_ARMV6T2_ : | |
| 687 ver >= 60 ? JIT_F_ARMV6_ : 0; | |
| 688 flags |= LJ_ARCH_HASFPU == 0 ? 0 : ver >= 70 ? JIT_F_VFPV3 : JIT_F_VFPV2; | |
| 689 | |
| 690 #elif LJ_TARGET_ARM64 | |
| 691 | |
| 692 /* No optional CPU features to detect (for now). */ | |
| 693 | |
| 694 #elif LJ_TARGET_PPC | |
| 695 | |
| 696 #if LJ_ARCH_SQRT | |
| 697 flags |= JIT_F_SQRT; | |
| 698 #endif | |
| 699 #if LJ_ARCH_ROUND | |
| 700 flags |= JIT_F_ROUND; | |
| 701 #endif | |
| 702 | |
| 703 #elif LJ_TARGET_MIPS | |
| 704 | |
| 705 /* Compile-time MIPS CPU detection. */ | |
| 706 #if LJ_ARCH_VERSION >= 20 | |
| 707 flags |= JIT_F_MIPSXXR2; | |
| 708 #endif | |
| 709 /* Runtime MIPS CPU detection. */ | |
| 710 #if defined(__GNUC__) | |
| 711 if (!(flags & JIT_F_MIPSXXR2)) { | |
| 712 int x; | |
| 713 #ifdef __mips16 | |
| 714 x = 0; /* Runtime detection is difficult. Ensure optimal -march flags. */ | |
| 715 #else | |
| 716 /* On MIPS32R1 rotr is treated as srl. rotr r2,r2,1 -> srl r2,r2,1. */ | |
| 717 __asm__("li $2, 1\n\t.long 0x00221042\n\tmove %0, $2" : "=r"(x) : : "$2"); | |
| 718 #endif | |
| 719 if (x) flags |= JIT_F_MIPSXXR2; /* Either 0x80000000 (R2) or 0 (R1). */ | |
| 720 } | |
| 721 #endif | |
| 722 | |
| 723 #else | |
| 724 #error "Missing CPU detection for this architecture" | |
| 725 #endif | |
| 726 return flags; | |
| 727 } | |
| 728 | |
| 729 /* Initialize JIT compiler. */ | |
| 730 static void jit_init(lua_State *L) | |
| 731 { | |
| 732 jit_State *J = L2J(L); | |
| 733 J->flags = jit_cpudetect() | JIT_F_ON | JIT_F_OPT_DEFAULT; | |
| 734 memcpy(J->param, jit_param_default, sizeof(J->param)); | |
| 735 lj_dispatch_update(G(L)); | |
| 736 } | |
| 737 #endif | |
| 738 | |
| 739 LUALIB_API int luaopen_jit(lua_State *L) | |
| 740 { | |
| 741 #if LJ_HASJIT | |
| 742 jit_init(L); | |
| 743 #endif | |
| 744 lua_pushliteral(L, LJ_OS_NAME); | |
| 745 lua_pushliteral(L, LJ_ARCH_NAME); | |
| 746 lua_pushinteger(L, LUAJIT_VERSION_NUM); /* Deprecated. */ | |
| 747 lua_pushliteral(L, LUAJIT_VERSION); | |
| 748 LJ_LIB_REG(L, LUA_JITLIBNAME, jit); | |
| 749 #if LJ_HASPROFILE | |
| 750 lj_lib_prereg(L, LUA_JITLIBNAME ".profile", luaopen_jit_profile, | |
| 751 tabref(L->env)); | |
| 752 #endif | |
| 753 #ifndef LUAJIT_DISABLE_JITUTIL | |
| 754 lj_lib_prereg(L, LUA_JITLIBNAME ".util", luaopen_jit_util, tabref(L->env)); | |
| 755 #endif | |
| 756 #if LJ_HASJIT | |
| 757 LJ_LIB_REG(L, "jit.opt", jit_opt); | |
| 758 #endif | |
| 759 L->top -= 2; | |
| 760 return 1; | |
| 761 } | |
| 762 |