diff --git a/lib/dump.lua b/lib/dump.lua index 5f32eb80..6ada21bc 100644 --- a/lib/dump.lua +++ b/lib/dump.lua @@ -504,13 +504,15 @@ local function dump_trace(what, tr, func, pc, otr, oex) if what == "abort" then out:write(" ", fmtfunc(func, pc), " -- ", fmterr(otr, oex), "\n") else - local link = traceinfo(tr).link - if link == tr then - link = "loop" - elseif link == 0 then - link = "interpreter" + local info = traceinfo(tr) + local link, ltype = info.link, info.linktype + if link == tr or link == 0 then + out:write(" -> ", ltype, "\n") + elseif ltype == "root" then + out:write(" -> ", link, "\n") + else + out:write(" -> ", link, " ", ltype, "\n") end - out:write(" -> ", link, "\n") end if dumpmode.H then out:write("\n\n") else out:write("\n") end else diff --git a/lib/v.lua b/lib/v.lua index bf61f125..d2a0c235 100644 --- a/lib/v.lua +++ b/lib/v.lua @@ -22,7 +22,7 @@ -- -- The output from the first example should look like this: -- --- [TRACE 1 (command line):1] +-- [TRACE 1 (command line):1 loop] -- [TRACE 2 (1/3) (command line):1 -> 1] -- -- The first number in each line is the internal trace number. Next are @@ -111,15 +111,20 @@ local function dump_trace(what, tr, func, pc, otr, oex) startex, startloc, fmterr(otr, oex))) end elseif what == "stop" then - local link = traceinfo(tr).link - if link == 0 then + local info = traceinfo(tr) + local link, ltype = info.link, info.linktype + if ltype == "interpreter" then out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n", tr, startex, startloc)) - elseif link == tr then - out:write(format("[TRACE %3s %s%s]\n", tr, startex, startloc)) - else + elseif link == tr or link == 0 then + out:write(format("[TRACE %3s %s%s %s]\n", + tr, startex, startloc, ltype)) + elseif ltype == "root" then out:write(format("[TRACE %3s %s%s -> %d]\n", tr, startex, startloc, link)) + else + out:write(format("[TRACE %3s %s%s -> %d %s]\n", + tr, startex, startloc, link, ltype)) end else out:write(format("[TRACE %s]\n", what)) diff --git a/src/lib_jit.c b/src/lib_jit.c index 66b3856a..d1f24f52 100644 --- a/src/lib_jit.c +++ b/src/lib_jit.c @@ -276,18 +276,26 @@ static GCtrace *jit_checktrace(lua_State *L) return NULL; } +/* Names of link types. ORDER LJ_TRLINK */ +static const char *const jit_trlinkname[] = { + "none", "root", "loop", "tail-recursion", "up-recursion", "down-recursion", + "interpreter", "return" +}; + /* local info = jit.util.traceinfo(tr) */ LJLIB_CF(jit_util_traceinfo) { GCtrace *T = jit_checktrace(L); if (T) { GCtab *t; - lua_createtable(L, 0, 4); /* Increment hash size if fields are added. */ + lua_createtable(L, 0, 8); /* Increment hash size if fields are added. */ t = tabV(L->top-1); setintfield(L, t, "nins", (int32_t)T->nins - REF_BIAS - 1); setintfield(L, t, "nk", REF_BIAS - (int32_t)T->nk); setintfield(L, t, "link", T->link); setintfield(L, t, "nexit", T->nsnap); + setstrV(L, L->top++, lj_str_newz(L, jit_trlinkname[T->linktype])); + lua_setfield(L, -2, "linktype"); /* There are many more fields. Add them only when needed. */ return 1; } diff --git a/src/lj_asm.c b/src/lj_asm.c index adb5a9ce..932ff8ea 100644 --- a/src/lj_asm.c +++ b/src/lj_asm.c @@ -1305,7 +1305,7 @@ static void asm_tail_link(ASMState *as) checkmclim(as); ra_allocref(as, REF_BASE, RID2RSET(RID_BASE)); - if (as->T->link == TRACE_INTERP) { + if (as->T->link == 0) { /* Setup fixed registers for exit to interpreter. */ const BCIns *pc = snap_pc(as->T->snapmap[snap->mapofs + snap->nent]); int32_t mres; diff --git a/src/lj_asm_arm.h b/src/lj_asm_arm.h index 31b300bf..99f3055f 100644 --- a/src/lj_asm_arm.h +++ b/src/lj_asm_arm.h @@ -1681,8 +1681,7 @@ static void asm_tail_fixup(ASMState *as, TraceNo lnk) p[-2] = (ARMI_ADD^k) | ARMF_D(RID_SP) | ARMF_N(RID_SP); } /* Patch exit branch. */ - target = lnk == TRACE_INTERP ? (MCode *)lj_vm_exit_interp : - traceref(as->J, lnk)->mcode; + target = lnk ? traceref(as->J, lnk)->mcode : (MCode *)lj_vm_exit_interp; p[-1] = ARMI_B|(((target-p)-1)&0x00ffffffu); } diff --git a/src/lj_asm_x86.h b/src/lj_asm_x86.h index 141957c7..0803ecef 100644 --- a/src/lj_asm_x86.h +++ b/src/lj_asm_x86.h @@ -2418,8 +2418,7 @@ static void asm_tail_fixup(ASMState *as, TraceNo lnk) } } /* Patch exit branch. */ - target = lnk == TRACE_INTERP ? (MCode *)lj_vm_exit_interp : - traceref(as->J, lnk)->mcode; + target = lnk ? traceref(as->J, lnk)->mcode : (MCode *)lj_vm_exit_interp; *(int32_t *)(p-4) = jmprel(p, target); p[-5] = XI_JMP; /* Drop unused mcode tail. Fill with NOPs to make the prefetcher happy. */ diff --git a/src/lj_jit.h b/src/lj_jit.h index ea2dd4ad..7e26aadc 100644 --- a/src/lj_jit.h +++ b/src/lj_jit.h @@ -174,13 +174,23 @@ typedef uint32_t ExitNo; typedef uint32_t TraceNo; /* Used to pass around trace numbers. */ typedef uint16_t TraceNo1; /* Stored trace number. */ -#define TRACE_INTERP 0 /* Fallback to interpreter. */ +/* Type of link. ORDER LJ_TRLINK */ +typedef enum { + LJ_TRLINK_NONE, /* Incomplete trace. No link, yet. */ + LJ_TRLINK_ROOT, /* Link to other root trace. */ + LJ_TRLINK_LOOP, /* Loop to same trace. */ + LJ_TRLINK_TAILREC, /* Tail-recursion. */ + LJ_TRLINK_UPREC, /* Up-recursion. */ + LJ_TRLINK_DOWNREC, /* Down-recursion. */ + LJ_TRLINK_INTERP, /* Fallback to interpreter. */ + LJ_TRLINK_RETURN /* Return to interpreter. */ +} TraceLink; /* Trace object. */ typedef struct GCtrace { GCHeader; uint8_t topslot; /* Top stack slot already checked to be allocated. */ - uint8_t unused1; + uint8_t linktype; /* Type of link. */ IRRef nins; /* Next IR instruction. Biased with REF_BIAS. */ GCRef gclist; IRIns *ir; /* IR instructions/constants. Biased with REF_BIAS. */ diff --git a/src/lj_record.c b/src/lj_record.c index 63d5e4c1..49d743a2 100644 --- a/src/lj_record.c +++ b/src/lj_record.c @@ -212,9 +212,10 @@ static void canonicalize_slots(jit_State *J) } /* Stop recording. */ -static void rec_stop(jit_State *J, TraceNo lnk) +static void rec_stop(jit_State *J, TraceLink linktype, TraceNo lnk) { lj_trace_end(J); + J->cur.linktype = (uint8_t)linktype; J->cur.link = (uint16_t)lnk; /* Looping back at the same stack level? */ if (lnk == J->cur.traceno && J->framedepth + J->retdepth == 0) { @@ -522,7 +523,7 @@ static void rec_loop_interp(jit_State *J, const BCIns *pc, LoopEvent ev) /* Same loop? */ if (ev == LOOPEV_LEAVE) /* Must loop back to form a root trace. */ lj_trace_err(J, LJ_TRERR_LLEAVE); - rec_stop(J, J->cur.traceno); /* Root trace forms a loop. */ + rec_stop(J, LJ_TRLINK_LOOP, J->cur.traceno); /* Looping root trace. */ } else if (ev != LOOPEV_LEAVE) { /* Entering inner loop? */ /* It's usually better to abort here and wait until the inner loop ** is traced. But if the inner loop repeatedly didn't loop back, @@ -553,8 +554,9 @@ static void rec_loop_jit(jit_State *J, TraceNo lnk, LoopEvent ev) } else if (ev != LOOPEV_LEAVE) { /* Side trace enters a compiled loop. */ J->instunroll = 0; /* Cannot continue across a compiled loop op. */ if (J->pc == J->startpc && J->framedepth + J->retdepth == 0) - lnk = J->cur.traceno; /* Can form an extra loop. */ - rec_stop(J, lnk); /* Link to the loop. */ + rec_stop(J, LJ_TRLINK_LOOP, J->cur.traceno); /* Form an extra loop. */ + else + rec_stop(J, LJ_TRLINK_ROOT, lnk); /* Link to the loop. */ } /* Side trace continues across a loop that's left or not entered. */ } @@ -678,7 +680,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) if (check_downrec_unroll(J, pt)) { J->maxslot = (BCReg)(rbase + gotresults); lj_snap_purge(J); - rec_stop(J, J->cur.traceno); /* Down-recursion. */ + rec_stop(J, LJ_TRLINK_DOWNREC, J->cur.traceno); /* Down-recursion. */ return; } lj_snap_add(J); @@ -1292,7 +1294,10 @@ static void check_call_unroll(jit_State *J) if (J->pc == J->startpc) { if (count + J->tailcalled > J->param[JIT_P_recunroll]) { J->pc++; - rec_stop(J, J->cur.traceno); /* Up-recursion or tail-recursion. */ + if (J->framedepth + J->retdepth == 0) + rec_stop(J, LJ_TRLINK_TAILREC, J->cur.traceno); /* Tail-recursion. */ + else + rec_stop(J, LJ_TRLINK_UPREC, J->cur.traceno); /* Up-recursion. */ } } else { if (count > J->param[JIT_P_callunroll]) @@ -1350,8 +1355,9 @@ static void rec_func_jit(jit_State *J, TraceNo lnk) rec_func_setup(J); J->instunroll = 0; /* Cannot continue across a compiled function. */ if (J->pc == J->startpc && J->framedepth + J->retdepth == 0) - lnk = J->cur.traceno; /* Can form an extra tail-recursive loop. */ - rec_stop(J, lnk); /* Link to the function. */ + rec_stop(J, LJ_TRLINK_TAILREC, J->cur.traceno); /* Extra tail-recursion. */ + else + rec_stop(J, LJ_TRLINK_ROOT, lnk); /* Link to the function. */ } /* -- Vararg handling ----------------------------------------------------- */ @@ -1863,7 +1869,7 @@ void lj_record_ins(jit_State *J) case BC_JFORI: lua_assert(bc_op(pc[(ptrdiff_t)rc-BCBIAS_J]) == BC_JFORL); if (rec_for(J, pc, 0) != LOOPEV_LEAVE) /* Link to existing loop. */ - rec_stop(J, bc_d(pc[(ptrdiff_t)rc-BCBIAS_J])); + rec_stop(J, LJ_TRLINK_ROOT, bc_d(pc[(ptrdiff_t)rc-BCBIAS_J])); /* Continue tracing if the loop is not entered. */ break; @@ -2121,8 +2127,9 @@ void lj_record_setup(jit_State *J) sidecheck: if (traceref(J, J->cur.root)->nchild >= J->param[JIT_P_maxside] || T->snap[J->exitno].count >= J->param[JIT_P_hotexit] + - J->param[JIT_P_tryside]) - rec_stop(J, TRACE_INTERP); + J->param[JIT_P_tryside]) { + rec_stop(J, LJ_TRLINK_INTERP, 0); + } } else { /* Root trace. */ J->cur.root = 0; J->cur.startins = *J->pc; diff --git a/src/lj_trace.c b/src/lj_trace.c index 0542ea1f..c65ca9cd 100644 --- a/src/lj_trace.c +++ b/src/lj_trace.c @@ -509,6 +509,7 @@ static int trace_abort(jit_State *J) if (traceno) { ptrdiff_t errobj = savestack(L, L->top-1); /* Stack may be resized. */ J->cur.link = 0; + J->cur.linktype = LJ_TRLINK_NONE; lj_vmevent_send(L, TRACE, TValue *frame; const BCIns *pc; @@ -590,6 +591,7 @@ static TValue *trace_state(lua_State *L, lua_CFunction dummy, void *ud) lj_opt_dce(J); if (lj_opt_loop(J)) { /* Loop optimization failed? */ J->cur.link = 0; + J->cur.linktype = LJ_TRLINK_NONE; J->loopref = J->cur.nins; J->state = LJ_TRACE_RECORD; /* Try to continue recording. */ break;