2 ** Instruction dispatch handling.
3 ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
24 #include "lj_ccallback.h"
27 #include "lj_dispatch.h"
31 /* Bump GG_NUM_ASMFF in lj_dispatch.h as needed. Ugly. */
32 LJ_STATIC_ASSERT(GG_NUM_ASMFF
== FF_NUM_ASMFUNC
);
34 /* -- Dispatch table management ------------------------------------------- */
38 LJ_FUNCA_NORET
void LJ_FASTCALL
lj_ffh_coroutine_wrap_err(lua_State
*L
,
41 #define GOTFUNC(name) (ASMFunction)name,
42 static const ASMFunction dispatch_got
[] = {
48 /* Initialize instruction dispatch table and hot counters. */
49 void lj_dispatch_init(GG_State
*GG
)
52 ASMFunction
*disp
= GG
->dispatch
;
53 for (i
= 0; i
< GG_LEN_SDISP
; i
++)
54 disp
[GG_LEN_DDISP
+i
] = disp
[i
] = makeasmfunc(lj_bc_ofs
[i
]);
55 for (i
= GG_LEN_SDISP
; i
< GG_LEN_DDISP
; i
++)
56 disp
[i
] = makeasmfunc(lj_bc_ofs
[i
]);
57 /* The JIT engine is off by default. luaopen_jit() turns it on. */
58 disp
[BC_FORL
] = disp
[BC_IFORL
];
59 disp
[BC_ITERL
] = disp
[BC_IITERL
];
60 disp
[BC_LOOP
] = disp
[BC_ILOOP
];
61 disp
[BC_FUNCF
] = disp
[BC_IFUNCF
];
62 disp
[BC_FUNCV
] = disp
[BC_IFUNCV
];
63 GG
->g
.bc_cfunc_ext
= GG
->g
.bc_cfunc_int
= BCINS_AD(BC_FUNCC
, LUA_MINSTACK
, 0);
64 for (i
= 0; i
< GG_NUM_ASMFF
; i
++)
65 GG
->bcff
[i
] = BCINS_AD(BC__MAX
+i
, 0, 0);
67 memcpy(GG
->got
, dispatch_got
, LJ_GOT__MAX
*4);
72 /* Initialize hotcount table. */
73 void lj_dispatch_init_hotcount(global_State
*g
)
75 int32_t hotloop
= G2J(g
)->param
[JIT_P_hotloop
];
76 HotCount start
= (HotCount
)(hotloop
*HOTCOUNT_LOOP
- 1);
77 HotCount
*hotcount
= G2GG(g
)->hotcount
;
79 for (i
= 0; i
< HOTCOUNT_SIZE
; i
++)
84 /* Internal dispatch mode bits. */
85 #define DISPMODE_JIT 0x01 /* JIT compiler on. */
86 #define DISPMODE_REC 0x02 /* Recording active. */
87 #define DISPMODE_INS 0x04 /* Override instruction dispatch. */
88 #define DISPMODE_CALL 0x08 /* Override call dispatch. */
89 #define DISPMODE_RET 0x10 /* Override return dispatch. */
91 /* Update dispatch table depending on various flags. */
92 void lj_dispatch_update(global_State
*g
)
94 uint8_t oldmode
= g
->dispatchmode
;
97 mode
|= (G2J(g
)->flags
& JIT_F_ON
) ? DISPMODE_JIT
: 0;
98 mode
|= G2J(g
)->state
!= LJ_TRACE_IDLE
?
99 (DISPMODE_REC
|DISPMODE_INS
|DISPMODE_CALL
) : 0;
101 mode
|= (g
->hookmask
& (LUA_MASKLINE
|LUA_MASKCOUNT
)) ? DISPMODE_INS
: 0;
102 mode
|= (g
->hookmask
& LUA_MASKCALL
) ? DISPMODE_CALL
: 0;
103 mode
|= (g
->hookmask
& LUA_MASKRET
) ? DISPMODE_RET
: 0;
104 if (oldmode
!= mode
) { /* Mode changed? */
105 ASMFunction
*disp
= G2GG(g
)->dispatch
;
106 ASMFunction f_forl
, f_iterl
, f_loop
, f_funcf
, f_funcv
;
107 g
->dispatchmode
= mode
;
109 /* Hotcount if JIT is on, but not while recording. */
110 if ((mode
& (DISPMODE_JIT
|DISPMODE_REC
)) == DISPMODE_JIT
) {
111 f_forl
= makeasmfunc(lj_bc_ofs
[BC_FORL
]);
112 f_iterl
= makeasmfunc(lj_bc_ofs
[BC_ITERL
]);
113 f_loop
= makeasmfunc(lj_bc_ofs
[BC_LOOP
]);
114 f_funcf
= makeasmfunc(lj_bc_ofs
[BC_FUNCF
]);
115 f_funcv
= makeasmfunc(lj_bc_ofs
[BC_FUNCV
]);
116 } else { /* Otherwise use the non-hotcounting instructions. */
117 f_forl
= disp
[GG_LEN_DDISP
+BC_IFORL
];
118 f_iterl
= disp
[GG_LEN_DDISP
+BC_IITERL
];
119 f_loop
= disp
[GG_LEN_DDISP
+BC_ILOOP
];
120 f_funcf
= makeasmfunc(lj_bc_ofs
[BC_IFUNCF
]);
121 f_funcv
= makeasmfunc(lj_bc_ofs
[BC_IFUNCV
]);
123 /* Init static counting instruction dispatch first (may be copied below). */
124 disp
[GG_LEN_DDISP
+BC_FORL
] = f_forl
;
125 disp
[GG_LEN_DDISP
+BC_ITERL
] = f_iterl
;
126 disp
[GG_LEN_DDISP
+BC_LOOP
] = f_loop
;
128 /* Set dynamic instruction dispatch. */
129 if ((oldmode
^ mode
) & (DISPMODE_REC
|DISPMODE_INS
)) {
130 /* Need to update the whole table. */
131 if (!(mode
& (DISPMODE_REC
|DISPMODE_INS
))) { /* No ins dispatch? */
132 /* Copy static dispatch table to dynamic dispatch table. */
133 memcpy(&disp
[0], &disp
[GG_LEN_DDISP
], GG_LEN_SDISP
*sizeof(ASMFunction
));
134 /* Overwrite with dynamic return dispatch. */
135 if ((mode
& DISPMODE_RET
)) {
136 disp
[BC_RETM
] = lj_vm_rethook
;
137 disp
[BC_RET
] = lj_vm_rethook
;
138 disp
[BC_RET0
] = lj_vm_rethook
;
139 disp
[BC_RET1
] = lj_vm_rethook
;
142 /* The recording dispatch also checks for hooks. */
143 ASMFunction f
= (mode
& DISPMODE_REC
) ? lj_vm_record
: lj_vm_inshook
;
145 for (i
= 0; i
< GG_LEN_SDISP
; i
++)
148 } else if (!(mode
& (DISPMODE_REC
|DISPMODE_INS
))) {
149 /* Otherwise set dynamic counting ins. */
150 disp
[BC_FORL
] = f_forl
;
151 disp
[BC_ITERL
] = f_iterl
;
152 disp
[BC_LOOP
] = f_loop
;
153 /* Set dynamic return dispatch. */
154 if ((mode
& DISPMODE_RET
)) {
155 disp
[BC_RETM
] = lj_vm_rethook
;
156 disp
[BC_RET
] = lj_vm_rethook
;
157 disp
[BC_RET0
] = lj_vm_rethook
;
158 disp
[BC_RET1
] = lj_vm_rethook
;
160 disp
[BC_RETM
] = disp
[GG_LEN_DDISP
+BC_RETM
];
161 disp
[BC_RET
] = disp
[GG_LEN_DDISP
+BC_RET
];
162 disp
[BC_RET0
] = disp
[GG_LEN_DDISP
+BC_RET0
];
163 disp
[BC_RET1
] = disp
[GG_LEN_DDISP
+BC_RET1
];
167 /* Set dynamic call dispatch. */
168 if ((oldmode
^ mode
) & DISPMODE_CALL
) { /* Update the whole table? */
170 if ((mode
& DISPMODE_CALL
) == 0) { /* No call hooks? */
171 for (i
= GG_LEN_SDISP
; i
< GG_LEN_DDISP
; i
++)
172 disp
[i
] = makeasmfunc(lj_bc_ofs
[i
]);
174 for (i
= GG_LEN_SDISP
; i
< GG_LEN_DDISP
; i
++)
175 disp
[i
] = lj_vm_callhook
;
178 if (!(mode
& DISPMODE_CALL
)) { /* Overwrite dynamic counting ins. */
179 disp
[BC_FUNCF
] = f_funcf
;
180 disp
[BC_FUNCV
] = f_funcv
;
184 /* Reset hotcounts for JIT off to on transition. */
185 if ((mode
& DISPMODE_JIT
) && !(oldmode
& DISPMODE_JIT
))
186 lj_dispatch_init_hotcount(g
);
191 /* -- JIT mode setting ---------------------------------------------------- */
194 /* Set JIT mode for a single prototype. */
195 static void setptmode(global_State
*g
, GCproto
*pt
, int mode
)
197 if ((mode
& LUAJIT_MODE_ON
)) { /* (Re-)enable JIT compilation. */
198 pt
->flags
&= ~PROTO_NOJIT
;
199 lj_trace_reenableproto(pt
); /* Unpatch all ILOOP etc. bytecodes. */
200 } else { /* Flush and/or disable JIT compilation. */
201 if (!(mode
& LUAJIT_MODE_FLUSH
))
202 pt
->flags
|= PROTO_NOJIT
;
203 lj_trace_flushproto(g
, pt
); /* Flush all traces of prototype. */
207 /* Recursively set the JIT mode for all children of a prototype. */
208 static void setptmode_all(global_State
*g
, GCproto
*pt
, int mode
)
211 if (!(pt
->flags
& PROTO_CHILD
)) return;
212 for (i
= -(ptrdiff_t)pt
->sizekgc
; i
< 0; i
++) {
213 GCobj
*o
= proto_kgc(pt
, i
);
214 if (o
->gch
.gct
== ~LJ_TPROTO
) {
215 setptmode(g
, gco2pt(o
), mode
);
216 setptmode_all(g
, gco2pt(o
), mode
);
222 /* Public API function: control the JIT engine. */
223 int luaJIT_setmode(lua_State
*L
, int idx
, int mode
)
225 global_State
*g
= G(L
);
226 int mm
= mode
& LUAJIT_MODE_MASK
;
227 lj_trace_abort(g
); /* Abort recording on any state change. */
228 /* Avoid pulling the rug from under our own feet. */
229 if ((g
->hookmask
& HOOK_GC
))
230 lj_err_caller(L
, LJ_ERR_NOGCMM
);
233 case LUAJIT_MODE_ENGINE
:
234 if ((mode
& LUAJIT_MODE_FLUSH
)) {
235 lj_trace_flushall(L
);
237 if (!(mode
& LUAJIT_MODE_ON
))
238 G2J(g
)->flags
&= ~(uint32_t)JIT_F_ON
;
239 #if LJ_TARGET_X86ORX64
240 else if ((G2J(g
)->flags
& JIT_F_SSE2
))
241 G2J(g
)->flags
|= (uint32_t)JIT_F_ON
;
243 return 0; /* Don't turn on JIT compiler without SSE2 support. */
246 G2J(g
)->flags
|= (uint32_t)JIT_F_ON
;
248 lj_dispatch_update(g
);
251 case LUAJIT_MODE_FUNC
:
252 case LUAJIT_MODE_ALLFUNC
:
253 case LUAJIT_MODE_ALLSUBFUNC
: {
254 cTValue
*tv
= idx
== 0 ? frame_prev(L
->base
-1) :
255 idx
> 0 ? L
->base
+ (idx
-1) : L
->top
+ idx
;
257 if ((idx
== 0 || tvisfunc(tv
)) && isluafunc(&gcval(tv
)->fn
))
258 pt
= funcproto(&gcval(tv
)->fn
); /* Cannot use funcV() for frame slot. */
259 else if (tvisproto(tv
))
262 return 0; /* Failed. */
263 if (mm
!= LUAJIT_MODE_ALLSUBFUNC
)
264 setptmode(g
, pt
, mode
);
265 if (mm
!= LUAJIT_MODE_FUNC
)
266 setptmode_all(g
, pt
, mode
);
269 case LUAJIT_MODE_TRACE
:
270 if (!(mode
& LUAJIT_MODE_FLUSH
))
271 return 0; /* Failed. */
272 lj_trace_flush(G2J(g
), idx
);
275 case LUAJIT_MODE_ENGINE
:
276 case LUAJIT_MODE_FUNC
:
277 case LUAJIT_MODE_ALLFUNC
:
278 case LUAJIT_MODE_ALLSUBFUNC
:
280 if ((mode
& LUAJIT_MODE_ON
))
281 return 0; /* Failed. */
284 case LUAJIT_MODE_WRAPCFUNC
:
285 if ((mode
& LUAJIT_MODE_ON
)) {
287 cTValue
*tv
= idx
> 0 ? L
->base
+ (idx
-1) : L
->top
+ idx
;
289 g
->wrapf
= (lua_CFunction
)lightudV(tv
);
291 return 0; /* Failed. */
293 return 0; /* Failed. */
295 setbc_op(&g
->bc_cfunc_ext
, BC_FUNCCW
);
297 setbc_op(&g
->bc_cfunc_ext
, BC_FUNCC
);
301 return 0; /* Failed. */
306 /* Enforce (dynamic) linker error for version mismatches. See luajit.c. */
307 LUA_API
void LUAJIT_VERSION_SYM(void)
311 /* -- Hooks --------------------------------------------------------------- */
313 /* This function can be called asynchronously (e.g. during a signal). */
314 LUA_API
int lua_sethook(lua_State
*L
, lua_Hook func
, int mask
, int count
)
316 global_State
*g
= G(L
);
317 mask
&= HOOK_EVENTMASK
;
318 if (func
== NULL
|| mask
== 0) { mask
= 0; func
= NULL
; } /* Consistency. */
320 g
->hookcount
= g
->hookcstart
= (int32_t)count
;
321 g
->hookmask
= (uint8_t)((g
->hookmask
& ~HOOK_EVENTMASK
) | mask
);
322 lj_trace_abort(g
); /* Abort recording on any hook change. */
323 lj_dispatch_update(g
);
327 LUA_API lua_Hook
lua_gethook(lua_State
*L
)
332 LUA_API
int lua_gethookmask(lua_State
*L
)
334 return G(L
)->hookmask
& HOOK_EVENTMASK
;
337 LUA_API
int lua_gethookcount(lua_State
*L
)
339 return (int)G(L
)->hookcstart
;
343 static void callhook(lua_State
*L
, int event
, BCLine line
)
345 global_State
*g
= G(L
);
346 lua_Hook hookf
= g
->hookf
;
347 if (hookf
&& !hook_active(g
)) {
349 lj_trace_abort(g
); /* Abort recording on any hook call. */
351 ar
.currentline
= line
;
352 /* Top frame, nextframe = NULL. */
353 ar
.i_ci
= (int)((L
->base
-1) - tvref(L
->stack
));
354 lj_state_checkstack(L
, 1+LUA_MINSTACK
);
357 lua_assert(hook_active(g
));
362 /* -- Dispatch callbacks -------------------------------------------------- */
364 /* Calculate number of used stack slots in the current frame. */
365 static BCReg
cur_topslot(GCproto
*pt
, const BCIns
*pc
, uint32_t nres
)
368 if (bc_op(ins
) == BC_UCLO
)
370 switch (bc_op(ins
)) {
371 case BC_CALLM
: case BC_CALLMT
: return bc_a(ins
) + bc_c(ins
) + nres
-1+1;
372 case BC_RETM
: return bc_a(ins
) + bc_d(ins
) + nres
-1;
373 case BC_TSETM
: return bc_a(ins
) + nres
-1;
374 default: return pt
->framesize
;
378 /* Instruction dispatch. Used by instr/line/return hooks or when recording. */
379 void LJ_FASTCALL
lj_dispatch_ins(lua_State
*L
, const BCIns
*pc
)
382 GCfunc
*fn
= curr_func(L
);
383 GCproto
*pt
= funcproto(fn
);
384 void *cf
= cframe_raw(L
->cframe
);
385 const BCIns
*oldpc
= cframe_pc(cf
);
386 global_State
*g
= G(L
);
388 setcframe_pc(cf
, pc
);
389 slots
= cur_topslot(pt
, pc
, cframe_multres_n(cf
));
390 L
->top
= L
->base
+ slots
; /* Fix top. */
393 jit_State
*J
= G2J(g
);
394 if (J
->state
!= LJ_TRACE_IDLE
) {
395 #ifdef LUA_USE_ASSERT
396 ptrdiff_t delta
= L
->top
- L
->base
;
399 lj_trace_ins(J
, pc
-1); /* The interpreter bytecode PC is offset by 1. */
400 lua_assert(L
->top
- L
->base
== delta
);
404 if ((g
->hookmask
& LUA_MASKCOUNT
) && g
->hookcount
== 0) {
405 g
->hookcount
= g
->hookcstart
;
406 callhook(L
, LUA_HOOKCOUNT
, -1);
407 L
->top
= L
->base
+ slots
; /* Fix top again. */
409 if ((g
->hookmask
& LUA_MASKLINE
)) {
410 BCPos npc
= proto_bcpos(pt
, pc
) - 1;
411 BCPos opc
= proto_bcpos(pt
, oldpc
) - 1;
412 BCLine line
= lj_debug_line(pt
, npc
);
413 if (pc
<= oldpc
|| opc
>= pt
->sizebc
|| line
!= lj_debug_line(pt
, opc
)) {
414 callhook(L
, LUA_HOOKLINE
, line
);
415 L
->top
= L
->base
+ slots
; /* Fix top again. */
418 if ((g
->hookmask
& LUA_MASKRET
) && bc_isret(bc_op(pc
[-1])))
419 callhook(L
, LUA_HOOKRET
, -1);
423 /* Initialize call. Ensure stack space and return # of missing parameters. */
424 static int call_init(lua_State
*L
, GCfunc
*fn
)
427 GCproto
*pt
= funcproto(fn
);
428 int numparams
= pt
->numparams
;
429 int gotparams
= (int)(L
->top
- L
->base
);
430 int need
= pt
->framesize
;
431 if ((pt
->flags
& PROTO_VARARG
)) need
+= 1+gotparams
;
432 lj_state_checkstack(L
, (MSize
)need
);
433 numparams
-= gotparams
;
434 return numparams
>= 0 ? numparams
: 0;
436 lj_state_checkstack(L
, LUA_MINSTACK
);
441 /* Call dispatch. Used by call hooks, hot calls or when recording. */
442 ASMFunction LJ_FASTCALL
lj_dispatch_call(lua_State
*L
, const BCIns
*pc
)
445 GCfunc
*fn
= curr_func(L
);
447 global_State
*g
= G(L
);
449 jit_State
*J
= G2J(g
);
451 int missing
= call_init(L
, fn
);
454 if ((uintptr_t)pc
& 1) { /* Marker for hot call. */
455 #ifdef LUA_USE_ASSERT
456 ptrdiff_t delta
= L
->top
- L
->base
;
458 pc
= (const BCIns
*)((uintptr_t)pc
& ~(uintptr_t)1);
460 lua_assert(L
->top
- L
->base
== delta
);
462 } else if (J
->state
!= LJ_TRACE_IDLE
&&
463 !(g
->hookmask
& (HOOK_GC
|HOOK_VMEVENT
))) {
464 #ifdef LUA_USE_ASSERT
465 ptrdiff_t delta
= L
->top
- L
->base
;
467 /* Record the FUNC* bytecodes, too. */
468 lj_trace_ins(J
, pc
-1); /* The interpreter bytecode PC is offset by 1. */
469 lua_assert(L
->top
- L
->base
== delta
);
472 if ((g
->hookmask
& LUA_MASKCALL
)) {
474 for (i
= 0; i
< missing
; i
++) /* Add missing parameters. */
476 callhook(L
, LUA_HOOKCALL
, -1);
477 /* Preserve modifications of missing parameters by lua_setlocal(). */
478 while (missing
-- > 0 && tvisnil(L
->top
- 1))
484 op
= bc_op(pc
[-1]); /* Get FUNC* op. */
486 /* Use the non-hotcounting variants if JIT is off or while recording. */
487 if ((!(J
->flags
& JIT_F_ON
) || J
->state
!= LJ_TRACE_IDLE
) &&
488 (op
== BC_FUNCF
|| op
== BC_FUNCV
))
489 op
= (BCOp
)((int)op
+(int)BC_IFUNCF
-(int)BC_FUNCF
);
492 return makeasmfunc(lj_bc_ofs
[op
]); /* Return static dispatch target. */