[INFER] Only carry tracked slots in FP registers across branches, bug 656259.
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 11 May 2011 10:22:42 -0700
changeset 75038 2178344055f561f77487bc01204e21359b9c44ca
parent 75037 20d04cc7ca8aff68df0a26682a79877bfa61c901
child 75039 5bcf457d942c631e7be0a1d95e93d2e413e16145
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs656259
milestone6.0a1
[INFER] Only carry tracked slots in FP registers across branches, bug 656259.
js/src/jit-test/tests/jaeger/bug656259.js
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FrameState.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug656259.js
@@ -0,0 +1,11 @@
+
+function throwsRangeError(t) {
+    try {
+        t: for (t[t++] in object) {
+            t++
+            break t;
+        }
+        date(t)
+    } catch (err) {}
+}
+throwsRangeError(Infinity);
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -2188,17 +2188,17 @@ mjit::Compiler::generateMethod()
 
             /*
              * Types of variables inferred as doubles need to be maintained as
              * doubles. We might forget the type of the variable by the next
              * call to fixDoubleTypes.
              */
             if (cx->typeInferenceEnabled()) {
                 uint32 slot = ArgSlot(GET_SLOTNO(PC));
-                if (a->varTypes[slot].type == JSVAL_TYPE_DOUBLE && fixDoubleSlot(slot))
+                if (a->varTypes[slot].type == JSVAL_TYPE_DOUBLE && analysis->trackSlot(slot))
                     frame.ensureDouble(frame.getArg(GET_SLOTNO(PC)));
             }
 
             if (pop) {
                 frame.pop();
                 PC += JSOP_SETARG_LENGTH + JSOP_POP_LENGTH;
                 break;
             }
@@ -2216,17 +2216,17 @@ mjit::Compiler::generateMethod()
           {
             updateVarType();
             jsbytecode *next = &PC[JSOP_SETLOCAL_LENGTH];
             bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next);
             frame.storeLocal(GET_SLOTNO(PC), pop, true);
 
             if (cx->typeInferenceEnabled()) {
                 uint32 slot = LocalSlot(script, GET_SLOTNO(PC));
-                if (a->varTypes[slot].type == JSVAL_TYPE_DOUBLE && fixDoubleSlot(slot))
+                if (a->varTypes[slot].type == JSVAL_TYPE_DOUBLE && analysis->trackSlot(slot))
                     frame.ensureDouble(frame.getLocal(GET_SLOTNO(PC)));
             }
 
             if (pop) {
                 frame.pop();
                 PC += JSOP_SETLOCAL_LENGTH + JSOP_POP_LENGTH;
                 break;
             }
@@ -6698,41 +6698,26 @@ mjit::Compiler::jsop_forgname(JSAtom *at
 
     // Before: ITER VALUE
     // After:  ITER
     frame.pop();
 }
 
 /*
  * For any locals or args which we know to be integers but are treated as
- * doubles by the type inference, convert to double.  These will be assumed to be
- * doubles at control flow join points.  This function must be called before branching
- * to another opcode.
- */
-
-/*
- * Whether to ensure that locals/args known to be ints or doubles should be
- * preserved as doubles across control flow edges.
+ * doubles by the type inference, convert to double. These will be assumed to be
+ * doubles at control flow join points. This function must be called before
+ * branching to another opcode.
+ *
+ * We can only carry entries as doubles when we can track all incoming edges to
+ * a join point (no try blocks etc.) and when we can track all writes to the
+ * local/arg (the slot does not escape) and ensure the Compiler representation
+ * matches the inferred type for the variable's SSA value. These properties are
+ * both ensured by analysis->trackSlot.
  */
