2 ** Instruction dispatch handling.
3 ** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
21 #include "lj_strfmt.h"
26 #include "lj_ccallback.h"
29 #include "lj_dispatch.h"
31 #include "lj_profile.h"
36 /* Bump GG_NUM_ASMFF in lj_dispatch.h as needed. Ugly. */
37 LJ_STATIC_ASSERT(GG_NUM_ASMFF
== FF_NUM_ASMFUNC
);
39 /* -- Dispatch table management ------------------------------------------- */
43 LJ_FUNCA_NORET
void LJ_FASTCALL
lj_ffh_coroutine_wrap_err(lua_State
*L
,
46 #define lj_dispatch_stitch lj_dispatch_ins
49 #define lj_dispatch_profile lj_dispatch_ins
52 #define GOTFUNC(name) (ASMFunction)name,
53 static const ASMFunction dispatch_got
[] = {
59 /* Initialize instruction dispatch table and hot counters. */
60 void lj_dispatch_init(GG_State
*GG
)
63 ASMFunction
*disp
= GG
->dispatch
;
64 for (i
= 0; i
< GG_LEN_SDISP
; i
++)
65 disp
[GG_LEN_DDISP
+i
] = disp
[i
] = makeasmfunc(lj_bc_ofs
[i
]);
66 for (i
= GG_LEN_SDISP
; i
< GG_LEN_DDISP
; i
++)
67 disp
[i
] = makeasmfunc(lj_bc_ofs
[i
]);
68 /* The JIT engine is off by default. luaopen_jit() turns it on. */
69 disp
[BC_FORL
] = disp
[BC_IFORL
];
70 disp
[BC_ITERL
] = disp
[BC_IITERL
];
71 disp
[BC_LOOP
] = disp
[BC_ILOOP
];
72 disp
[BC_FUNCF
] = disp
[BC_IFUNCF
];
73 disp
[BC_FUNCV
] = disp
[BC_IFUNCV
];
74 GG
->g
.bc_cfunc_ext
= GG
->g
.bc_cfunc_int
= BCINS_AD(BC_FUNCC
, LUA_MINSTACK
, 0);
75 for (i
= 0; i
< GG_NUM_ASMFF
; i
++)
76 GG
->bcff
[i
] = BCINS_AD(BC__MAX
+i
, 0, 0);
78 memcpy(GG
->got
, dispatch_got
, LJ_GOT__MAX
*4);
83 /* Initialize hotcount table. */
84 void lj_dispatch_init_hotcount(global_State
*g
)
86 int32_t hotloop
= G2J(g
)->param
[JIT_P_hotloop
];
87 HotCount start
= (HotCount
)(hotloop
*HOTCOUNT_LOOP
- 1);
88 HotCount
*hotcount
= G2GG(g
)->hotcount
;
90 for (i
= 0; i
< HOTCOUNT_SIZE
; i
++)
95 /* Internal dispatch mode bits. */
96 #define DISPMODE_CALL 0x01 /* Override call dispatch. */
97 #define DISPMODE_RET 0x02 /* Override return dispatch. */
98 #define DISPMODE_INS 0x04 /* Override instruction dispatch. */
99 #define DISPMODE_JIT 0x10 /* JIT compiler on. */
100 #define DISPMODE_REC 0x20 /* Recording active. */
101 #define DISPMODE_PROF 0x40 /* Profiling active. */
103 /* Update dispatch table depending on various flags. */
104 void lj_dispatch_update(global_State
*g
)
106 uint8_t oldmode
= g
->dispatchmode
;
109 mode
|= (G2J(g
)->flags
& JIT_F_ON
) ? DISPMODE_JIT
: 0;
110 mode
|= G2J(g
)->state
!= LJ_TRACE_IDLE
?
111 (DISPMODE_REC
|DISPMODE_INS
|DISPMODE_CALL
) : 0;
114 mode
|= (g
->hookmask
& HOOK_PROFILE
) ? (DISPMODE_PROF
|DISPMODE_INS
) : 0;
116 mode
|= (g
->hookmask
& (LUA_MASKLINE
|LUA_MASKCOUNT
)) ? DISPMODE_INS
: 0;
117 mode
|= (g
->hookmask
& LUA_MASKCALL
) ? DISPMODE_CALL
: 0;
118 mode
|= (g
->hookmask
& LUA_MASKRET
) ? DISPMODE_RET
: 0;
119 if (oldmode
!= mode
) { /* Mode changed? */
120 ASMFunction
*disp
= G2GG(g
)->dispatch
;
121 ASMFunction f_forl
, f_iterl
, f_loop
, f_funcf
, f_funcv
;
122 g
->dispatchmode
= mode
;
124 /* Hotcount if JIT is on, but not while recording. */
125 if ((mode
& (DISPMODE_JIT
|DISPMODE_REC
)) == DISPMODE_JIT
) {
126 f_forl
= makeasmfunc(lj_bc_ofs
[BC_FORL
]);
127 f_iterl
= makeasmfunc(lj_bc_ofs
[BC_ITERL
]);
128 f_loop
= makeasmfunc(lj_bc_ofs
[BC_LOOP
]);
129 f_funcf
= makeasmfunc(lj_bc_ofs
[BC_FUNCF
]);
130 f_funcv
= makeasmfunc(lj_bc_ofs
[BC_FUNCV
]);
131 } else { /* Otherwise use the non-hotcounting instructions. */
132 f_forl
= disp
[GG_LEN_DDISP
+BC_IFORL
];
133 f_iterl
= disp
[GG_LEN_DDISP
+BC_IITERL
];
134 f_loop
= disp
[GG_LEN_DDISP
+BC_ILOOP
];
135 f_funcf
= makeasmfunc(lj_bc_ofs
[BC_IFUNCF
]);
136 f_funcv
= makeasmfunc(lj_bc_ofs
[BC_IFUNCV
]);
138 /* Init static counting instruction dispatch first (may be copied below). */
139 disp
[GG_LEN_DDISP
+BC_FORL
] = f_forl
;
140 disp
[GG_LEN_DDISP
+BC_ITERL
] = f_iterl
;
141 disp
[GG_LEN_DDISP
+BC_LOOP
] = f_loop
;
143 /* Set dynamic instruction dispatch. */
144 if ((oldmode
^ mode
) & (DISPMODE_PROF
|DISPMODE_REC
|DISPMODE_INS
)) {
145 /* Need to update the whole table. */
146 if (!(mode
& DISPMODE_INS
)) { /* No ins dispatch? */
147 /* Copy static dispatch table to dynamic dispatch table. */
148 memcpy(&disp
[0], &disp
[GG_LEN_DDISP
], GG_LEN_SDISP
*sizeof(ASMFunction
));
149 /* Overwrite with dynamic return dispatch. */
150 if ((mode
& DISPMODE_RET
)) {
151 disp
[BC_RETM
] = lj_vm_rethook
;
152 disp
[BC_RET
] = lj_vm_rethook
;
153 disp
[BC_RET0
] = lj_vm_rethook
;
154 disp
[BC_RET1
] = lj_vm_rethook
;
157 /* The recording dispatch also checks for hooks. */
158 ASMFunction f
= (mode
& DISPMODE_PROF
) ? lj_vm_profhook
:
159 (mode
& DISPMODE_REC
) ? lj_vm_record
: lj_vm_inshook
;
161 for (i
= 0; i
< GG_LEN_SDISP
; i
++)
164 } else if (!(mode
& DISPMODE_INS
)) {
165 /* Otherwise set dynamic counting ins. */
166 disp
[BC_FORL
] = f_forl
;
167 disp
[BC_ITERL
] = f_iterl
;
168 disp
[BC_LOOP
] = f_loop
;
169 /* Set dynamic return dispatch. */
170 if ((mode
& DISPMODE_RET
)) {
171 disp
[BC_RETM
] = lj_vm_rethook
;
172 disp
[BC_RET
] = lj_vm_rethook
;
173 disp
[BC_RET0
] = lj_vm_rethook
;
174 disp
[BC_RET1
] = lj_vm_rethook
;
176 disp
[BC_RETM
] = disp
[GG_LEN_DDISP
+BC_RETM
];
177 disp
[BC_RET
] = disp
[GG_LEN_DDISP
+BC_RET
];
178 disp
[BC_RET0
] = disp
[GG_LEN_DDISP
+BC_RET0
];
179 disp
[BC_RET1
] = disp
[GG_LEN_DDISP
+BC_RET1
];
183 /* Set dynamic call dispatch. */
184 if ((oldmode
^ mode
) & DISPMODE_CALL
) { /* Update the whole table? */
186 if ((mode
& DISPMODE_CALL
) == 0) { /* No call hooks? */
187 for (i
= GG_LEN_SDISP
; i
< GG_LEN_DDISP
; i
++)
188 disp
[i
] = makeasmfunc(lj_bc_ofs
[i
]);
190 for (i
= GG_LEN_SDISP
; i
< GG_LEN_DDISP
; i
++)
191 disp
[i
] = lj_vm_callhook
;
194 if (!(mode
& DISPMODE_CALL
)) { /* Overwrite dynamic counting ins. */
195 disp
[BC_FUNCF
] = f_funcf
;
196 disp
[BC_FUNCV
] = f_funcv
;
200 /* Reset hotcounts for JIT off to on transition. */
201 if ((mode
& DISPMODE_JIT
) && !(oldmode
& DISPMODE_JIT
))
202 lj_dispatch_init_hotcount(g
);
207 /* -- JIT mode setting ---------------------------------------------------- */
210 /* Set JIT mode for a single prototype. */
211 static void setptmode(global_State
*g
, GCproto
*pt
, int mode
)
213 if ((mode
& LUAJIT_MODE_ON
)) { /* (Re-)enable JIT compilation. */
214 pt
->flags
&= ~PROTO_NOJIT
;
215 lj_trace_reenableproto(pt
); /* Unpatch all ILOOP etc. bytecodes. */
216 } else { /* Flush and/or disable JIT compilation. */
217 if (!(mode
& LUAJIT_MODE_FLUSH
))
218 pt
->flags
|= PROTO_NOJIT
;
219 lj_trace_flushproto(g
, pt
); /* Flush all traces of prototype. */
223 /* Recursively set the JIT mode for all children of a prototype. */
224 static void setptmode_all(global_State
*g
, GCproto
*pt
, int mode
)
227 if (!(pt
->flags
& PROTO_CHILD
)) return;
228 for (i
= -(ptrdiff_t)pt
->sizekgc
; i
< 0; i
++) {
229 GCobj
*o
= proto_kgc(pt
, i
);
230 if (o
->gch
.gct
== ~LJ_TPROTO
) {
231 setptmode(g
, gco2pt(o
), mode
);
232 setptmode_all(g
, gco2pt(o
), mode
);
238 /* Public API function: control the JIT engine. */
239 int luaJIT_setmode(lua_State
*L
, int idx
, int mode
)
241 global_State
*g
= G(L
);
242 int mm
= mode
& LUAJIT_MODE_MASK
;
243 lj_trace_abort(g
); /* Abort recording on any state change. */
244 /* Avoid pulling the rug from under our own feet. */
245 if ((g
->hookmask
& HOOK_GC
))
246 lj_err_caller(L
, LJ_ERR_NOGCMM
);
249 case LUAJIT_MODE_ENGINE
:
250 if ((mode
& LUAJIT_MODE_FLUSH
)) {
251 lj_trace_flushall(L
);
253 if (!(mode
& LUAJIT_MODE_ON
))
254 G2J(g
)->flags
&= ~(uint32_t)JIT_F_ON
;
255 #if LJ_TARGET_X86ORX64
256 else if ((G2J(g
)->flags
& JIT_F_SSE2
))
257 G2J(g
)->flags
|= (uint32_t)JIT_F_ON
;
259 return 0; /* Don't turn on JIT compiler without SSE2 support. */
262 G2J(g
)->flags
|= (uint32_t)JIT_F_ON
;
264 lj_dispatch_update(g
);
267 case LUAJIT_MODE_FUNC
:
268 case LUAJIT_MODE_ALLFUNC
:
269 case LUAJIT_MODE_ALLSUBFUNC
: {
270 cTValue
*tv
= idx
== 0 ? frame_prev(L
->base
-1) :
271 idx
> 0 ? L
->base
+ (idx
-1) : L
->top
+ idx
;
273 if ((idx
== 0 || tvisfunc(tv
)) && isluafunc(&gcval(tv
)->fn
))
274 pt
= funcproto(&gcval(tv
)->fn
); /* Cannot use funcV() for frame slot. */
275 else if (tvisproto(tv
))
278 return 0; /* Failed. */
279 if (mm
!= LUAJIT_MODE_ALLSUBFUNC
)
280 setptmode(g
, pt
, mode
);
281 if (mm
!= LUAJIT_MODE_FUNC
)
282 setptmode_all(g
, pt
, mode
);
285 case LUAJIT_MODE_TRACE
:
286 if (!(mode
& LUAJIT_MODE_FLUSH
))
287 return 0; /* Failed. */
288 lj_trace_flush(G2J(g
), idx
);
291 case LUAJIT_MODE_ENGINE
:
292 case LUAJIT_MODE_FUNC
:
293 case LUAJIT_MODE_ALLFUNC
:
294 case LUAJIT_MODE_ALLSUBFUNC
:
296 if ((mode
& LUAJIT_MODE_ON
))
297 return 0; /* Failed. */
300 case LUAJIT_MODE_WRAPCFUNC
:
301 if ((mode
& LUAJIT_MODE_ON
)) {
303 cTValue
*tv
= idx
> 0 ? L
->base
+ (idx
-1) : L
->top
+ idx
;
305 g
->wrapf
= (lua_CFunction
)lightudV(tv
);
307 return 0; /* Failed. */
309 return 0; /* Failed. */
311 g
->bc_cfunc_ext
= BCINS_AD(BC_FUNCCW
, 0, 0);
313 g
->bc_cfunc_ext
= BCINS_AD(BC_FUNCC
, 0, 0);
317 return 0; /* Failed. */
322 /* Enforce (dynamic) linker error for version mismatches. See luajit.c. */
323 LUA_API
void LUAJIT_VERSION_SYM(void)
327 /* -- Hooks --------------------------------------------------------------- */
329 /* This function can be called asynchronously (e.g. during a signal). */
330 LUA_API
int lua_sethook(lua_State
*L
, lua_Hook func
, int mask
, int count
)
332 global_State
*g
= G(L
);
333 mask
&= HOOK_EVENTMASK
;
334 if (func
== NULL
|| mask
== 0) { mask
= 0; func
= NULL
; } /* Consistency. */
336 g
->hookcount
= g
->hookcstart
= (int32_t)count
;
337 g
->hookmask
= (uint8_t)((g
->hookmask
& ~HOOK_EVENTMASK
) | mask
);
338 lj_trace_abort(g
); /* Abort recording on any hook change. */
339 lj_dispatch_update(g
);
343 LUA_API lua_Hook
lua_gethook(lua_State
*L
)
348 LUA_API
int lua_gethookmask(lua_State
*L
)
350 return G(L
)->hookmask
& HOOK_EVENTMASK
;
353 LUA_API
int lua_gethookcount(lua_State
*L
)
355 return (int)G(L
)->hookcstart
;
359 static void callhook(lua_State
*L
, int event
, BCLine line
)
361 global_State
*g
= G(L
);
362 lua_Hook hookf
= g
->hookf
;
363 if (hookf
&& !hook_active(g
)) {
365 lj_trace_abort(g
); /* Abort recording on any hook call. */
367 ar
.currentline
= line
;
368 /* Top frame, nextframe = NULL. */
369 ar
.i_ci
= (int)((L
->base
-1) - tvref(L
->stack
));
370 lj_state_checkstack(L
, 1+LUA_MINSTACK
);
371 #if LJ_HASPROFILE && !LJ_PROFILE_SIGPROF
372 lj_profile_hook_enter(g
);
377 lua_assert(hook_active(g
));
378 setgcref(g
->cur_L
, obj2gco(L
));
379 #if LJ_HASPROFILE && !LJ_PROFILE_SIGPROF
380 lj_profile_hook_leave(g
);
387 /* -- Dispatch callbacks -------------------------------------------------- */
389 /* Calculate number of used stack slots in the current frame. */
390 static BCReg
cur_topslot(GCproto
*pt
, const BCIns
*pc
, uint32_t nres
)
393 if (bc_op(ins
) == BC_UCLO
)
395 switch (bc_op(ins
)) {
396 case BC_CALLM
: case BC_CALLMT
: return bc_a(ins
) + bc_c(ins
) + nres
-1+1+LJ_FR2
;
397 case BC_RETM
: return bc_a(ins
) + bc_d(ins
) + nres
-1;
398 case BC_TSETM
: return bc_a(ins
) + nres
-1;
399 default: return pt
->framesize
;
403 /* Instruction dispatch. Used by instr/line/return hooks or when recording. */
404 void LJ_FASTCALL
lj_dispatch_ins(lua_State
*L
, const BCIns
*pc
)
407 GCfunc
*fn
= curr_func(L
);
408 GCproto
*pt
= funcproto(fn
);
409 void *cf
= cframe_raw(L
->cframe
);
410 const BCIns
*oldpc
= cframe_pc(cf
);
411 global_State
*g
= G(L
);
413 setcframe_pc(cf
, pc
);
414 slots
= cur_topslot(pt
, pc
, cframe_multres_n(cf
));
415 L
->top
= L
->base
+ slots
; /* Fix top. */
418 jit_State
*J
= G2J(g
);
419 if (J
->state
!= LJ_TRACE_IDLE
) {
420 #ifdef LUA_USE_ASSERT
421 ptrdiff_t delta
= L
->top
- L
->base
;
424 lj_trace_ins(J
, pc
-1); /* The interpreter bytecode PC is offset by 1. */
425 lua_assert(L
->top
- L
->base
== delta
);
429 if ((g
->hookmask
& LUA_MASKCOUNT
) && g
->hookcount
== 0) {
430 g
->hookcount
= g
->hookcstart
;
431 callhook(L
, LUA_HOOKCOUNT
, -1);
432 L
->top
= L
->base
+ slots
; /* Fix top again. */
434 if ((g
->hookmask
& LUA_MASKLINE
)) {
435 BCPos npc
= proto_bcpos(pt
, pc
) - 1;
436 BCPos opc
= proto_bcpos(pt
, oldpc
) - 1;
437 BCLine line
= lj_debug_line(pt
, npc
);
438 if (pc
<= oldpc
|| opc
>= pt
->sizebc
|| line
!= lj_debug_line(pt
, opc
)) {
439 callhook(L
, LUA_HOOKLINE
, line
);
440 L
->top
= L
->base
+ slots
; /* Fix top again. */
443 if ((g
->hookmask
& LUA_MASKRET
) && bc_isret(bc_op(pc
[-1])))
444 callhook(L
, LUA_HOOKRET
, -1);
448 /* Initialize call. Ensure stack space and return # of missing parameters. */
449 static int call_init(lua_State
*L
, GCfunc
*fn
)
452 GCproto
*pt
= funcproto(fn
);
453 int numparams
= pt
->numparams
;
454 int gotparams
= (int)(L
->top
- L
->base
);
455 int need
= pt
->framesize
;
456 if ((pt
->flags
& PROTO_VARARG
)) need
+= 1+gotparams
;
457 lj_state_checkstack(L
, (MSize
)need
);
458 numparams
-= gotparams
;
459 return numparams
>= 0 ? numparams
: 0;
461 lj_state_checkstack(L
, LUA_MINSTACK
);
466 /* Call dispatch. Used by call hooks, hot calls or when recording. */
467 ASMFunction LJ_FASTCALL
lj_dispatch_call(lua_State
*L
, const BCIns
*pc
)
470 GCfunc
*fn
= curr_func(L
);
472 global_State
*g
= G(L
);
474 jit_State
*J
= G2J(g
);
476 int missing
= call_init(L
, fn
);
479 if ((uintptr_t)pc
& 1) { /* Marker for hot call. */
480 #ifdef LUA_USE_ASSERT
481 ptrdiff_t delta
= L
->top
- L
->base
;
483 pc
= (const BCIns
*)((uintptr_t)pc
& ~(uintptr_t)1);
485 lua_assert(L
->top
- L
->base
== delta
);
487 } else if (J
->state
!= LJ_TRACE_IDLE
&&
488 !(g
->hookmask
& (HOOK_GC
|HOOK_VMEVENT
))) {
489 #ifdef LUA_USE_ASSERT
490 ptrdiff_t delta
= L
->top
- L
->base
;
492 /* Record the FUNC* bytecodes, too. */
493 lj_trace_ins(J
, pc
-1); /* The interpreter bytecode PC is offset by 1. */
494 lua_assert(L
->top
- L
->base
== delta
);
497 if ((g
->hookmask
& LUA_MASKCALL
)) {
499 for (i
= 0; i
< missing
; i
++) /* Add missing parameters. */
501 callhook(L
, LUA_HOOKCALL
, -1);
502 /* Preserve modifications of missing parameters by lua_setlocal(). */
503 while (missing
-- > 0 && tvisnil(L
->top
- 1))
509 op
= bc_op(pc
[-1]); /* Get FUNC* op. */
511 /* Use the non-hotcounting variants if JIT is off or while recording. */
512 if ((!(J
->flags
& JIT_F_ON
) || J
->state
!= LJ_TRACE_IDLE
) &&
513 (op
== BC_FUNCF
|| op
== BC_FUNCV
))
514 op
= (BCOp
)((int)op
+(int)BC_IFUNCF
-(int)BC_FUNCF
);
517 return makeasmfunc(lj_bc_ofs
[op
]); /* Return static dispatch target. */
521 /* Stitch a new trace. */
522 void LJ_FASTCALL
lj_dispatch_stitch(jit_State
*J
, const BCIns
*pc
)
526 void *cf
= cframe_raw(L
->cframe
);
527 const BCIns
*oldpc
= cframe_pc(cf
);
528 setcframe_pc(cf
, pc
);
529 /* Before dispatch, have to bias PC by 1. */
530 L
->top
= L
->base
+ cur_topslot(curr_proto(L
), pc
+1, cframe_multres_n(cf
));
531 lj_trace_stitch(J
, pc
-1); /* Point to the CALL instruction. */
532 setcframe_pc(cf
, oldpc
);
538 /* Profile dispatch. */
539 void LJ_FASTCALL
lj_dispatch_profile(lua_State
*L
, const BCIns
*pc
)
542 GCfunc
*fn
= curr_func(L
);
543 GCproto
*pt
= funcproto(fn
);
544 void *cf
= cframe_raw(L
->cframe
);
545 const BCIns
*oldpc
= cframe_pc(cf
);
547 setcframe_pc(cf
, pc
);
548 L
->top
= L
->base
+ cur_topslot(pt
, pc
, cframe_multres_n(cf
));
549 lj_profile_interpreter(L
);
550 setcframe_pc(cf
, oldpc
);
552 setgcref(g
->cur_L
, obj2gco(L
));
553 setvmstate(g
, INTERP
);