summaryrefslogtreecommitdiff
path: root/src/lib_jit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib_jit.c')
-rw-r--r--src/lib_jit.c589
1 files changed, 589 insertions, 0 deletions
diff --git a/src/lib_jit.c b/src/lib_jit.c
new file mode 100644
index 00000000..4a57f3b4
--- /dev/null
+++ b/src/lib_jit.c
@@ -0,0 +1,589 @@
1/*
2** JIT library.
3** Copyright (C) 2005-2009 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_arch.h"
14#include "lj_obj.h"
15#include "lj_err.h"
16#include "lj_str.h"
17#include "lj_tab.h"
18#if LJ_HASJIT
19#include "lj_ir.h"
20#include "lj_jit.h"
21#include "lj_iropt.h"
22#endif
23#include "lj_dispatch.h"
24#include "lj_vm.h"
25#include "lj_vmevent.h"
26#include "lj_lib.h"
27
28#include "luajit.h"
29
30/* -- jit.* functions ----------------------------------------------------- */
31
32#define LJLIB_MODULE_jit
33
34static int setjitmode(lua_State *L, int mode)
35{
36 int idx = 0;
37 if (L->base == L->top || tvisnil(L->base)) { /* jit.on/off/flush([nil]) */
38 mode |= LUAJIT_MODE_ENGINE;
39 } else {
40 /* jit.on/off/flush(func|proto, nil|true|false) */
41 if (tvisfunc(L->base) || tvisproto(L->base))
42 idx = 1;
43 else if (!tvistrue(L->base)) /* jit.on/off/flush(true, nil|true|false) */
44 goto err;
45 if (L->base+1 < L->top && tvisbool(L->base+1))
46 mode |= boolV(L->base+1) ? LUAJIT_MODE_ALLFUNC : LUAJIT_MODE_ALLSUBFUNC;
47 else
48 mode |= LUAJIT_MODE_FUNC;
49 }
50 if (luaJIT_setmode(L, idx, mode) != 1) {
51 err:
52#if LJ_HASJIT
53 lj_err_arg(L, 1, LJ_ERR_NOLFUNC);
54#else
55 lj_err_caller(L, LJ_ERR_NOJIT);
56#endif
57 }
58 return 0;
59}
60
61LJLIB_CF(jit_on)
62{
63 return setjitmode(L, LUAJIT_MODE_ON);
64}
65
66LJLIB_CF(jit_off)
67{
68 return setjitmode(L, LUAJIT_MODE_OFF);
69}
70
71LJLIB_CF(jit_flush)
72{
73#if LJ_HASJIT
74 if (L->base < L->top && (tvisnum(L->base) || tvisstr(L->base))) {
75 int traceno = lj_lib_checkint(L, 1);
76 luaJIT_setmode(L, traceno, LUAJIT_MODE_FLUSH|LUAJIT_MODE_TRACE);
77 return 0;
78 }
79#endif
80 return setjitmode(L, LUAJIT_MODE_FLUSH);
81}
82
83#if LJ_HASJIT
84/* Push a string for every flag bit that is set. */
85static void flagbits_to_strings(lua_State *L, uint32_t flags, uint32_t base,
86 const char *str)
87{
88 for (; *str; base <<= 1, str += 1+*str)
89 if (flags & base)
90 setstrV(L, L->top++, lj_str_new(L, str+1, *(uint8_t *)str));
91}
92#endif
93
94LJLIB_CF(jit_status)
95{
96#if LJ_HASJIT
97 jit_State *J = L2J(L);
98 L->top = L->base;
99 setboolV(L->top++, (J->flags & JIT_F_ON) ? 1 : 0);
100 flagbits_to_strings(L, J->flags, JIT_F_CPU_FIRST, JIT_F_CPUSTRING);
101 flagbits_to_strings(L, J->flags, JIT_F_OPT_FIRST, JIT_F_OPTSTRING);
102 return L->top - L->base;
103#else
104 setboolV(L->top++, 0);
105 return 1;
106#endif
107}
108
109LJLIB_CF(jit_attach)
110{
111#ifdef LUAJIT_DISABLE_VMEVENT
112 luaL_error(L, "vmevent API disabled");
113#else
114 GCfunc *fn = lj_lib_checkfunc(L, 1);
115 GCstr *s = lj_lib_optstr(L, 2);
116 luaL_findtable(L, LUA_REGISTRYINDEX, LJ_VMEVENTS_REGKEY, LJ_VMEVENTS_HSIZE);
117 if (s) { /* Attach to given event. */
118 lua_pushvalue(L, 1);
119 lua_rawseti(L, -2, VMEVENT_HASHIDX(s->hash));
120 G(L)->vmevmask = VMEVENT_NOCACHE; /* Invalidate cache. */
121 } else { /* Detach if no event given. */
122 setnilV(L->top++);
123 while (lua_next(L, -2)) {
124 L->top--;
125 if (tvisfunc(L->top) && funcV(L->top) == fn) {
126 setnilV(lj_tab_set(L, tabV(L->top-2), L->top-1));
127 }
128 }
129 }
130#endif
131 return 0;
132}
133
134LJLIB_PUSH(top-4) LJLIB_SET(arch)
135LJLIB_PUSH(top-3) LJLIB_SET(version_num)
136LJLIB_PUSH(top-2) LJLIB_SET(version)
137
138#include "lj_libdef.h"
139
140/* -- jit.util.* functions ------------------------------------------------ */
141
142#define LJLIB_MODULE_jit_util
143
144/* -- Reflection API for Lua functions ------------------------------------ */
145
146/* Return prototype of first argument (Lua function or prototype object) */
147static GCproto *check_Lproto(lua_State *L, int nolua)
148{
149 TValue *o = L->base;
150 if (L->top > o) {
151 if (tvisproto(o)) {
152 return protoV(o);
153 } else if (tvisfunc(o)) {
154 if (isluafunc(funcV(o)))
155 return funcproto(funcV(o));
156 else if (nolua)
157 return NULL;
158 }
159 }
160 lj_err_argt(L, 1, LUA_TFUNCTION);
161 return NULL; /* unreachable */
162}
163
164static void setintfield(lua_State *L, GCtab *t, const char *name, int32_t val)
165{
166 setintV(lj_tab_setstr(L, t, lj_str_newz(L, name)), val);
167}
168
169/* local info = jit.util.funcinfo(func [,pc]) */
170LJLIB_CF(jit_util_funcinfo)
171{
172 GCproto *pt = check_Lproto(L, 1);
173 if (pt) {
174 BCPos pc = (BCPos)lj_lib_optint(L, 2, 0);
175 GCtab *t;
176 lua_createtable(L, 0, 16); /* Increment hash size if fields are added. */
177 t = tabV(L->top-1);
178 setintfield(L, t, "linedefined", pt->linedefined);
179 setintfield(L, t, "lastlinedefined", pt->lastlinedefined);
180 setintfield(L, t, "stackslots", pt->framesize);
181 setintfield(L, t, "params", pt->numparams);
182 setintfield(L, t, "bytecodes", (int32_t)pt->sizebc);
183 setintfield(L, t, "gcconsts", (int32_t)pt->sizekgc);
184 setintfield(L, t, "nconsts", (int32_t)pt->sizekn);
185 setintfield(L, t, "upvalues", (int32_t)pt->sizeuv);
186 if (pc > 0)
187 setintfield(L, t, "currentline", pt->lineinfo ? pt->lineinfo[pc-1] : 0);
188 lua_pushboolean(L, (pt->flags & PROTO_IS_VARARG));
189 lua_setfield(L, -2, "isvararg");
190 setstrV(L, L->top++, pt->chunkname);
191 lua_setfield(L, -2, "source");
192 lj_err_pushloc(L, pt, pc);
193 lua_setfield(L, -2, "loc");
194 } else {
195 GCfunc *fn = funcV(L->base);
196 GCtab *t;
197 lua_createtable(L, 0, 2); /* Increment hash size if fields are added. */
198 t = tabV(L->top-1);
199 setintfield(L, t, "ffid", fn->c.ffid);
200 setintfield(L, t, "upvalues", fn->c.nupvalues);
201 }
202 return 1;
203}
204
205/* local ins, m = jit.util.funcbc(func, pc) */
206LJLIB_CF(jit_util_funcbc)
207{
208 GCproto *pt = check_Lproto(L, 0);
209 BCPos pc = (BCPos)lj_lib_checkint(L, 2) - 1;
210 if (pc < pt->sizebc) {
211 BCIns ins = pt->bc[pc];
212 BCOp op = bc_op(ins);
213 lua_assert(op < BC__MAX);
214 setintV(L->top, ins);
215 setintV(L->top+1, lj_bc_mode[op]);
216 L->top += 2;
217 return 2;
218 }
219 return 0;
220}
221
222/* local k = jit.util.funck(func, idx) */
223LJLIB_CF(jit_util_funck)
224{
225 GCproto *pt = check_Lproto(L, 0);
226 MSize idx = (MSize)lj_lib_checkint(L, 2);
227 if ((int32_t)idx >= 0) {
228 if (idx < pt->sizekn) {
229 setnumV(L->top-1, pt->k.n[idx]);
230 return 1;
231 }
232 } else {
233 if (~idx < pt->sizekgc) {
234 GCobj *gc = gcref(pt->k.gc[idx]);
235 setgcV(L, L->top-1, &gc->gch, ~gc->gch.gct);
236 return 1;
237 }
238 }
239 return 0;
240}
241
242/* local name = jit.util.funcuvname(func, idx) */
243LJLIB_CF(jit_util_funcuvname)
244{
245 GCproto *pt = check_Lproto(L, 0);
246 uint32_t idx = (uint32_t)lj_lib_checkint(L, 2);
247 if (idx < pt->sizeuvname) {
248 setstrV(L, L->top-1, pt->uvname[idx]);
249 return 1;
250 }
251 return 0;
252}
253
254/* -- Reflection API for traces ------------------------------------------- */
255
256#if LJ_HASJIT
257
258/* Check trace argument. Must not throw for non-existent trace numbers. */
259static Trace *jit_checktrace(lua_State *L)
260{
261 TraceNo tr = (TraceNo)lj_lib_checkint(L, 1);
262 jit_State *J = L2J(L);
263 if (tr > 0 && tr < J->sizetrace)
264 return J->trace[tr];
265 return NULL;
266}
267
268/* local info = jit.util.traceinfo(tr) */
269LJLIB_CF(jit_util_traceinfo)
270{
271 Trace *T = jit_checktrace(L);
272 if (T) {
273 GCtab *t;
274 lua_createtable(L, 0, 4); /* Increment hash size if fields are added. */
275 t = tabV(L->top-1);
276 setintfield(L, t, "nins", (int32_t)T->nins - REF_BIAS - 1);
277 setintfield(L, t, "nk", REF_BIAS - (int32_t)T->nk);
278 setintfield(L, t, "link", T->link);
279 setintfield(L, t, "nexit", T->nsnap);
280 /* There are many more fields. Add them only when needed. */
281 return 1;
282 }
283 return 0;
284}
285
286/* local m, ot, op1, op2, prev = jit.util.traceir(tr, idx) */
287LJLIB_CF(jit_util_traceir)
288{
289 Trace *T = jit_checktrace(L);
290 IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS;
291 if (T && ref >= REF_BIAS && ref < T->nins) {
292 IRIns *ir = &T->ir[ref];
293 int32_t m = lj_ir_mode[ir->o];
294 setintV(L->top-2, m);
295 setintV(L->top-1, ir->ot);
296 setintV(L->top++, (int32_t)ir->op1 - (irm_op1(m)==IRMref ? REF_BIAS : 0));
297 setintV(L->top++, (int32_t)ir->op2 - (irm_op2(m)==IRMref ? REF_BIAS : 0));
298 setintV(L->top++, ir->prev);
299 return 5;
300 }
301 return 0;
302}
303
304/* local k, t [, slot] = jit.util.tracek(tr, idx) */
305LJLIB_CF(jit_util_tracek)
306{
307 Trace *T = jit_checktrace(L);
308 IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS;
309 if (T && ref >= T->nk && ref < REF_BIAS) {
310 IRIns *ir = &T->ir[ref];
311 int32_t slot = -1;
312 if (ir->o == IR_KSLOT) {
313 slot = ir->op2;
314 ir = &T->ir[ir->op1];
315 }
316 lj_ir_kvalue(L, L->top-2, ir);
317 setintV(L->top-1, (int32_t)irt_type(ir->t));
318 if (slot == -1)
319 return 2;
320 setintV(L->top++, slot);
321 return 3;
322 }
323 return 0;
324}
325
326/* local snap = jit.util.tracesnap(tr, sn) */
327LJLIB_CF(jit_util_tracesnap)
328{
329 Trace *T = jit_checktrace(L);
330 SnapNo sn = (SnapNo)lj_lib_checkint(L, 2);
331 if (T && sn < T->nsnap) {
332 SnapShot *snap = &T->snap[sn];
333 IRRef2 *map = &T->snapmap[snap->mapofs];
334 BCReg s, nslots = snap->nslots;
335 GCtab *t;
336 lua_createtable(L, nslots ? (int)nslots : 1, 0);
337 t = tabV(L->top-1);
338 setintV(lj_tab_setint(L, t, 0), (int32_t)snap->ref - REF_BIAS);
339 for (s = 0; s < nslots; s++) {
340 TValue *o = lj_tab_setint(L, t, (int32_t)(s+1));
341 IRRef ref = snap_ref(map[s]);
342 if (ref)
343 setintV(o, (int32_t)ref - REF_BIAS);
344 else
345 setboolV(o, 0);
346 }
347 return 1;
348 }
349 return 0;
350}
351
352/* local mcode, addr, loop = jit.util.tracemc(tr) */
353LJLIB_CF(jit_util_tracemc)
354{
355 Trace *T = jit_checktrace(L);
356 if (T && T->mcode != NULL) {
357 setstrV(L, L->top-1, lj_str_new(L, (const char *)T->mcode, T->szmcode));
358 setnumV(L->top++, cast_num((intptr_t)T->mcode));
359 setintV(L->top++, T->mcloop);
360 return 3;
361 }
362 return 0;
363}
364
365/* local addr = jit.util.traceexitstub(idx) */
366LJLIB_CF(jit_util_traceexitstub)
367{
368 ExitNo exitno = (ExitNo)lj_lib_checkint(L, 1);
369 jit_State *J = L2J(L);
370 if (exitno < EXITSTUBS_PER_GROUP*LJ_MAX_EXITSTUBGR) {
371 setnumV(L->top-1, cast_num((intptr_t)exitstub_addr(J, exitno)));
372 return 1;
373 }
374 return 0;
375}
376
377#else
378
379static int trace_nojit(lua_State *L)
380{
381 UNUSED(L);
382 return 0;
383}
384#define lj_cf_jit_util_traceinfo trace_nojit
385#define lj_cf_jit_util_traceir trace_nojit
386#define lj_cf_jit_util_tracek trace_nojit
387#define lj_cf_jit_util_tracesnap trace_nojit
388#define lj_cf_jit_util_tracemc trace_nojit
389#define lj_cf_jit_util_traceexitstub trace_nojit
390
391#endif
392
393#include "lj_libdef.h"
394
395/* -- jit.opt module ------------------------------------------------------ */
396
397#define LJLIB_MODULE_jit_opt
398
399#if LJ_HASJIT
400/* Parse optimization level. */
401static int jitopt_level(jit_State *J, const char *str)
402{
403 if (str[0] >= '0' && str[0] <= '9' && str[1] == '\0') {
404 uint32_t flags;
405 if (str[0] == '0') flags = JIT_F_OPT_0;
406 else if (str[0] == '1') flags = JIT_F_OPT_1;
407 else if (str[0] == '2') flags = JIT_F_OPT_2;
408 else flags = JIT_F_OPT_3;
409 J->flags = (J->flags & ~JIT_F_OPT_MASK) | flags;
410 return 1; /* Ok. */
411 }
412 return 0; /* No match. */
413}
414
415/* Parse optimization flag. */
416static int jitopt_flag(jit_State *J, const char *str)
417{
418 const char *lst = JIT_F_OPTSTRING;
419 uint32_t opt;
420 int set = 1;
421 if (str[0] == '+') {
422 str++;
423 } else if (str[0] == '-') {
424 str++;
425 set = 0;
426 } else if (str[0] == 'n' && str[1] == 'o') {
427 str += str[2] == '-' ? 3 : 2;
428 set = 0;
429 }
430 for (opt = JIT_F_OPT_FIRST; ; opt <<= 1) {
431 size_t len = *(const uint8_t *)lst;
432 if (len == 0)
433 break;
434 if (strncmp(str, lst+1, len) == 0 && str[len] == '\0') {
435 if (set) J->flags |= opt; else J->flags &= ~opt;
436 return 1; /* Ok. */
437 }
438 lst += 1+len;
439 }
440 return 0; /* No match. */
441}
442
443/* Forward declaration. */
444static void jit_init_hotcount(jit_State *J);
445
446/* Parse optimization parameter. */
447static int jitopt_param(jit_State *J, const char *str)
448{
449 const char *lst = JIT_P_STRING;
450 int i;
451 for (i = 0; i < JIT_P__MAX; i++) {
452 size_t len = *(const uint8_t *)lst;
453 TValue tv;
454 lua_assert(len != 0);
455 if (strncmp(str, lst+1, len) == 0 && str[len] == '=' &&
456 lj_str_numconv(&str[len+1], &tv)) {
457 J->param[i] = lj_num2int(tv.n);
458 if (i == JIT_P_hotloop)
459 jit_init_hotcount(J);
460 return 1; /* Ok. */
461 }
462 lst += 1+len;
463 }
464 return 0; /* No match. */
465}
466#endif
467
468/* jit.opt.start(flags...) */
469LJLIB_CF(jit_opt_start)
470{
471#if LJ_HASJIT
472 jit_State *J = L2J(L);
473 int nargs = (int)(L->top - L->base);
474 if (nargs == 0) {
475 J->flags = (J->flags & ~JIT_F_OPT_MASK) | JIT_F_OPT_DEFAULT;
476 } else {
477 int i;
478 for (i = 1; i <= nargs; i++) {
479 const char *str = strdata(lj_lib_checkstr(L, i));
480 if (!jitopt_level(J, str) &&
481 !jitopt_flag(J, str) &&
482 !jitopt_param(J, str))
483 lj_err_callerv(L, LJ_ERR_JITOPT, str);
484 }
485 }
486#else
487 lj_err_caller(L, LJ_ERR_NOJIT);
488#endif
489 return 0;
490}
491
492#include "lj_libdef.h"
493
494/* -- JIT compiler initialization ----------------------------------------- */
495
496#if LJ_HASJIT
497/* Default values for JIT parameters. */
498static const int32_t jit_param_default[JIT_P__MAX+1] = {
499#define JIT_PARAMINIT(len, name, value) (value),
500JIT_PARAMDEF(JIT_PARAMINIT)
501#undef JIT_PARAMINIT
502 0
503};
504
505/* Initialize hotcount table. */
506static void jit_init_hotcount(jit_State *J)
507{
508 HotCount start = (HotCount)J->param[JIT_P_hotloop];
509 HotCount *hotcount = J2GG(J)->hotcount;
510 uint32_t i;
511 for (i = 0; i < HOTCOUNT_SIZE; i++)
512 hotcount[i] = start;
513}
514#endif
515
516/* Arch-dependent CPU detection. */
517static uint32_t jit_cpudetect(lua_State *L)
518{
519 uint32_t flags = 0;
520#if LJ_TARGET_X86ORX64
521 uint32_t vendor[4];
522 uint32_t features[4];
523 if (lj_vm_cpuid(0, vendor) && lj_vm_cpuid(1, features)) {
524#if !LJ_HASJIT
525#define JIT_F_CMOV 1
526#endif
527 flags |= ((features[3] >> 15)&1) * JIT_F_CMOV;
528#if LJ_HASJIT
529 flags |= ((features[3] >> 26)&1) * JIT_F_SSE2;
530 flags |= ((features[2] >> 19)&1) * JIT_F_SSE4_1;
531 if (vendor[2] == 0x6c65746e) { /* Intel. */
532 if ((features[0] & 0x0ff00f00) == 0x00000f00) /* P4. */
533 flags |= JIT_F_P4; /* Currently unused. */
534 else if ((features[0] & 0x0fff0ff0) == 0x000106c0) /* Atom. */
535 flags |= JIT_F_LEA_AGU;
536 } else if (vendor[2] == 0x444d4163) { /* AMD. */
537 uint32_t fam = (features[0] & 0x0ff00f00);
538 if (fam == 0x00000f00) /* K8. */
539 flags |= JIT_F_SPLIT_XMM;
540 if (fam >= 0x00000f00) /* K8, K10. */
541 flags |= JIT_F_PREFER_IMUL;
542 }
543#endif
544 }
545#ifndef LUAJIT_CPU_NOCMOV
546 if (!(flags & JIT_F_CMOV))
547 luaL_error(L, "Ancient CPU lacks CMOV support (recompile with -DLUAJIT_CPU_NOCMOV)");
548#endif
549#if LJ_HASJIT
550 if (!(flags & JIT_F_SSE2))
551 luaL_error(L, "Sorry, SSE2 CPU support required for this beta release");
552#endif
553 UNUSED(L);
554#else
555#error "Missing CPU detection for this architecture"
556#endif
557 return flags;
558}
559
560/* Initialize JIT compiler. */
561static void jit_init(lua_State *L)
562{
563 uint32_t flags = jit_cpudetect(L);
564#if LJ_HASJIT
565 jit_State *J = L2J(L);
566 J->flags = flags | JIT_F_ON | JIT_F_OPT_DEFAULT;
567 memcpy(J->param, jit_param_default, sizeof(J->param));
568 jit_init_hotcount(J);
569 lj_dispatch_update(G(L));
570#else
571 UNUSED(flags);
572#endif
573}
574
575LUALIB_API int luaopen_jit(lua_State *L)
576{
577 lua_pushliteral(L, LJ_ARCH_NAME);
578 lua_pushinteger(L, LUAJIT_VERSION_NUM);
579 lua_pushliteral(L, LUAJIT_VERSION);
580 LJ_LIB_REG(L, jit);
581#ifndef LUAJIT_DISABLE_JITUTIL
582 LJ_LIB_REG_(L, "jit.util", jit_util);
583#endif
584 LJ_LIB_REG_(L, "jit.opt", jit_opt);
585 L->top -= 2;
586 jit_init(L);
587 return 1;
588}
589