Bug 1077991 - IonMonkey: Simplify the handling of try-catch block control flow r=jandem
authorDan Gohman <sunfish@mozilla.com>
Tue, 28 Oct 2014 17:30:31 -0700
changeset 237324 0be3a777ab2b0843d6844ec8ed7f3de3737436e1
parent 237323 750b497aea432c8d478ced57791414d7c13d7772
child 237325 0f69fbc0d65d60b169b4d1d3f87359c753344a5e
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1077991
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1077991 - IonMonkey: Simplify the handling of try-catch block control flow r=jandem
js/src/jit/IonBuilder.cpp
js/src/jit/Lowering.cpp
js/src/jit/Lowering.h
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/ParallelSafetyAnalysis.cpp
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -3912,38 +3912,35 @@ IonBuilder::jsop_try()
     //     try {
     //         throw 3;
     //     } catch(e) { }
     //
     //     for (var i=0; i<1000; i++) {}
     //
     // To handle this, we create two blocks: one for the try block and one
     // for the code following the try-catch statement. Both blocks are
-    // connected to the graph with an MTest instruction that always jumps to
-    // the try block. This ensures the successor block always has a predecessor
-    // and later passes will optimize this MTest to a no-op.
+    // connected to the graph with an MGotoWithFake instruction that always
+    // jumps to the try block. This ensures the successor block always has a
+    // predecessor.
     //
     // If the code after the try block is unreachable (control flow in both the
     // try and catch blocks is terminated), only create the try block, to avoid
     // parsing unreachable code.
 
     MBasicBlock *tryBlock = newBlock(current, GetNextPc(pc));
     if (!tryBlock)
         return false;
 
     MBasicBlock *successor;
     if (analysis().maybeInfo(afterTry)) {
         successor = newBlock(current, afterTry);
         if (!successor)
             return false;
 
-        // Add MTest(true, tryBlock, successorBlock).
-        MConstant *true_ = MConstant::New(alloc(), BooleanValue(true));
-        current->add(true_);
-        current->end(newTest(true_, tryBlock, successor));
+        current->end(MGotoWithFake::New(alloc(), tryBlock, successor));
     } else {
         successor = nullptr;
         current->end(MGoto::New(alloc(), tryBlock));
     }
 
     if (!cfgStack_.append(CFGState::Try(endpc, successor)))
         return false;
 
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -873,16 +873,22 @@ LIRGenerator::visitTest(MTest *test)
     if (opd->type() == MIRType_Float32)
         return add(new(alloc()) LTestFAndBranch(useRegister(opd), ifTrue, ifFalse));
 
     MOZ_ASSERT(opd->type() == MIRType_Int32 || opd->type() == MIRType_Boolean);
     return add(new(alloc()) LTestIAndBranch(useRegister(opd), ifTrue, ifFalse));
 }
 
 bool
+LIRGenerator::visitGotoWithFake(MGotoWithFake *gotoWithFake)
+{
+    return add(new(alloc()) LGoto(gotoWithFake->target()));
+}
+
+bool
 LIRGenerator::visitFunctionDispatch(MFunctionDispatch *ins)
 {
     LFunctionDispatch *lir = new(alloc()) LFunctionDispatch(useRegister(ins->input()));
     return add(lir, ins);
 }
 
 bool
 LIRGenerator::visitTypeObjectDispatch(MTypeObjectDispatch *ins)
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -104,16 +104,17 @@ class LIRGenerator : public LIRGenerator
     bool visitArraySplice(MArraySplice *splice);
     bool visitBail(MBail *bail);
     bool visitUnreachable(MUnreachable *unreachable);
     bool visitAssertFloat32(MAssertFloat32 *ins);
     bool visitGetDynamicName(MGetDynamicName *ins);
     bool visitFilterArgumentsOrEval(MFilterArgumentsOrEval *ins);
     bool visitCallDirectEval(MCallDirectEval *ins);
     bool visitTest(MTest *test);
+    bool visitGotoWithFake(MGotoWithFake *ins);
     bool visitFunctionDispatch(MFunctionDispatch *ins);
     bool visitTypeObjectDispatch(MTypeObjectDispatch *ins);
     bool visitCompare(MCompare *comp);
     bool visitTypeOf(MTypeOf *ins);
     bool visitToId(MToId *ins);
     bool visitBitNot(MBitNot *ins);
     bool visitBitAnd(MBitAnd *ins);
     bool visitBitOr(MBitOr *ins);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -2409,16 +2409,43 @@ class MTest
     }
 #ifdef DEBUG
     bool isConsistentFloat32Use(MUse *use) const {
         return true;
     }
 #endif
 };
 
+// Equivalent to MTest(true, successor, fake), except without the foldsTo
+// method. This allows IonBuilder to insert fake CFG edges to magically protect
+// control flow for try-catch blocks.
+class MGotoWithFake
+  : public MAryControlInstruction<0, 2>
+{
+    MGotoWithFake(MBasicBlock *successor, MBasicBlock *fake)
+    {
+        setSuccessor(0, successor);
+        setSuccessor(1, fake);
+    }
+
+  public:
+    INSTRUCTION_HEADER(GotoWithFake)
+    static MGotoWithFake *New(TempAllocator &alloc, MBasicBlock *successor, MBasicBlock *fake) {
+        return new(alloc) MGotoWithFake(successor, fake);
+    }
+
+    MBasicBlock *target() const {
+        return getSuccessor(0);
+    }
+
+    AliasSet getAliasSet() const {
+        return AliasSet::None();
+    }
+};
+
 // Returns from this function to the previous caller.
 class MReturn
   : public MAryControlInstruction<1, 0>,
     public BoxInputsPolicy::Data
 {
     explicit MReturn(MDefinition *ins) {
         initOperand(0, ins);
     }
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -30,16 +30,17 @@ namespace jit {
     _(SimdTernaryBitwise)                                                   \
     _(CloneLiteral)                                                         \
     _(Parameter)                                                            \
     _(Callee)                                                               \
     _(IsConstructing)                                                       \
     _(TableSwitch)                                                          \
     _(Goto)                                                                 \
     _(Test)                                                                 \
+    _(GotoWithFake)                                                         \
     _(TypeObjectDispatch)                                                   \
     _(FunctionDispatch)                                                     \
     _(Compare)                                                              \
     _(Phi)                                                                  \
     _(Beta)                                                                 \
     _(OsrValue)                                                             \
     _(OsrScopeChain)                                                        \
     _(OsrReturnValue)                                                       \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -129,16 +129,17 @@ class ParallelSafetyVisitor : public MDe
     SAFE_OP(SimdTernaryBitwise)
     UNSAFE_OP(CloneLiteral)
     SAFE_OP(Parameter)
     SAFE_OP(Callee)
     SAFE_OP(IsConstructing)
     SAFE_OP(TableSwitch)
     SAFE_OP(Goto)
     SAFE_OP(Test)
+    SAFE_OP(GotoWithFake)
     SAFE_OP(Compare)
     SAFE_OP(Phi)
     SAFE_OP(Beta)
     UNSAFE_OP(OsrValue)
     UNSAFE_OP(OsrScopeChain)
     UNSAFE_OP(OsrReturnValue)
     UNSAFE_OP(OsrArgumentsObject)
     UNSAFE_OP(ReturnFromCtor)