From deeb8196c4d4085f3cc5a3389b568de7da739190 Mon Sep 17 00:00:00 2001
From: Mike Pall <mike>
Date: Tue, 28 Jun 2011 23:23:34 +0200
Subject: Reorganize trace linking and track link types.

---
 lib/dump.lua     | 14 ++++++++------
 lib/v.lua        | 17 +++++++++++------
 src/lib_jit.c    | 10 +++++++++-
 src/lj_asm.c     |  2 +-
 src/lj_asm_arm.h |  3 +--
 src/lj_asm_x86.h |  3 +--
 src/lj_jit.h     | 14 ++++++++++++--
 src/lj_record.c  | 29 ++++++++++++++++++-----------
 src/lj_trace.c   |  2 ++
 9 files changed, 63 insertions(+), 31 deletions(-)

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("</pre>\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;
-- 
cgit v1.2.3-55-g6feb