diff options
| author | Mike Pall <mike> | 2013-12-25 02:55:25 +0100 |
|---|---|---|
| committer | Mike Pall <mike> | 2013-12-25 02:55:25 +0100 |
| commit | b5d741fa7e11a2a58df65f3c71489c58f8758f75 (patch) | |
| tree | 3c33ec24c8fd363ca2ce797c998b21a8a0e39a5b /src | |
| parent | 6e02c210c485791a5451cc74731acf319b2067bb (diff) | |
| download | luajit-b5d741fa7e11a2a58df65f3c71489c58f8758f75.tar.gz luajit-b5d741fa7e11a2a58df65f3c71489c58f8758f75.tar.bz2 luajit-b5d741fa7e11a2a58df65f3c71489c58f8758f75.zip | |
Add trace stitching.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib_base.c | 4 | ||||
| -rw-r--r-- | src/lib_jit.c | 2 | ||||
| -rw-r--r-- | src/lj_dispatch.c | 23 | ||||
| -rw-r--r-- | src/lj_dispatch.h | 6 | ||||
| -rw-r--r-- | src/lj_ffrecord.c | 130 | ||||
| -rw-r--r-- | src/lj_jit.h | 4 | ||||
| -rw-r--r-- | src/lj_record.c | 57 | ||||
| -rw-r--r-- | src/lj_record.h | 1 | ||||
| -rw-r--r-- | src/lj_snap.c | 3 | ||||
| -rw-r--r-- | src/lj_trace.c | 30 | ||||
| -rw-r--r-- | src/lj_trace.h | 1 | ||||
| -rw-r--r-- | src/lj_traceerr.h | 3 | ||||
| -rw-r--r-- | src/lj_vm.h | 1 | ||||
| -rw-r--r-- | src/vm_arm.dasc | 50 | ||||
| -rw-r--r-- | src/vm_mips.dasc | 58 | ||||
| -rw-r--r-- | src/vm_ppc.dasc | 55 | ||||
| -rw-r--r-- | src/vm_x86.dasc | 63 |
17 files changed, 422 insertions, 69 deletions
diff --git a/src/lib_base.c b/src/lib_base.c index a19926a7..495e1ab1 100644 --- a/src/lib_base.c +++ b/src/lib_base.c | |||
| @@ -101,7 +101,7 @@ static int ffh_pairs(lua_State *L, MMS mm) | |||
| 101 | #endif | 101 | #endif |
| 102 | 102 | ||
| 103 | LJLIB_PUSH(lastcl) | 103 | LJLIB_PUSH(lastcl) |
| 104 | LJLIB_ASM(pairs) | 104 | LJLIB_ASM(pairs) LJLIB_REC(xpairs 0) |
| 105 | { | 105 | { |
| 106 | return ffh_pairs(L, MM_pairs); | 106 | return ffh_pairs(L, MM_pairs); |
| 107 | } | 107 | } |
| @@ -114,7 +114,7 @@ LJLIB_NOREGUV LJLIB_ASM(ipairs_aux) LJLIB_REC(.) | |||
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | LJLIB_PUSH(lastcl) | 116 | LJLIB_PUSH(lastcl) |
| 117 | LJLIB_ASM(ipairs) LJLIB_REC(.) | 117 | LJLIB_ASM(ipairs) LJLIB_REC(xpairs 1) |
| 118 | { | 118 | { |
| 119 | return ffh_pairs(L, MM_ipairs); | 119 | return ffh_pairs(L, MM_ipairs); |
| 120 | } | 120 | } |
diff --git a/src/lib_jit.c b/src/lib_jit.c index a87e1833..1ee04b7d 100644 --- a/src/lib_jit.c +++ b/src/lib_jit.c | |||
| @@ -284,7 +284,7 @@ static GCtrace *jit_checktrace(lua_State *L) | |||
| 284 | /* Names of link types. ORDER LJ_TRLINK */ | 284 | /* Names of link types. ORDER LJ_TRLINK */ |
| 285 | static const char *const jit_trlinkname[] = { | 285 | static const char *const jit_trlinkname[] = { |
| 286 | "none", "root", "loop", "tail-recursion", "up-recursion", "down-recursion", | 286 | "none", "root", "loop", "tail-recursion", "up-recursion", "down-recursion", |
| 287 | "interpreter", "return" | 287 | "interpreter", "return", "stitch" |
| 288 | }; | 288 | }; |
| 289 | 289 | ||
| 290 | /* local info = jit.util.traceinfo(tr) */ | 290 | /* local info = jit.util.traceinfo(tr) */ |
diff --git a/src/lj_dispatch.c b/src/lj_dispatch.c index 0146d8cd..b76e8048 100644 --- a/src/lj_dispatch.c +++ b/src/lj_dispatch.c | |||
| @@ -42,6 +42,12 @@ LJ_STATIC_ASSERT(GG_NUM_ASMFF == FF_NUM_ASMFUNC); | |||
| 42 | #include <math.h> | 42 | #include <math.h> |
| 43 | LJ_FUNCA_NORET void LJ_FASTCALL lj_ffh_coroutine_wrap_err(lua_State *L, | 43 | LJ_FUNCA_NORET void LJ_FASTCALL lj_ffh_coroutine_wrap_err(lua_State *L, |
| 44 | lua_State *co); | 44 | lua_State *co); |
| 45 | #if !LJ_HASJIT | ||
| 46 | #define lj_dispatch_stitch lj_dispatch_ins | ||
| 47 | #endif | ||
| 48 | #if !LJ_HASPROFILE | ||
| 49 | #define lj_dispatch_profile lj_dispatch_ins | ||
| 50 | #endif | ||
| 45 | 51 | ||
| 46 | #define GOTFUNC(name) (ASMFunction)name, | 52 | #define GOTFUNC(name) (ASMFunction)name, |
| 47 | static const ASMFunction dispatch_got[] = { | 53 | static const ASMFunction dispatch_got[] = { |
| @@ -511,6 +517,23 @@ out: | |||
| 511 | return makeasmfunc(lj_bc_ofs[op]); /* Return static dispatch target. */ | 517 | return makeasmfunc(lj_bc_ofs[op]); /* Return static dispatch target. */ |
| 512 | } | 518 | } |
| 513 | 519 | ||
| 520 | #if LJ_HASJIT | ||
| 521 | /* Stitch a new trace. */ | ||
| 522 | void LJ_FASTCALL lj_dispatch_stitch(jit_State *J, const BCIns *pc) | ||
| 523 | { | ||
| 524 | ERRNO_SAVE | ||
| 525 | lua_State *L = J->L; | ||
| 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); | ||
| 533 | ERRNO_RESTORE | ||
| 534 | } | ||
| 535 | #endif | ||
| 536 | |||
| 514 | #if LJ_HASPROFILE | 537 | #if LJ_HASPROFILE |
| 515 | /* Profile dispatch. */ | 538 | /* Profile dispatch. */ |
| 516 | void LJ_FASTCALL lj_dispatch_profile(lua_State *L, const BCIns *pc) | 539 | void LJ_FASTCALL lj_dispatch_profile(lua_State *L, const BCIns *pc) |
diff --git a/src/lj_dispatch.h b/src/lj_dispatch.h index 811a0ae4..447eb2d8 100644 --- a/src/lj_dispatch.h +++ b/src/lj_dispatch.h | |||
| @@ -29,7 +29,8 @@ | |||
| 29 | _(floor) _(ceil) _(trunc) _(log) _(log10) _(exp) _(sin) _(cos) _(tan) \ | 29 | _(floor) _(ceil) _(trunc) _(log) _(log10) _(exp) _(sin) _(cos) _(tan) \ |
| 30 | _(asin) _(acos) _(atan) _(sinh) _(cosh) _(tanh) _(frexp) _(modf) _(atan2) \ | 30 | _(asin) _(acos) _(atan) _(sinh) _(cosh) _(tanh) _(frexp) _(modf) _(atan2) \ |
| 31 | _(pow) _(fmod) _(ldexp) \ | 31 | _(pow) _(fmod) _(ldexp) \ |
| 32 | _(lj_dispatch_call) _(lj_dispatch_ins) _(lj_dispatch_profile) _(lj_err_throw)\ | 32 | _(lj_dispatch_call) _(lj_dispatch_ins) _(lj_dispatch_stitch) \ |
| 33 | _(lj_dispatch_profile) _(lj_err_throw) \ | ||
| 33 | _(lj_ffh_coroutine_wrap_err) _(lj_func_closeuv) _(lj_func_newL_gc) \ | 34 | _(lj_ffh_coroutine_wrap_err) _(lj_func_closeuv) _(lj_func_newL_gc) \ |
| 34 | _(lj_gc_barrieruv) _(lj_gc_step) _(lj_gc_step_fixtop) _(lj_meta_arith) \ | 35 | _(lj_gc_barrieruv) _(lj_gc_step) _(lj_gc_step_fixtop) _(lj_meta_arith) \ |
| 35 | _(lj_meta_call) _(lj_meta_cat) _(lj_meta_comp) _(lj_meta_equal) \ | 36 | _(lj_meta_call) _(lj_meta_cat) _(lj_meta_comp) _(lj_meta_equal) \ |
| @@ -110,6 +111,9 @@ LJ_FUNC void lj_dispatch_update(global_State *g); | |||
| 110 | /* Instruction dispatch callback for hooks or when recording. */ | 111 | /* Instruction dispatch callback for hooks or when recording. */ |
| 111 | LJ_FUNCA void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc); | 112 | LJ_FUNCA void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc); |
| 112 | LJ_FUNCA ASMFunction LJ_FASTCALL lj_dispatch_call(lua_State *L, const BCIns*pc); | 113 | LJ_FUNCA ASMFunction LJ_FASTCALL lj_dispatch_call(lua_State *L, const BCIns*pc); |
| 114 | #if LJ_HASJIT | ||
| 115 | LJ_FUNCA void LJ_FASTCALL lj_dispatch_stitch(jit_State *J, const BCIns *pc); | ||
| 116 | #endif | ||
| 113 | #if LJ_HASPROFILE | 117 | #if LJ_HASPROFILE |
| 114 | LJ_FUNCA void LJ_FASTCALL lj_dispatch_profile(lua_State *L, const BCIns *pc); | 118 | LJ_FUNCA void LJ_FASTCALL lj_dispatch_profile(lua_State *L, const BCIns *pc); |
| 115 | #endif | 119 | #endif |
diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c index 42aae8b5..6a156c7c 100644 --- a/src/lj_ffrecord.c +++ b/src/lj_ffrecord.c | |||
| @@ -96,28 +96,81 @@ static ptrdiff_t results_wanted(jit_State *J) | |||
| 96 | return -1; | 96 | return -1; |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | /* Throw error for unsupported variant of fast function. */ | 99 | /* Trace stitching: add continuation below frame to start a new trace. */ |
| 100 | LJ_NORET static void recff_nyiu(jit_State *J) | 100 | static void recff_stitch(jit_State *J) |
| 101 | { | 101 | { |
| 102 | setfuncV(J->L, &J->errinfo, J->fn); | 102 | ASMFunction cont = lj_cont_stitch; |
| 103 | lj_trace_err_info(J, LJ_TRERR_NYIFFU); | 103 | TraceNo traceno = J->cur.traceno; |
| 104 | lua_State *L = J->L; | ||
| 105 | TValue *base = L->base; | ||
| 106 | const BCIns *pc = frame_pc(base-1); | ||
| 107 | TValue *pframe = frame_prevl(base-1); | ||
| 108 | TRef trcont; | ||
| 109 | |||
| 110 | /* Move func + args up in Lua stack and insert continuation. */ | ||
| 111 | memmove(&base[1], &base[-1], sizeof(TValue)*(J->maxslot+1)); | ||
| 112 | setframe_ftsz(base+1, (int)((char *)(base+1) - (char *)pframe) + FRAME_CONT); | ||
| 113 | setcont(base, cont); | ||
| 114 | setframe_pc(base, pc); | ||
| 115 | if (LJ_DUALNUM) setintV(base-1, traceno); else base[-1].u64 = traceno; | ||
| 116 | L->base += 2; | ||
| 117 | L->top += 2; | ||
| 118 | |||
| 119 | /* Ditto for the IR. */ | ||
| 120 | memmove(&J->base[1], &J->base[-1], sizeof(TRef)*(J->maxslot+1)); | ||
| 121 | #if LJ_64 | ||
| 122 | trcont = lj_ir_kptr(J, (void *)((int64_t)cont-(int64_t)lj_vm_asm_begin)); | ||
| 123 | #else | ||
| 124 | trcont = lj_ir_kptr(J, (void *)cont); | ||
| 125 | #endif | ||
| 126 | J->base[0] = trcont | TREF_CONT; | ||
| 127 | J->base[-1] = LJ_DUALNUM ? lj_ir_kint(J,traceno) : lj_ir_knum_u64(J,traceno); | ||
| 128 | J->maxslot += 2; | ||
| 129 | J->framedepth++; | ||
| 130 | |||
| 131 | lj_record_stop(J, LJ_TRLINK_STITCH, 0); | ||
| 132 | |||
| 133 | /* Undo Lua stack changes. */ | ||
| 134 | memmove(&base[-1], &base[1], sizeof(TValue)*(J->maxslot+1)); | ||
| 135 | setframe_pc(base-1, pc); | ||
| 136 | L->base -= 2; | ||
| 137 | L->top -= 2; | ||
| 104 | } | 138 | } |
| 105 | 139 | ||
| 106 | /* Fallback handler for all fast functions that are not recorded (yet). */ | 140 | /* Fallback handler for fast functions that are not recorded (yet). */ |
| 107 | static void LJ_FASTCALL recff_nyi(jit_State *J, RecordFFData *rd) | 141 | static void LJ_FASTCALL recff_nyi(jit_State *J, RecordFFData *rd) |
| 108 | { | 142 | { |
| 109 | setfuncV(J->L, &J->errinfo, J->fn); | 143 | if (J->cur.nins < (IRRef)J->param[JIT_P_minstitch] + REF_BASE) { |
| 110 | lj_trace_err_info(J, LJ_TRERR_NYIFF); | 144 | lj_trace_err_info(J, LJ_TRERR_TRACEUV); |
| 111 | UNUSED(rd); | 145 | } else { |
| 146 | /* Can only stitch from Lua call. */ | ||
| 147 | if (J->framedepth && frame_islua(J->L->base-1)) { | ||
| 148 | BCOp op = bc_op(*frame_pc(J->L->base-1)); | ||
| 149 | /* Stitched trace cannot start with *M op with variable # of args. */ | ||
| 150 | if (!(op == BC_CALLM || op == BC_RETM || op == BC_TSETM)) { | ||
| 151 | switch (J->fn->c.ffid) { | ||
| 152 | case FF_error: | ||
| 153 | case FF_debug_sethook: | ||
| 154 | case FF_jit_flush: | ||
| 155 | break; /* Don't stitch across special builtins. */ | ||
| 156 | default: | ||
| 157 | recff_stitch(J); /* Use trace stitching. */ | ||
| 158 | rd->nres = -1; | ||
| 159 | return; | ||
| 160 | } | ||
| 161 | } | ||
| 162 | } | ||
| 163 | /* Otherwise stop trace and return to interpreter. */ | ||
| 164 | lj_record_stop(J, LJ_TRLINK_RETURN, 0); | ||
| 165 | rd->nres = -1; | ||
| 166 | } | ||
| 112 | } | 167 | } |
| 113 | 168 | ||
| 114 | /* C functions can have arbitrary side-effects and are not recorded (yet). */ | 169 | /* Fallback handler for unsupported variants of fast functions. */ |
| 115 | static void LJ_FASTCALL recff_c(jit_State *J, RecordFFData *rd) | 170 | #define recff_nyiu recff_nyi |
| 116 | { | 171 | |
| 117 | setfuncV(J->L, &J->errinfo, J->fn); | 172 | /* Must stop the trace for classic C functions with arbitrary side-effects. */ |
| 118 | lj_trace_err_info(J, LJ_TRERR_NYICF); | 173 | #define recff_c recff_nyi |
| 119 | UNUSED(rd); | ||
| 120 | } | ||
| 121 | 174 | ||
| 122 | /* Emit BUFHDR for the global temporary buffer. */ | 175 | /* Emit BUFHDR for the global temporary buffer. */ |
| 123 | static TRef recff_bufhdr(jit_State *J) | 176 | static TRef recff_bufhdr(jit_State *J) |
| @@ -268,7 +321,8 @@ static void LJ_FASTCALL recff_select(jit_State *J, RecordFFData *rd) | |||
| 268 | J->base[i] = J->base[start+i]; | 321 | J->base[i] = J->base[start+i]; |
| 269 | } /* else: Interpreter will throw. */ | 322 | } /* else: Interpreter will throw. */ |
| 270 | } else { | 323 | } else { |
| 271 | recff_nyiu(J); | 324 | recff_nyiu(J, rd); |
| 325 | return; | ||
| 272 | } | 326 | } |
| 273 | } /* else: Interpreter will throw. */ | 327 | } /* else: Interpreter will throw. */ |
| 274 | } | 328 | } |
| @@ -279,14 +333,18 @@ static void LJ_FASTCALL recff_tonumber(jit_State *J, RecordFFData *rd) | |||
| 279 | TRef base = J->base[1]; | 333 | TRef base = J->base[1]; |
| 280 | if (tr && !tref_isnil(base)) { | 334 | if (tr && !tref_isnil(base)) { |
| 281 | base = lj_opt_narrow_toint(J, base); | 335 | base = lj_opt_narrow_toint(J, base); |
| 282 | if (!tref_isk(base) || IR(tref_ref(base))->i != 10) | 336 | if (!tref_isk(base) || IR(tref_ref(base))->i != 10) { |
| 283 | recff_nyiu(J); | 337 | recff_nyiu(J, rd); |
| 338 | return; | ||
| 339 | } | ||
| 284 | } | 340 | } |
| 285 | if (tref_isnumber_str(tr)) { | 341 | if (tref_isnumber_str(tr)) { |
| 286 | if (tref_isstr(tr)) { | 342 | if (tref_isstr(tr)) { |
| 287 | TValue tmp; | 343 | TValue tmp; |
| 288 | if (!lj_strscan_num(strV(&rd->argv[0]), &tmp)) | 344 | if (!lj_strscan_num(strV(&rd->argv[0]), &tmp)) { |
| 289 | recff_nyiu(J); /* Would need an inverted STRTO for this case. */ | 345 | recff_nyiu(J, rd); /* Would need an inverted STRTO for this case. */ |
| 346 | return; | ||
| 347 | } | ||
| 290 | tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); | 348 | tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); |
| 291 | } | 349 | } |
| 292 | #if LJ_HASFFI | 350 | #if LJ_HASFFI |
| @@ -348,7 +406,8 @@ static void LJ_FASTCALL recff_tostring(jit_State *J, RecordFFData *rd) | |||
| 348 | } else if (tref_ispri(tr)) { | 406 | } else if (tref_ispri(tr)) { |
| 349 | J->base[0] = lj_ir_kstr(J, lj_strfmt_obj(J->L, &rd->argv[0])); | 407 | J->base[0] = lj_ir_kstr(J, lj_strfmt_obj(J->L, &rd->argv[0])); |
| 350 | } else { | 408 | } else { |
| 351 | recff_nyiu(J); | 409 | recff_nyiu(J, rd); |
| 410 | return; | ||
| 352 | } | 411 | } |
| 353 | } | 412 | } |
| 354 | } | 413 | } |
| @@ -370,14 +429,14 @@ static void LJ_FASTCALL recff_ipairs_aux(jit_State *J, RecordFFData *rd) | |||
| 370 | } /* else: Interpreter will throw. */ | 429 | } /* else: Interpreter will throw. */ |
| 371 | } | 430 | } |
| 372 | 431 | ||
| 373 | static void LJ_FASTCALL recff_ipairs(jit_State *J, RecordFFData *rd) | 432 | static void LJ_FASTCALL recff_xpairs(jit_State *J, RecordFFData *rd) |
| 374 | { | 433 | { |
| 375 | if (!(LJ_52 && recff_metacall(J, rd, MM_ipairs))) { | 434 | if (!(LJ_52 && recff_metacall(J, rd, MM_ipairs))) { |
| 376 | TRef tab = J->base[0]; | 435 | TRef tab = J->base[0]; |
| 377 | if (tref_istab(tab)) { | 436 | if (tref_istab(tab)) { |
| 378 | J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0])); | 437 | J->base[0] = lj_ir_kfunc(J, funcV(&J->fn->c.upvalue[0])); |
| 379 | J->base[1] = tab; | 438 | J->base[1] = tab; |
| 380 | J->base[2] = lj_ir_kint(J, 0); | 439 | J->base[2] = rd->data ? lj_ir_kint(J, 0) : TREF_NIL; |
| 381 | rd->nres = 3; | 440 | rd->nres = 3; |
| 382 | } /* else: Interpreter will throw. */ | 441 | } /* else: Interpreter will throw. */ |
| 383 | } | 442 | } |
| @@ -431,8 +490,7 @@ static void LJ_FASTCALL recff_getfenv(jit_State *J, RecordFFData *rd) | |||
| 431 | J->base[0] = emitir(IRT(IR_FLOAD, IRT_TAB), trl, IRFL_THREAD_ENV); | 490 | J->base[0] = emitir(IRT(IR_FLOAD, IRT_TAB), trl, IRFL_THREAD_ENV); |
| 432 | return; | 491 | return; |
| 433 | } | 492 | } |
| 434 | recff_nyiu(J); | 493 | recff_nyiu(J, rd); |
| 435 | UNUSED(rd); | ||
| 436 | } | 494 | } |
| 437 | 495 | ||
| 438 | /* -- Math library fast functions ----------------------------------------- */ | 496 | /* -- Math library fast functions ----------------------------------------- */ |
| @@ -672,8 +730,7 @@ static void LJ_FASTCALL recff_bit_tohex(jit_State *J, RecordFFData *rd) | |||
| 672 | TRef tr = recff_bit64_tohex(J, rd, hdr); | 730 | TRef tr = recff_bit64_tohex(J, rd, hdr); |
| 673 | J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); | 731 | J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); |
| 674 | #else | 732 | #else |
| 675 | UNUSED(rd); | 733 | recff_nyiu(J, rd); /* Don't bother working around this NYI. */ |
| 676 | recff_nyiu(J); /* Don't bother working around this NYI. */ | ||
| 677 | #endif | 734 | #endif |
| 678 | } | 735 | } |
| 679 | 736 | ||
| @@ -891,7 +948,8 @@ static void LJ_FASTCALL recff_string_find(jit_State *J, RecordFFData *rd) | |||
| 891 | J->base[0] = TREF_NIL; | 948 | J->base[0] = TREF_NIL; |
| 892 | } | 949 | } |
| 893 | } else { /* Search for pattern. */ | 950 | } else { /* Search for pattern. */ |
| 894 | recff_nyiu(J); | 951 | recff_nyiu(J, rd); |
| 952 | return; | ||
| 895 | } | 953 | } |
| 896 | } | 954 | } |
| 897 | 955 | ||
| @@ -931,7 +989,8 @@ static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd) | |||
| 931 | tr = lj_ir_call(J, IRCALL_lj_strfmt_putfxint, tr, trsf, tra); | 989 | tr = lj_ir_call(J, IRCALL_lj_strfmt_putfxint, tr, trsf, tra); |
| 932 | lj_needsplit(J); | 990 | lj_needsplit(J); |
| 933 | #else | 991 | #else |
| 934 | recff_nyiu(J); /* Don't bother working around this NYI. */ | 992 | recff_nyiu(J, rd); /* Don't bother working around this NYI. */ |
| 993 | return; | ||
| 935 | #endif | 994 | #endif |
| 936 | } | 995 | } |
| 937 | break; | 996 | break; |
| @@ -946,8 +1005,10 @@ static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd) | |||
| 946 | if (LJ_SOFTFP) lj_needsplit(J); | 1005 | if (LJ_SOFTFP) lj_needsplit(J); |
| 947 | break; | 1006 | break; |
| 948 | case STRFMT_STR: | 1007 | case STRFMT_STR: |
| 949 | if (!tref_isstr(tra)) | 1008 | if (!tref_isstr(tra)) { |
| 950 | recff_nyiu(J); /* NYI: __tostring and non-string types for %s. */ | 1009 | recff_nyiu(J, rd); /* NYI: __tostring and non-string types for %s. */ |
| 1010 | return; | ||
| 1011 | } | ||
| 951 | if (sf == STRFMT_STR) /* Shortcut for plain %s. */ | 1012 | if (sf == STRFMT_STR) /* Shortcut for plain %s. */ |
| 952 | tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr, tra); | 1013 | tr = emitir(IRT(IR_BUFPUT, IRT_P32), tr, tra); |
| 953 | else if ((sf & STRFMT_T_QUOTED)) | 1014 | else if ((sf & STRFMT_T_QUOTED)) |
| @@ -966,8 +1027,8 @@ static void LJ_FASTCALL recff_string_format(jit_State *J, RecordFFData *rd) | |||
| 966 | case STRFMT_PTR: /* NYI */ | 1027 | case STRFMT_PTR: /* NYI */ |
| 967 | case STRFMT_ERR: | 1028 | case STRFMT_ERR: |
| 968 | default: | 1029 | default: |
| 969 | recff_nyiu(J); | 1030 | recff_nyiu(J, rd); |
| 970 | break; | 1031 | return; |
| 971 | } | 1032 | } |
| 972 | } | 1033 | } |
| 973 | J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); | 1034 | J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); |
| @@ -991,7 +1052,8 @@ static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd) | |||
| 991 | ix.idxchain = 0; | 1052 | ix.idxchain = 0; |
| 992 | lj_record_idx(J, &ix); /* Set new value. */ | 1053 | lj_record_idx(J, &ix); /* Set new value. */ |
| 993 | } else { /* Complex case: insert in the middle. */ | 1054 | } else { /* Complex case: insert in the middle. */ |
| 994 | recff_nyiu(J); | 1055 | recff_nyiu(J, rd); |
| 1056 | return; | ||
| 995 | } | 1057 | } |
| 996 | } /* else: Interpreter will throw. */ | 1058 | } /* else: Interpreter will throw. */ |
| 997 | } | 1059 | } |
diff --git a/src/lj_jit.h b/src/lj_jit.h index cfb04aa7..52a216cc 100644 --- a/src/lj_jit.h +++ b/src/lj_jit.h | |||
| @@ -97,6 +97,7 @@ | |||
| 97 | _(\012, maxirconst, 500) /* Max. # of IR constants of a trace. */ \ | 97 | _(\012, maxirconst, 500) /* Max. # of IR constants of a trace. */ \ |
| 98 | _(\007, maxside, 100) /* Max. # of side traces of a root trace. */ \ | 98 | _(\007, maxside, 100) /* Max. # of side traces of a root trace. */ \ |
| 99 | _(\007, maxsnap, 500) /* Max. # of snapshots for a trace. */ \ | 99 | _(\007, maxsnap, 500) /* Max. # of snapshots for a trace. */ \ |
| 100 | _(\011, minstitch, 0) /* Min. # of IR ins for a stitched trace. */ \ | ||
| 100 | \ | 101 | \ |
| 101 | _(\007, hotloop, 56) /* # of iter. to detect a hot loop/call. */ \ | 102 | _(\007, hotloop, 56) /* # of iter. to detect a hot loop/call. */ \ |
| 102 | _(\007, hotexit, 10) /* # of taken exits to start a side trace. */ \ | 103 | _(\007, hotexit, 10) /* # of taken exits to start a side trace. */ \ |
| @@ -202,7 +203,8 @@ typedef enum { | |||
| 202 | LJ_TRLINK_UPREC, /* Up-recursion. */ | 203 | LJ_TRLINK_UPREC, /* Up-recursion. */ |
| 203 | LJ_TRLINK_DOWNREC, /* Down-recursion. */ | 204 | LJ_TRLINK_DOWNREC, /* Down-recursion. */ |
| 204 | LJ_TRLINK_INTERP, /* Fallback to interpreter. */ | 205 | LJ_TRLINK_INTERP, /* Fallback to interpreter. */ |
| 205 | LJ_TRLINK_RETURN /* Return to interpreter. */ | 206 | LJ_TRLINK_RETURN, /* Return to interpreter. */ |
| 207 | LJ_TRLINK_STITCH /* Trace stitching. */ | ||
| 206 | } TraceLink; | 208 | } TraceLink; |
| 207 | 209 | ||
| 208 | /* Trace object. */ | 210 | /* Trace object. */ |
diff --git a/src/lj_record.c b/src/lj_record.c index ce9e20de..4ab474ad 100644 --- a/src/lj_record.c +++ b/src/lj_record.c | |||
| @@ -233,7 +233,7 @@ static void canonicalize_slots(jit_State *J) | |||
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | /* Stop recording. */ | 235 | /* Stop recording. */ |
| 236 | static void rec_stop(jit_State *J, TraceLink linktype, TraceNo lnk) | 236 | void lj_record_stop(jit_State *J, TraceLink linktype, TraceNo lnk) |
| 237 | { | 237 | { |
| 238 | lj_trace_end(J); | 238 | lj_trace_end(J); |
| 239 | J->cur.linktype = (uint8_t)linktype; | 239 | J->cur.linktype = (uint8_t)linktype; |
| @@ -501,8 +501,7 @@ static LoopEvent rec_for(jit_State *J, const BCIns *fori, int isforl) | |||
| 501 | static LoopEvent rec_iterl(jit_State *J, const BCIns iterins) | 501 | static LoopEvent rec_iterl(jit_State *J, const BCIns iterins) |
| 502 | { | 502 | { |
| 503 | BCReg ra = bc_a(iterins); | 503 | BCReg ra = bc_a(iterins); |
| 504 | lua_assert(J->base[ra] != 0); | 504 | if (!tref_isnil(getslot(J, ra))) { /* Looping back? */ |
| 505 | if (!tref_isnil(J->base[ra])) { /* Looping back? */ | ||
| 506 | J->base[ra-1] = J->base[ra]; /* Copy result of ITERC to control var. */ | 505 | J->base[ra-1] = J->base[ra]; /* Copy result of ITERC to control var. */ |
| 507 | J->maxslot = ra-1+bc_b(J->pc[-1]); | 506 | J->maxslot = ra-1+bc_b(J->pc[-1]); |
| 508 | J->pc += bc_j(iterins)+1; | 507 | J->pc += bc_j(iterins)+1; |
| @@ -540,12 +539,12 @@ static int innerloopleft(jit_State *J, const BCIns *pc) | |||
| 540 | /* Handle the case when an interpreted loop op is hit. */ | 539 | /* Handle the case when an interpreted loop op is hit. */ |
| 541 | static void rec_loop_interp(jit_State *J, const BCIns *pc, LoopEvent ev) | 540 | static void rec_loop_interp(jit_State *J, const BCIns *pc, LoopEvent ev) |
| 542 | { | 541 | { |
| 543 | if (J->parent == 0) { | 542 | if (J->parent == 0 && J->exitno == 0) { |
| 544 | if (pc == J->startpc && J->framedepth + J->retdepth == 0) { | 543 | if (pc == J->startpc && J->framedepth + J->retdepth == 0) { |
| 545 | /* Same loop? */ | 544 | /* Same loop? */ |
| 546 | if (ev == LOOPEV_LEAVE) /* Must loop back to form a root trace. */ | 545 | if (ev == LOOPEV_LEAVE) /* Must loop back to form a root trace. */ |
| 547 | lj_trace_err(J, LJ_TRERR_LLEAVE); | 546 | lj_trace_err(J, LJ_TRERR_LLEAVE); |
| 548 | rec_stop(J, LJ_TRLINK_LOOP, J->cur.traceno); /* Looping root trace. */ | 547 | lj_record_stop(J, LJ_TRLINK_LOOP, J->cur.traceno); /* Looping trace. */ |
| 549 | } else if (ev != LOOPEV_LEAVE) { /* Entering inner loop? */ | 548 | } else if (ev != LOOPEV_LEAVE) { /* Entering inner loop? */ |
| 550 | /* It's usually better to abort here and wait until the inner loop | 549 | /* It's usually better to abort here and wait until the inner loop |
| 551 | ** is traced. But if the inner loop repeatedly didn't loop back, | 550 | ** is traced. But if the inner loop repeatedly didn't loop back, |
| @@ -570,15 +569,15 @@ static void rec_loop_interp(jit_State *J, const BCIns *pc, LoopEvent ev) | |||
| 570 | /* Handle the case when an already compiled loop op is hit. */ | 569 | /* Handle the case when an already compiled loop op is hit. */ |
| 571 | static void rec_loop_jit(jit_State *J, TraceNo lnk, LoopEvent ev) | 570 | static void rec_loop_jit(jit_State *J, TraceNo lnk, LoopEvent ev) |
| 572 | { | 571 | { |
| 573 | if (J->parent == 0) { /* Root trace hit an inner loop. */ | 572 | if (J->parent == 0 && J->exitno == 0) { /* Root trace hit an inner loop. */ |
| 574 | /* Better let the inner loop spawn a side trace back here. */ | 573 | /* Better let the inner loop spawn a side trace back here. */ |
| 575 | lj_trace_err(J, LJ_TRERR_LINNER); | 574 | lj_trace_err(J, LJ_TRERR_LINNER); |
| 576 | } else if (ev != LOOPEV_LEAVE) { /* Side trace enters a compiled loop. */ | 575 | } else if (ev != LOOPEV_LEAVE) { /* Side trace enters a compiled loop. */ |
| 577 | J->instunroll = 0; /* Cannot continue across a compiled loop op. */ | 576 | J->instunroll = 0; /* Cannot continue across a compiled loop op. */ |
| 578 | if (J->pc == J->startpc && J->framedepth + J->retdepth == 0) | 577 | if (J->pc == J->startpc && J->framedepth + J->retdepth == 0) |
| 579 | rec_stop(J, LJ_TRLINK_LOOP, J->cur.traceno); /* Form an extra loop. */ | 578 | lj_record_stop(J, LJ_TRLINK_LOOP, J->cur.traceno); /* Form extra loop. */ |
| 580 | else | 579 | else |
| 581 | rec_stop(J, LJ_TRLINK_ROOT, lnk); /* Link to the loop. */ | 580 | lj_record_stop(J, LJ_TRLINK_ROOT, lnk); /* Link to the loop. */ |
| 582 | } /* Side trace continues across a loop that's left or not entered. */ | 581 | } /* Side trace continues across a loop that's left or not entered. */ |
| 583 | } | 582 | } |
| 584 | 583 | ||
| @@ -643,6 +642,18 @@ static TRef rec_call_specialize(jit_State *J, GCfunc *fn, TRef tr) | |||
| 643 | (void)lj_ir_kgc(J, obj2gco(pt), IRT_PROTO); /* Prevent GC of proto. */ | 642 | (void)lj_ir_kgc(J, obj2gco(pt), IRT_PROTO); /* Prevent GC of proto. */ |
| 644 | return tr; | 643 | return tr; |
| 645 | } | 644 | } |
| 645 | } else { | ||
| 646 | /* Don't specialize to non-monomorphic builtins. */ | ||
| 647 | switch (fn->c.ffid) { | ||
| 648 | case FF_coroutine_wrap_aux: | ||
| 649 | case FF_string_gmatch_aux: | ||
| 650 | /* NYI: io_file_iter doesn't have an ffid, yet. */ | ||
| 651 | /* NYI: specialize to ffid? Not strictly necessary, trace will stop. */ | ||
| 652 | return tr; | ||
| 653 | default: | ||
| 654 | /* NYI: don't specialize to non-monomorphic C functions. */ | ||
| 655 | break; | ||
| 656 | } | ||
| 646 | } | 657 | } |
| 647 | /* Otherwise specialize to the function (closure) value itself. */ | 658 | /* Otherwise specialize to the function (closure) value itself. */ |
| 648 | kfunc = lj_ir_kfunc(J, fn); | 659 | kfunc = lj_ir_kfunc(J, fn); |
| @@ -750,12 +761,13 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) | |||
| 750 | /* Return to lower frame via interpreter for unhandled cases. */ | 761 | /* Return to lower frame via interpreter for unhandled cases. */ |
| 751 | if (J->framedepth == 0 && J->pt && bc_isret(bc_op(*J->pc)) && | 762 | if (J->framedepth == 0 && J->pt && bc_isret(bc_op(*J->pc)) && |
| 752 | (!frame_islua(frame) || | 763 | (!frame_islua(frame) || |
| 753 | (J->parent == 0 && !bc_isret(bc_op(J->cur.startins))))) { | 764 | (J->parent == 0 && J->exitno == 0 && |
| 765 | !bc_isret(bc_op(J->cur.startins))))) { | ||
| 754 | /* NYI: specialize to frame type and return directly, not via RET*. */ | 766 | /* NYI: specialize to frame type and return directly, not via RET*. */ |
| 755 | for (i = -1; i < (ptrdiff_t)rbase; i++) | 767 | for (i = -1; i < (ptrdiff_t)rbase; i++) |
| 756 | J->base[i] = 0; /* Purge dead slots. */ | 768 | J->base[i] = 0; /* Purge dead slots. */ |
| 757 | J->maxslot = rbase + (BCReg)gotresults; | 769 | J->maxslot = rbase + (BCReg)gotresults; |
| 758 | rec_stop(J, LJ_TRLINK_RETURN, 0); /* Return to interpreter. */ | 770 | lj_record_stop(J, LJ_TRLINK_RETURN, 0); /* Return to interpreter. */ |
| 759 | return; | 771 | return; |
| 760 | } | 772 | } |
| 761 | if (frame_isvarg(frame)) { | 773 | if (frame_isvarg(frame)) { |
| @@ -779,7 +791,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) | |||
| 779 | if (check_downrec_unroll(J, pt)) { | 791 | if (check_downrec_unroll(J, pt)) { |
| 780 | J->maxslot = (BCReg)(rbase + gotresults); | 792 | J->maxslot = (BCReg)(rbase + gotresults); |
| 781 | lj_snap_purge(J); | 793 | lj_snap_purge(J); |
| 782 | rec_stop(J, LJ_TRLINK_DOWNREC, J->cur.traceno); /* Down-recursion. */ | 794 | lj_record_stop(J, LJ_TRLINK_DOWNREC, J->cur.traceno); /* Down-rec. */ |
| 783 | return; | 795 | return; |
| 784 | } | 796 | } |
| 785 | lj_snap_add(J); | 797 | lj_snap_add(J); |
| @@ -792,7 +804,8 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) | |||
| 792 | lua_assert(J->baseslot > cbase+1); | 804 | lua_assert(J->baseslot > cbase+1); |
| 793 | J->baseslot -= cbase+1; | 805 | J->baseslot -= cbase+1; |
| 794 | J->base -= cbase+1; | 806 | J->base -= cbase+1; |
| 795 | } else if (J->parent == 0 && !bc_isret(bc_op(J->cur.startins))) { | 807 | } else if (J->parent == 0 && J->exitno == 0 && |
| 808 | !bc_isret(bc_op(J->cur.startins))) { | ||
| 796 | /* Return to lower frame would leave the loop in a root trace. */ | 809 | /* Return to lower frame would leave the loop in a root trace. */ |
| 797 | lj_trace_err(J, LJ_TRERR_LLEAVE); | 810 | lj_trace_err(J, LJ_TRERR_LLEAVE); |
| 798 | } else { /* Return to lower frame. Guard for the target we return to. */ | 811 | } else { /* Return to lower frame. Guard for the target we return to. */ |
| @@ -1480,9 +1493,9 @@ static void check_call_unroll(jit_State *J, TraceNo lnk) | |||
| 1480 | if (count + J->tailcalled > J->param[JIT_P_recunroll]) { | 1493 | if (count + J->tailcalled > J->param[JIT_P_recunroll]) { |
| 1481 | J->pc++; | 1494 | J->pc++; |
| 1482 | if (J->framedepth + J->retdepth == 0) | 1495 | if (J->framedepth + J->retdepth == 0) |
| 1483 | rec_stop(J, LJ_TRLINK_TAILREC, J->cur.traceno); /* Tail-recursion. */ | 1496 | lj_record_stop(J, LJ_TRLINK_TAILREC, J->cur.traceno); /* Tail-rec. */ |
| 1484 | else | 1497 | else |
| 1485 | rec_stop(J, LJ_TRLINK_UPREC, J->cur.traceno); /* Up-recursion. */ | 1498 | lj_record_stop(J, LJ_TRLINK_UPREC, J->cur.traceno); /* Up-recursion. */ |
| 1486 | } | 1499 | } |
| 1487 | } else { | 1500 | } else { |
| 1488 | if (count > J->param[JIT_P_callunroll]) { | 1501 | if (count > J->param[JIT_P_callunroll]) { |
| @@ -1556,9 +1569,9 @@ static void rec_func_jit(jit_State *J, TraceNo lnk) | |||
| 1556 | } | 1569 | } |
| 1557 | J->instunroll = 0; /* Cannot continue across a compiled function. */ | 1570 | J->instunroll = 0; /* Cannot continue across a compiled function. */ |
| 1558 | if (J->pc == J->startpc && J->framedepth + J->retdepth == 0) | 1571 | if (J->pc == J->startpc && J->framedepth + J->retdepth == 0) |
| 1559 | rec_stop(J, LJ_TRLINK_TAILREC, J->cur.traceno); /* Extra tail-recursion. */ | 1572 | lj_record_stop(J, LJ_TRLINK_TAILREC, J->cur.traceno); /* Extra tail-rec. */ |
| 1560 | else | 1573 | else |
| 1561 | rec_stop(J, LJ_TRLINK_ROOT, lnk); /* Link to the function. */ | 1574 | lj_record_stop(J, LJ_TRLINK_ROOT, lnk); /* Link to the function. */ |
| 1562 | } | 1575 | } |
| 1563 | 1576 | ||
| 1564 | /* -- Vararg handling ----------------------------------------------------- */ | 1577 | /* -- Vararg handling ----------------------------------------------------- */ |
| @@ -2165,7 +2178,7 @@ void lj_record_ins(jit_State *J) | |||
| 2165 | case BC_JFORI: | 2178 | case BC_JFORI: |
| 2166 | lua_assert(bc_op(pc[(ptrdiff_t)rc-BCBIAS_J]) == BC_JFORL); | 2179 | lua_assert(bc_op(pc[(ptrdiff_t)rc-BCBIAS_J]) == BC_JFORL); |
| 2167 | if (rec_for(J, pc, 0) != LOOPEV_LEAVE) /* Link to existing loop. */ | 2180 | if (rec_for(J, pc, 0) != LOOPEV_LEAVE) /* Link to existing loop. */ |
| 2168 | rec_stop(J, LJ_TRLINK_ROOT, bc_d(pc[(ptrdiff_t)rc-BCBIAS_J])); | 2181 | lj_record_stop(J, LJ_TRLINK_ROOT, bc_d(pc[(ptrdiff_t)rc-BCBIAS_J])); |
| 2169 | /* Continue tracing if the loop is not entered. */ | 2182 | /* Continue tracing if the loop is not entered. */ |
| 2170 | break; | 2183 | break; |
| 2171 | 2184 | ||
| @@ -2299,6 +2312,12 @@ static const BCIns *rec_setup_root(jit_State *J) | |||
| 2299 | J->maxslot = J->pt->numparams; | 2312 | J->maxslot = J->pt->numparams; |
| 2300 | pc++; | 2313 | pc++; |
| 2301 | break; | 2314 | break; |
| 2315 | case BC_CALLM: | ||
| 2316 | case BC_CALL: | ||
| 2317 | case BC_ITERC: | ||
| 2318 | /* No bytecode range check for stitched traces. */ | ||
| 2319 | pc++; | ||
| 2320 | break; | ||
| 2302 | default: | 2321 | default: |
| 2303 | lua_assert(0); | 2322 | lua_assert(0); |
| 2304 | break; | 2323 | break; |
| @@ -2366,7 +2385,7 @@ void lj_record_setup(jit_State *J) | |||
| 2366 | if (traceref(J, J->cur.root)->nchild >= J->param[JIT_P_maxside] || | 2385 | if (traceref(J, J->cur.root)->nchild >= J->param[JIT_P_maxside] || |
| 2367 | T->snap[J->exitno].count >= J->param[JIT_P_hotexit] + | 2386 | T->snap[J->exitno].count >= J->param[JIT_P_hotexit] + |
| 2368 | J->param[JIT_P_tryside]) { | 2387 | J->param[JIT_P_tryside]) { |
| 2369 | rec_stop(J, LJ_TRLINK_INTERP, 0); | 2388 | lj_record_stop(J, LJ_TRLINK_INTERP, 0); |
| 2370 | } | 2389 | } |
| 2371 | } else { /* Root trace. */ | 2390 | } else { /* Root trace. */ |
| 2372 | J->cur.root = 0; | 2391 | J->cur.root = 0; |
| @@ -2378,6 +2397,8 @@ void lj_record_setup(jit_State *J) | |||
| 2378 | lj_snap_add(J); | 2397 | lj_snap_add(J); |
| 2379 | if (bc_op(J->cur.startins) == BC_FORL) | 2398 | if (bc_op(J->cur.startins) == BC_FORL) |
| 2380 | rec_for_loop(J, J->pc-1, &J->scev, 1); | 2399 | rec_for_loop(J, J->pc-1, &J->scev, 1); |
| 2400 | else if (bc_op(J->cur.startins) == BC_ITERC) | ||
| 2401 | J->startpc = NULL; | ||
| 2381 | if (1 + J->pt->framesize >= LJ_MAX_JSLOTS) | 2402 | if (1 + J->pt->framesize >= LJ_MAX_JSLOTS) |
| 2382 | lj_trace_err(J, LJ_TRERR_STACKOV); | 2403 | lj_trace_err(J, LJ_TRERR_STACKOV); |
| 2383 | } | 2404 | } |
diff --git a/src/lj_record.h b/src/lj_record.h index 287b2604..5f08c18d 100644 --- a/src/lj_record.h +++ b/src/lj_record.h | |||
| @@ -28,6 +28,7 @@ typedef struct RecordIndex { | |||
| 28 | 28 | ||
| 29 | LJ_FUNC int lj_record_objcmp(jit_State *J, TRef a, TRef b, | 29 | LJ_FUNC int lj_record_objcmp(jit_State *J, TRef a, TRef b, |
| 30 | cTValue *av, cTValue *bv); | 30 | cTValue *av, cTValue *bv); |
| 31 | LJ_FUNC void lj_record_stop(jit_State *J, TraceLink linktype, TraceNo lnk); | ||
| 31 | LJ_FUNC TRef lj_record_constify(jit_State *J, cTValue *o); | 32 | LJ_FUNC TRef lj_record_constify(jit_State *J, cTValue *o); |
| 32 | 33 | ||
| 33 | LJ_FUNC void lj_record_call(jit_State *J, BCReg func, ptrdiff_t nargs); | 34 | LJ_FUNC void lj_record_call(jit_State *J, BCReg func, ptrdiff_t nargs); |
diff --git a/src/lj_snap.c b/src/lj_snap.c index a25e4601..0c6cd776 100644 --- a/src/lj_snap.c +++ b/src/lj_snap.c | |||
| @@ -97,7 +97,8 @@ static BCReg snapshot_framelinks(jit_State *J, SnapEntry *map) | |||
| 97 | { | 97 | { |
| 98 | cTValue *frame = J->L->base - 1; | 98 | cTValue *frame = J->L->base - 1; |
| 99 | cTValue *lim = J->L->base - J->baseslot; | 99 | cTValue *lim = J->L->base - J->baseslot; |
| 100 | cTValue *ftop = frame + funcproto(frame_func(frame))->framesize; | 100 | GCfunc *fn = frame_func(frame); |
| 101 | cTValue *ftop = isluafunc(fn) ? (frame+funcproto(fn)->framesize) : J->L->top; | ||
| 101 | MSize f = 0; | 102 | MSize f = 0; |
| 102 | map[f++] = SNAP_MKPC(J->pc); /* The current PC is always the first entry. */ | 103 | map[f++] = SNAP_MKPC(J->pc); /* The current PC is always the first entry. */ |
| 103 | while (frame > lim) { /* Backwards traversal of all frames above base. */ | 104 | while (frame > lim) { /* Backwards traversal of all frames above base. */ |
diff --git a/src/lj_trace.c b/src/lj_trace.c index 2b8d931f..fa15e23d 100644 --- a/src/lj_trace.c +++ b/src/lj_trace.c | |||
| @@ -360,7 +360,7 @@ static void trace_start(jit_State *J) | |||
| 360 | TraceNo traceno; | 360 | TraceNo traceno; |
| 361 | 361 | ||
| 362 | if ((J->pt->flags & PROTO_NOJIT)) { /* JIT disabled for this proto? */ | 362 | if ((J->pt->flags & PROTO_NOJIT)) { /* JIT disabled for this proto? */ |
| 363 | if (J->parent == 0) { | 363 | if (J->parent == 0 && J->exitno == 0) { |
| 364 | /* Lazy bytecode patching to disable hotcount events. */ | 364 | /* Lazy bytecode patching to disable hotcount events. */ |
| 365 | lua_assert(bc_op(*J->pc) == BC_FORL || bc_op(*J->pc) == BC_ITERL || | 365 | lua_assert(bc_op(*J->pc) == BC_FORL || bc_op(*J->pc) == BC_ITERL || |
| 366 | bc_op(*J->pc) == BC_LOOP || bc_op(*J->pc) == BC_FUNCF); | 366 | bc_op(*J->pc) == BC_LOOP || bc_op(*J->pc) == BC_FUNCF); |
| @@ -453,6 +453,12 @@ static void trace_stop(jit_State *J) | |||
| 453 | root->nextside = (TraceNo1)traceno; | 453 | root->nextside = (TraceNo1)traceno; |
| 454 | } | 454 | } |
| 455 | break; | 455 | break; |
| 456 | case BC_CALLM: | ||
| 457 | case BC_CALL: | ||
| 458 | case BC_ITERC: | ||
| 459 | /* Trace stitching: patch link of previous trace. */ | ||
| 460 | traceref(J, J->exitno)->link = traceno; | ||
| 461 | break; | ||
| 456 | default: | 462 | default: |
| 457 | lua_assert(0); | 463 | lua_assert(0); |
| 458 | break; | 464 | break; |
| @@ -502,8 +508,12 @@ static int trace_abort(jit_State *J) | |||
| 502 | return 1; /* Retry ASM with new MCode area. */ | 508 | return 1; /* Retry ASM with new MCode area. */ |
| 503 | } | 509 | } |
| 504 | /* Penalize or blacklist starting bytecode instruction. */ | 510 | /* Penalize or blacklist starting bytecode instruction. */ |
| 505 | if (J->parent == 0 && !bc_isret(bc_op(J->cur.startins))) | 511 | if (J->parent == 0 && !bc_isret(bc_op(J->cur.startins))) { |
| 506 | penalty_pc(J, &gcref(J->cur.startpt)->pt, mref(J->cur.startpc, BCIns), e); | 512 | if (J->exitno == 0) |
| 513 | penalty_pc(J, &gcref(J->cur.startpt)->pt, mref(J->cur.startpc, BCIns), e); | ||
| 514 | else | ||
| 515 | traceref(J, J->exitno)->link = J->exitno; /* Self-link is blacklisted. */ | ||
| 516 | } | ||
| 507 | 517 | ||
| 508 | /* Is there anything to abort? */ | 518 | /* Is there anything to abort? */ |
| 509 | traceno = J->cur.traceno; | 519 | traceno = J->cur.traceno; |
| @@ -680,6 +690,20 @@ static void trace_hotside(jit_State *J, const BCIns *pc) | |||
| 680 | } | 690 | } |
| 681 | } | 691 | } |
| 682 | 692 | ||
| 693 | /* Stitch a new trace to the previous trace. */ | ||
| 694 | void LJ_FASTCALL lj_trace_stitch(jit_State *J, const BCIns *pc) | ||
| 695 | { | ||
| 696 | /* Only start a new trace if not recording or inside __gc call or vmevent. */ | ||
| 697 | if (J->state == LJ_TRACE_IDLE && | ||
| 698 | !(J2G(J)->hookmask & (HOOK_GC|HOOK_VMEVENT))) { | ||
| 699 | J->parent = 0; /* Have to treat it like a root trace. */ | ||
| 700 | /* J->exitno is set to the invoking trace. */ | ||
| 701 | J->state = LJ_TRACE_START; | ||
| 702 | lj_trace_ins(J, pc); | ||
| 703 | } | ||
| 704 | } | ||
| 705 | |||
| 706 | |||
| 683 | /* Tiny struct to pass data to protected call. */ | 707 | /* Tiny struct to pass data to protected call. */ |
| 684 | typedef struct ExitDataCP { | 708 | typedef struct ExitDataCP { |
| 685 | jit_State *J; | 709 | jit_State *J; |
diff --git a/src/lj_trace.h b/src/lj_trace.h index e30d3d59..be55e9d1 100644 --- a/src/lj_trace.h +++ b/src/lj_trace.h | |||
| @@ -34,6 +34,7 @@ LJ_FUNC void lj_trace_freestate(global_State *g); | |||
| 34 | /* Event handling. */ | 34 | /* Event handling. */ |
| 35 | LJ_FUNC void lj_trace_ins(jit_State *J, const BCIns *pc); | 35 | LJ_FUNC void lj_trace_ins(jit_State *J, const BCIns *pc); |
| 36 | LJ_FUNCA void LJ_FASTCALL lj_trace_hot(jit_State *J, const BCIns *pc); | 36 | LJ_FUNCA void LJ_FASTCALL lj_trace_hot(jit_State *J, const BCIns *pc); |
| 37 | LJ_FUNCA void LJ_FASTCALL lj_trace_stitch(jit_State *J, const BCIns *pc); | ||
| 37 | LJ_FUNCA int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr); | 38 | LJ_FUNCA int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr); |
| 38 | 39 | ||
| 39 | /* Signal asynchronous abort of trace or end of trace. */ | 40 | /* Signal asynchronous abort of trace or end of trace. */ |
diff --git a/src/lj_traceerr.h b/src/lj_traceerr.h index 8f463ca6..2546fc8f 100644 --- a/src/lj_traceerr.h +++ b/src/lj_traceerr.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | /* Recording. */ | 8 | /* Recording. */ |
| 9 | TREDEF(RECERR, "error thrown or hook called during recording") | 9 | TREDEF(RECERR, "error thrown or hook called during recording") |
| 10 | TREDEF(TRACEUV, "trace too short") | ||
| 10 | TREDEF(TRACEOV, "trace too long") | 11 | TREDEF(TRACEOV, "trace too long") |
| 11 | TREDEF(STACKOV, "trace too deep") | 12 | TREDEF(STACKOV, "trace too deep") |
| 12 | TREDEF(SNAPOV, "too many snapshots") | 13 | TREDEF(SNAPOV, "too many snapshots") |
| @@ -23,8 +24,6 @@ TREDEF(BADTYPE, "bad argument type") | |||
| 23 | TREDEF(CJITOFF, "JIT compilation disabled for function") | 24 | TREDEF(CJITOFF, "JIT compilation disabled for function") |
| 24 | TREDEF(CUNROLL, "call unroll limit reached") | 25 | TREDEF(CUNROLL, "call unroll limit reached") |
| 25 | TREDEF(DOWNREC, "down-recursion, restarting") | 26 | TREDEF(DOWNREC, "down-recursion, restarting") |
| 26 | TREDEF(NYICF, "NYI: C function %p") | ||
| 27 | TREDEF(NYIFF, "NYI: FastFunc %s") | ||
| 28 | TREDEF(NYIFFU, "NYI: unsupported variant of FastFunc %s") | 27 | TREDEF(NYIFFU, "NYI: unsupported variant of FastFunc %s") |
| 29 | TREDEF(NYIRETL, "NYI: return to lower frame") | 28 | TREDEF(NYIRETL, "NYI: return to lower frame") |
| 30 | 29 | ||
diff --git a/src/lj_vm.h b/src/lj_vm.h index 5893d0b2..4a1c2f2d 100644 --- a/src/lj_vm.h +++ b/src/lj_vm.h | |||
| @@ -107,6 +107,7 @@ LJ_ASMF void lj_cont_nop(void); /* Do nothing, just continue execution. */ | |||
| 107 | LJ_ASMF void lj_cont_condt(void); /* Branch if result is true. */ | 107 | LJ_ASMF void lj_cont_condt(void); /* Branch if result is true. */ |
| 108 | LJ_ASMF void lj_cont_condf(void); /* Branch if result is false. */ | 108 | LJ_ASMF void lj_cont_condf(void); /* Branch if result is false. */ |
| 109 | LJ_ASMF void lj_cont_hook(void); /* Continue from hook yield. */ | 109 | LJ_ASMF void lj_cont_hook(void); /* Continue from hook yield. */ |
| 110 | LJ_ASMF void lj_cont_stitch(void); /* Trace stitching. */ | ||
| 110 | 111 | ||
| 111 | enum { LJ_CONT_TAILCALL, LJ_CONT_FFI_CALLBACK }; /* Special continuations. */ | 112 | enum { LJ_CONT_TAILCALL, LJ_CONT_FFI_CALLBACK }; /* Special continuations. */ |
| 112 | 113 | ||
diff --git a/src/vm_arm.dasc b/src/vm_arm.dasc index b728d52f..559d20bd 100644 --- a/src/vm_arm.dasc +++ b/src/vm_arm.dasc | |||
| @@ -2082,6 +2082,55 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 2082 | | ldr INS, [PC, #-4] | 2082 | | ldr INS, [PC, #-4] |
| 2083 | | bx CRET1 | 2083 | | bx CRET1 |
| 2084 | | | 2084 | | |
| 2085 | |->cont_stitch: // Trace stitching. | ||
| 2086 | |.if JIT | ||
| 2087 | | // RA = resultptr, CARG4 = meta base | ||
| 2088 | | ldr RB, SAVE_MULTRES | ||
| 2089 | | ldr INS, [PC, #-4] | ||
| 2090 | | ldr CARG3, [CARG4, #-24] // Save previous trace number. | ||
| 2091 | | subs RB, RB, #8 | ||
| 2092 | | decode_RA8 RC, INS // Call base. | ||
| 2093 | | beq >2 | ||
| 2094 | |1: // Move results down. | ||
| 2095 | | ldrd CARG12, [RA] | ||
| 2096 | | add RA, RA, #8 | ||
| 2097 | | subs RB, RB, #8 | ||
| 2098 | | strd CARG12, [BASE, RC] | ||
| 2099 | | add RC, RC, #8 | ||
| 2100 | | bne <1 | ||
| 2101 | |2: | ||
| 2102 | | decode_RA8 RA, INS | ||
| 2103 | | decode_RB8 RB, INS | ||
| 2104 | | add RA, RA, RB | ||
| 2105 | | ldr CARG1, [DISPATCH, #DISPATCH_J(trace)] | ||
| 2106 | |3: | ||
| 2107 | | cmp RA, RC | ||
| 2108 | | mvn CARG2, #~LJ_TNIL | ||
| 2109 | | bhi >9 // More results wanted? | ||
| 2110 | | | ||
| 2111 | | ldr TRACE:RA, [CARG1, CARG3, lsl #2] | ||
| 2112 | | ldrh RC, TRACE:RA->link | ||
| 2113 | | cmp RC, CARG3 | ||
| 2114 | | beq ->cont_nop // Blacklisted. | ||
| 2115 | | cmp RC, #0 | ||
| 2116 | | bne =>BC_JLOOP // Jump to stitched trace. | ||
| 2117 | | | ||
| 2118 | | // Stitch a new trace to the previous trace. | ||
| 2119 | | str CARG3, [DISPATCH, #DISPATCH_J(exitno)] | ||
| 2120 | | str L, [DISPATCH, #DISPATCH_J(L)] | ||
| 2121 | | str BASE, L->base | ||
| 2122 | | sub CARG1, DISPATCH, #-GG_DISP2J | ||
| 2123 | | mov CARG2, PC | ||
| 2124 | | bl extern lj_dispatch_stitch // (jit_State *J, const BCIns *pc) | ||
| 2125 | | ldr BASE, L->base | ||
| 2126 | | b ->cont_nop | ||
| 2127 | | | ||
| 2128 | |9: // Fill up results with nil. | ||
| 2129 | | strd CARG12, [BASE, RC] | ||
| 2130 | | add RC, RC, #8 | ||
| 2131 | | b <3 | ||
| 2132 | |.endif | ||
| 2133 | | | ||
| 2085 | |->vm_profhook: // Dispatch target for profiler hook. | 2134 | |->vm_profhook: // Dispatch target for profiler hook. |
| 2086 | #if LJ_HASPROFILE | 2135 | #if LJ_HASPROFILE |
| 2087 | | mov CARG1, L | 2136 | | mov CARG1, L |
| @@ -2166,6 +2215,7 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 2166 | | lsrlo RC, INS, #16 // No: Decode operands A*8 and D. | 2215 | | lsrlo RC, INS, #16 // No: Decode operands A*8 and D. |
| 2167 | | subhs RC, RC, #8 | 2216 | | subhs RC, RC, #8 |
| 2168 | | addhs RA, RA, BASE // Yes: RA = BASE+framesize*8, RC = nargs*8 | 2217 | | addhs RA, RA, BASE // Yes: RA = BASE+framesize*8, RC = nargs*8 |
| 2218 | | ldrhs CARG3, [BASE, FRAME_FUNC] | ||
| 2169 | | bx OP | 2219 | | bx OP |
| 2170 | | | 2220 | | |
| 2171 | |3: // Rethrow error from the right C frame. | 2221 | |3: // Rethrow error from the right C frame. |
diff --git a/src/vm_mips.dasc b/src/vm_mips.dasc index f45a5c49..094ffe38 100644 --- a/src/vm_mips.dasc +++ b/src/vm_mips.dasc | |||
| @@ -2011,6 +2011,60 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 2011 | | jr CRET1 | 2011 | | jr CRET1 |
| 2012 | |. lw INS, -4(PC) | 2012 | |. lw INS, -4(PC) |
| 2013 | | | 2013 | | |
| 2014 | |->cont_stitch: // Trace stitching. | ||
| 2015 | |.if JIT | ||
| 2016 | | // RA = resultptr, RB = meta base | ||
| 2017 | | lw INS, -4(PC) | ||
| 2018 | | lw TMP3, -24+LO(RB) // Save previous trace number. | ||
| 2019 | | decode_RA8a RC, INS | ||
| 2020 | | addiu AT, MULTRES, -8 | ||
| 2021 | | decode_RA8b RC | ||
| 2022 | | beqz AT, >2 | ||
| 2023 | |. addu RC, BASE, RC // Call base. | ||
| 2024 | |1: // Move results down. | ||
| 2025 | | ldc1 f0, 0(RA) | ||
| 2026 | | addiu AT, AT, -8 | ||
| 2027 | | addiu RA, RA, 8 | ||
| 2028 | | sdc1 f0, 0(RC) | ||
| 2029 | | bnez AT, <1 | ||
| 2030 | |. addiu RC, RC, 8 | ||
| 2031 | |2: | ||
| 2032 | | decode_RA8a RA, INS | ||
| 2033 | | decode_RB8a RB, INS | ||
| 2034 | | decode_RA8b RA | ||
| 2035 | | decode_RB8b RB | ||
| 2036 | | addu RA, RA, RB | ||
| 2037 | | lw TMP1, DISPATCH_J(trace)(DISPATCH) | ||
| 2038 | | addu RA, BASE, RA | ||
| 2039 | |3: | ||
| 2040 | | sltu AT, RC, RA | ||
| 2041 | | bnez AT, >9 // More results wanted? | ||
| 2042 | |. sll TMP2, TMP3, 2 | ||
| 2043 | | | ||
| 2044 | | addu TMP2, TMP1, TMP2 | ||
| 2045 | | lw TRACE:TMP2, 0(TMP2) | ||
| 2046 | | lhu RD, TRACE:TMP2->link | ||
| 2047 | | beq RD, TMP3, ->cont_nop // Blacklisted. | ||
| 2048 | |. load_got lj_dispatch_stitch | ||
| 2049 | | bnez RD, =>BC_JLOOP // Jump to stitched trace. | ||
| 2050 | |. sll RD, RD, 3 | ||
| 2051 | | | ||
| 2052 | | // Stitch a new trace to the previous trace. | ||
| 2053 | | sw TMP3, DISPATCH_J(exitno)(DISPATCH) | ||
| 2054 | | sw L, DISPATCH_J(L)(DISPATCH) | ||
| 2055 | | sw BASE, L->base | ||
| 2056 | | addiu CARG1, DISPATCH, GG_DISP2J | ||
| 2057 | | call_intern lj_dispatch_stitch // (jit_State *J, const BCIns *pc) | ||
| 2058 | |. move CARG2, PC | ||
| 2059 | | b ->cont_nop | ||
| 2060 | |. lw BASE, L->base | ||
| 2061 | | | ||
| 2062 | |9: | ||
| 2063 | | sw TISNIL, HI(RC) | ||
| 2064 | | b <3 | ||
| 2065 | |. addiu RC, RC, 8 | ||
| 2066 | |.endif | ||
| 2067 | | | ||
| 2014 | |->vm_profhook: // Dispatch target for profiler hook. | 2068 | |->vm_profhook: // Dispatch target for profiler hook. |
| 2015 | #if LJ_HASPROFILE | 2069 | #if LJ_HASPROFILE |
| 2016 | | load_got lj_dispatch_profile | 2070 | | load_got lj_dispatch_profile |
| @@ -2091,13 +2145,13 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 2091 | | sw BASE, L->base | 2145 | | sw BASE, L->base |
| 2092 | |1: | 2146 | |1: |
| 2093 | | bltz CRET1, >3 // Check for error from exit. | 2147 | | bltz CRET1, >3 // Check for error from exit. |
| 2094 | |. lw LFUNC:TMP1, FRAME_FUNC(BASE) | 2148 | |. lw LFUNC:RB, FRAME_FUNC(BASE) |
| 2095 | | lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). | 2149 | | lui TMP3, 0x59c0 // TOBIT = 2^52 + 2^51 (float). |
| 2096 | | sll MULTRES, CRET1, 3 | 2150 | | sll MULTRES, CRET1, 3 |
| 2097 | | li TISNIL, LJ_TNIL | 2151 | | li TISNIL, LJ_TNIL |
| 2098 | | sw MULTRES, SAVE_MULTRES | 2152 | | sw MULTRES, SAVE_MULTRES |
| 2099 | | mtc1 TMP3, TOBIT | 2153 | | mtc1 TMP3, TOBIT |
| 2100 | | lw TMP1, LFUNC:TMP1->pc | 2154 | | lw TMP1, LFUNC:RB->pc |
| 2101 | | sw r0, DISPATCH_GL(jit_base)(DISPATCH) | 2155 | | sw r0, DISPATCH_GL(jit_base)(DISPATCH) |
| 2102 | | lw KBASE, PC2PROTO(k)(TMP1) | 2156 | | lw KBASE, PC2PROTO(k)(TMP1) |
| 2103 | | cvt.d.s TOBIT, TOBIT | 2157 | | cvt.d.s TOBIT, TOBIT |
diff --git a/src/vm_ppc.dasc b/src/vm_ppc.dasc index 91de682d..c21f5c43 100644 --- a/src/vm_ppc.dasc +++ b/src/vm_ppc.dasc | |||
| @@ -2505,6 +2505,55 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 2505 | | mtctr CRET1 | 2505 | | mtctr CRET1 |
| 2506 | | bctr | 2506 | | bctr |
| 2507 | | | 2507 | | |
| 2508 | |->cont_stitch: // Trace stitching. | ||
| 2509 | |.if JIT | ||
| 2510 | | // RA = resultptr, RB = meta base | ||
| 2511 | | lwz INS, -4(PC) | ||
| 2512 | | lwz TMP3, -20(RB) // Save previous trace number. | ||
| 2513 | | addic. TMP1, MULTRES, -8 | ||
| 2514 | | decode_RA8 RC, INS // Call base. | ||
| 2515 | | beq >2 | ||
| 2516 | |1: // Move results down. | ||
| 2517 | | lfd f0, 0(RA) | ||
| 2518 | | addic. TMP1, TMP1, -8 | ||
| 2519 | | addi RA, RA, 8 | ||
| 2520 | | stfdx f0, BASE, RC | ||
| 2521 | | addi RC, RC, 8 | ||
| 2522 | | bne <1 | ||
| 2523 | |2: | ||
| 2524 | | decode_RA8 RA, INS | ||
| 2525 | | decode_RB8 RB, INS | ||
| 2526 | | add RA, RA, RB | ||
| 2527 | | lwz TMP1, DISPATCH_J(trace)(DISPATCH) | ||
| 2528 | |3: | ||
| 2529 | | cmplw RA, RC | ||
| 2530 | | bgt >9 // More results wanted? | ||
| 2531 | | | ||
| 2532 | | slwi TMP2, TMP3, 2 | ||
| 2533 | | lwzx TRACE:TMP2, TMP1, TMP2 | ||
| 2534 | | lhz RD, TRACE:TMP2->link | ||
| 2535 | | cmpw RD, TMP3 | ||
| 2536 | | cmpwi cr1, RD, 0 | ||
| 2537 | | beq ->cont_nop // Blacklisted. | ||
| 2538 | | slwi RD, RD, 3 | ||
| 2539 | | bne cr1, =>BC_JLOOP // Jump to stitched trace. | ||
| 2540 | | | ||
| 2541 | | // Stitch a new trace to the previous trace. | ||
| 2542 | | stw TMP3, DISPATCH_J(exitno)(DISPATCH) | ||
| 2543 | | stp L, DISPATCH_J(L)(DISPATCH) | ||
| 2544 | | stp BASE, L->base | ||
| 2545 | | addi CARG1, DISPATCH, GG_DISP2J | ||
| 2546 | | mr CARG2, PC | ||
| 2547 | | bl extern lj_dispatch_stitch // (jit_State *J, const BCIns *pc) | ||
| 2548 | | lp BASE, L->base | ||
| 2549 | | b ->cont_nop | ||
| 2550 | | | ||
| 2551 | |9: | ||
| 2552 | | stwx TISNIL, BASE, RC | ||
| 2553 | | addi RC, RC, 8 | ||
| 2554 | | b <3 | ||
| 2555 | |.endif | ||
| 2556 | | | ||
| 2508 | |->vm_profhook: // Dispatch target for profiler hook. | 2557 | |->vm_profhook: // Dispatch target for profiler hook. |
| 2509 | #if LJ_HASPROFILE | 2558 | #if LJ_HASPROFILE |
| 2510 | | mr CARG1, L | 2559 | | mr CARG1, L |
| @@ -2557,7 +2606,7 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 2557 | | sub CARG3, TMP0, CARG3 // Compute exit number. | 2606 | | sub CARG3, TMP0, CARG3 // Compute exit number. |
| 2558 | | lp BASE, DISPATCH_GL(jit_base)(DISPATCH) | 2607 | | lp BASE, DISPATCH_GL(jit_base)(DISPATCH) |
| 2559 | | srwi CARG3, CARG3, 2 | 2608 | | srwi CARG3, CARG3, 2 |
| 2560 | | stw L, DISPATCH_J(L)(DISPATCH) | 2609 | | stp L, DISPATCH_J(L)(DISPATCH) |
| 2561 | | subi CARG3, CARG3, 2 | 2610 | | subi CARG3, CARG3, 2 |
| 2562 | | stp BASE, L->base | 2611 | | stp BASE, L->base |
| 2563 | | stw CARG4, DISPATCH_J(parent)(DISPATCH) | 2612 | | stw CARG4, DISPATCH_J(parent)(DISPATCH) |
| @@ -2589,11 +2638,11 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 2589 | |1: | 2638 | |1: |
| 2590 | | cmpwi CARG1, 0 | 2639 | | cmpwi CARG1, 0 |
| 2591 | | blt >3 // Check for error from exit. | 2640 | | blt >3 // Check for error from exit. |
| 2592 | | lwz LFUNC:TMP1, FRAME_FUNC(BASE) | 2641 | | lwz LFUNC:RB, FRAME_FUNC(BASE) |
| 2593 | | slwi MULTRES, CARG1, 3 | 2642 | | slwi MULTRES, CARG1, 3 |
| 2594 | | li TMP2, 0 | 2643 | | li TMP2, 0 |
| 2595 | | stw MULTRES, SAVE_MULTRES | 2644 | | stw MULTRES, SAVE_MULTRES |
| 2596 | | lwz TMP1, LFUNC:TMP1->pc | 2645 | | lwz TMP1, LFUNC:RB->pc |
| 2597 | | stw TMP2, DISPATCH_GL(jit_base)(DISPATCH) | 2646 | | stw TMP2, DISPATCH_GL(jit_base)(DISPATCH) |
| 2598 | | lwz KBASE, PC2PROTO(k)(TMP1) | 2647 | | lwz KBASE, PC2PROTO(k)(TMP1) |
| 2599 | | // Setup type comparison constants. | 2648 | | // Setup type comparison constants. |
diff --git a/src/vm_x86.dasc b/src/vm_x86.dasc index 8ed6efd1..c2f03d80 100644 --- a/src/vm_x86.dasc +++ b/src/vm_x86.dasc | |||
| @@ -2659,6 +2659,67 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 2659 | | add NARGS:RD, 1 | 2659 | | add NARGS:RD, 1 |
| 2660 | | jmp RBa | 2660 | | jmp RBa |
| 2661 | | | 2661 | | |
| 2662 | |->cont_stitch: // Trace stitching. | ||
| 2663 | |.if JIT | ||
| 2664 | | // BASE = base, RC = result, RB = mbase | ||
| 2665 | | mov RA, [RB-24] // Save previous trace number. | ||
| 2666 | | mov TMP1, RA | ||
| 2667 | | mov TMP3, DISPATCH // Need one more register. | ||
| 2668 | | mov DISPATCH, MULTRES | ||
| 2669 | | movzx RA, PC_RA | ||
| 2670 | | lea RA, [BASE+RA*8] // Call base. | ||
| 2671 | | sub DISPATCH, 1 | ||
| 2672 | | jz >2 | ||
| 2673 | |1: // Move results down. | ||
| 2674 | |.if X64 | ||
| 2675 | | mov RBa, [RC] | ||
| 2676 | | mov [RA], RBa | ||
| 2677 | |.else | ||
| 2678 | | mov RB, [RC] | ||
| 2679 | | mov [RA], RB | ||
| 2680 | | mov RB, [RC+4] | ||
| 2681 | | mov [RA+4], RB | ||
| 2682 | |.endif | ||
| 2683 | | add RC, 8 | ||
| 2684 | | add RA, 8 | ||
| 2685 | | sub DISPATCH, 1 | ||
| 2686 | | jnz <1 | ||
| 2687 | |2: | ||
| 2688 | | movzx RC, PC_RA | ||
| 2689 | | movzx RB, PC_RB | ||
| 2690 | | add RC, RB | ||
| 2691 | | lea RC, [BASE+RC*8-8] | ||
| 2692 | |3: | ||
| 2693 | | cmp RC, RA | ||
| 2694 | | ja >9 // More results wanted? | ||
| 2695 | | | ||
| 2696 | | mov DISPATCH, TMP3 | ||
| 2697 | | mov RB, TMP1 // Get previous trace number. | ||
| 2698 | | mov RA, [DISPATCH+DISPATCH_J(trace)] | ||
| 2699 | | mov TRACE:RD, [RA+RB*4] | ||
| 2700 | | movzx RD, word TRACE:RD->link | ||
| 2701 | | cmp RD, RB | ||
| 2702 | | je ->cont_nop // Blacklisted. | ||
| 2703 | | test RD, RD | ||
| 2704 | | jne =>BC_JLOOP // Jump to stitched trace. | ||
| 2705 | | | ||
| 2706 | | // Stitch a new trace to the previous trace. | ||
| 2707 | | mov [DISPATCH+DISPATCH_J(exitno)], RB | ||
| 2708 | | mov L:RB, SAVE_L | ||
| 2709 | | mov L:RB->base, BASE | ||
| 2710 | | mov FCARG2, PC | ||
| 2711 | | lea FCARG1, [DISPATCH+GG_DISP2J] | ||
| 2712 | | mov aword [DISPATCH+DISPATCH_J(L)], L:RBa | ||
| 2713 | | call extern lj_dispatch_stitch@8 // (jit_State *J, const BCIns *pc) | ||
| 2714 | | mov BASE, L:RB->base | ||
| 2715 | | jmp ->cont_nop | ||
| 2716 | | | ||
| 2717 | |9: // Fill up results with nil. | ||
| 2718 | | mov dword [RA+4], LJ_TNIL | ||
| 2719 | | add RA, 8 | ||
| 2720 | | jmp <3 | ||
| 2721 | |.endif | ||
| 2722 | | | ||
| 2662 | |->vm_profhook: // Dispatch target for profiler hook. | 2723 | |->vm_profhook: // Dispatch target for profiler hook. |
| 2663 | #if LJ_HASPROFILE | 2724 | #if LJ_HASPROFILE |
| 2664 | | mov L:RB, SAVE_L | 2725 | | mov L:RB, SAVE_L |
| @@ -5382,7 +5443,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | |||
| 5382 | | ins_A // RA = base, RD = target (loop extent) | 5443 | | ins_A // RA = base, RD = target (loop extent) |
| 5383 | | // Note: RA/RD is only used by trace recorder to determine scope/extent | 5444 | | // Note: RA/RD is only used by trace recorder to determine scope/extent |
| 5384 | | // This opcode does NOT jump, it's only purpose is to detect a hot loop. | 5445 | | // This opcode does NOT jump, it's only purpose is to detect a hot loop. |
| 5385 | |.if JIT | 5446 | |.if JIT |
| 5386 | | hotloop RB | 5447 | | hotloop RB |
| 5387 | |.endif | 5448 | |.endif |
| 5388 | | // Fall through. Assumes BC_ILOOP follows and ins_A is a no-op. | 5449 | | // Fall through. Assumes BC_ILOOP follows and ins_A is a no-op. |
