Bug 1382973 part 7 - Change BytecodeAnalysis to mark code after try-catch as reachable to simplify Ion code. r=nbp
authorJan de Mooij <jdemooij@mozilla.com>
Sat, 22 Jul 2017 14:31:13 +0200
changeset 419128 bfc33f7e1de45d0c219ea83298cd6813964b8b37
parent 419127 dd2c01041ec8a21b055a672898161938b6f62a2f
child 419129 f5acec377801fd8f1a193f2fba787d439c3b078b
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs1382973
milestone56.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 1382973 part 7 - Change BytecodeAnalysis to mark code after try-catch as reachable to simplify Ion code. r=nbp
js/src/jit/BytecodeAnalysis.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/IonControlFlow.cpp
js/src/jit/IonControlFlow.h
--- a/js/src/jit/BytecodeAnalysis.cpp
+++ b/js/src/jit/BytecodeAnalysis.cpp
@@ -132,16 +132,22 @@ BytecodeAnalysis::init(TempAllocator& al
             MOZ_ASSERT(SN_TYPE(sn) == SRC_TRY);
 
             jsbytecode* endOfTry = pc + GetSrcNoteOffset(sn, 0);
             MOZ_ASSERT(JSOp(*endOfTry) == JSOP_GOTO);
 
             jsbytecode* afterTry = endOfTry + GET_JUMP_OFFSET(endOfTry);
             MOZ_ASSERT(afterTry > endOfTry);
 
+            // Ensure the code following the try-block is always marked as
+            // reachable, to simplify Ion's ControlFlowGenerator.
+            uint32_t afterTryOffset = script_->pcToOffset(afterTry);
+            infos_[afterTryOffset].init(stackDepth);
+            infos_[afterTryOffset].jumpTarget = true;
+
             // Pop CatchFinallyRanges that are no longer needed.
             while (!catchFinallyRanges.empty() && catchFinallyRanges.back().end <= offset)
                 catchFinallyRanges.popBack();
 
             CatchFinallyRange range(script_->pcToOffset(endOfTry), script_->pcToOffset(afterTry));
             if (!catchFinallyRanges.append(range))
                 return false;
             break;
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -3035,40 +3035,30 @@ IonBuilder::visitTry(CFGTry* try_)
 
     graph().setHasTryBlock();
 
     MBasicBlock* tryBlock;
     MOZ_TRY_VAR(tryBlock, newBlock(current, try_->tryBlock()->startPc()));
 
     blockWorklist[try_->tryBlock()->id()] = tryBlock;
 
-    // If the code after the try catch is reachable we connected it to the
-    // graph with an MGotoWithFake instruction that always jumps to the try
-    // block. This ensures the successor block always has a predecessor.
-    if (try_->codeAfterTryCatchReachable()) {
-        MBasicBlock* successor;
-        MOZ_TRY_VAR(successor, newBlock(current, try_->getSuccessor(1)->startPc()));
-
-        blockWorklist[try_->afterTryCatchBlock()->id()] = successor;
-
-        current->end(MGotoWithFake::New(alloc(), tryBlock, successor));
-
-        // The baseline compiler should not attempt to enter the catch block
-        // via OSR.
-        MOZ_ASSERT(info().osrPc() < try_->catchStartPc() ||
-                   info().osrPc() >= try_->afterTryCatchBlock()->startPc());
-
-    } else {
-        current->end(MGoto::New(alloc(), tryBlock));
-
-        // The baseline compiler should not attempt to enter the catch block
-        // via OSR or the code after the catch block.
-        // TODO: pre-existing bug. OSR after the catch block. Shouldn't happen.
-        //MOZ_ASSERT(info().osrPc() < try_->catchStartPc());
-    }
+    // Connect the code after the try-catch to the graph with an MGotoWithFake
+    // instruction that always jumps to the try block. This ensures the
+    // successor block always has a predecessor.
+    MBasicBlock* successor;
+    MOZ_TRY_VAR(successor, newBlock(current, try_->getSuccessor(1)->startPc()));
+
+    blockWorklist[try_->afterTryCatchBlock()->id()] = successor;
+
+    current->end(MGotoWithFake::New(alloc(), tryBlock, successor));
+
+    // The baseline compiler should not attempt to enter the catch block
+    // via OSR.
+    MOZ_ASSERT(info().osrPc() < try_->catchStartPc() ||
+               info().osrPc() >= try_->afterTryCatchBlock()->startPc());
 
     return Ok();
 }
 
 AbortReasonOr<Ok>
 IonBuilder::visitReturn(CFGControlInstruction* control)
 {
     MDefinition* def;
--- a/js/src/jit/IonControlFlow.cpp
+++ b/js/src/jit/IonControlFlow.cpp
@@ -569,31 +569,21 @@ ControlFlowGenerator::processTry()
     //     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.
-    //
-    // 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.
 
     CFGBlock* tryBlock = CFGBlock::New(alloc(), GetNextPc(pc));
 
-    CFGBlock* successor;
-    if (analysis_.maybeInfo(afterTry)) {
-        successor = CFGBlock::New(alloc(), afterTry);
-        current->setStopIns(CFGTry::New(alloc(), tryBlock, endpc, successor));
-    } else {
-        successor = nullptr;
-        current->setStopIns(CFGTry::New(alloc(), tryBlock, endpc));
-    }
+    CFGBlock* successor = CFGBlock::New(alloc(), afterTry);
+    current->setStopIns(CFGTry::New(alloc(), tryBlock, endpc, successor));
     current->setStopPc(pc);
 
     if (!cfgStack_.append(CFGState::Try(endpc, successor)))
         return ControlStatus::Error;
 
     current = tryBlock;
     pc = current->startPc();
 
@@ -602,21 +592,17 @@ ControlFlowGenerator::processTry()
 
     return ControlStatus::Jumped;
 }
 
 ControlFlowGenerator::ControlStatus
 ControlFlowGenerator::processTryEnd(CFGState& state)
 {
     MOZ_ASSERT(state.state == CFGState::TRY);
-
-    if (!state.try_.successor) {
-        MOZ_ASSERT(!current);
-        return ControlStatus::Ended;
-    }
+    MOZ_ASSERT(state.try_.successor);
 
     if (current) {
         current->setStopIns(CFGGoto::New(alloc(), state.try_.successor));
         current->setStopPc(pc);
     }
 
     // Start parsing the code after this try-catch statement.
     current = state.try_.successor;
--- a/js/src/jit/IonControlFlow.h
+++ b/js/src/jit/IonControlFlow.h
@@ -204,34 +204,34 @@ class CFGAryControlInstruction : public 
 };
 
 class CFGTry : public CFGControlInstruction
 {
     CFGBlock* tryBlock_;
     jsbytecode* catchStartPc_;
     CFGBlock* mergePoint_;
 
-    CFGTry(CFGBlock* successor, jsbytecode* catchStartPc, CFGBlock* mergePoint = nullptr)
+    CFGTry(CFGBlock* successor, jsbytecode* catchStartPc, CFGBlock* mergePoint)
       : tryBlock_(successor),
         catchStartPc_(catchStartPc),
         mergePoint_(mergePoint)
     { }
 
   public:
     CFG_CONTROL_HEADER(Try)
     TRIVIAL_CFG_NEW_WRAPPERS
 
     static CFGTry* CopyWithNewTargets(TempAllocator& alloc, CFGTry* old,
                                       CFGBlock* tryBlock, CFGBlock* merge)
     {
         return new(alloc) CFGTry(tryBlock, old->catchStartPc(), merge);
     }
 
     size_t numSuccessors() const final override {
-        return mergePoint_ ? 2 : 1;
+        return 2;
     }
     CFGBlock* getSuccessor(size_t i) const final override {
         MOZ_ASSERT(i < numSuccessors());
         return (i == 0) ? tryBlock_ : mergePoint_;
     }
     void replaceSuccessor(size_t i, CFGBlock* succ) final override {
         MOZ_ASSERT(i < numSuccessors());
         if (i == 0)
@@ -246,20 +246,16 @@ class CFGTry : public CFGControlInstruct
 
     jsbytecode* catchStartPc() const {
         return catchStartPc_;
     }
 
     CFGBlock* afterTryCatchBlock() const {
         return getSuccessor(1);
     }
-
-    bool codeAfterTryCatchReachable() const {
-        return !!mergePoint_;
-    }
 };
 
 class CFGTableSwitch : public CFGControlInstruction
 {
     Vector<CFGBlock*, 4, JitAllocPolicy> successors_;
     size_t low_;
     size_t high_;