1/*
2** JIT library.
3** Copyright (C) 2005-2021 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
43static 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
68LJLIB_CF(jit_on)
69{
70 return setjitmode(L, LUAJIT_MODE_ON);
71}
72
73LJLIB_CF(jit_off)
74{
75 return setjitmode(L, LUAJIT_MODE_OFF);
76}
77
78LJLIB_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. */
92static 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
101LJLIB_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
116LJLIB_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
123LJLIB_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
151LJLIB_PUSH(top-5) LJLIB_SET(os)
152LJLIB_PUSH(top-4) LJLIB_SET(arch)
153LJLIB_PUSH(top-3) LJLIB_SET(version_num)
154LJLIB_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) */
165static 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
182static 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]) */
188LJLIB_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) */
230LJLIB_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) */
247LJLIB_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) */
267LJLIB_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. */
283static 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 */
293static 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) */
299LJLIB_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) */
319LJLIB_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) */
337LJLIB_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_ctsG(G(L))) {
350 ptrdiff_t oldtop = savestack(L, L->top);
351 luaopen_ffi(L); /* Load FFI library on-demand. */
352 L->top = restorestack(L, oldtop);
353 }
354#endif
355 lj_ir_kvalue(L, L->top-2, ir);
356 setintV(L->top-1, (int32_t)irt_type(ir->t));
357 if (slot == -1)
358 return 2;
359 setintV(L->top++, slot);
360 return 3;
361 }
362 return 0;
363}
364
365/* local snap = jit.util.tracesnap(tr, sn) */
366LJLIB_CF(jit_util_tracesnap)
367{
368 GCtrace *T = jit_checktrace(L);
369 SnapNo sn = (SnapNo)lj_lib_checkint(L, 2);
370 if (T && sn < T->nsnap) {
371 SnapShot *snap = &T->snap[sn];
372 SnapEntry *map = &T->snapmap[snap->mapofs];
373 MSize n, nent = snap->nent;
374 GCtab *t;
375 lua_createtable(L, nent+2, 0);
376 t = tabV(L->top-1);
377 setintV(lj_tab_setint(L, t, 0), (int32_t)snap->ref - REF_BIAS);
378 setintV(lj_tab_setint(L, t, 1), (int32_t)snap->nslots);
379 for (n = 0; n < nent; n++)
380 setintV(lj_tab_setint(L, t, (int32_t)(n+2)), (int32_t)map[n]);
381 setintV(lj_tab_setint(L, t, (int32_t)(nent+2)), (int32_t)SNAP(255, 0, 0));
382 return 1;
383 }
384 return 0;
385}
386
387/* local mcode, addr, loop = jit.util.tracemc(tr) */
388LJLIB_CF(jit_util_tracemc)
389{
390 GCtrace *T = jit_checktrace(L);
391 if (T && T->mcode != NULL) {
392 setstrV(L, L->top-1, lj_str_new(L, (const char *)T->mcode, T->szmcode));
393 setintptrV(L->top++, (intptr_t)(void *)T->mcode);
394 setintV(L->top++, T->mcloop);
395 return 3;
396 }
397 return 0;
398}
399
400/* local addr = jit.util.traceexitstub([tr,] exitno) */
401LJLIB_CF(jit_util_traceexitstub)
402{
403#ifdef EXITSTUBS_PER_GROUP
404 ExitNo exitno = (ExitNo)lj_lib_checkint(L, 1);
405 jit_State *J = L2J(L);
406 if (exitno < EXITSTUBS_PER_GROUP*LJ_MAX_EXITSTUBGR) {
407 setintptrV(L->top-1, (intptr_t)(void *)exitstub_addr(J, exitno));
408 return 1;
409 }
410#else
411 if (L->top > L->base+1) { /* Don't throw for one-argument variant. */
412 GCtrace *T = jit_checktrace(L);
413 ExitNo exitno = (ExitNo)lj_lib_checkint(L, 2);
414 ExitNo maxexit = T->root ? T->nsnap+1 : T->nsnap;
415 if (T && T->mcode != NULL && exitno < maxexit) {
416 setintptrV(L->top-1, (intptr_t)(void *)exitstub_trace_addr(T, exitno));
417 return 1;
418 }
419 }
420#endif
421 return 0;
422}
423
424/* local addr = jit.util.ircalladdr(idx) */
425LJLIB_CF(jit_util_ircalladdr)
426{
427 uint32_t idx = (uint32_t)lj_lib_checkint(L, 1);
428 if (idx < IRCALL__MAX) {
429 setintptrV(L->top-1, (intptr_t)(void *)lj_ir_callinfo[idx].func);
430 return 1;
431 }
432 return 0;
433}
434
435#endif
436
437#include "lj_libdef.h"
438
439static int luaopen_jit_util(lua_State *L)
440{
441 LJ_LIB_REG(L, NULL, jit_util);
442 return 1;
443}
444
445/* -- jit.opt module ------------------------------------------------------ */
446
447#if LJ_HASJIT
448
449#define LJLIB_MODULE_jit_opt
450
451/* Parse optimization level. */
452static int jitopt_level(jit_State *J, const char *str)
453{
454 if (str[0] >= '0' && str[0] <= '9' && str[1] == '\0') {
455 uint32_t flags;
456 if (str[0] == '0') flags = JIT_F_OPT_0;
457 else if (str[0] == '1') flags = JIT_F_OPT_1;
458 else if (str[0] == '2') flags = JIT_F_OPT_2;
459 else flags = JIT_F_OPT_3;
460 J->flags = (J->flags & ~JIT_F_OPT_MASK) | flags;
461 return 1; /* Ok. */
462 }
463 return 0; /* No match. */
464}
465
466/* Parse optimization flag. */
467static int jitopt_flag(jit_State *J, const char *str)
468{
469 const char *lst = JIT_F_OPTSTRING;
470 uint32_t opt;
471 int set = 1;
472 if (str[0] == '+') {
473 str++;
474 } else if (str[0] == '-') {
475 str++;
476 set = 0;
477 } else if (str[0] == 'n' && str[1] == 'o') {
478 str += str[2] == '-' ? 3 : 2;
479 set = 0;
480 }
481 for (opt = JIT_F_OPT; ; opt <<= 1) {
482 size_t len = *(const uint8_t *)lst;
483 if (len == 0)
484 break;
485 if (strncmp(str, lst+1, len) == 0 && str[len] == '\0') {
486 if (set) J->flags |= opt; else J->flags &= ~opt;
487 return 1; /* Ok. */
488 }
489 lst += 1+len;
490 }
491 return 0; /* No match. */
492}
493
494/* Parse optimization parameter. */
495static int jitopt_param(jit_State *J, const char *str)
496{
497 const char *lst = JIT_P_STRING;
498 int i;
499 for (i = 0; i < JIT_P__MAX; i++) {
500 size_t len = *(const uint8_t *)lst;
501 lj_assertJ(len != 0, "bad JIT_P_STRING");
502 if (strncmp(str, lst+1, len) == 0 && str[len] == '=') {
503 int32_t n = 0;
504 const char *p = &str[len+1];
505 while (*p >= '0' && *p <= '9')
506 n = n*10 + (*p++ - '0');
507 if (*p) return 0; /* Malformed number. */
508 J->param[i] = n;
509 if (i == JIT_P_hotloop)
510 lj_dispatch_init_hotcount(J2G(J));
511 return 1; /* Ok. */
512 }
513 lst += 1+len;
514 }
515 return 0; /* No match. */
516}
517
518/* jit.opt.start(flags...) */
519LJLIB_CF(jit_opt_start)
520{
521 jit_State *J = L2J(L);
522 int nargs = (int)(L->top - L->base);
523 if (nargs == 0) {
524 J->flags = (J->flags & ~JIT_F_OPT_MASK) | JIT_F_OPT_DEFAULT;
525 } else {
526 int i;
527 for (i = 1; i <= nargs; i++) {
528 const char *str = strdata(lj_lib_checkstr(L, i));
529 if (!jitopt_level(J, str) &&
530 !jitopt_flag(J, str) &&
531 !jitopt_param(J, str))
532 lj_err_callerv(L, LJ_ERR_JITOPT, str);
533 }
534 }
535 return 0;
536}
537
538#include "lj_libdef.h"
539
540#endif
541
542/* -- jit.profile module -------------------------------------------------- */
543
544#if LJ_HASPROFILE
545
546#define LJLIB_MODULE_jit_profile
547
548/* Not loaded by default, use: local profile = require("jit.profile") */
549
550#define KEY_PROFILE_THREAD (U64x(80000000,00000000)|'t')
551#define KEY_PROFILE_FUNC (U64x(80000000,00000000)|'f')
552
553static void jit_profile_callback(lua_State *L2, lua_State *L, int samples,
554 int vmstate)
555{
556 TValue key;
557 cTValue *tv;
558 key.u64 = KEY_PROFILE_FUNC;
559 tv = lj_tab_get(L, tabV(registry(L)), &key);
560 if (tvisfunc(tv)) {
561 char vmst = (char)vmstate;
562 int status;
563 setfuncV(L2, L2->top++, funcV(tv));
564 setthreadV(L2, L2->top++, L);
565 setintV(L2->top++, samples);
566 setstrV(L2, L2->top++, lj_str_new(L2, &vmst, 1));
567 status = lua_pcall(L2, 3, 0, 0); /* callback(thread, samples, vmstate) */
568 if (status) {
569 if (G(L2)->panic) G(L2)->panic(L2);
570 exit(EXIT_FAILURE);
571 }
572 lj_trace_abort(G(L2));
573 }
574}
575
576/* profile.start(mode, cb) */
577LJLIB_CF(jit_profile_start)
578{
579 GCtab *registry = tabV(registry(L));
580 GCstr *mode = lj_lib_optstr(L, 1);
581 GCfunc *func = lj_lib_checkfunc(L, 2);
582 lua_State *L2 = lua_newthread(L); /* Thread that runs profiler callback. */
583 TValue key;
584 /* Anchor thread and function in registry. */
585 key.u64 = KEY_PROFILE_THREAD;
586 setthreadV(L, lj_tab_set(L, registry, &key), L2);
587 key.u64 = KEY_PROFILE_FUNC;
588 setfuncV(L, lj_tab_set(L, registry, &key), func);
589 lj_gc_anybarriert(L, registry);
590 luaJIT_profile_start(L, mode ? strdata(mode) : "",
591 (luaJIT_profile_callback)jit_profile_callback, L2);
592 return 0;
593}
594
595/* profile.stop() */
596LJLIB_CF(jit_profile_stop)
597{
598 GCtab *registry;
599 TValue key;
600 luaJIT_profile_stop(L);
601 registry = tabV(registry(L));
602 key.u64 = KEY_PROFILE_THREAD;
603 setnilV(lj_tab_set(L, registry, &key));
604 key.u64 = KEY_PROFILE_FUNC;
605 setnilV(lj_tab_set(L, registry, &key));
606 lj_gc_anybarriert(L, registry);
607 return 0;
608}
609
610/* dump = profile.dumpstack([thread,] fmt, depth) */
611LJLIB_CF(jit_profile_dumpstack)
612{
613 lua_State *L2 = L;
614 int arg = 0;
615 size_t len;
616 int depth;
617 GCstr *fmt;
618 const char *p;
619 if (L->top > L->base && tvisthread(L->base)) {
620 L2 = threadV(L->base);
621 arg = 1;
622 }
623 fmt = lj_lib_checkstr(L, arg+1);
624 depth = lj_lib_checkint(L, arg+2);
625 p = luaJIT_profile_dumpstack(L2, strdata(fmt), depth, &len);
626 lua_pushlstring(L, p, len);
627 return 1;
628}
629
630#include "lj_libdef.h"
631
632static int luaopen_jit_profile(lua_State *L)
633{
634 LJ_LIB_REG(L, NULL, jit_profile);
635 return 1;
636}
637
638#endif
639
640/* -- JIT compiler initialization ----------------------------------------- */
641
642#if LJ_HASJIT
643/* Default values for JIT parameters. */
644static const int32_t jit_param_default[JIT_P__MAX+1] = {
645#define JIT_PARAMINIT(len, name, value) (value),
646JIT_PARAMDEF(JIT_PARAMINIT)
647#undef JIT_PARAMINIT
648 0
649};
650
651#if LJ_TARGET_ARM && LJ_TARGET_LINUX
652#include <sys/utsname.h>
653#endif
654
655/* Arch-dependent CPU feature detection. */
656static uint32_t jit_cpudetect(void)
657{
658 uint32_t flags = 0;
659#if LJ_TARGET_X86ORX64
660
661 uint32_t vendor[4];
662 uint32_t features[4];
663 if (lj_vm_cpuid(0, vendor) && lj_vm_cpuid(1, features)) {
664 flags |= ((features[2] >> 0)&1) * JIT_F_SSE3;
665 flags |= ((features[2] >> 19)&1) * JIT_F_SSE4_1;
666 if (vendor[0] >= 7) {
667 uint32_t xfeatures[4];
668 lj_vm_cpuid(7, xfeatures);
669 flags |= ((xfeatures[1] >> 8)&1) * JIT_F_BMI2;
670 }
671 }
672 /* Don't bother checking for SSE2 -- the VM will crash before getting here. */
673
674#elif LJ_TARGET_ARM
675
676 int ver = LJ_ARCH_VERSION; /* Compile-time ARM CPU detection. */
677#if LJ_TARGET_LINUX
678 if (ver < 70) { /* Runtime ARM CPU detection. */
679 struct utsname ut;
680 uname(&ut);
681 if (strncmp(ut.machine, "armv", 4) == 0) {
682 if (ut.machine[4] >= '8') ver = 80;
683 else if (ut.machine[4] == '7') ver = 70;
684 else if (ut.machine[4] == '6') ver = 60;
685 }
686 }
687#endif
688 flags |= ver >= 70 ? JIT_F_ARMV7 :
689 ver >= 61 ? JIT_F_ARMV6T2_ :
690 ver >= 60 ? JIT_F_ARMV6_ : 0;
691 flags |= LJ_ARCH_HASFPU == 0 ? 0 : ver >= 70 ? JIT_F_VFPV3 : JIT_F_VFPV2;
692
693#elif LJ_TARGET_ARM64
694
695 /* No optional CPU features to detect (for now). */
696
697#elif LJ_TARGET_PPC
698
699#if LJ_ARCH_SQRT
700 flags |= JIT_F_SQRT;
701#endif
702#if LJ_ARCH_ROUND
703 flags |= JIT_F_ROUND;
704#endif
705
706#elif LJ_TARGET_MIPS
707
708 /* Compile-time MIPS CPU detection. */
709#if LJ_ARCH_VERSION >= 20
710 flags |= JIT_F_MIPSXXR2;
711#endif
712 /* Runtime MIPS CPU detection. */
713#if defined(__GNUC__)
714 if (!(flags & JIT_F_MIPSXXR2)) {
715 int x;
716#ifdef __mips16
717 x = 0; /* Runtime detection is difficult. Ensure optimal -march flags. */
718#else
719 /* On MIPS32R1 rotr is treated as srl. rotr r2,r2,1 -> srl r2,r2,1. */
720 __asm__("li $2, 1\n\t.long 0x00221042\n\tmove %0, $2" : "=r"(x) : : "$2");
721#endif
722 if (x) flags |= JIT_F_MIPSXXR2; /* Either 0x80000000 (R2) or 0 (R1). */
723 }
724#endif
725
726#else
727#error "Missing CPU detection for this architecture"
728#endif
729 return flags;
730}
731
732/* Initialize JIT compiler. */
733static void jit_init(lua_State *L)
734{
735 jit_State *J = L2J(L);
736 J->flags = jit_cpudetect() | JIT_F_ON | JIT_F_OPT_DEFAULT;
737 memcpy(J->param, jit_param_default, sizeof(J->param));
738 lj_dispatch_update(G(L));
739}
740#endif
741
742LUALIB_API int luaopen_jit(lua_State *L)
743{
744#if LJ_HASJIT
745 jit_init(L);
746#endif
747 lua_pushliteral(L, LJ_OS_NAME);
748 lua_pushliteral(L, LJ_ARCH_NAME);
749 lua_pushinteger(L, LUAJIT_VERSION_NUM);
750 lua_pushliteral(L, LUAJIT_VERSION);
751 LJ_LIB_REG(L, LUA_JITLIBNAME, jit);
752#if LJ_HASPROFILE
753 lj_lib_prereg(L, LUA_JITLIBNAME ".profile", luaopen_jit_profile,
754 tabref(L->env));
755#endif
756#ifndef LUAJIT_DISABLE_JITUTIL
757 lj_lib_prereg(L, LUA_JITLIBNAME ".util", luaopen_jit_util, tabref(L->env));
758#endif
759#if LJ_HASJIT
760 LJ_LIB_REG(L, "jit.opt", jit_opt);
761#endif
762 L->top -= 2;
763 return 1;
764}
765
766