Backed out changeset 31a4c08387f1 (orange).
authorDavid Anderson <danderson@mozilla.com>
Wed, 21 Oct 2009 13:54:15 -0700
changeset 34313 165212c43078dfedcd03a9e93e0dbd41a8b1edab
parent 34305 31a4c08387f160d40a1b1268c499c626bc9b84ae
child 34314 2101bc26fed0513a8403c5ecc686a4a5e687cd7e
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.3a1pre
backs out31a4c08387f160d40a1b1268c499c626bc9b84ae
Backed out changeset 31a4c08387f1 (orange).
js/src/jsrecursion.cpp
js/src/jstracer.cpp
js/src/jstracer.h
--- a/js/src/jsrecursion.cpp
+++ b/js/src/jsrecursion.cpp
@@ -35,93 +35,25 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 class RecursiveSlotMap : public SlotMap
 {
-  protected:
-    unsigned downPostSlots;
-    LIns *rval_ins;
-
   public:
-    RecursiveSlotMap(TraceRecorder& rec, unsigned downPostSlots, LIns* rval_ins)
-      : SlotMap(rec), downPostSlots(downPostSlots), rval_ins(rval_ins)
+    RecursiveSlotMap(TraceRecorder& rec)
+      : SlotMap(rec)
     {
     }
 
     JS_REQUIRES_STACK void
     adjustTypes()
     {
-        /* Check if the return value should be promoted. */
-        if (slots[downPostSlots].lastCheck == TypeCheck_Demote)
-            rval_ins = mRecorder.lir->ins1(LIR_i2f, rval_ins);
-        /* Adjust any global variables. */
-        for (unsigned i = downPostSlots + 1; i < slots.length(); i++)
-            adjustType(slots[i]);
-    }
-
-    JS_REQUIRES_STACK void
-    adjustTail(TypeConsensus consensus)
-    {
-        /*
-         * exit->sp_adj = ((downPostSlots + 1) * sizeof(double)) - nativeStackBase
-         *
-         * Store at exit->sp_adj - sizeof(double)
-         */
-        ptrdiff_t retOffset = downPostSlots * sizeof(double) -
-                              mRecorder.treeInfo->nativeStackBase;
-        mRecorder.lir->insStorei(mRecorder.addName(rval_ins, "rval_ins"),
-                                 mRecorder.lirbuf->sp, retOffset);
-    }
-};
-
-class UpRecursiveSlotMap : public RecursiveSlotMap
-{
-  public:
-    UpRecursiveSlotMap(TraceRecorder& rec, unsigned downPostSlots, LIns* rval_ins)
-      : RecursiveSlotMap(rec, downPostSlots, rval_ins)
-    {
-    }
-
-    JS_REQUIRES_STACK void
-    adjustTail(TypeConsensus consensus)
-    {
-        LirBuffer* lirbuf = mRecorder.lirbuf;
-        LirWriter* lir = mRecorder.lir;
-
-        /*
-         * The native stack offset of the return value once this frame has
-         * returned, is:
-         *      -treeInfo->nativeStackBase + downPostSlots * sizeof(double)
-         *
-         * Note, not +1, since the offset is 0-based.
-         *
-         * This needs to be adjusted down one frame. The amount to adjust must
-         * be the amount down recursion added, which was just guarded as
-         * |downPostSlots|. So the offset is:
-         *
-         *      -treeInfo->nativeStackBase + downPostSlots * sizeof(double) -
-         *                                   downPostSlots * sizeof(double)
-         * Or:
-         *      -treeInfo->nativeStackBase
-         *
-         * This makes sense because this slot is just above the highest sp for
-         * the down frame.
-         */
-        lir->insStorei(rval_ins, lirbuf->sp, -mRecorder.treeInfo->nativeStackBase);
-
-        lirbuf->sp = lir->ins2(LIR_piadd, lirbuf->sp,
-                               lir->insImmWord(-int(downPostSlots) * sizeof(double)));
-        lir->insStorei(lirbuf->sp, lirbuf->state, offsetof(InterpState, sp));
-        lirbuf->rp = lir->ins2(LIR_piadd, lirbuf->rp,
-                               lir->insImmWord(-int(sizeof(FrameInfo*))));
-        lir->insStorei(lirbuf->rp, lirbuf->state, offsetof(InterpState, rp));
     }
 };
 
 #if defined DEBUG
 static JS_REQUIRES_STACK void
 AssertDownFrameIsConsistent(JSContext* cx, VMSideExit* anchor, FrameInfo* fi)
 {
     JS_ASSERT(anchor->recursive_down);
@@ -291,28 +223,50 @@ TraceRecorder::upRecursion()
     guard(true, lir->ins2(LIR_peq, prev_rp, INS_CONSTPTR(fi)), exit);
 
     /*
      * Now it's time to try and close the loop. Get a special exit that points
      * at the down frame, after the return has been propagated up.
      */
     exit = downSnapshot(fi);
 
-    LIns* rval_ins = (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) ?
-                     get(&stackval(-1)) :
-                     NULL;
-    JS_ASSERT(rval_ins != NULL);
-    JSTraceType returnType = exit->stackTypeMap()[downPostSlots];
-    if (returnType == TT_INT32) {
-        JS_ASSERT(determineSlotType(&stackval(-1)) == TT_INT32);
-        JS_ASSERT(isPromoteInt(rval_ins));
-        rval_ins = ::demote(lir, rval_ins);
-    }
+    /* Move the return value down from this frame to the one below it. */
+    rval_ins = get(&stackval(-1));
+    if (isPromoteInt(rval_ins))
+        rval_ins = demoteIns(rval_ins);
 
-    UpRecursiveSlotMap slotMap(*this, downPostSlots, rval_ins);
+    /*
+     * The native stack offset of the return value once this frame has returned, is:
+     *      -treeInfo->nativeStackBase + downPostSlots * sizeof(double)
+     *
+     * Note, not +1, since the offset is 0-based.
+     *
+     * This needs to be adjusted down one frame. The amount to adjust must be
+     * the amount down recursion added, which was just guarded as |downPostSlots|.
+     *
+     * So the offset is:
+     *      -treeInfo->nativeStackBase + downPostSlots * sizeof(double) -
+     *                                   downPostSlots * sizeof(double)
+     * Or:
+     *      -treeInfo->nativeStackBase
+     *
+     * This makes sense because this slot is just above the highest sp for the
+     * down frame.
+     */
+    lir->insStorei(rval_ins, lirbuf->sp, -treeInfo->nativeStackBase);
+
+    /* Adjust stacks. See above for |downPostSlots| reasoning. */
+    lirbuf->sp = lir->ins2(LIR_piadd, lirbuf->sp,
+                           lir->insImmWord(-int(downPostSlots) * sizeof(double)));
+    lir->insStorei(lirbuf->sp, lirbuf->state, offsetof(InterpState, sp));
+    lirbuf->rp = lir->ins2(LIR_piadd, lirbuf->rp,
+                           lir->insImmWord(-int(sizeof(FrameInfo*))));
+    lir->insStorei(lirbuf->rp, lirbuf->state, offsetof(InterpState, rp));
+
+    RecursiveSlotMap slotMap(*this);
     for (unsigned i = 0; i < downPostSlots; i++)
         slotMap.addSlot(exit->stackType(i));
     slotMap.addSlot(&stackval(-1));
     VisitGlobalSlots(slotMap, cx, *treeInfo->globalSlots);
     if (recursive_pc == (jsbytecode*)fragment->root->ip) {
         debug_only_print0(LC_TMTracer, "Compiling up-recursive loop...\n");
     } else {
         debug_only_print0(LC_TMTracer, "Compiling up-recursive branch...\n");
@@ -443,63 +397,36 @@ TraceRecorder::slurpDownFrames(jsbytecod
      * thrown away.
      */
     JSTraceType* typeMap = exit->stackTypeMap();
     jsbytecode* oldpc = cx->fp->regs->pc;
     cx->fp->regs->pc = exit->pc;
     js_CaptureStackTypes(cx, frameDepth, typeMap);
     cx->fp->regs->pc = oldpc;
     typeMap[downPostSlots] = determineSlotType(&stackval(-1));
+    if (typeMap[downPostSlots] == TT_INT32 &&
+        oracle.isStackSlotUndemotable(cx, downPostSlots, recursive_pc)) {
+        typeMap[downPostSlots] = TT_DOUBLE;
+    }
     determineGlobalTypes(&typeMap[exit->numStackSlots]);
 #if defined JS_JIT_SPEW
     TreevisLogExit(cx, exit);
 #endif
 
     /*
-     * Return values are tricky because there are two cases. Anchoring off a
-     * slurp failure (the second case) means the return value has already been
-     * moved. However it can still be promoted to link trees together, so we
-     * load it from the new location.
-     *
-     * In all other cases, the return value lives in the tracker and it can be
-     * grabbed safely.
+     * Move return value to the right place, if necessary. The previous store
+     * could have been killed so it is necessary to write it again.
      */
-    LIns* rval_ins;
-    JSTraceType returnType = exit->stackTypeMap()[downPostSlots];
     if (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) {
-        rval_ins = get(&stackval(-1));
-        if (returnType == TT_INT32) {
-            JS_ASSERT(determineSlotType(&stackval(-1)) == TT_INT32);
-            JS_ASSERT(isPromoteInt(rval_ins));
-            rval_ins = ::demote(lir, rval_ins);
-        }
-        /*
-         * The return value must be written out early, before slurping can fail,
-         * otherwise it will not be available when there's a type mismatch.
-         */
-        lir->insStorei(rval_ins, lirbuf->sp, exit->sp_adj - sizeof(double));
-    } else {
-        switch (returnType)
-        {
-          case TT_PSEUDOBOOLEAN:
-          case TT_INT32:
-            rval_ins = lir->insLoad(LIR_ld, lirbuf->sp, exit->sp_adj - sizeof(double));
-            break;
-          case TT_DOUBLE:
-            rval_ins = lir->insLoad(LIR_ldq, lirbuf->sp, exit->sp_adj - sizeof(double));
-            break;
-          case TT_FUNCTION:
-          case TT_OBJECT:
-          case TT_STRING:
-          case TT_NULL:
-            rval_ins = lir->insLoad(LIR_ldp, lirbuf->sp, exit->sp_adj - sizeof(double));
-            break;
-          default:
-            JS_NOT_REACHED("unknown type");
-        }
+        JS_ASSERT(exit->sp_adj >= int(sizeof(double)));
+        ptrdiff_t actRetOffset = exit->sp_adj - sizeof(double);
+        LIns* rval = get(&stackval(-1));
+        if (typeMap[downPostSlots] == TT_INT32)
+            rval = demoteIns(rval);
+        lir->insStorei(addName(rval, "rval"), lirbuf->sp, actRetOffset);
     }
 
     /* Slurp */
     SlurpInfo info;
     info.curSlot = 0;
     info.exit = exit;
     info.typeMap = typeMap;
     info.slurpFailSlot = (anchor && anchor->exitType == RECURSIVE_SLURP_FAIL_EXIT) ?
@@ -544,17 +471,18 @@ TraceRecorder::slurpDownFrames(jsbytecod
 
     /* Jump back to the start */
     exit = copy(exit);
     exit->exitType = UNSTABLE_LOOP_EXIT;
 #if defined JS_JIT_SPEW
     TreevisLogExit(cx, exit);
 #endif
 
-    RecursiveSlotMap slotMap(*this, downPostSlots, rval_ins);
+    /* Finally, close the loop. */
+    RecursiveSlotMap slotMap(*this);
     for (unsigned i = 0; i < downPostSlots; i++)
         slotMap.addSlot(typeMap[i]);
     slotMap.addSlot(&stackval(-1));
     VisitGlobalSlots(slotMap, cx, *treeInfo->globalSlots);
     debug_only_print0(LC_TMTracer, "Compiling up-recursive slurp...\n");
     exit = copy(exit);
     if (exit->recursive_pc == fragment->root->ip)
         exit->exitType = UNSTABLE_LOOP_EXIT;
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -4456,43 +4456,33 @@ class SlotMap : public SlotVisitorBase
     {
         for (unsigned i = 0; i < length(); i++) {
             if (get(i).lastCheck == TypeCheck_Undemote)
                 MarkSlotUndemotable(mRecorder.cx, mRecorder.treeInfo, i);
         }
     }
 
     JS_REQUIRES_STACK virtual void
-    adjustTail(TypeConsensus consensus)
-    {
-    }
-
-    JS_REQUIRES_STACK virtual void
     adjustTypes()
     {
-        for (unsigned i = 0; i < length(); i++)
-            adjustType(get(i));
-    }
-
-  protected:
-    JS_REQUIRES_STACK virtual void
-    adjustType(SlotInfo& info) {
-        JS_ASSERT(info.lastCheck != TypeCheck_Undemote && info.lastCheck != TypeCheck_Bad);
-        if (info.lastCheck == TypeCheck_Promote) {
-            JS_ASSERT(info.type == TT_INT32 || info.type == TT_DOUBLE);
-            mRecorder.set(info.v, mRecorder.f2i(mRecorder.get(info.v)));
-        } else if (info.lastCheck == TypeCheck_Demote) {
-            JS_ASSERT(info.type == TT_INT32 || info.type == TT_DOUBLE);
-            JS_ASSERT(mRecorder.get(info.v)->isQuad());
-
-            /* Never demote this final i2f. */
-            mRecorder.set(info.v, mRecorder.get(info.v), false, false);
-        }
-    }
-
+        for (unsigned i = 0; i < length(); i++) {
+            SlotInfo& info = get(i);
+            JS_ASSERT(info.lastCheck != TypeCheck_Undemote && info.lastCheck != TypeCheck_Bad);
+            if (info.lastCheck == TypeCheck_Promote) {
+                JS_ASSERT(info.type == TT_INT32 || info.type == TT_DOUBLE);
+                mRecorder.set(info.v, mRecorder.f2i(mRecorder.get(info.v)));
+            } else if (info.lastCheck == TypeCheck_Demote) {
+                JS_ASSERT(info.type == TT_INT32 || info.type == TT_DOUBLE);
+                JS_ASSERT(mRecorder.get(info.v)->isQuad());
+
+                /* Never demote this final i2f. */
+                mRecorder.set(info.v, mRecorder.get(info.v), false, false);
+            }
+        }
+    }
   private:
     TypeCheckResult
     checkType(unsigned i, JSTraceType t)
     {
         debug_only_printf(LC_TMTracer,
                           "checkType slot %d: interp=%c typemap=%c isNum=%d promoteInt=%d\n",
                           i,
                           typeChar[slots[i].type],
@@ -4654,26 +4644,22 @@ TraceRecorder::closeLoop(SlotMap& slotMa
 
 #if DEBUG
     if (consensus != TypeConsensus_Okay || peer)
         AUDIT(unstableLoopVariable);
 #endif
 
     JS_ASSERT(!trashSelf);
 
-    /*
-     * This exit is indeed linkable to something now. Process any promote or
-     * demotes that are pending in the slot map.
+    /* This exit is indeed linkable to something now. Process any promote/demotes that
+     * are pending in the slot map.
      */
     if (consensus == TypeConsensus_Okay)
         slotMap.adjustTypes();
 
-    /* Give up-recursion a chance to pop the stack frame. */
-    slotMap.adjustTail(consensus);
-
     if (consensus != TypeConsensus_Okay || peer) {
         fragment->lastIns = lir->insGuard(LIR_x, NULL, createGuardRecord(exit));
 
         /* If there is a peer, there must have been an "Okay" consensus. */
         JS_ASSERT_IF(peer, consensus == TypeConsensus_Okay);
 
         /* Compile as a type-unstable loop, and hope for a connection later. */
         if (!peer) {
@@ -14737,10 +14723,16 @@ js_CaptureStackTypes(JSContext* cx, unsi
 
 JS_REQUIRES_STACK void
 TraceRecorder::determineGlobalTypes(JSTraceType* typeMap)
 {
     DetermineTypesVisitor detVisitor(*this, typeMap);
     VisitGlobalSlots(detVisitor, cx, *treeInfo->globalSlots);
 }
 
+LIns*
+TraceRecorder::demoteIns(LIns* ins)
+{
+    return ::demote(lir, ins);
+}
+
 #include "jsrecursion.cpp"
 
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -1261,16 +1261,17 @@ public:
     JS_REQUIRES_STACK void prepareTreeCall(VMFragment* inner);
     JS_REQUIRES_STACK void emitTreeCall(VMFragment* inner, VMSideExit* exit);
     JS_REQUIRES_STACK VMFragment* findNestedCompatiblePeer(VMFragment* f);
     JS_REQUIRES_STACK AbortableRecordingStatus attemptTreeCall(VMFragment* inner,
                                                                uintN& inlineCallCount);
     unsigned getCallDepth() const;
 
     JS_REQUIRES_STACK void determineGlobalTypes(JSTraceType* typeMap);
+    nanojit::LIns* demoteIns(nanojit::LIns* ins);
 
     JS_REQUIRES_STACK VMSideExit* downSnapshot(FrameInfo* downFrame);
     JS_REQUIRES_STACK AbortableRecordingStatus upRecursion();
     JS_REQUIRES_STACK AbortableRecordingStatus downRecursion();
     JS_REQUIRES_STACK AbortableRecordingStatus record_EnterFrame(uintN& inlineCallCount);
     JS_REQUIRES_STACK AbortableRecordingStatus record_LeaveFrame();
     JS_REQUIRES_STACK AbortableRecordingStatus record_SetPropHit(JSPropCacheEntry* entry,
                                                                   JSScopeProperty* sprop);
@@ -1308,17 +1309,16 @@ public:
     friend class ImportUnboxedStackSlotVisitor;
     friend class ImportGlobalSlotVisitor;
     friend class AdjustCallerGlobalTypesVisitor;
     friend class AdjustCallerStackTypesVisitor;
     friend class TypeCompatibilityVisitor;
     friend class SlotMap;
     friend class DefaultSlotMap;
     friend class RecursiveSlotMap;
-    friend class UpRecursiveSlotMap;
     friend jsval *js_ConcatPostImacroStackCleanup(uint32 argc, JSFrameRegs &regs,
                                                   TraceRecorder *recorder);
 };
 #define TRACING_ENABLED(cx)       JS_HAS_OPTION(cx, JSOPTION_JIT)
 #define TRACE_RECORDER(cx)        (JS_TRACE_MONITOR(cx).recorder)
 #define SET_TRACE_RECORDER(cx,tr) (JS_TRACE_MONITOR(cx).recorder = (tr))
 
 #define JSOP_IN_RANGE(op,lo,hi)   (uintN((op) - (lo)) <= uintN((hi) - (lo)))