-inline bool
-mjit::Compiler::fixDoubleSlot(uint32 slot)
-{
-    if (!analysis->trackSlot(slot))
-        return false;
-
-    /*
-     * Don't preserve double arguments in inline calls across branches, as we
-     * can't mutate them when inlining. :XXX: could be more precise here.
-     */
-    if (slot < LocalSlot(script, 0) && a->parent)
-        return false;
-
-    return true;
-}
-
 void
 mjit::Compiler::fixDoubleTypes(jsbytecode *target)
 {
     if (!cx->typeInferenceEnabled())
         return;
 
     /*
      * Fill fixedDoubleEntries with all variables that are known to be an int
@@ -6748,17 +6733,17 @@ mjit::Compiler::fixDoubleTypes(jsbytecod
                 newv->value.phiOffset() != uint32(target - script->code)) {
                 newv++;
                 continue;
             }
             if (newv->slot < TotalSlots(script)) {
                 types::TypeSet *targetTypes = analysis->getValueTypes(newv->value);
                 VarType &vt = a->varTypes[newv->slot];
                 if (targetTypes->getKnownTypeTag(cx) == JSVAL_TYPE_DOUBLE &&
-                    fixDoubleSlot(newv->slot)) {
+                    analysis->trackSlot(newv->slot)) {
                     FrameEntry *fe = frame.getSlotEntry(newv->slot);
                     if (vt.type == JSVAL_TYPE_INT32) {
                         fixedDoubleEntries.append(newv->slot);
                         frame.ensureDouble(fe);
                     } else if (vt.type == JSVAL_TYPE_UNKNOWN) {
                         /*
                          * Unknown here but a double at the target. The type
                          * set for the existing value must be empty, so this
@@ -6793,17 +6778,18 @@ mjit::Compiler::restoreAnalysisTypes()
             }
             newv++;
         }
     }
 
     /* Restore known types of locals/args. */
     for (uint32 slot = ArgSlot(0); slot < TotalSlots(script); slot++) {
         JSValueType type = a->varTypes[slot].type;
-        if (type != JSVAL_TYPE_UNKNOWN && (type != JSVAL_TYPE_DOUBLE || fixDoubleSlot(slot))) {
+        if (type != JSVAL_TYPE_UNKNOWN &&
+            (type != JSVAL_TYPE_DOUBLE || analysis->trackSlot(slot))) {
             FrameEntry *fe = frame.getSlotEntry(slot);
             JS_ASSERT_IF(fe->isTypeKnown(), fe->isType(type));
             if (!fe->isTypeKnown())
                 frame.learnType(fe, type, false);
         }
     }
 }
 
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -525,17 +525,16 @@ class Compiler : public BaseCompiler
     CompileStatus generateMethod();
     CompileStatus generateEpilogue();
     CompileStatus finishThisUp(JITScript **jitp);
     CompileStatus pushActiveFrame(JSScript *script, uint32 argc);
     void popActiveFrame();
 
     /* Analysis helpers. */
     CompileStatus prepareInferenceTypes(JSScript *script, ActiveFrame *a);
-    inline bool fixDoubleSlot(uint32 slot);
     void fixDoubleTypes(jsbytecode *target);
     void restoreAnalysisTypes();
     void watchGlobalReallocation();
     void updateVarType();
     JSValueType knownPushedType(uint32 pushed);
     bool mayPushUndefined(uint32 pushed);
     types::TypeSet *pushedTypeSet(uint32 which);
     bool monitored(jsbytecode *pc);
--- a/js/src/methodjit/FrameState.cpp
+++ b/js/src/methodjit/FrameState.cpp
@@ -529,32 +529,36 @@ FrameState::computeAllocation(jsbytecode
             dumpAllocation(alloc);
         }
 #endif
         return alloc;
     }
 
     /*
      * The allocation to use at the target consists of all parent, temporary
-     * and non-stack entries currently in registers which are live at the
-     * target. For entries currently in floating point registers, we need to
-     * check they are known to be doubles at the target. We don't need to do
-     * this for entries in normal registers, as fixDoubleTypes must have been
-     * called to convert them to floats.
+     * and non-stack entries currently in registers which are live at target.
      */
     Registers regs = Registers::AvailAnyRegs;
     while (!regs.empty()) {
         AnyRegisterID reg = regs.takeAnyReg();
         if (freeRegs.hasReg(reg) || regstate(reg).type() == RematInfo::TYPE)
             continue;
         FrameEntry *fe = regstate(reg).fe();
         if (fe < a->callee_ ||
             (fe > a->callee_ && fe < a->spBase && variableLive(fe, target)) ||
             (isTemporary(fe) && (a->parent || uint32(target - a->script->code) <= loop->backedgeOffset()))) {
+            /*
+             * For entries currently in floating point registers, check they
+             * are known to be doubles at the target. We don't need to do this
+             * for entries in normal registers, as fixDoubleTypes must have been
+             * called to convert them to floats.
+             */
             if (!reg.isReg() && !isTemporary(fe) && fe >= a->callee_ && fe < a->spBase) {
+                if (!a->analysis->trackSlot(entrySlot(fe)))
+                    continue;
                 bool nonDoubleTarget = false;
                 const SlotValue *newv = a->analysis->newValues(target);
                 while (newv && newv->slot) {
                     if (newv->value.kind() == SSAValue::PHI &&
                         newv->value.phiOffset() == uint32(target - a->script->code) &&
                         newv->slot == entrySlot(fe)) {
                         types::TypeSet *types = a->analysis->getValueTypes(newv->value);
                         if (types->getKnownTypeTag(cx) != JSVAL_TYPE_DOUBLE)