diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/LuaJIT-1.1.7/src/ljitlib.c | 637 |
1 files changed, 637 insertions, 0 deletions
diff --git a/libraries/LuaJIT-1.1.7/src/ljitlib.c b/libraries/LuaJIT-1.1.7/src/ljitlib.c new file mode 100644 index 0000000..4efc04d --- /dev/null +++ b/libraries/LuaJIT-1.1.7/src/ljitlib.c | |||
@@ -0,0 +1,637 @@ | |||
1 | /* | ||
2 | ** Lua library for the JIT engine. | ||
3 | ** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h | ||
4 | */ | ||
5 | |||
6 | #include <stdio.h> | ||
7 | #include <string.h> | ||
8 | |||
9 | #define ljitlib_c | ||
10 | #define LUA_LIB | ||
11 | |||
12 | #include "lua.h" | ||
13 | #include "lauxlib.h" | ||
14 | #include "luajit.h" | ||
15 | #include "lualib.h" | ||
16 | |||
17 | /* This file is not a pure C API user. Some internals are required. */ | ||
18 | #include "lobject.h" | ||
19 | #include "lstate.h" | ||
20 | #include "lstring.h" | ||
21 | #include "ltable.h" | ||
22 | #include "lfunc.h" | ||
23 | #include "lgc.h" | ||
24 | #include "lopcodes.h" | ||
25 | |||
26 | #include "ljit.h" | ||
27 | #include "ljit_hints.h" | ||
28 | |||
29 | #define STRING_HINTS | ||
30 | #include "ljit_hints.h" | ||
31 | |||
32 | /* ------------------------------------------------------------------------ */ | ||
33 | |||
34 | /* Static pointer addresses used as registry keys. */ | ||
35 | /* The values do not matter, but must be different to prevent joining. */ | ||
36 | static const int regkey_frontend = 0x6c6a6c01; | ||
37 | static const int regkey_comthread = 0x6c6a6c02; | ||
38 | |||
39 | /* Check that the first argument is a Lua function and return its closure. */ | ||
40 | static Closure *check_LCL(lua_State *L) | ||
41 | { | ||
42 | StkId o = L->base; | ||
43 | switch (lua_type(L, 1)) { | ||
44 | case LUA_TBOOLEAN: | ||
45 | o = (L->ci-1)->func; | ||
46 | case LUA_TFUNCTION: | ||
47 | if (isLfunction(o)) | ||
48 | return clvalue(o); | ||
49 | break; | ||
50 | } | ||
51 | luaL_argerror(L, 1, "Lua function expected"); | ||
52 | return NULL; | ||
53 | } | ||
54 | |||
55 | /* Create a new closure from a prototype. */ | ||
56 | /* Note: upvalues are assumed to be after first two slots. */ | ||
57 | static void push_LCL(lua_State *L, Proto *pt, Table *env) | ||
58 | { | ||
59 | Closure *cl; | ||
60 | int i, nup = pt->nups; | ||
61 | /* Adjust the number of stack slots to the number of upvalues. */ | ||
62 | luaL_checkstack(L, nup, "too many upvalues"); | ||
63 | lua_settop(L, 2+nup); | ||
64 | /* Create a closure from the subroutine prototype. */ | ||
65 | cl = luaF_newLclosure(L, nup, env); | ||
66 | cl->l.p = pt; | ||
67 | /* Allocate new upvalues and close them. */ | ||
68 | for (i = 0; i < nup; i++) | ||
69 | cl->l.upvals[i] = luaF_findupval(L, L->base + (2+i)); | ||
70 | luaF_close(L, L->base + 2); | ||
71 | lua_settop(L, 2); /* Remove upvalues. */ | ||
72 | setclvalue(L, L->top++, cl); /* Return closure on top of stack. */ | ||
73 | luaC_checkGC(L); | ||
74 | } | ||
75 | |||
76 | /* ------------------------------------------------------------------------ */ | ||
77 | |||
78 | /* Set JIT mode for the engine or a closure and/or its subroutines. */ | ||
79 | static int setmode(lua_State *L, int mode) | ||
80 | { | ||
81 | int idx = 0; | ||
82 | switch (lua_type(L, 1)) { | ||
83 | case LUA_TNONE: /* jit.on/off() */ | ||
84 | case LUA_TNIL: /* jit.on/off(nil) */ | ||
85 | luaJIT_setmode(L, 0, mode | LUAJIT_MODE_ENGINE); | ||
86 | break; | ||
87 | case LUA_TFUNCTION: /* jit.on/off(func, nil|true|false) */ | ||
88 | idx = 1; | ||
89 | case LUA_TBOOLEAN: /* jit.on/off(true, nil|true|false) (parent frame) */ | ||
90 | if (lua_isboolean(L, 2)) | ||
91 | mode |= lua_toboolean(L, 2)?LUAJIT_MODE_ALLFUNC:LUAJIT_MODE_ALLSUBFUNC; | ||
92 | else | ||
93 | mode |= LUAJIT_MODE_FUNC; | ||
94 | if (luaJIT_setmode(L, idx, mode) == 1) /* Ok? */ | ||
95 | break; | ||
96 | default: | ||
97 | luaL_argerror(L, 1, "Lua function expected"); | ||
98 | break; | ||
99 | } | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | /* Set JIT mode to on: (re-)enable compilation. */ | ||
104 | static int j_on(lua_State *L) | ||
105 | { | ||
106 | return setmode(L, LUAJIT_MODE_ON); | ||
107 | } | ||
108 | |||
109 | /* Set JIT mode to off: disable compilation. */ | ||
110 | static int j_off(lua_State *L) | ||
111 | { | ||
112 | return setmode(L, LUAJIT_MODE_OFF); | ||
113 | } | ||
114 | |||
115 | /* Set JIT debug level. Defaults to maximum level for use with -j. */ | ||
116 | static int j_debug(lua_State *L) | ||
117 | { | ||
118 | luaJIT_setmode(L, luaL_optinteger(L, 1, 100), LUAJIT_MODE_DEBUG); | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | /* ------------------------------------------------------------------------ */ | ||
123 | |||
124 | /* Report the compilation status. */ | ||
125 | static int compstatus(lua_State *L, int status) | ||
126 | { | ||
127 | if (status == -1) | ||
128 | return luaL_argerror(L, 1, "Lua function expected"); | ||
129 | else if (status == JIT_S_OK) | ||
130 | return 0; | ||
131 | else { | ||
132 | lua_pushinteger(L, status); | ||
133 | return 1; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /* Compile a function. Pass typical args to help the optimizer. */ | ||
138 | static int j_compile(lua_State *L) | ||
139 | { | ||
140 | int nargs = lua_gettop(L) - 1; | ||
141 | return compstatus(L, nargs >= 0 ? luaJIT_compile(L, nargs) : -1); | ||
142 | } | ||
143 | |||
144 | /* Recursively compile all subroutine prototypes. */ | ||
145 | static int rec_compile(lua_State *L, Proto *pt, Table *env, int stoponerror) | ||
146 | { | ||
147 | int rstatus = JIT_S_OK; | ||
148 | int i; | ||
149 | for (i = 0; i < pt->sizep; i++) { | ||
150 | Proto *pti = pt->p[i]; | ||
151 | int status; | ||
152 | push_LCL(L, pti, env); /* Assumes stack is at 2 (no upvalues). */ | ||
153 | status = luaJIT_compile(L, 0); | ||
154 | lua_settop(L, 2); /* Clear stack */ | ||
155 | if (status != JIT_S_OK) { | ||
156 | rstatus = status; | ||
157 | if (stoponerror) break; | ||
158 | } | ||
159 | status = rec_compile(L, pti, env, stoponerror); | ||
160 | if (status != JIT_S_OK) { | ||
161 | rstatus = status; | ||
162 | if (stoponerror) break; | ||
163 | } | ||
164 | } | ||
165 | return rstatus; | ||
166 | } | ||
167 | |||
168 | /* Compile all subroutines of a function. */ | ||
169 | /* Note: the function itself is _not_ compiled (use jit.compile()). */ | ||
170 | static int j_compilesub(lua_State *L) | ||
171 | { | ||
172 | Closure *cl = check_LCL(L); | ||
173 | int stoponerror = lua_toboolean(L, 2); /* Stop on first error? */ | ||
174 | lua_settop(L, 2); | ||
175 | return compstatus(L, rec_compile(L, cl->l.p, cl->l.env, stoponerror)); | ||
176 | } | ||
177 | |||
178 | /* jit.* functions. */ | ||
179 | static const luaL_Reg jitlib[] = { | ||
180 | { "on", j_on }, | ||
181 | { "off", j_off }, | ||
182 | { "debug", j_debug }, | ||
183 | { "compile", j_compile }, | ||
184 | { "compilesub", j_compilesub }, | ||
185 | /* j_attach is added below. */ | ||
186 | { NULL, NULL } | ||
187 | }; | ||
188 | |||
189 | /* ------------------------------------------------------------------------ */ | ||
190 | |||
191 | /* Get the compiler pipeline table from an upvalue (j_attach, j_frontend). */ | ||
192 | #define COMPIPE lua_upvalueindex(1) | ||
193 | |||
194 | /* Attach/detach handler to/from compiler pipeline. */ | ||
195 | static int j_attach(lua_State *L) | ||
196 | { | ||
197 | int pipesz; | ||
198 | luaL_checktype(L, 1, LUA_TFUNCTION); | ||
199 | pipesz = lua_objlen(L, COMPIPE); | ||
200 | if (lua_isnoneornil(L, 2)) { /* Detach if no priority given. */ | ||
201 | int i; | ||
202 | for (i = 1; i <= pipesz; i += 2) { | ||
203 | lua_rawgeti(L, COMPIPE, i); | ||
204 | if (lua_rawequal(L, 1, -1)) { /* Found: delete from pipeline. */ | ||
205 | for (; i+2 <= pipesz; i++) { /* Shift down. */ | ||
206 | lua_rawgeti(L, COMPIPE, i+2); | ||
207 | lua_rawseti(L, COMPIPE, i); | ||
208 | } | ||
209 | /* Clear last two elements. */ | ||
210 | lua_pushnil(L); lua_rawseti(L, COMPIPE, i); | ||
211 | lua_pushnil(L); lua_rawseti(L, COMPIPE, i+1); | ||
212 | return 0; | ||
213 | } | ||
214 | lua_pop(L, 1); | ||
215 | } | ||
216 | return 0; /* Not found: ignore detach request. */ | ||
217 | } else { /* Attach if priority given. */ | ||
218 | int prio = luaL_checkint(L, 2); | ||
219 | int pos, i; | ||
220 | for (pos = 2; pos <= pipesz; pos += 2) { | ||
221 | lua_rawgeti(L, COMPIPE, pos); | ||
222 | if (prio > (int)lua_tointeger(L, -1)) break; /* Insertion point found. */ | ||
223 | lua_pop(L, 1); | ||
224 | } | ||
225 | for (i = pipesz+2; i > pos; i--) { /* Shift up. */ | ||
226 | lua_rawgeti(L, COMPIPE, i-2); | ||
227 | lua_rawseti(L, COMPIPE, i); | ||
228 | } | ||
229 | /* Set handler and priority. */ | ||
230 | lua_pushvalue(L, 1); lua_rawseti(L, COMPIPE, i-1); | ||
231 | lua_pushvalue(L, 2); lua_rawseti(L, COMPIPE, i); | ||
232 | return 0; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | /* Compiler frontend. Runs in the compiler thread. */ | ||
237 | /* First and only arg is the compiler state table. */ | ||
238 | static int j_frontend(lua_State *L) | ||
239 | { | ||
240 | int status = JIT_S_OK; | ||
241 | int pos; | ||
242 | /* Loop through all handlers in the compiler pipeline. */ | ||
243 | for (pos = 1; ; pos += 2) { | ||
244 | if (status != JIT_S_OK) { /* Pending failure? */ | ||
245 | int prio; | ||
246 | lua_rawgeti(L, COMPIPE, pos+1); /* Must check for odd/even priority. */ | ||
247 | if (lua_isnil(L, -1)) break; /* End of pipeline. */ | ||
248 | prio = (int)lua_tointeger(L, -1); | ||
249 | lua_pop(L, 1); | ||
250 | if ((prio & 1) == 0) continue; /* Skip handlers with even priority. */ | ||
251 | } | ||
252 | /* Call handler with compiler state table and optional failure status. */ | ||
253 | lua_rawgeti(L, COMPIPE, pos); | ||
254 | if (lua_isnil(L, -1)) break; /* End of pipeline. */ | ||
255 | lua_pushvalue(L, 1); | ||
256 | if (status != JIT_S_OK) | ||
257 | lua_pushinteger(L, status); | ||
258 | lua_call(L, status ? 2 : 1, 1); | ||
259 | if (!lua_isnil(L, -1)) /* Remember failure status. */ | ||
260 | status = (int)lua_tointeger(L, -1); | ||
261 | lua_pop(L, 1); | ||
262 | } | ||
263 | lua_pushinteger(L, status); | ||
264 | return 1; | ||
265 | } | ||
266 | |||
267 | /* Compiler frontend wrapper. */ | ||
268 | static int frontwrap(lua_State *L, Table *st) | ||
269 | { | ||
270 | jit_State *J = G(L)->jit_state; | ||
271 | lua_State *JL; | ||
272 | int status; | ||
273 | |||
274 | /* Allocate compiler thread on demand. */ | ||
275 | if (J->L == NULL) { | ||
276 | if (!lua_checkstack(L, 3)) return JIT_S_COMPILER_ERROR; | ||
277 | sethvalue(L, L->top++, st); /* Prevent GC of state table. */ | ||
278 | lua_pushlightuserdata(L, (void *)®key_comthread); | ||
279 | /* Cannot use C stack, since it's deallocated early in Coco. */ | ||
280 | /* But we don't need one -- the compiler thread never yields, anyway. */ | ||
281 | J->L = lua_newthread(L); | ||
282 | lua_rawset(L, LUA_REGISTRYINDEX); | ||
283 | L->top--; /* Remove state table from this stack. */ | ||
284 | } | ||
285 | JL = J->L; | ||
286 | |||
287 | /* Initialize compiler thread stack with frontend and state table. */ | ||
288 | lua_settop(JL, 0); | ||
289 | lua_pushlightuserdata(JL, (void *)®key_frontend); | ||
290 | lua_rawget(JL, LUA_REGISTRYINDEX); | ||
291 | sethvalue(JL, JL->top, st); | ||
292 | JL->top++; | ||
293 | |||
294 | /* Start the frontend by resuming the compiler thread. */ | ||
295 | if (lua_resume(JL, 1) != 0) { /* Failed? */ | ||
296 | /* Note: LUA_YIELD is treated like any other error. */ | ||
297 | J->L = NULL; /* Get a new thread next time. */ | ||
298 | fprintf(stderr, "[LuaJIT frontend failed: %s]\n", | ||
299 | lua_isstring(JL, -1) ? lua_tostring(JL, -1) : "(unknown error)"); | ||
300 | return JIT_S_COMPILER_ERROR; | ||
301 | } | ||
302 | |||
303 | /* Get status from terminated thread. */ | ||
304 | status = (int)lua_tointeger(JL, -1); | ||
305 | lua_settop(JL, 0); /* Help the GC. */ | ||
306 | return status; | ||
307 | } | ||
308 | |||
309 | /* Create the compiler pipeline and register it. */ | ||
310 | static void makepipeline(lua_State *L) | ||
311 | { | ||
312 | lua_createtable(L, 20, 0); /* 10 handlers+priorities should be enough. */ | ||
313 | lua_pushcfunction(L, luaJIT_backend); | ||
314 | lua_rawseti(L, -2, 1); | ||
315 | lua_pushinteger(L, 0); /* Fill in the backend at prio 0. */ | ||
316 | lua_rawseti(L, -2, 2); | ||
317 | |||
318 | /* Store the compiler frontend in the registry. */ | ||
319 | lua_pushlightuserdata(L, (void *)®key_frontend); | ||
320 | lua_pushvalue(L, -2); /* Pipeline table as upvalue. */ | ||
321 | lua_pushcclosure(L, j_frontend, 1); | ||
322 | lua_rawset(L, LUA_REGISTRYINDEX); | ||
323 | |||
324 | /* Register the frontend wrapper. */ | ||
325 | G(L)->jit_state->frontwrap = frontwrap; | ||
326 | |||
327 | /* Add jit.attach with the pipeline table as upvalue. */ | ||
328 | lua_pushcclosure(L, j_attach, 1); | ||
329 | lua_setfield(L, -2, "attach"); /* "jit" table must be below. */ | ||
330 | } | ||
331 | |||
332 | /* ------------------------------------------------------------------------ */ | ||
333 | |||
334 | /* Calculate total mcode size without mfm and only for active mcode blocks. */ | ||
335 | static size_t mcodesize(Proto *pt) | ||
336 | { | ||
337 | jit_MCTrailer tr; | ||
338 | size_t sz = 0; | ||
339 | tr.mcode = (char *)pt->jit_mcode; | ||
340 | tr.sz = pt->jit_szmcode; | ||
341 | do { | ||
342 | jit_Mfm *mfm = JIT_MCMFM(tr.mcode, tr.sz); | ||
343 | if (sz != 0 && jit_mfm_ismain(mfm)) break; /* Stop at old main mfm. */ | ||
344 | while (*mfm != JIT_MFM_STOP) mfm--; /* Search for end of mcode. */ | ||
345 | sz += (char *)mfm-(char *)tr.mcode; /* Add size of mcode without mfm. */ | ||
346 | memcpy((void *)&tr, JIT_MCTRAILER(tr.mcode, tr.sz), sizeof(jit_MCTrailer)); | ||
347 | } while (tr.mcode != NULL); | ||
348 | return sz; | ||
349 | } | ||
350 | |||
351 | #define setintfield(name, i) \ | ||
352 | do { lua_pushinteger(L, i); lua_setfield(L, -2, name); } while (0) | ||
353 | |||
354 | /* local stats = jit.util.stats(func) */ | ||
355 | static int ju_stats(lua_State *L) | ||
356 | { | ||
357 | if (!(L->top > L->base)) | ||
358 | luaL_argerror(L, 1, "Lua function expected"); | ||
359 | if (isLfunction(L->base)) { | ||
360 | Proto *pt = clvalue(L->base)->l.p; | ||
361 | lua_createtable(L, 0, 11); | ||
362 | setintfield("status", pt->jit_status); | ||
363 | setintfield("stackslots", pt->maxstacksize); | ||
364 | setintfield("params", pt->numparams); | ||
365 | setintfield("bytecodes", pt->sizecode); | ||
366 | setintfield("consts", pt->sizek); | ||
367 | setintfield("upvalues", pt->nups); | ||
368 | setintfield("subs", pt->sizep); | ||
369 | lua_pushboolean(L, pt->is_vararg); | ||
370 | lua_setfield(L, -2, "isvararg"); | ||
371 | lua_getfenv(L, 1); | ||
372 | lua_setfield(L, -2, "env"); | ||
373 | if (pt->jit_szmcode != 0) { | ||
374 | setintfield("mcodesize", (int)mcodesize(pt)); | ||
375 | lua_pushnumber(L, (lua_Number)(size_t)pt->jit_mcode); | ||
376 | lua_setfield(L, -2, "mcodeaddr"); | ||
377 | } | ||
378 | return 1; | ||
379 | } else { | ||
380 | return 0; /* Don't throw an error like the other util functions. */ | ||
381 | } | ||
382 | } | ||
383 | |||
384 | /* local op, a, b, c, test = jit.util.bytecode(func, pc) */ | ||
385 | static int ju_bytecode(lua_State *L) | ||
386 | { | ||
387 | Proto *pt = check_LCL(L)->l.p; | ||
388 | int pc = luaL_checkint(L, 2); | ||
389 | if (pc >= 1 && pc <= pt->sizecode) { | ||
390 | Instruction ins = pt->code[pc-1]; | ||
391 | OpCode op = GET_OPCODE(ins); | ||
392 | if (pc > 1 && (((int)OP_SETLIST) << POS_OP) == | ||
393 | (pt->code[pc-2] & (MASK1(SIZE_OP,POS_OP) | MASK1(SIZE_C,POS_C)))) { | ||
394 | lua_pushstring(L, luaP_opnames[OP_SETLIST]); | ||
395 | lua_pushnumber(L, (lua_Number)ins); /* Fake extended op. */ | ||
396 | return 1; | ||
397 | } | ||
398 | if (op >= NUM_OPCODES) return 0; /* Just in case. */ | ||
399 | lua_pushstring(L, luaP_opnames[op]); | ||
400 | lua_pushinteger(L, GETARG_A(ins)); | ||
401 | switch (getOpMode(op)) { | ||
402 | case iABC: { | ||
403 | int b = GETARG_B(ins), c = GETARG_C(ins); | ||
404 | switch (getBMode(op)) { | ||
405 | case OpArgN: lua_pushnil(L); break; | ||
406 | case OpArgK: if (ISK(b)) b = -1-INDEXK(b); | ||
407 | case OpArgR: case OpArgU: lua_pushinteger(L, b); break; | ||
408 | } | ||
409 | switch (getCMode(op)) { | ||
410 | case OpArgN: lua_pushnil(L); break; | ||
411 | case OpArgK: if (ISK(c)) c = -1-INDEXK(c); | ||
412 | case OpArgR: case OpArgU: lua_pushinteger(L, c); break; | ||
413 | } | ||
414 | lua_pushboolean(L, testTMode(op)); | ||
415 | return 5; | ||
416 | } | ||
417 | case iABx: { | ||
418 | int bx = GETARG_Bx(ins); | ||
419 | lua_pushinteger(L, getBMode(op) == OpArgK ? -1-bx : bx); | ||
420 | return 3; | ||
421 | } | ||
422 | case iAsBx: | ||
423 | lua_pushinteger(L, GETARG_sBx(ins)); | ||
424 | return 3; | ||
425 | } | ||
426 | } | ||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | /* local const, ok = jit.util.const(func, idx) */ | ||
431 | static int ju_const(lua_State *L) | ||
432 | { | ||
433 | Proto *pt = check_LCL(L)->l.p; | ||
434 | int idx = luaL_checkint(L, 2); | ||
435 | if (idx < 0) idx = -idx; /* Handle both positive and negative indices. */ | ||
436 | if (idx >= 1 && idx <= pt->sizek) { | ||
437 | setobj2s(L, L->top-1, &pt->k[idx-1]); | ||
438 | lua_pushboolean(L, 1); | ||
439 | return 2; | ||
440 | } | ||
441 | lua_pushnil(L); | ||
442 | lua_pushboolean(L, 0); | ||
443 | return 2; | ||
444 | } | ||
445 | |||
446 | /* local upvalue, ok = jit.util.upvalue(func, idx) */ | ||
447 | static int ju_upvalue(lua_State *L) | ||
448 | { | ||
449 | Closure *cl = check_LCL(L); | ||
450 | Proto *pt = cl->l.p; | ||
451 | int idx = luaL_checkint(L, 2); | ||
452 | if (idx >= 0 && idx < pt->nups) { | ||
453 | setobj2s(L, L->top-1, cl->l.upvals[idx]->v); | ||
454 | lua_pushboolean(L, 1); | ||
455 | return 2; | ||
456 | } | ||
457 | lua_pushnil(L); | ||
458 | lua_pushboolean(L, 0); | ||
459 | return 2; | ||
460 | } | ||
461 | |||
462 | /* local nup = jit.util.closurenup(func, idx) */ | ||
463 | static int ju_closurenup(lua_State *L) | ||
464 | { | ||
465 | Closure *cl = check_LCL(L); | ||
466 | Proto *pt = cl->l.p; | ||
467 | int idx = luaL_checkint(L, 2); | ||
468 | if (idx >= 0 && idx < pt->sizep) { | ||
469 | lua_pushinteger(L, pt->p[idx]->nups); | ||
470 | return 1; | ||
471 | } | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | /* for tag, mark in mfmiter do ... end. */ | ||
476 | static int ju_mfmiter(lua_State *L) | ||
477 | { | ||
478 | jit_Mfm *mfm = (jit_Mfm *)lua_touserdata(L, lua_upvalueindex(1)); | ||
479 | int m = *mfm--; | ||
480 | switch (m) { | ||
481 | case JIT_MFM_STOP: return 0; | ||
482 | case JIT_MFM_COMBINE: lua_pushliteral(L, "COMBINE"); lua_pushnil(L); break; | ||
483 | case JIT_MFM_DEAD: lua_pushliteral(L, "DEAD"); lua_pushnil(L); break; | ||
484 | default: | ||
485 | lua_pushinteger(L, m & JIT_MFM_MASK); | ||
486 | lua_pushboolean(L, m & JIT_MFM_MARK); | ||
487 | break; | ||
488 | } | ||
489 | lua_pushlightuserdata(L, (void *)mfm); | ||
490 | lua_replace(L, lua_upvalueindex(1)); | ||
491 | return 2; | ||
492 | } | ||
493 | |||
494 | /* local addr, mcode, mfmiter = jit.util.mcode(func, block) */ | ||
495 | static int ju_mcode(lua_State *L) | ||
496 | { | ||
497 | Proto *pt = check_LCL(L)->l.p; | ||
498 | if (pt->jit_szmcode == 0) { /* Not compiled (yet): return nil, status. */ | ||
499 | lua_pushnil(L); | ||
500 | lua_pushinteger(L, pt->jit_status); | ||
501 | return 2; | ||
502 | } else { | ||
503 | jit_Mfm *mfm; | ||
504 | jit_MCTrailer tr; | ||
505 | int block = luaL_checkint(L, 2); | ||
506 | tr.mcode = (char *)pt->jit_mcode; | ||
507 | tr.sz = pt->jit_szmcode; | ||
508 | while (--block > 0) { | ||
509 | void *trp = JIT_MCTRAILER(tr.mcode, tr.sz); | ||
510 | memcpy((void *)&tr, trp, sizeof(jit_MCTrailer)); | ||
511 | if (tr.sz == 0) return 0; | ||
512 | } | ||
513 | mfm = JIT_MCMFM(tr.mcode, tr.sz); | ||
514 | while (*mfm != JIT_MFM_STOP) mfm--; /* Search for end of mcode. */ | ||
515 | lua_pushnumber(L, (lua_Number)(size_t)tr.mcode); | ||
516 | lua_pushlstring(L, (const char *)tr.mcode, (char *)mfm-(char *)tr.mcode); | ||
517 | lua_pushlightuserdata(L, (void *)JIT_MCMFM(tr.mcode, tr.sz)); | ||
518 | lua_pushvalue(L, 1); /* Must hold onto function to avoid GC. */ | ||
519 | lua_pushcclosure(L, ju_mfmiter, 2); | ||
520 | return 3; | ||
521 | } | ||
522 | } | ||
523 | |||
524 | /* local addr [, mcode] = jit.util.jsubmcode([idx]) */ | ||
525 | static int ju_jsubmcode(lua_State *L) | ||
526 | { | ||
527 | jit_State *J = G(L)->jit_state; | ||
528 | if (lua_isnoneornil(L, 1)) { | ||
529 | lua_pushnumber(L, (lua_Number)(size_t)J->jsubmcode); | ||
530 | lua_pushlstring(L, (const char *)J->jsubmcode, J->szjsubmcode); | ||
531 | return 2; | ||
532 | } else { | ||
533 | int idx = luaL_checkint(L, 1); | ||
534 | if (idx >= 0 && idx < J->numjsub) { | ||
535 | lua_pushnumber(L, (lua_Number)(size_t)J->jsub[idx]); | ||
536 | return 1; | ||
537 | } | ||
538 | return 0; | ||
539 | } | ||
540 | } | ||
541 | |||
542 | /* FOR INTERNAL DEBUGGING USE ONLY: local addr = jit.util.stackptr() */ | ||
543 | static int ju_stackptr(lua_State *L) | ||
544 | { | ||
545 | jit_State *J = G(L)->jit_state; | ||
546 | size_t addr = cast(size_t (*)(void), J->jsub[0])(); /* JSUB_STACKPTR == 0! */ | ||
547 | lua_pushnumber(L, (lua_Number)addr); | ||
548 | return 1; | ||
549 | } | ||
550 | |||
551 | /* jit.util.* functions. */ | ||
552 | static const luaL_Reg jitutillib[] = { | ||
553 | {"stats", ju_stats }, | ||
554 | {"bytecode", ju_bytecode }, | ||
555 | {"const", ju_const }, | ||
556 | {"upvalue", ju_upvalue }, | ||
557 | {"closurenup", ju_closurenup }, | ||
558 | {"mcode", ju_mcode }, | ||
559 | {"jsubmcode", ju_jsubmcode }, | ||
560 | {"stackptr", ju_stackptr }, | ||
561 | { NULL, NULL } | ||
562 | }; | ||
563 | |||
564 | /* Make hint name to hint number map. */ | ||
565 | static void makehints(lua_State *L, const char *const *t, int tmax, | ||
566 | const char *name) | ||
567 | { | ||
568 | int i; | ||
569 | lua_createtable(L, 0, tmax); | ||
570 | for (i = 1; i < tmax; i++) { | ||
571 | lua_pushinteger(L, JIT_H2NUM(i)); | ||
572 | lua_setfield(L, -2, t[i-1]); | ||
573 | } | ||
574 | lua_setfield(L, -2, name); | ||
575 | } | ||
576 | |||
577 | /* CHECK: must match with ljit.h (grep "ORDER JIT_S"). */ | ||
578 | static const char *const status_list[] = { | ||
579 | "OK", | ||
580 | "NONE", | ||
581 | "OFF", | ||
582 | "ENGINE_OFF", | ||
583 | "DELAYED", | ||
584 | "TOOLARGE", | ||
585 | "COMPILER_ERROR", | ||
586 | "DASM_ERROR" | ||
587 | }; | ||
588 | |||
589 | /* Make bidirectional status name to status number map. */ | ||
590 | static void makestatus(lua_State *L, const char *name) | ||
591 | { | ||
592 | int i; | ||
593 | lua_createtable(L, JIT_S_MAX-1, JIT_S_MAX+1); /* Codes are not 1-based. */ | ||
594 | for (i = 0; i < JIT_S_MAX; i++) { | ||
595 | lua_pushstring(L, status_list[i]); | ||
596 | lua_pushinteger(L, i); | ||
597 | lua_pushvalue(L, -2); | ||
598 | lua_rawseti(L, -4, i); | ||
599 | lua_rawset(L, -3); | ||
600 | } | ||
601 | lua_setfield(L, -2, name); | ||
602 | } | ||
603 | |||
604 | /* ------------------------------------------------------------------------ */ | ||
605 | |||
606 | /* | ||
607 | ** Open JIT library | ||
608 | */ | ||
609 | LUALIB_API int luaopen_jit(lua_State *L) | ||
610 | { | ||
611 | /* Add the core JIT library. */ | ||
612 | luaL_register(L, LUA_JITLIBNAME, jitlib); | ||
613 | lua_pushliteral(L, LUAJIT_VERSION); | ||
614 | lua_setfield(L, -2, "version"); | ||
615 | setintfield("version_num", LUAJIT_VERSION_NUM); | ||
616 | lua_pushstring(L, luaJIT_arch); | ||
617 | lua_setfield(L, -2, "arch"); | ||
618 | makepipeline(L); | ||
619 | |||
620 | /* Add the utility JIT library. */ | ||
621 | luaL_register(L, LUA_JITLIBNAME ".util", jitutillib); | ||
622 | makestatus(L, "status"); | ||
623 | makehints(L, hints_H, JIT_H_MAX, "hints"); | ||
624 | makehints(L, hints_FH, JIT_FH_MAX, "fhints"); | ||
625 | lua_pop(L, 1); | ||
626 | |||
627 | /* Everything ok, so turn the JIT engine on. Vroooom! */ | ||
628 | if (luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE|LUAJIT_MODE_ON) <= 0) { | ||
629 | /* Ouch. Someone screwed up DynASM or the JSUBs. Probably me. */ | ||
630 | /* But if you get 999999999, look at jit_consistency_check(). */ | ||
631 | return luaL_error(L, "JIT engine init failed (%d)", | ||
632 | G(L)->jit_state->dasmstatus); | ||
633 | } | ||
634 | |||
635 | return 1; | ||
636 | } | ||
637 | |||