Bug 1004527 - Don't eliminate MNewDerivedTypedObject from resume points and recover them on bailout. (r=nmatsakis)
authorShu-yu Guo <shu@rfrn.org>
Fri, 02 May 2014 13:04:12 -0700
changeset 181777 e66519a652242d04e288f33683616b1605398e41
parent 181776 08f0167547ce18ddea0d7597a37bc5c19c3cd858
child 181778 b3a88dc52da78d6de5a31eca1d0a4512f2481979
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersnmatsakis
bugs1004527
milestone32.0a1
Bug 1004527 - Don't eliminate MNewDerivedTypedObject from resume points and recover them on bailout. (r=nmatsakis)
js/src/jit-test/tests/TypedObject/bug1004527.js
js/src/jit/IonAnalysis.cpp
js/src/jit/MIR.h
js/src/jit/Recover.cpp
js/src/jit/Recover.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/TypedObject/bug1004527.js
@@ -0,0 +1,8 @@
+if (!this.hasOwnProperty("TypedObject"))
+  quit();
+
+var { ArrayType, StructType, uint32 } = TypedObject;
+var L = 1024;
+var Matrix = uint32.array(L, 2);
+var matrix = new Matrix();
+evaluate("for (var i = 0; i < L; i++) matrix[i][0] = (function d() {});", { compileAndGo : true });
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -49,17 +49,17 @@ jit::SplitCriticalEdges(MIRGraph &graph)
             block->replaceSuccessor(i, split);
             target->replacePredecessor(*block, split);
         }
     }
     return true;
 }
 
 // Operands to a resume point which are dead at the point of the resume can be
-// replaced with undefined values. This analysis supports limited detection of
+// replaced with a magic value. This analysis supports limited detection of
 // dead operands, pruning those which are defined in the resume point's basic
 // block and have no uses outside the block or at points later than the resume
 // point.
 //
 // This is intended to ensure that extra resume points within a basic block
 // will not artificially extend the lifetimes of any SSA values. This could
 // otherwise occur if the new resume point captured a value which is created
 // between the old and new resume point and is dead at the new resume point.
@@ -88,16 +88,24 @@ jit::EliminateDeadResumePointOperands(MI
             // Scanning uses does not give us sufficient information to tell
             // where instructions that are involved in box/unbox operations or
             // parameter passing might be live. Rewriting uses of these terms
             // in resume points may affect the interpreter's behavior. Rather
             // than doing a more sophisticated analysis, just ignore these.
             if (ins->isUnbox() || ins->isParameter() || ins->isTypeBarrier() || ins->isComputeThis())
                 continue;
 
+            // TypedObject intermediate values captured by resume points may
+            // be legitimately dead in Ion code, but are still needed if we
+            // bail out. They can recover on bailout.
+            if (ins->isNewDerivedTypedObject()) {
+                MOZ_ASSERT(ins->canRecoverOnBailout());
+                continue;
+            }
+
             // If the instruction's behavior has been constant folded into a
             // separate instruction, we can't determine precisely where the
             // instruction becomes dead and can't eliminate its uses.
             if (ins->isImplicitlyUsed())
                 continue;
 
             // Check if this instruction's result is only used within the
             // current block, and keep track of its last use in a definition
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1584,16 +1584,21 @@ class MNewDerivedTypedObject
 
     TypePolicy *typePolicy() {
         return this;
     }
 
     virtual AliasSet getAliasSet() const {
         return AliasSet::None();
     }
+
+    bool writeRecoverData(CompactBufferWriter &writer) const;
+    bool canRecoverOnBailout() const {
+        return true;
+    }
 };
 
 // Abort parallel execution.
 class MAbortPar : public MAryControlInstruction<0, 0>
 {
     MAbortPar()
       : MAryControlInstruction<0, 0>()
     {
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -4,16 +4,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/Recover.h"
 
 #include "jscntxt.h"
 #include "jsmath.h"
 
+#include "builtin/TypedObject.h"
+
 #include "jit/IonSpewer.h"
 #include "jit/JitFrameIterator.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
 
 #include "vm/Interpreter.h"
 
 using namespace js;
@@ -162,8 +164,35 @@ RAdd::recover(JSContext *cx, SnapshotIte
     // MIRType_Float32 is a specialization embedding the fact that the result is
     // rounded to a Float32.
     if (isFloatOperation_ && !RoundFloat32(cx, result, &result))
         return false;
 
     iter.storeInstructionResult(result);
     return true;
 }
+
+bool
+MNewDerivedTypedObject::writeRecoverData(CompactBufferWriter &writer) const
+{
+    MOZ_ASSERT(canRecoverOnBailout());
+    writer.writeUnsigned(uint32_t(RInstruction::Recover_NewDerivedTypedObject));
+    return true;
+}
+
+RNewDerivedTypedObject::RNewDerivedTypedObject(CompactBufferReader &reader)
+{ }
+
+bool
+RNewDerivedTypedObject::recover(JSContext *cx, SnapshotIterator &iter) const
+{
+    Rooted<SizedTypeDescr *> descr(cx, &iter.read().toObject().as<SizedTypeDescr>());
+    Rooted<TypedObject *> owner(cx, &iter.read().toObject().as<TypedObject>());
+    int32_t offset = iter.read().toInt32();
+
+    JSObject *obj = TypedObject::createDerived(cx, descr, owner, offset);
+    if (!obj)
+        return false;
+
+    RootedValue result(cx, ObjectValue(*obj));
+    iter.storeInstructionResult(result);
+    return true;
+}
--- a/js/src/jit/Recover.h
+++ b/js/src/jit/Recover.h
@@ -13,17 +13,18 @@
 
 class JSContext;
 
 namespace js {
 namespace jit {
 
 #define RECOVER_OPCODE_LIST(_)                  \
     _(ResumePoint)                              \
-    _(Add)
+    _(Add)                                      \
+    _(NewDerivedTypedObject)
 
 class RResumePoint;
 class SnapshotIterator;
 
 class RInstruction
 {
   public:
     enum Opcode
@@ -96,16 +97,28 @@ class RAdd MOZ_FINAL : public RInstructi
 
     virtual uint32_t numOperands() const {
         return 2;
     }
 
     bool recover(JSContext *cx, SnapshotIterator &iter) const;
 };
 
+class RNewDerivedTypedObject MOZ_FINAL : public RInstruction
+{
+  public:
+    RINSTRUCTION_HEADER_(NewDerivedTypedObject)
+
+    virtual uint32_t numOperands() const {
+        return 3;
+    }
+
+    bool recover(JSContext *cx, SnapshotIterator &iter) const;
+};
+
 #undef RINSTRUCTION_HEADER_
 
 const RResumePoint *
 RInstruction::toResumePoint() const
 {
     MOZ_ASSERT(isResumePoint());
     return static_cast<const RResumePoint *>(this);
 }