diff options
Diffstat (limited to 'src/lj_dispatch.c')
-rw-r--r-- | src/lj_dispatch.c | 109 |
1 files changed, 89 insertions, 20 deletions
diff --git a/src/lj_dispatch.c b/src/lj_dispatch.c index 72211dca..42ffd2b8 100644 --- a/src/lj_dispatch.c +++ b/src/lj_dispatch.c | |||
@@ -57,21 +57,30 @@ void lj_dispatch_init_hotcount(global_State *g) | |||
57 | } | 57 | } |
58 | #endif | 58 | #endif |
59 | 59 | ||
60 | /* Internal dispatch mode bits. */ | ||
61 | #define DISPMODE_JIT 0x01 /* JIT compiler on. */ | ||
62 | #define DISPMODE_REC 0x02 /* Recording active. */ | ||
63 | #define DISPMODE_INS 0x04 /* Override instruction dispatch. */ | ||
64 | #define DISPMODE_CALL 0x08 /* Override call dispatch. */ | ||
65 | |||
60 | /* Update dispatch table depending on various flags. */ | 66 | /* Update dispatch table depending on various flags. */ |
61 | void lj_dispatch_update(global_State *g) | 67 | void lj_dispatch_update(global_State *g) |
62 | { | 68 | { |
63 | uint8_t oldmode = g->dispatchmode; | 69 | uint8_t oldmode = g->dispatchmode; |
64 | uint8_t mode = 0; | 70 | uint8_t mode = 0; |
65 | #if LJ_HASJIT | 71 | #if LJ_HASJIT |
66 | mode |= (G2J(g)->flags & JIT_F_ON) ? 1 : 0; | 72 | mode |= (G2J(g)->flags & JIT_F_ON) ? DISPMODE_JIT : 0; |
67 | mode |= G2J(g)->state != LJ_TRACE_IDLE ? 6 : 0; | 73 | mode |= G2J(g)->state != LJ_TRACE_IDLE ? (DISPMODE_REC|DISPMODE_INS) : 0; |
68 | #endif | 74 | #endif |
69 | mode |= (g->hookmask & (LUA_MASKLINE|LUA_MASKCOUNT)) ? 2 : 0; | 75 | mode |= (g->hookmask & (LUA_MASKLINE|LUA_MASKCOUNT)) ? DISPMODE_INS : 0; |
76 | mode |= (g->hookmask & LUA_MASKCALL) ? DISPMODE_CALL : 0; | ||
70 | if (oldmode != mode) { /* Mode changed? */ | 77 | if (oldmode != mode) { /* Mode changed? */ |
71 | ASMFunction *disp = G2GG(g)->dispatch; | 78 | ASMFunction *disp = G2GG(g)->dispatch; |
72 | ASMFunction f_forl, f_iterl, f_loop, f_funcf, f_funcv; | 79 | ASMFunction f_forl, f_iterl, f_loop, f_funcf, f_funcv; |
73 | g->dispatchmode = mode; | 80 | g->dispatchmode = mode; |
74 | if ((mode & 5) == 1) { /* Hotcount if JIT is on, but not when recording. */ | 81 | |
82 | /* Hotcount if JIT is on, but not while recording. */ | ||
83 | if ((mode & (DISPMODE_JIT|DISPMODE_REC)) == DISPMODE_JIT) { | ||
75 | f_forl = makeasmfunc(lj_bc_ofs[BC_FORL]); | 84 | f_forl = makeasmfunc(lj_bc_ofs[BC_FORL]); |
76 | f_iterl = makeasmfunc(lj_bc_ofs[BC_ITERL]); | 85 | f_iterl = makeasmfunc(lj_bc_ofs[BC_ITERL]); |
77 | f_loop = makeasmfunc(lj_bc_ofs[BC_LOOP]); | 86 | f_loop = makeasmfunc(lj_bc_ofs[BC_LOOP]); |
@@ -81,38 +90,53 @@ void lj_dispatch_update(global_State *g) | |||
81 | f_forl = disp[GG_LEN_DDISP+BC_IFORL]; | 90 | f_forl = disp[GG_LEN_DDISP+BC_IFORL]; |
82 | f_iterl = disp[GG_LEN_DDISP+BC_IITERL]; | 91 | f_iterl = disp[GG_LEN_DDISP+BC_IITERL]; |
83 | f_loop = disp[GG_LEN_DDISP+BC_ILOOP]; | 92 | f_loop = disp[GG_LEN_DDISP+BC_ILOOP]; |
84 | f_funcf = disp[GG_LEN_DDISP+BC_IFUNCF]; | 93 | f_funcf = makeasmfunc(lj_bc_ofs[BC_IFUNCF]); |
85 | f_funcv = disp[GG_LEN_DDISP+BC_IFUNCV]; | 94 | f_funcv = makeasmfunc(lj_bc_ofs[BC_IFUNCV]); |
86 | } | 95 | } |
87 | /* Set static counting ins first (may be copied below). */ | 96 | /* Init static counting instruction dispatch first (may be copied below). */ |
88 | disp[GG_LEN_DDISP+BC_FORL] = f_forl; | 97 | disp[GG_LEN_DDISP+BC_FORL] = f_forl; |
89 | disp[GG_LEN_DDISP+BC_ITERL] = f_iterl; | 98 | disp[GG_LEN_DDISP+BC_ITERL] = f_iterl; |
90 | disp[GG_LEN_DDISP+BC_LOOP] = f_loop; | 99 | disp[GG_LEN_DDISP+BC_LOOP] = f_loop; |
91 | disp[GG_LEN_DDISP+BC_FUNCF] = f_funcf; | 100 | |
92 | disp[GG_LEN_DDISP+BC_FUNCV] = f_funcv; | 101 | /* Set dynamic instruction dispatch. */ |
93 | if ((oldmode & 6) != (mode & 6)) { /* Need to change whole table? */ | 102 | if ((oldmode ^ mode) & (DISPMODE_REC|DISPMODE_INS)) { |
94 | if ((mode & 6) == 0) { /* No hooks and no recording? */ | 103 | /* Need to update the whole table. */ |
104 | if (!(mode & (DISPMODE_REC|DISPMODE_INS))) { /* No ins dispatch? */ | ||
95 | /* Copy static dispatch table to dynamic dispatch table. */ | 105 | /* Copy static dispatch table to dynamic dispatch table. */ |
96 | memcpy(&disp[0], &disp[GG_LEN_DDISP], GG_LEN_SDISP*sizeof(ASMFunction)); | 106 | memcpy(&disp[0], &disp[GG_LEN_DDISP], GG_LEN_SDISP*sizeof(ASMFunction)); |
97 | } else { | 107 | } else { |
98 | /* The recording dispatch also checks for hooks. */ | 108 | /* The recording dispatch also checks for hooks. */ |
99 | ASMFunction f = (mode & 6) == 6 ? lj_vm_record : lj_vm_hook; | 109 | ASMFunction f = (mode & DISPMODE_REC) ? lj_vm_record : lj_vm_hook; |
100 | uint32_t i; | 110 | uint32_t i; |
101 | for (i = 0; i < BC_FUNCF; i++) | 111 | for (i = 0; i < GG_LEN_SDISP; i++) |
102 | disp[i] = f; | 112 | disp[i] = f; |
103 | /* NYI: call hooks for function headers. */ | ||
104 | memcpy(&disp[BC_FUNCF], &disp[GG_LEN_DDISP+BC_FUNCF], | ||
105 | (GG_LEN_SDISP-BC_FUNCF)*sizeof(ASMFunction)); | ||
106 | } | 113 | } |
107 | } else if ((mode & 6) == 0) { /* Set dynamic counting ins. */ | 114 | } else if (!(mode & (DISPMODE_REC|DISPMODE_INS))) { |
115 | /* Otherwise only set dynamic counting ins. */ | ||
108 | disp[BC_FORL] = f_forl; | 116 | disp[BC_FORL] = f_forl; |
109 | disp[BC_ITERL] = f_iterl; | 117 | disp[BC_ITERL] = f_iterl; |
110 | disp[BC_LOOP] = f_loop; | 118 | disp[BC_LOOP] = f_loop; |
119 | } | ||
120 | |||
121 | /* Set dynamic call dispatch. */ | ||
122 | if ((oldmode ^ mode) & DISPMODE_CALL) { /* Update the whole table? */ | ||
123 | uint32_t i; | ||
124 | if ((mode & 8) == 0) { /* No call hooks? */ | ||
125 | for (i = GG_LEN_SDISP; i < GG_LEN_DDISP; i++) | ||
126 | disp[i] = makeasmfunc(lj_bc_ofs[i]); | ||
127 | } else { | ||
128 | for (i = GG_LEN_SDISP; i < GG_LEN_DDISP; i++) | ||
129 | disp[i] = lj_vm_callhook; | ||
130 | } | ||
131 | } | ||
132 | if (!(mode & DISPMODE_CALL)) { /* Overwrite dynamic counting ins. */ | ||
111 | disp[BC_FUNCF] = f_funcf; | 133 | disp[BC_FUNCF] = f_funcf; |
112 | disp[BC_FUNCV] = f_funcv; | 134 | disp[BC_FUNCV] = f_funcv; |
113 | } | 135 | } |
136 | |||
114 | #if LJ_HASJIT | 137 | #if LJ_HASJIT |
115 | if ((mode & 1) && !(oldmode & 1)) /* JIT off to on transition. */ | 138 | /* Reset hotcounts for JIT off to on transition. */ |
139 | if ((mode & DISPMODE_JIT) && !(oldmode & DISPMODE_JIT)) | ||
116 | lj_dispatch_init_hotcount(g); | 140 | lj_dispatch_init_hotcount(g); |
117 | #endif | 141 | #endif |
118 | } | 142 | } |
@@ -279,7 +303,7 @@ static void callhook(lua_State *L, int event, BCLine line) | |||
279 | } | 303 | } |
280 | } | 304 | } |
281 | 305 | ||
282 | /* -- Instruction dispatch callbacks -------------------------------------- */ | 306 | /* -- Dispatch callbacks -------------------------------------------------- */ |
283 | 307 | ||
284 | /* Calculate number of used stack slots in the current frame. */ | 308 | /* Calculate number of used stack slots in the current frame. */ |
285 | static BCReg cur_topslot(GCproto *pt, const BCIns *pc, uint32_t nres) | 309 | static BCReg cur_topslot(GCproto *pt, const BCIns *pc, uint32_t nres) |
@@ -297,7 +321,7 @@ static BCReg cur_topslot(GCproto *pt, const BCIns *pc, uint32_t nres) | |||
297 | } | 321 | } |
298 | } | 322 | } |
299 | 323 | ||
300 | /* Instruction dispatch callback for instr/line hooks or when recording. */ | 324 | /* Instruction dispatch. Used by instr/line hooks or when recording. */ |
301 | void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc) | 325 | void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc) |
302 | { | 326 | { |
303 | GCfunc *fn = curr_func(L); | 327 | GCfunc *fn = curr_func(L); |
@@ -337,3 +361,48 @@ void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc) | |||
337 | } | 361 | } |
338 | } | 362 | } |
339 | 363 | ||
364 | /* Initialize call. Ensure stack space and clear missing parameters. */ | ||
365 | static void call_init(lua_State *L, GCfunc *fn) | ||
366 | { | ||
367 | if (isluafunc(fn)) { | ||
368 | MSize numparams = funcproto(fn)->numparams; | ||
369 | TValue *o; | ||
370 | lj_state_checkstack(L, numparams); | ||
371 | for (o = L->base + numparams; L->top < o; L->top++) | ||
372 | setnilV(L->top); /* Clear missing parameters. */ | ||
373 | } else { | ||
374 | lj_state_checkstack(L, LUA_MINSTACK); | ||
375 | } | ||
376 | } | ||
377 | |||
378 | /* Call dispatch. Used by call hooks and hot calls. */ | ||
379 | ASMFunction LJ_FASTCALL lj_dispatch_call(lua_State *L, const BCIns *pc) | ||
380 | { | ||
381 | GCfunc *fn = curr_func(L); | ||
382 | BCOp op; | ||
383 | global_State *g = G(L); | ||
384 | #if LJ_HASJIT | ||
385 | jit_State *J = G2J(g); | ||
386 | #endif | ||
387 | call_init(L, fn); | ||
388 | #if LJ_HASJIT | ||
389 | if (J->L) { /* Marker for hot call. */ | ||
390 | lj_trace_hot(J, pc); | ||
391 | goto out; | ||
392 | } | ||
393 | #endif | ||
394 | if ((g->hookmask & LUA_MASKCALL)) | ||
395 | callhook(L, LUA_HOOKCALL, -1); | ||
396 | #if LJ_HASJIT | ||
397 | out: | ||
398 | #endif | ||
399 | op = bc_op(pc[-1]); /* Get FUNC* op. */ | ||
400 | #if LJ_HASJIT | ||
401 | /* Use the non-hotcounting variants if JIT is off or while recording. */ | ||
402 | if ((!(J->flags & JIT_F_ON) || J->state != LJ_TRACE_IDLE) && | ||
403 | (op == BC_FUNCF || op == BC_FUNCV)) | ||
404 | op = (BCOp)((int)op+(int)BC_IFUNCF-(int)BC_FUNCF); | ||
405 | #endif | ||
406 | return makeasmfunc(lj_bc_ofs[op]); /* Return static dispatch target. */ | ||
407 | } | ||
408 | |||