Don't demote slots in overly long traces (based on counting the number of guards, current threshold=32).
authorAndreas Gal <gal@mozilla.com>
Thu, 24 Jul 2008 16:25:18 -0700
changeset 17821 81375d2214942696bc81f38b1de872085fad105b
parent 17820 6747a00cdc2c2d82c1fe8c459222afdad7625920
child 17822 8809b9fffa2749035f47cbfeccaacc40b27e4168
push id1452
push usershaver@mozilla.com
push dateFri, 22 Aug 2008 00:08:22 +0000
treeherderautoland@d13bb0868596 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.1a1pre
Don't demote slots in overly long traces (based on counting the number of guards, current threshold=32).
js/src/jstracer.cpp
js/src/jstracer.h
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -58,16 +58,25 @@
 #include "jsscript.h"
 #include "jsscope.h"
 #include "jsemit.h"
 #include "jsdbgapi.h"
 #include "jstracer.h"
 
 #include "jsautooplen.h"        // generated headers last
 
+/* Number of iterations of a loop before we start tracing. */
+#define HOTLOOP 2
+
+/* Number of times we wait to exit on a side exit before we try to extend the tree. */
+#define HOTEXIT 0
+
+/* Maximum number of guards after which we no longer try to demote loop variables. */
+#define DEMOTE_THRESHOLD 32
+
 #ifdef DEBUG
 #define ABORT_TRACE(msg)   do { fprintf(stdout, "abort: %d: %s\n", __LINE__, msg); return false; } while(0)
 #else
 #define ABORT_TRACE(msg)   return false
 #endif
 
 #ifdef DEBUG
 static struct {
@@ -973,16 +982,17 @@ TraceRecorder::snapshot()
        interpreter is using. For numbers we have to check what kind of store we used last
        (integer or double) to figure out what the side exit show reflect in its typemap. */
     FORALL_SLOTS(cx, treeInfo->ngslots, treeInfo->gslots, callDepth,
         LIns* i = get(vp);
         *m++ = isNumber(*vp)
             ? (isPromoteInt(i) ? JSVAL_INT : JSVAL_DOUBLE)
             : JSVAL_TAG(*vp);
     );
+    ++guardCount;
     return &exit;
 }
 
 LIns*
 TraceRecorder::guard(bool expected, LIns* cond)
 {
     return lir->insGuard(expected ? LIR_xf : LIR_xt,
                          cond,
@@ -995,16 +1005,19 @@ TraceRecorder::checkType(jsval& v, uint8
     if (t == TYPEMAP_TYPE_ANY) /* ignore unused slots */
         return true;
     if (isNumber(v)) {
         /* Initially we start out all numbers as JSVAL_DOUBLE in the type map. If we still
            see a number in v, its a valid trace but we might want to ask to demote the
            slot if we know or suspect that its integer. */
         LIns* i = get(&v);
         if (TYPEMAP_GET_TYPE(t) == JSVAL_DOUBLE) {
+            /* Don't type specialize really long traces (we count the number of guards in them). */
+            if (guardCount > DEMOTE_THRESHOLD)
+                return true;
             if (isInt32(v) && !TYPEMAP_GET_FLAG(t, TYPEMAP_FLAG_DONT_DEMOTE)) {
                 /* If the value associated with v via the tracker comes from a i2f operation,
                    we can be sure it will always be an int. If we see INCVAR, we similarly
                    speculate that the result will be int, even though this is not
                    guaranteed and this might cause the entry map to mismatch and thus
                    the trace never to be entered. */
                 if (i->isop(LIR_i2f) ||
                         (i->isop(LIR_fadd) && i->oprnd2()->isconstq() &&
@@ -1196,19 +1209,16 @@ js_IsLoopExit(JSContext* cx, JSScript* s
       case JSOP_IFNEX:
         return GET_JUMP_OFFSET(pc) < 0;
 
       default:;
     }
     return false;
 }
 
-#define HOTLOOP 2
-#define HOTEXIT 0
-
 bool
 js_LoopEdge(JSContext* cx, jsbytecode* oldpc)
 {
     JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
 
     /* is the recorder currently active? */
     if (tm->recorder) {
         TraceRecorder* r = tm->recorder;
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -144,16 +144,17 @@ class TraceRecorder {
     nanojit::LirWriter*     cse_filter;
     nanojit::LirWriter*     expr_filter;
     nanojit::LirWriter*     func_filter;
     nanojit::LIns*          cx_ins;
     nanojit::LIns*          gp_ins;
     nanojit::LIns*          rval_ins;
     nanojit::SideExit       exit;
     bool                    recompileFlag;
+    unsigned                guardCount;
 
     bool isGlobal(jsval* p) const;
     ptrdiff_t nativeStackOffset(jsval* p) const;
     ptrdiff_t nativeGlobalOffset(jsval* p) const;
     void import(nanojit::LIns* base, ptrdiff_t offset, jsval* p, uint8& t, 
             const char *prefix, int index, jsuword* localNames);
     void trackNativeStackUse(unsigned slots);