2009-12-08 18:46:35 +00:00
|
|
|
/*
|
|
|
|
** JIT library.
|
2020-01-20 22:26:51 +00:00
|
|
|
** Copyright (C) 2005-2020 Mike Pall. See Copyright Notice in luajit.h
|
2009-12-08 18:46:35 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#define lib_jit_c
|
|
|
|
#define LUA_LIB
|
|
|
|
|
|
|
|
#include "lua.h"
|
|
|
|
#include "lauxlib.h"
|
|
|
|
#include "lualib.h"
|
|
|
|
|
|
|
|
#include "lj_obj.h"
|
2013-09-09 22:47:28 +00:00
|
|
|
#include "lj_gc.h"
|
2009-12-08 18:46:35 +00:00
|
|
|
#include "lj_err.h"
|
2011-06-07 19:37:24 +00:00
|
|
|
#include "lj_debug.h"
|
2009-12-08 18:46:35 +00:00
|
|
|
#include "lj_str.h"
|
|
|
|
#include "lj_tab.h"
|
2013-05-13 19:07:14 +00:00
|
|
|
#include "lj_state.h"
|
2010-02-11 15:21:18 +00:00
|
|
|
#include "lj_bc.h"
|
2013-05-13 19:07:14 +00:00
|
|
|
#if LJ_HASFFI
|
|
|
|
#include "lj_ctype.h"
|
|
|
|
#endif
|
2009-12-08 18:46:35 +00:00
|
|
|
#if LJ_HASJIT
|
|
|
|
#include "lj_ir.h"
|
|
|
|
#include "lj_jit.h"
|
2011-05-22 14:19:53 +00:00
|
|
|
#include "lj_ircall.h"
|
2009-12-08 18:46:35 +00:00
|
|
|
#include "lj_iropt.h"
|
2011-05-16 17:31:07 +00:00
|
|
|
#include "lj_target.h"
|
2009-12-08 18:46:35 +00:00
|
|
|
#endif
|
2013-09-18 13:17:39 +00:00
|
|
|
#include "lj_trace.h"
|
2009-12-08 18:46:35 +00:00
|
|
|
#include "lj_dispatch.h"
|
|
|
|
#include "lj_vm.h"
|
|
|
|
#include "lj_vmevent.h"
|
|
|
|
#include "lj_lib.h"
|
|
|
|
|
|
|
|
#include "luajit.h"
|
|
|
|
|
|
|
|
/* -- jit.* functions ----------------------------------------------------- */
|
|
|
|
|
|
|
|
#define LJLIB_MODULE_jit
|
|
|
|
|
|
|
|
static int setjitmode(lua_State *L, int mode)
|
|
|
|
{
|
|
|
|
int idx = 0;
|
|
|
|
if (L->base == L->top || tvisnil(L->base)) { /* jit.on/off/flush([nil]) */
|
|
|
|
mode |= LUAJIT_MODE_ENGINE;
|
|
|
|
} else {
|
|
|
|
/* jit.on/off/flush(func|proto, nil|true|false) */
|
|
|
|
if (tvisfunc(L->base) || tvisproto(L->base))
|
|
|
|
idx = 1;
|
|
|
|
else if (!tvistrue(L->base)) /* jit.on/off/flush(true, nil|true|false) */
|
|
|
|
goto err;
|
|
|
|
if (L->base+1 < L->top && tvisbool(L->base+1))
|
|
|
|
mode |= boolV(L->base+1) ? LUAJIT_MODE_ALLFUNC : LUAJIT_MODE_ALLSUBFUNC;
|
|
|
|
else
|
|
|
|
mode |= LUAJIT_MODE_FUNC;
|
|
|
|
}
|
|
|
|
if (luaJIT_setmode(L, idx, mode) != 1) {
|
2010-02-16 22:39:24 +00:00
|
|
|
if ((mode & LUAJIT_MODE_MASK) == LUAJIT_MODE_ENGINE)
|
|
|
|
lj_err_caller(L, LJ_ERR_NOJIT);
|
2009-12-08 18:46:35 +00:00
|
|
|
err:
|
2010-11-17 19:07:55 +00:00
|
|
|
lj_err_argt(L, 1, LUA_TFUNCTION);
|
2009-12-08 18:46:35 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
LJLIB_CF(jit_on)
|
|
|
|
{
|
|
|
|
return setjitmode(L, LUAJIT_MODE_ON);
|
|
|
|
}
|
|
|
|
|
|
|
|
LJLIB_CF(jit_off)
|
|
|
|
{
|
|
|
|
return setjitmode(L, LUAJIT_MODE_OFF);
|
|
|
|
}
|
|
|
|
|
|
|
|
LJLIB_CF(jit_flush)
|
|
|
|
{
|
|
|
|
#if LJ_HASJIT
|
2013-08-11 11:47:35 +00:00
|
|
|
if (L->base < L->top && tvisnumber(L->base)) {
|
2009-12-08 18:46:35 +00:00
|
|
|
int traceno = lj_lib_checkint(L, 1);
|
2010-04-25 01:32:29 +00:00
|
|
|
luaJIT_setmode(L, traceno, LUAJIT_MODE_FLUSH|LUAJIT_MODE_TRACE);
|
|
|
|
return 0;
|
2009-12-08 18:46:35 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return setjitmode(L, LUAJIT_MODE_FLUSH);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if LJ_HASJIT
|
|
|
|
/* Push a string for every flag bit that is set. */
|
|
|
|
static void flagbits_to_strings(lua_State *L, uint32_t flags, uint32_t base,
|
|
|
|
const char *str)
|
|
|
|
{
|
|
|
|
for (; *str; base <<= 1, str += 1+*str)
|
|
|
|
if (flags & base)
|
|
|
|
setstrV(L, L->top++, lj_str_new(L, str+1, *(uint8_t *)str));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
LJLIB_CF(jit_status)
|
|
|
|
{
|
|
|
|
#if LJ_HASJIT
|
|
|
|
jit_State *J = L2J(L);
|
|
|
|
L->top = L->base;
|
|
|
|
setboolV(L->top++, (J->flags & JIT_F_ON) ? 1 : 0);
|
2020-05-20 18:42:04 +00:00
|
|
|
flagbits_to_strings(L, J->flags, JIT_F_CPU, JIT_F_CPUSTRING);
|
|
|
|
flagbits_to_strings(L, J->flags, JIT_F_OPT, JIT_F_OPTSTRING);
|
2010-02-24 19:02:20 +00:00
|
|
|
return (int)(L->top - L->base);
|
2009-12-08 18:46:35 +00:00
|
|
|
#else
|
|
|
|
setboolV(L->top++, 0);
|
|
|
|
return 1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
LJLIB_CF(jit_attach)
|
|
|
|
{
|
|
|
|
#ifdef LUAJIT_DISABLE_VMEVENT
|
|
|
|
luaL_error(L, "vmevent API disabled");
|
|
|
|
#else
|
|
|
|
GCfunc *fn = lj_lib_checkfunc(L, 1);
|
|
|
|
GCstr *s = lj_lib_optstr(L, 2);
|
|
|
|
luaL_findtable(L, LUA_REGISTRYINDEX, LJ_VMEVENTS_REGKEY, LJ_VMEVENTS_HSIZE);
|
|
|
|
if (s) { /* Attach to given event. */
|
2010-07-21 19:23:45 +00:00
|
|
|
const uint8_t *p = (const uint8_t *)strdata(s);
|
|
|
|
uint32_t h = s->len;
|
|
|
|
while (*p) h = h ^ (lj_rol(h, 6) + *p++);
|
2009-12-08 18:46:35 +00:00
|
|
|
lua_pushvalue(L, 1);
|
2010-07-21 19:23:45 +00:00
|
|
|
lua_rawseti(L, -2, VMEVENT_HASHIDX(h));
|
2009-12-08 18:46:35 +00:00
|
|
|
G(L)->vmevmask = VMEVENT_NOCACHE; /* Invalidate cache. */
|
|
|
|
} else { /* Detach if no event given. */
|
|
|
|
setnilV(L->top++);
|
|
|
|
while (lua_next(L, -2)) {
|
|
|
|
L->top--;
|
|
|
|
if (tvisfunc(L->top) && funcV(L->top) == fn) {
|
|
|
|
setnilV(lj_tab_set(L, tabV(L->top-2), L->top-1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-11-16 14:05:21 +00:00
|
|
|
LJLIB_PUSH(top-5) LJLIB_SET(os)
|
2009-12-08 18:46:35 +00:00
|
|
|
LJLIB_PUSH(top-4) LJLIB_SET(arch)
|
|
|
|
LJLIB_PUSH(top-3) LJLIB_SET(version_num)
|
|
|
|
LJLIB_PUSH(top-2) LJLIB_SET(version)
|
|
|
|
|
|
|
|
#include "lj_libdef.h"
|
|
|
|
|
|
|
|
/* -- jit.util.* functions ------------------------------------------------ */
|
|
|
|
|
|
|
|
#define LJLIB_MODULE_jit_util
|
|
|
|
|
|
|
|
/* -- Reflection API for Lua functions ------------------------------------ */
|
|
|
|
|
|
|
|
/* Return prototype of first argument (Lua function or prototype object) */
|
|
|
|
static GCproto *check_Lproto(lua_State *L, int nolua)
|
|
|
|
{
|
|
|
|
TValue *o = L->base;
|
|
|
|
if (L->top > o) {
|
|
|
|
if (tvisproto(o)) {
|
|
|
|
return protoV(o);
|
|
|
|
} else if (tvisfunc(o)) {
|
|
|
|
if (isluafunc(funcV(o)))
|
|
|
|
return funcproto(funcV(o));
|
|
|
|
else if (nolua)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lj_err_argt(L, 1, LUA_TFUNCTION);
|
|
|
|
return NULL; /* unreachable */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void setintfield(lua_State *L, GCtab *t, const char *name, int32_t val)
|
|
|
|
{
|
|
|
|
setintV(lj_tab_setstr(L, t, lj_str_newz(L, name)), val);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* local info = jit.util.funcinfo(func [,pc]) */
|
|
|
|
LJLIB_CF(jit_util_funcinfo)
|
|
|
|
{
|
|
|
|
GCproto *pt = check_Lproto(L, 1);
|
|
|
|
if (pt) {
|
|
|
|
BCPos pc = (BCPos)lj_lib_optint(L, 2, 0);
|
|
|
|
GCtab *t;
|
|
|
|
lua_createtable(L, 0, 16); /* Increment hash size if fields are added. */
|
|
|
|
t = tabV(L->top-1);
|
2011-06-08 23:27:37 +00:00
|
|
|
setintfield(L, t, "linedefined", pt->firstline);
|
|
|
|
setintfield(L, t, "lastlinedefined", pt->firstline + pt->numline);
|
2009-12-08 18:46:35 +00:00
|
|
|
setintfield(L, t, "stackslots", pt->framesize);
|
|
|
|
setintfield(L, t, "params", pt->numparams);
|
|
|
|
setintfield(L, t, "bytecodes", (int32_t)pt->sizebc);
|
|
|
|
setintfield(L, t, "gcconsts", (int32_t)pt->sizekgc);
|
|
|
|
setintfield(L, t, "nconsts", (int32_t)pt->sizekn);
|
|
|
|
setintfield(L, t, "upvalues", (int32_t)pt->sizeuv);
|
2010-02-13 03:51:56 +00:00
|
|
|
if (pc < pt->sizebc)
|
2011-06-07 19:37:24 +00:00
|
|
|
setintfield(L, t, "currentline", lj_debug_line(pt, pc));
|
2011-06-09 11:54:40 +00:00
|
|
|
lua_pushboolean(L, (pt->flags & PROTO_VARARG));
|
2009-12-08 18:46:35 +00:00
|
|
|
lua_setfield(L, -2, "isvararg");
|
2011-06-12 21:51:13 +00:00
|
|
|
lua_pushboolean(L, (pt->flags & PROTO_CHILD));
|
|
|
|
lua_setfield(L, -2, "children");
|
2010-02-04 23:52:21 +00:00
|
|
|
setstrV(L, L->top++, proto_chunkname(pt));
|
2009-12-08 18:46:35 +00:00
|
|
|
lua_setfield(L, -2, "source");
|
2011-06-07 19:37:24 +00:00
|
|
|
lj_debug_pushloc(L, pt, pc);
|
2009-12-08 18:46:35 +00:00
|
|
|
lua_setfield(L, -2, "loc");
|
2016-12-13 20:30:13 +00:00
|
|
|
setprotoV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "proto")), pt);
|
2009-12-08 18:46:35 +00:00
|
|
|
} else {
|
|
|
|
GCfunc *fn = funcV(L->base);
|
|
|
|
GCtab *t;
|
2010-02-15 16:36:29 +00:00
|
|
|
lua_createtable(L, 0, 4); /* Increment hash size if fields are added. */
|
2009-12-08 18:46:35 +00:00
|
|
|
t = tabV(L->top-1);
|
2010-02-15 16:36:29 +00:00
|
|
|
if (!iscfunc(fn))
|
|
|
|
setintfield(L, t, "ffid", fn->c.ffid);
|
2011-02-16 23:44:14 +00:00
|
|
|
setintptrV(lj_tab_setstr(L, t, lj_str_newlit(L, "addr")),
|
|
|
|
(intptr_t)(void *)fn->c.f);
|
2009-12-08 18:46:35 +00:00
|
|
|
setintfield(L, t, "upvalues", fn->c.nupvalues);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* local ins, m = jit.util.funcbc(func, pc) */
|
|
|
|
LJLIB_CF(jit_util_funcbc)
|
|
|
|
{
|
|
|
|
GCproto *pt = check_Lproto(L, 0);
|
2010-02-13 03:51:56 +00:00
|
|
|
BCPos pc = (BCPos)lj_lib_checkint(L, 2);
|
2009-12-08 18:46:35 +00:00
|
|
|
if (pc < pt->sizebc) {
|
2010-02-08 19:17:34 +00:00
|
|
|
BCIns ins = proto_bc(pt)[pc];
|
2009-12-08 18:46:35 +00:00
|
|
|
BCOp op = bc_op(ins);
|
2020-06-12 22:52:54 +00:00
|
|
|
lj_assertL(op < BC__MAX, "bad bytecode op %d", op);
|
2009-12-08 18:46:35 +00:00
|
|
|
setintV(L->top, ins);
|
|
|
|
setintV(L->top+1, lj_bc_mode[op]);
|
|
|
|
L->top += 2;
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* local k = jit.util.funck(func, idx) */
|
|
|
|
LJLIB_CF(jit_util_funck)
|
|
|
|
{
|
|
|
|
GCproto *pt = check_Lproto(L, 0);
|
2009-12-29 00:38:26 +00:00
|
|
|
ptrdiff_t idx = (ptrdiff_t)lj_lib_checkint(L, 2);
|
|
|
|
if (idx >= 0) {
|
|
|
|
if (idx < (ptrdiff_t)pt->sizekn) {
|
2011-02-16 23:44:14 +00:00
|
|
|
copyTV(L, L->top-1, proto_knumtv(pt, idx));
|
2009-12-08 18:46:35 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
} else {
|
2009-12-29 00:38:26 +00:00
|
|
|
if (~idx < (ptrdiff_t)pt->sizekgc) {
|
2010-02-04 23:07:32 +00:00
|
|
|
GCobj *gc = proto_kgc(pt, idx);
|
2010-04-25 22:28:44 +00:00
|
|
|
setgcV(L, L->top-1, gc, ~gc->gch.gct);
|
2009-12-08 18:46:35 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* local name = jit.util.funcuvname(func, idx) */
|
|
|
|
LJLIB_CF(jit_util_funcuvname)
|
|
|
|
{
|
|
|
|
GCproto *pt = check_Lproto(L, 0);
|
|
|
|
uint32_t idx = (uint32_t)lj_lib_checkint(L, 2);
|
2010-02-08 04:30:57 +00:00
|
|
|
if (idx < pt->sizeuv) {
|
2011-06-08 23:27:37 +00:00
|
|
|
setstrV(L, L->top-1, lj_str_newz(L, lj_debug_uvname(pt, idx)));
|
2009-12-08 18:46:35 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -- Reflection API for traces ------------------------------------------- */
|
|
|
|
|
|
|
|
#if LJ_HASJIT
|
|
|
|
|
|
|
|
/* Check trace argument. Must not throw for non-existent trace numbers. */
|
2010-04-25 01:32:29 +00:00
|
|
|
static GCtrace *jit_checktrace(lua_State *L)
|
2009-12-08 18:46:35 +00:00
|
|
|
{
|
|
|
|
TraceNo tr = (TraceNo)lj_lib_checkint(L, 1);
|
|
|
|
jit_State *J = L2J(L);
|
|
|
|
if (tr > 0 && tr < J->sizetrace)
|
2010-04-25 01:32:29 +00:00
|
|
|
return traceref(J, tr);
|
2009-12-08 18:46:35 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-06-28 21:23:34 +00:00
|
|
|
/* Names of link types. ORDER LJ_TRLINK */
|
|
|
|
static const char *const jit_trlinkname[] = {
|
|
|
|
"none", "root", "loop", "tail-recursion", "up-recursion", "down-recursion",
|
2013-12-25 01:55:25 +00:00
|
|
|
"interpreter", "return", "stitch"
|
2011-06-28 21:23:34 +00:00
|
|
|
};
|
|
|
|
|
2009-12-08 18:46:35 +00:00
|
|
|
/* local info = jit.util.traceinfo(tr) */
|
|
|
|
LJLIB_CF(jit_util_traceinfo)
|
|
|
|
{
|
2010-04-25 01:32:29 +00:00
|
|
|
GCtrace *T = jit_checktrace(L);
|
2009-12-08 18:46:35 +00:00
|
|
|
if (T) {
|
|
|
|
GCtab *t;
|
2011-06-28 21:23:34 +00:00
|
|
|
lua_createtable(L, 0, 8); /* Increment hash size if fields are added. */
|
2009-12-08 18:46:35 +00:00
|
|
|
t = tabV(L->top-1);
|
|
|
|
setintfield(L, t, "nins", (int32_t)T->nins - REF_BIAS - 1);
|
|
|
|
setintfield(L, t, "nk", REF_BIAS - (int32_t)T->nk);
|
|
|
|
setintfield(L, t, "link", T->link);
|
|
|
|
setintfield(L, t, "nexit", T->nsnap);
|
2011-06-28 21:23:34 +00:00
|
|
|
setstrV(L, L->top++, lj_str_newz(L, jit_trlinkname[T->linktype]));
|
|
|
|
lua_setfield(L, -2, "linktype");
|
2009-12-08 18:46:35 +00:00
|
|
|
/* There are many more fields. Add them only when needed. */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* local m, ot, op1, op2, prev = jit.util.traceir(tr, idx) */
|
|
|
|
LJLIB_CF(jit_util_traceir)
|
|
|
|
{
|
2010-04-25 01:32:29 +00:00
|
|
|
GCtrace *T = jit_checktrace(L);
|
2009-12-08 18:46:35 +00:00
|
|
|
IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS;
|
|
|
|
if (T && ref >= REF_BIAS && ref < T->nins) {
|
|
|
|
IRIns *ir = &T->ir[ref];
|
|
|
|
int32_t m = lj_ir_mode[ir->o];
|
|
|
|
setintV(L->top-2, m);
|
|
|
|
setintV(L->top-1, ir->ot);
|
|
|
|
setintV(L->top++, (int32_t)ir->op1 - (irm_op1(m)==IRMref ? REF_BIAS : 0));
|
|
|
|
setintV(L->top++, (int32_t)ir->op2 - (irm_op2(m)==IRMref ? REF_BIAS : 0));
|
|
|
|
setintV(L->top++, ir->prev);
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* local k, t [, slot] = jit.util.tracek(tr, idx) */
|
|
|
|
LJLIB_CF(jit_util_tracek)
|
|
|
|
{
|
2010-04-25 01:32:29 +00:00
|
|
|
GCtrace *T = jit_checktrace(L);
|
2009-12-08 18:46:35 +00:00
|
|
|
IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS;
|
|
|
|
if (T && ref >= T->nk && ref < REF_BIAS) {
|
|
|
|
IRIns *ir = &T->ir[ref];
|
|
|
|
int32_t slot = -1;
|
|
|
|
if (ir->o == IR_KSLOT) {
|
|
|
|
slot = ir->op2;
|
|
|
|
ir = &T->ir[ir->op1];
|
|
|
|
}
|
2013-05-13 19:07:14 +00:00
|
|
|
#if LJ_HASFFI
|
|
|
|
if (ir->o == IR_KINT64 && !ctype_ctsG(G(L))) {
|
|
|
|
ptrdiff_t oldtop = savestack(L, L->top);
|
|
|
|
luaopen_ffi(L); /* Load FFI library on-demand. */
|
|
|
|
L->top = restorestack(L, oldtop);
|
|
|
|
}
|
|
|
|
#endif
|
2009-12-08 18:46:35 +00:00
|
|
|
lj_ir_kvalue(L, L->top-2, ir);
|
|
|
|
setintV(L->top-1, (int32_t)irt_type(ir->t));
|
|
|
|
if (slot == -1)
|
|
|
|
return 2;
|
|
|
|
setintV(L->top++, slot);
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* local snap = jit.util.tracesnap(tr, sn) */
|
|
|
|
LJLIB_CF(jit_util_tracesnap)
|
|
|
|
{
|
2010-04-25 01:32:29 +00:00
|
|
|
GCtrace *T = jit_checktrace(L);
|
2009-12-08 18:46:35 +00:00
|
|
|
SnapNo sn = (SnapNo)lj_lib_checkint(L, 2);
|
|
|
|
if (T && sn < T->nsnap) {
|
|
|
|
SnapShot *snap = &T->snap[sn];
|
2010-01-25 18:51:52 +00:00
|
|
|
SnapEntry *map = &T->snapmap[snap->mapofs];
|
2010-01-26 20:49:04 +00:00
|
|
|
MSize n, nent = snap->nent;
|
2009-12-08 18:46:35 +00:00
|
|
|
GCtab *t;
|
2010-01-27 19:06:03 +00:00
|
|
|
lua_createtable(L, nent+2, 0);
|
2009-12-08 18:46:35 +00:00
|
|
|
t = tabV(L->top-1);
|
|
|
|
setintV(lj_tab_setint(L, t, 0), (int32_t)snap->ref - REF_BIAS);
|
2010-01-27 19:06:03 +00:00
|
|
|
setintV(lj_tab_setint(L, t, 1), (int32_t)snap->nslots);
|
|
|
|
for (n = 0; n < nent; n++)
|
|
|
|
setintV(lj_tab_setint(L, t, (int32_t)(n+2)), (int32_t)map[n]);
|
|
|
|
setintV(lj_tab_setint(L, t, (int32_t)(nent+2)), (int32_t)SNAP(255, 0, 0));
|
2009-12-08 18:46:35 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* local mcode, addr, loop = jit.util.tracemc(tr) */
|
|
|
|
LJLIB_CF(jit_util_tracemc)
|
|
|
|
{
|
2010-04-25 01:32:29 +00:00
|
|
|
GCtrace *T = jit_checktrace(L);
|
2009-12-08 18:46:35 +00:00
|
|
|
if (T && T->mcode != NULL) {
|
|
|
|
setstrV(L, L->top-1, lj_str_new(L, (const char *)T->mcode, T->szmcode));
|
2011-02-16 23:44:14 +00:00
|
|
|
setintptrV(L->top++, (intptr_t)(void *)T->mcode);
|
2009-12-08 18:46:35 +00:00
|
|
|
setintV(L->top++, T->mcloop);
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-10-24 14:13:12 +00:00
|
|
|
/* local addr = jit.util.traceexitstub([tr,] exitno) */
|
2009-12-08 18:46:35 +00:00
|
|
|
LJLIB_CF(jit_util_traceexitstub)
|
|
|
|
{
|
2011-10-24 14:13:12 +00:00
|
|
|
#ifdef EXITSTUBS_PER_GROUP
|
2009-12-08 18:46:35 +00:00
|
|
|
ExitNo exitno = (ExitNo)lj_lib_checkint(L, 1);
|
|
|
|
jit_State *J = L2J(L);
|
|
|
|
if (exitno < EXITSTUBS_PER_GROUP*LJ_MAX_EXITSTUBGR) {
|
2011-02-16 23:44:14 +00:00
|
|
|
setintptrV(L->top-1, (intptr_t)(void *)exitstub_addr(J, exitno));
|
2010-09-14 22:51:43 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2011-10-24 14:13:12 +00:00
|
|
|
#else
|
|
|
|
if (L->top > L->base+1) { /* Don't throw for one-argument variant. */
|
|
|
|
GCtrace *T = jit_checktrace(L);
|
|
|
|
ExitNo exitno = (ExitNo)lj_lib_checkint(L, 2);
|
|
|
|
ExitNo maxexit = T->root ? T->nsnap+1 : T->nsnap;
|
|
|
|
if (T && T->mcode != NULL && exitno < maxexit) {
|
|
|
|
setintptrV(L->top-1, (intptr_t)(void *)exitstub_trace_addr(T, exitno));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2010-09-14 22:51:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* local addr = jit.util.ircalladdr(idx) */
|
|
|
|
LJLIB_CF(jit_util_ircalladdr)
|
|
|
|
{
|
|
|
|
uint32_t idx = (uint32_t)lj_lib_checkint(L, 1);
|
|
|
|
if (idx < IRCALL__MAX) {
|
2011-02-16 23:44:14 +00:00
|
|
|
setintptrV(L->top-1, (intptr_t)(void *)lj_ir_callinfo[idx].func);
|
2009-12-08 18:46:35 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "lj_libdef.h"
|
|
|
|
|
2013-09-08 01:01:00 +00:00
|
|
|
static int luaopen_jit_util(lua_State *L)
|
|
|
|
{
|
|
|
|
LJ_LIB_REG(L, NULL, jit_util);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-12-08 18:46:35 +00:00
|
|
|
/* -- jit.opt module ------------------------------------------------------ */
|
|
|
|
|
2012-09-24 14:56:07 +00:00
|
|
|
#if LJ_HASJIT
|
|
|
|
|
2009-12-08 18:46:35 +00:00
|
|
|
#define LJLIB_MODULE_jit_opt
|
|
|
|
|
|
|
|
/* Parse optimization level. */
|
|
|
|
static int jitopt_level(jit_State *J, const char *str)
|
|
|
|
{
|
|
|
|
if (str[0] >= '0' && str[0] <= '9' && str[1] == '\0') {
|
|
|
|
uint32_t flags;
|
|
|
|
if (str[0] == '0') flags = JIT_F_OPT_0;
|
|
|
|
else if (str[0] == '1') flags = JIT_F_OPT_1;
|
|
|
|
else if (str[0] == '2') flags = JIT_F_OPT_2;
|
|
|
|
else flags = JIT_F_OPT_3;
|
|
|
|
J->flags = (J->flags & ~JIT_F_OPT_MASK) | flags;
|
|
|
|
return 1; /* Ok. */
|
|
|
|
}
|
|
|
|
return 0; /* No match. */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse optimization flag. */
|
|
|
|
static int jitopt_flag(jit_State *J, const char *str)
|
|
|
|
{
|
|
|
|
const char *lst = JIT_F_OPTSTRING;
|
|
|
|
uint32_t opt;
|
|
|
|
int set = 1;
|
|
|
|
if (str[0] == '+') {
|
|
|
|
str++;
|
|
|
|
} else if (str[0] == '-') {
|
|
|
|
str++;
|
|
|
|
set = 0;
|
|
|
|
} else if (str[0] == 'n' && str[1] == 'o') {
|
|
|
|
str += str[2] == '-' ? 3 : 2;
|
|
|
|
set = 0;
|
|
|
|
}
|
2020-05-20 18:42:04 +00:00
|
|
|
for (opt = JIT_F_OPT; ; opt <<= 1) {
|
2009-12-08 18:46:35 +00:00
|
|
|
size_t len = *(const uint8_t *)lst;
|
|
|
|
if (len == 0)
|
|
|
|
break;
|
|
|
|
if (strncmp(str, lst+1, len) == 0 && str[len] == '\0') {
|
|
|
|
if (set) J->flags |= opt; else J->flags &= ~opt;
|
|
|
|
return 1; /* Ok. */
|
|
|
|
}
|
|
|
|
lst += 1+len;
|
|
|
|
}
|
|
|
|
return 0; /* No match. */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse optimization parameter. */
|
|
|
|
static int jitopt_param(jit_State *J, const char *str)
|
|
|
|
{
|
|
|
|
const char *lst = JIT_P_STRING;
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < JIT_P__MAX; i++) {
|
|
|
|
size_t len = *(const uint8_t *)lst;
|
2020-06-12 22:52:54 +00:00
|
|
|
lj_assertJ(len != 0, "bad JIT_P_STRING");
|
2011-02-16 23:44:14 +00:00
|
|
|
if (strncmp(str, lst+1, len) == 0 && str[len] == '=') {
|
|
|
|
int32_t n = 0;
|
|
|
|
const char *p = &str[len+1];
|
|
|
|
while (*p >= '0' && *p <= '9')
|
|
|
|
n = n*10 + (*p++ - '0');
|
|
|
|
if (*p) return 0; /* Malformed number. */
|
|
|
|
J->param[i] = n;
|
2009-12-08 18:46:35 +00:00
|
|
|
if (i == JIT_P_hotloop)
|
2010-02-04 19:40:00 +00:00
|
|
|
lj_dispatch_init_hotcount(J2G(J));
|
2009-12-08 18:46:35 +00:00
|
|
|
return 1; /* Ok. */
|
|
|
|
}
|
|
|
|
lst += 1+len;
|
|
|
|
}
|
|
|
|
return 0; /* No match. */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* jit.opt.start(flags...) */
|
|
|
|
LJLIB_CF(jit_opt_start)
|
|
|
|
{
|
|
|
|
jit_State *J = L2J(L);
|
|
|
|
int nargs = (int)(L->top - L->base);
|
|
|
|
if (nargs == 0) {
|
|
|
|
J->flags = (J->flags & ~JIT_F_OPT_MASK) | JIT_F_OPT_DEFAULT;
|
|
|
|
} else {
|
|
|
|
int i;
|
|
|
|
for (i = 1; i <= nargs; i++) {
|
|
|
|
const char *str = strdata(lj_lib_checkstr(L, i));
|
|
|
|
if (!jitopt_level(J, str) &&
|
|
|
|
!jitopt_flag(J, str) &&
|
|
|
|
!jitopt_param(J, str))
|
|
|
|
lj_err_callerv(L, LJ_ERR_JITOPT, str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "lj_libdef.h"
|
|
|
|
|
2012-09-24 14:56:07 +00:00
|
|
|
#endif
|
|
|
|
|
2013-09-01 23:55:20 +00:00
|
|
|
/* -- jit.profile module -------------------------------------------------- */
|
|
|
|
|
|
|
|
#if LJ_HASPROFILE
|
|
|
|
|
|
|
|
#define LJLIB_MODULE_jit_profile
|
|
|
|
|
|
|
|
/* Not loaded by default, use: local profile = require("jit.profile") */
|
|
|
|
|
|
|
|
static const char KEY_PROFILE_THREAD = 't';
|
|
|
|
static const char KEY_PROFILE_FUNC = 'f';
|
|
|
|
|
|
|
|
static void jit_profile_callback(lua_State *L2, lua_State *L, int samples,
|
|
|
|
int vmstate)
|
|
|
|
{
|
|
|
|
TValue key;
|
|
|
|
cTValue *tv;
|
|
|
|
setlightudV(&key, (void *)&KEY_PROFILE_FUNC);
|
|
|
|
tv = lj_tab_get(L, tabV(registry(L)), &key);
|
|
|
|
if (tvisfunc(tv)) {
|
|
|
|
char vmst = (char)vmstate;
|
|
|
|
int status;
|
|
|
|
setfuncV(L2, L2->top++, funcV(tv));
|
|
|
|
setthreadV(L2, L2->top++, L);
|
|
|
|
setintV(L2->top++, samples);
|
|
|
|
setstrV(L2, L2->top++, lj_str_new(L2, &vmst, 1));
|
|
|
|
status = lua_pcall(L2, 3, 0, 0); /* callback(thread, samples, vmstate) */
|
|
|
|
if (status) {
|
|
|
|
if (G(L2)->panic) G(L2)->panic(L2);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2013-09-16 09:23:10 +00:00
|
|
|
lj_trace_abort(G(L2));
|
2013-09-01 23:55:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-09 22:02:20 +00:00
|
|
|
/* profile.start(mode, cb) */
|
2013-09-01 23:55:20 +00:00
|
|
|
LJLIB_CF(jit_profile_start)
|
|
|
|
{
|
|
|
|
GCtab *registry = tabV(registry(L));
|
|
|
|
GCstr *mode = lj_lib_optstr(L, 1);
|
|
|
|
GCfunc *func = lj_lib_checkfunc(L, 2);
|
|
|
|
lua_State *L2 = lua_newthread(L); /* Thread that runs profiler callback. */
|
|
|
|
TValue key;
|
|
|
|
/* Anchor thread and function in registry. */
|
|
|
|
setlightudV(&key, (void *)&KEY_PROFILE_THREAD);
|
|
|
|
setthreadV(L, lj_tab_set(L, registry, &key), L2);
|
|
|
|
setlightudV(&key, (void *)&KEY_PROFILE_FUNC);
|
|
|
|
setfuncV(L, lj_tab_set(L, registry, &key), func);
|
|
|
|
lj_gc_anybarriert(L, registry);
|
|
|
|
luaJIT_profile_start(L, mode ? strdata(mode) : "",
|
|
|
|
(luaJIT_profile_callback)jit_profile_callback, L2);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* profile.stop() */
|
|
|
|
LJLIB_CF(jit_profile_stop)
|
|
|
|
{
|
|
|
|
GCtab *registry;
|
|
|
|
TValue key;
|
|
|
|
luaJIT_profile_stop(L);
|
|
|
|
registry = tabV(registry(L));
|
|
|
|
setlightudV(&key, (void *)&KEY_PROFILE_THREAD);
|
|
|
|
setnilV(lj_tab_set(L, registry, &key));
|
|
|
|
setlightudV(&key, (void *)&KEY_PROFILE_FUNC);
|
|
|
|
setnilV(lj_tab_set(L, registry, &key));
|
|
|
|
lj_gc_anybarriert(L, registry);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-09 22:02:20 +00:00
|
|
|
/* dump = profile.dumpstack([thread,] fmt, depth) */
|
2013-09-01 23:55:20 +00:00
|
|
|
LJLIB_CF(jit_profile_dumpstack)
|
|
|
|
{
|
|
|
|
lua_State *L2 = L;
|
|
|
|
int arg = 0;
|
|
|
|
size_t len;
|
|
|
|
int depth;
|
|
|
|
GCstr *fmt;
|
|
|
|
const char *p;
|
|
|
|
if (L->top > L->base && tvisthread(L->base)) {
|
|
|
|
L2 = threadV(L->base);
|
|
|
|
arg = 1;
|
|
|
|
}
|
|
|
|
fmt = lj_lib_checkstr(L, arg+1);
|
|
|
|
depth = lj_lib_checkint(L, arg+2);
|
|
|
|
p = luaJIT_profile_dumpstack(L2, strdata(fmt), depth, &len);
|
|
|
|
lua_pushlstring(L, p, len);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "lj_libdef.h"
|
|
|
|
|
|
|
|
static int luaopen_jit_profile(lua_State *L)
|
|
|
|
{
|
|
|
|
LJ_LIB_REG(L, NULL, jit_profile);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2009-12-08 18:46:35 +00:00
|
|
|
/* -- JIT compiler initialization ----------------------------------------- */
|
|
|
|
|
|
|
|
#if LJ_HASJIT
|
|
|
|
/* Default values for JIT parameters. */
|
|
|
|
static const int32_t jit_param_default[JIT_P__MAX+1] = {
|
|
|
|
#define JIT_PARAMINIT(len, name, value) (value),
|
|
|
|
JIT_PARAMDEF(JIT_PARAMINIT)
|
|
|
|
#undef JIT_PARAMINIT
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
2011-05-26 15:58:29 +00:00
|
|
|
#if LJ_TARGET_ARM && LJ_TARGET_LINUX
|
|
|
|
#include <sys/utsname.h>
|
|
|
|
#endif
|
|
|
|
|
2020-05-20 18:42:04 +00:00
|
|
|
/* Arch-dependent CPU feature detection. */
|
|
|
|
static uint32_t jit_cpudetect(void)
|
2009-12-08 18:46:35 +00:00
|
|
|
{
|
|
|
|
uint32_t flags = 0;
|
|
|
|
#if LJ_TARGET_X86ORX64
|
2020-05-20 18:42:04 +00:00
|
|
|
|
2009-12-08 18:46:35 +00:00
|
|
|
uint32_t vendor[4];
|
|
|
|
uint32_t features[4];
|
|
|
|
if (lj_vm_cpuid(0, vendor) && lj_vm_cpuid(1, features)) {
|
2011-02-01 18:28:03 +00:00
|
|
|
flags |= ((features[2] >> 0)&1) * JIT_F_SSE3;
|
2009-12-08 18:46:35 +00:00
|
|
|
flags |= ((features[2] >> 19)&1) * JIT_F_SSE4_1;
|
2016-03-28 21:04:33 +00:00
|
|
|
if (vendor[0] >= 7) {
|
|
|
|
uint32_t xfeatures[4];
|
|
|
|
lj_vm_cpuid(7, xfeatures);
|
|
|
|
flags |= ((xfeatures[1] >> 8)&1) * JIT_F_BMI2;
|
|
|
|
}
|
2009-12-08 18:46:35 +00:00
|
|
|
}
|
2020-05-20 18:42:04 +00:00
|
|
|
/* Don't bother checking for SSE2 -- the VM will crash before getting here. */
|
|
|
|
|
2011-01-25 17:50:24 +00:00
|
|
|
#elif LJ_TARGET_ARM
|
2020-05-20 18:42:04 +00:00
|
|
|
|
2012-07-08 20:20:11 +00:00
|
|
|
int ver = LJ_ARCH_VERSION; /* Compile-time ARM CPU detection. */
|
2011-05-26 15:58:29 +00:00
|
|
|
#if LJ_TARGET_LINUX
|
2012-07-08 20:20:11 +00:00
|
|
|
if (ver < 70) { /* Runtime ARM CPU detection. */
|
2011-05-26 15:58:29 +00:00
|
|
|
struct utsname ut;
|
|
|
|
uname(&ut);
|
|
|
|
if (strncmp(ut.machine, "armv", 4) == 0) {
|
2020-05-20 18:42:04 +00:00
|
|
|
if (ut.machine[4] >= '8') ver = 80;
|
|
|
|
else if (ut.machine[4] == '7') ver = 70;
|
|
|
|
else if (ut.machine[4] == '6') ver = 60;
|
2011-05-26 15:58:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2012-07-08 20:20:11 +00:00
|
|
|
flags |= ver >= 70 ? JIT_F_ARMV7 :
|
|
|
|
ver >= 61 ? JIT_F_ARMV6T2_ :
|
|
|
|
ver >= 60 ? JIT_F_ARMV6_ : 0;
|
|
|
|
flags |= LJ_ARCH_HASFPU == 0 ? 0 : ver >= 70 ? JIT_F_VFPV3 : JIT_F_VFPV2;
|
2020-05-20 18:42:04 +00:00
|
|
|
|
2015-01-03 14:28:33 +00:00
|
|
|
#elif LJ_TARGET_ARM64
|
2020-05-20 18:42:04 +00:00
|
|
|
|
2015-01-03 14:28:33 +00:00
|
|
|
/* No optional CPU features to detect (for now). */
|
2020-05-20 18:42:04 +00:00
|
|
|
|
2012-06-09 18:53:22 +00:00
|
|
|
#elif LJ_TARGET_PPC
|
2020-05-20 18:42:04 +00:00
|
|
|
|
2012-06-09 18:53:22 +00:00
|
|
|
#if LJ_ARCH_SQRT
|
|
|
|
flags |= JIT_F_SQRT;
|
|
|
|
#endif
|
|
|
|
#if LJ_ARCH_ROUND
|
|
|
|
flags |= JIT_F_ROUND;
|
|
|
|
#endif
|
2020-05-20 18:42:04 +00:00
|
|
|
|
2011-12-15 19:39:30 +00:00
|
|
|
#elif LJ_TARGET_MIPS
|
2020-05-20 18:42:04 +00:00
|
|
|
|
2012-03-29 23:34:17 +00:00
|
|
|
/* Compile-time MIPS CPU detection. */
|
2012-06-09 18:53:22 +00:00
|
|
|
#if LJ_ARCH_VERSION >= 20
|
2016-05-28 03:10:55 +00:00
|
|
|
flags |= JIT_F_MIPSXXR2;
|
2012-03-29 23:34:17 +00:00
|
|
|
#endif
|
|
|
|
/* Runtime MIPS CPU detection. */
|
|
|
|
#if defined(__GNUC__)
|
2016-05-28 03:10:55 +00:00
|
|
|
if (!(flags & JIT_F_MIPSXXR2)) {
|
2012-03-29 23:34:17 +00:00
|
|
|
int x;
|
2016-06-08 08:24:00 +00:00
|
|
|
#ifdef __mips16
|
|
|
|
x = 0; /* Runtime detection is difficult. Ensure optimal -march flags. */
|
|
|
|
#else
|
2012-03-29 23:34:17 +00:00
|
|
|
/* On MIPS32R1 rotr is treated as srl. rotr r2,r2,1 -> srl r2,r2,1. */
|
|
|
|
__asm__("li $2, 1\n\t.long 0x00221042\n\tmove %0, $2" : "=r"(x) : : "$2");
|
2016-06-08 08:24:00 +00:00
|
|
|
#endif
|
2016-05-28 03:10:55 +00:00
|
|
|
if (x) flags |= JIT_F_MIPSXXR2; /* Either 0x80000000 (R2) or 0 (R1). */
|
2012-03-29 23:34:17 +00:00
|
|
|
}
|
|
|
|
#endif
|
2020-05-20 18:42:04 +00:00
|
|
|
|
2009-12-08 18:46:35 +00:00
|
|
|
#else
|
|
|
|
#error "Missing CPU detection for this architecture"
|
|
|
|
#endif
|
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize JIT compiler. */
|
|
|
|
static void jit_init(lua_State *L)
|
|
|
|
{
|
|
|
|
jit_State *J = L2J(L);
|
2020-05-20 18:42:04 +00:00
|
|
|
J->flags = jit_cpudetect() | JIT_F_ON | JIT_F_OPT_DEFAULT;
|
2009-12-08 18:46:35 +00:00
|
|
|
memcpy(J->param, jit_param_default, sizeof(J->param));
|
|
|
|
lj_dispatch_update(G(L));
|
|
|
|
}
|
2020-05-20 18:42:04 +00:00
|
|
|
#endif
|
2009-12-08 18:46:35 +00:00
|
|
|
|
|
|
|
LUALIB_API int luaopen_jit(lua_State *L)
|
|
|
|
{
|
2020-05-20 18:42:04 +00:00
|
|
|
#if LJ_HASJIT
|
2013-02-21 15:56:59 +00:00
|
|
|
jit_init(L);
|
2020-05-20 18:42:04 +00:00
|
|
|
#endif
|
2010-11-16 14:05:21 +00:00
|
|
|
lua_pushliteral(L, LJ_OS_NAME);
|
2009-12-08 18:46:35 +00:00
|
|
|
lua_pushliteral(L, LJ_ARCH_NAME);
|
|
|
|
lua_pushinteger(L, LUAJIT_VERSION_NUM);
|
|
|
|
lua_pushliteral(L, LUAJIT_VERSION);
|
2011-02-02 01:38:59 +00:00
|
|
|
LJ_LIB_REG(L, LUA_JITLIBNAME, jit);
|
2013-09-01 23:55:20 +00:00
|
|
|
#if LJ_HASPROFILE
|
|
|
|
lj_lib_prereg(L, LUA_JITLIBNAME ".profile", luaopen_jit_profile,
|
|
|
|
tabref(L->env));
|
|
|
|
#endif
|
2009-12-08 18:46:35 +00:00
|
|
|
#ifndef LUAJIT_DISABLE_JITUTIL
|
2013-09-08 01:01:00 +00:00
|
|
|
lj_lib_prereg(L, LUA_JITLIBNAME ".util", luaopen_jit_util, tabref(L->env));
|
2009-12-08 18:46:35 +00:00
|
|
|
#endif
|
2012-09-24 14:56:07 +00:00
|
|
|
#if LJ_HASJIT
|
2011-02-02 01:38:59 +00:00
|
|
|
LJ_LIB_REG(L, "jit.opt", jit_opt);
|
2012-09-24 14:56:07 +00:00
|
|
|
#endif
|
2009-12-08 18:46:35 +00:00
|
|
|
L->top -= 2;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|