From 3a24c0c1be777f4463fefaf4998f34d389f95175 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Tue, 15 Mar 2016 16:55:42 +0000 Subject: [PATCH] Bug 1186006 - Add a copy of the successor resume point to the split-edge blocks. r=bhackett --- js/src/jit/IonAnalysis.cpp | 22 ++--------- js/src/jit/Lowering.cpp | 22 +---------- js/src/jit/MIRGraph.cpp | 75 +++++++++++++++++++++++++++++++++++--- js/src/jit/MIRGraph.h | 4 +- 4 files changed, 76 insertions(+), 47 deletions(-) diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index f00439ee99b1..1894fcc82bfa 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -421,27 +421,11 @@ SplitCriticalEdgesForBlock(MIRGraph& graph, MBasicBlock* block) if (target->numPredecessors() < 2) continue; - // Create a new block inheriting from the predecessor. - MBasicBlock* split = MBasicBlock::NewSplitEdge(graph, block->info(), block); + // Create a simple new block which contains a goto and which split the + // edge between block and target. + MBasicBlock* split = MBasicBlock::NewSplitEdge(graph, block->info(), block, i, target); if (!split) return false; - split->setLoopDepth(block->loopDepth()); - graph.insertBlockAfter(block, split); - split->end(MGoto::New(graph.alloc(), target)); - - // The entry resume point won't properly reflect state at the start of - // the split edge, so remove it. Split edges start out empty, but might - // have fallible code moved into them later. Rather than immediately - // figure out a valid resume point and pc we can use for the split edge, - // we wait until lowering (see LIRGenerator::visitBlock), where this - // will be easier. - if (MResumePoint* rp = split->entryResumePoint()) { - rp->releaseUses(); - split->clearEntryResumePoint(); - } - - block->replaceSuccessor(i, split); - target->replacePredecessor(block, split); } return true; } diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 1c7978d0880d..d86e311a44bc 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -4682,6 +4682,7 @@ LIRGenerator::updateResumeState(MInstruction* ins) void LIRGenerator::updateResumeState(MBasicBlock* block) { + MOZ_ASSERT_IF(!mir()->compilingAsmJS(), block->entryResumePoint()); lastResumePoint_ = block->entryResumePoint(); if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_) SpewResumePoint(block, nullptr, lastResumePoint_); @@ -4726,27 +4727,6 @@ LIRGenerator::visitBlock(MBasicBlock* block) if (!visitInstruction(block->lastIns())) return false; - // If we have a resume point check that all the following blocks have one, - // otherwise reuse the last resume point as the entry resume point of the - // basic block. This is used to handle fallible code which is moved/added - // into split edge blocks, which do not have resume points. See - // SplitCriticalEdgesForBlock. - // - // When folding conditions, we might create split-edge blocks which have - // multiple predecessors, in such case it is invalid to have any instruction - // in these blocks, as these blocks have no associated pc, thus we cannot - // safely bailout from such block. - if (lastResumePoint_) { - for (size_t s = 0; s < block->numSuccessors(); s++) { - MBasicBlock* succ = block->getSuccessor(s); - if (!succ->entryResumePoint() && succ->numPredecessors() == 1) { - MOZ_ASSERT(succ->isSplitEdge()); - MOZ_ASSERT(succ->phisBegin() == succ->phisEnd()); - succ->setEntryResumePoint(lastResumePoint_); - } - } - } - return true; } diff --git a/js/src/jit/MIRGraph.cpp b/js/src/jit/MIRGraph.cpp index 9663d0193365..b2448cb4b143 100644 --- a/js/src/jit/MIRGraph.cpp +++ b/js/src/jit/MIRGraph.cpp @@ -333,13 +333,76 @@ MBasicBlock::NewPendingLoopHeader(MIRGraph& graph, const CompileInfo& info, } MBasicBlock* -MBasicBlock::NewSplitEdge(MIRGraph& graph, const CompileInfo& info, MBasicBlock* pred) +MBasicBlock::NewSplitEdge(MIRGraph& graph, const CompileInfo& info, MBasicBlock* pred, size_t predEdgeIdx, MBasicBlock* succ) { - return pred->pc() - ? MBasicBlock::New(graph, nullptr, info, pred, - new(graph.alloc()) BytecodeSite(pred->trackedTree(), pred->pc()), - SPLIT_EDGE) - : MBasicBlock::NewAsmJS(graph, info, pred, SPLIT_EDGE); + MBasicBlock* split = nullptr; + if (!pred->pc()) { + // The predecessor does not have a PC, this is an AsmJS compilation. + split = MBasicBlock::NewAsmJS(graph, info, pred, SPLIT_EDGE); + if (!split) + return nullptr; + } else { + // The predecessor has a PC, this is an IonBuilder compilation. + MResumePoint* succEntry = succ->entryResumePoint(); + + BytecodeSite* site = new(graph.alloc()) BytecodeSite(succ->trackedTree(), succEntry->pc()); + split = new(graph.alloc()) MBasicBlock(graph, info, site, SPLIT_EDGE); + + if (!split->init()) + return nullptr; + + // A split edge is used to simplify the graph to avoid having a + // predecessor with multiple successors as well as a successor with + // multiple predecessors. As instructions can be moved in this + // split-edge block, we need to give this block a resume point. To do + // so, we copy the entry resume points of the successor and filter the + // phis to keep inputs from the current edge. + + // Propagate the caller resume point from the inherited block. + split->callerResumePoint_ = succ->callerResumePoint(); + + // Split-edge are created after the interpreter stack emulation. Thus, + // there is no need for creating slots. + split->stackPosition_ = succEntry->stackDepth(); + + // Create a resume point using our initial stack position. + MResumePoint* splitEntry = new(graph.alloc()) MResumePoint(split, succEntry->pc(), + MResumePoint::ResumeAt); + if (!splitEntry->init(graph.alloc())) + return nullptr; + split->entryResumePoint_ = splitEntry; + + // The target entry resume point might have phi operands, keep the + // operands of the phi coming from our edge. + size_t succEdgeIdx = succ->indexForPredecessor(pred); + + for (size_t i = 0, e = splitEntry->numOperands(); i < e; i++) { + MDefinition* def = succEntry->getOperand(i); + // This early in the pipeline, we have no recover instructions in + // any entry resume point. + MOZ_ASSERT_IF(def->block() == succ, def->isPhi()); + if (def->block() == succ) + def = def->toPhi()->getOperand(succEdgeIdx); + + splitEntry->initOperand(i, def); + } + + // This is done in the NewAsmJS, so we cannot keep this line below, + // where the rest of the graph is modified. + if (!split->predecessors_.append(pred)) + return nullptr; + } + + split->setLoopDepth(succ->loopDepth()); + + // Insert the split edge block in-between. + split->end(MGoto::New(graph.alloc(), succ)); + + graph.insertBlockAfter(pred, split); + + pred->replaceSuccessor(predEdgeIdx, split); + succ->replacePredecessor(pred, split); + return split; } MBasicBlock* diff --git a/js/src/jit/MIRGraph.h b/js/src/jit/MIRGraph.h index 0581f37d0420..16ff92ed5d03 100644 --- a/js/src/jit/MIRGraph.h +++ b/js/src/jit/MIRGraph.h @@ -116,7 +116,9 @@ class MBasicBlock : public TempObject, public InlineListNode static MBasicBlock* NewPendingLoopHeader(MIRGraph& graph, const CompileInfo& info, MBasicBlock* pred, BytecodeSite* site, unsigned loopStateSlots); - static MBasicBlock* NewSplitEdge(MIRGraph& graph, const CompileInfo& info, MBasicBlock* pred); + static MBasicBlock* NewSplitEdge(MIRGraph& graph, const CompileInfo& info, + MBasicBlock* pred, size_t predEdgeIdx, + MBasicBlock* succ); static MBasicBlock* NewAsmJS(MIRGraph& graph, const CompileInfo& info, MBasicBlock* pred, Kind kind);