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