diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp | 187 |
1 files changed, 109 insertions, 78 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp b/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp index a10fbe853..09dbf328b 100644 --- a/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,7 +31,7 @@ #include "DFGBasicBlockInlines.h" #include "DFGGraph.h" #include "DFGPhase.h" -#include "Operations.h" +#include "JSCInlines.h" namespace JSC { namespace DFG { @@ -44,14 +44,19 @@ public: bool run() { + RELEASE_ASSERT(m_graph.m_refCountState == EverythingIsLive); + if (m_graph.m_form == ThreadedCPS) return false; clearIsLoadedFrom(); freeUnnecessaryNodes(); + m_graph.clearReplacements(); canonicalizeLocalsInBlocks(); + specialCaseArguments(); propagatePhis<LocalOperand>(); propagatePhis<ArgumentOperand>(); + computeIsFlushed(); m_graph.m_form = ThreadedCPS; return true; @@ -69,8 +74,8 @@ private: { SamplingRegion samplingRegion("DFG CPS Rethreading: freeUnnecessaryNodes"); - for (BlockIndex blockIndex = m_graph.m_blocks.size(); blockIndex--;) { - BasicBlock* block = m_graph.m_blocks[blockIndex].get(); + for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { + BasicBlock* block = m_graph.block(blockIndex); if (!block) continue; ASSERT(block->isReachable); @@ -86,25 +91,24 @@ private: node->children.setChild1(Edge()); break; case Phantom: - if (!node->child1()) + if (!node->child1()) { + m_graph.m_allocator.free(node); continue; + } switch (node->child1()->op()) { case Phi: case SetArgument: case SetLocal: - node->convertToPhantomLocal(); + node->convertPhantomToPhantomLocal(); break; default: ASSERT(node->child1()->hasResult()); break; } break; - case Nop: - continue; default: break; } - node->replacement = 0; // Reset the replacement since the next phase will use it. block->at(toIndex++) = node; } block->resize(toIndex); @@ -116,37 +120,37 @@ private: } template<OperandKind operandKind> - void clearVariablesAtHeadAndTail() + void clearVariables() { ASSERT( m_block->variablesAtHead.sizeFor<operandKind>() == m_block->variablesAtTail.sizeFor<operandKind>()); for (unsigned i = m_block->variablesAtHead.sizeFor<operandKind>(); i--;) { - m_block->variablesAtHead.atFor<operandKind>(i) = 0; - m_block->variablesAtTail.atFor<operandKind>(i) = 0; + m_block->variablesAtHead.atFor<operandKind>(i) = nullptr; + m_block->variablesAtTail.atFor<operandKind>(i) = nullptr; } } - ALWAYS_INLINE Node* addPhiSilently(BasicBlock* block, const CodeOrigin& codeOrigin, VariableAccessData* variable) + ALWAYS_INLINE Node* addPhiSilently(BasicBlock* block, const NodeOrigin& origin, VariableAccessData* variable) { - Node* result = m_graph.addNode(SpecNone, Phi, codeOrigin, OpInfo(variable)); + Node* result = m_graph.addNode(SpecNone, Phi, origin, OpInfo(variable)); block->phis.append(result); return result; } template<OperandKind operandKind> - ALWAYS_INLINE Node* addPhi(BasicBlock* block, const CodeOrigin& codeOrigin, VariableAccessData* variable, size_t index) + ALWAYS_INLINE Node* addPhi(BasicBlock* block, const NodeOrigin& origin, VariableAccessData* variable, size_t index) { - Node* result = addPhiSilently(block, codeOrigin, variable); + Node* result = addPhiSilently(block, origin, variable); phiStackFor<operandKind>().append(PhiStackEntry(block, index, result)); return result; } template<OperandKind operandKind> - ALWAYS_INLINE Node* addPhi(const CodeOrigin& codeOrigin, VariableAccessData* variable, size_t index) + ALWAYS_INLINE Node* addPhi(const NodeOrigin& origin, VariableAccessData* variable, size_t index) { - return addPhi<operandKind>(m_block, codeOrigin, variable, index); + return addPhi<operandKind>(m_block, origin, variable, index); } template<OperandKind operandKind> @@ -183,34 +187,19 @@ private: return; } - if (variable->isCaptured()) { - variable->setIsLoadedFrom(true); - if (otherNode->op() == GetLocal) - otherNode = otherNode->child1().node(); - else - ASSERT(otherNode->op() == SetLocal || otherNode->op() == SetArgument); - - ASSERT(otherNode->op() == Phi || otherNode->op() == SetLocal || otherNode->op() == SetArgument); - - // Keep this GetLocal but link it to the prior ones. - node->children.setChild1(Edge(otherNode)); - m_block->variablesAtTail.atFor<operandKind>(idx) = node; - return; - } - if (otherNode->op() == GetLocal) { // Replace all references to this GetLocal with otherNode. - node->replacement = otherNode; + node->replaceWith(otherNode); return; } ASSERT(otherNode->op() == SetLocal); - node->replacement = otherNode->child1().node(); + node->replaceWith(otherNode->child1().node()); return; } variable->setIsLoadedFrom(true); - Node* phi = addPhi<operandKind>(node->codeOrigin, variable, idx); + Node* phi = addPhi<operandKind>(node->origin, variable, idx); node->children.setChild1(Edge(phi)); m_block->variablesAtHead.atFor<operandKind>(idx) = phi; m_block->variablesAtTail.atFor<operandKind>(idx) = node; @@ -219,15 +208,10 @@ private: void canonicalizeGetLocal(Node* node) { VariableAccessData* variable = node->variableAccessData(); - if (operandIsArgument(variable->local())) - canonicalizeGetLocalFor<ArgumentOperand>(node, variable, operandToArgument(variable->local())); + if (variable->local().isArgument()) + canonicalizeGetLocalFor<ArgumentOperand>(node, variable, variable->local().toArgument()); else - canonicalizeGetLocalFor<LocalOperand>(node, variable, variable->local()); - } - - void canonicalizeSetLocal(Node* node) - { - m_block->variablesAtTail.setOperand(node->local(), node); + canonicalizeGetLocalFor<LocalOperand>(node, variable, variable->local().toLocal()); } template<NodeType nodeType, OperandKind operandKind> @@ -256,13 +240,9 @@ private: // for the purpose of OSR. PhantomLocal(SetLocal) means: at this point I // know that I would have read the value written by that SetLocal. This is // redundant and inefficient, since really it just means that we want to - // be keeping the operand to the SetLocal alive. The SetLocal may die, and - // we'll be fine because OSR tracks dead SetLocals. + // keep the last MovHinted value of that local alive. - // So we turn this into a Phantom on the child of the SetLocal. - - node->convertToPhantom(); - node->children.setChild1(otherNode->child1()); + node->remove(); return; } @@ -278,7 +258,7 @@ private: } variable->setIsLoadedFrom(true); - node->children.setChild1(Edge(addPhi<operandKind>(node->codeOrigin, variable, idx))); + node->children.setChild1(Edge(addPhi<operandKind>(node->origin, variable, idx))); m_block->variablesAtHead.atFor<operandKind>(idx) = node; m_block->variablesAtTail.atFor<operandKind>(idx) = node; } @@ -287,19 +267,15 @@ private: void canonicalizeFlushOrPhantomLocal(Node* node) { VariableAccessData* variable = node->variableAccessData(); - if (operandIsArgument(variable->local())) - canonicalizeFlushOrPhantomLocalFor<nodeType, ArgumentOperand>(node, variable, operandToArgument(variable->local())); + if (variable->local().isArgument()) + canonicalizeFlushOrPhantomLocalFor<nodeType, ArgumentOperand>(node, variable, variable->local().toArgument()); else - canonicalizeFlushOrPhantomLocalFor<nodeType, LocalOperand>(node, variable, variable->local()); + canonicalizeFlushOrPhantomLocalFor<nodeType, LocalOperand>(node, variable, variable->local().toLocal()); } - void canonicalizeSetArgument(Node* node) + void canonicalizeSet(Node* node) { - int local = node->local(); - ASSERT(operandIsArgument(local)); - int argument = operandToArgument(local); - m_block->variablesAtHead.setArgumentFirstTime(argument, node); - m_block->variablesAtTail.setArgumentFirstTime(argument, node); + m_block->variablesAtTail.setOperand(node->local(), node); } void canonicalizeLocalsInBlock() @@ -308,8 +284,8 @@ private: return; ASSERT(m_block->isReachable); - clearVariablesAtHeadAndTail<ArgumentOperand>(); - clearVariablesAtHeadAndTail<LocalOperand>(); + clearVariables<ArgumentOperand>(); + clearVariables<LocalOperand>(); // Assumes that all phi references have been removed. Assumes that things that // should be live have a non-zero ref count, but doesn't assume that the ref @@ -329,17 +305,17 @@ private: // SetArgument may only appear in the root block. // // Tail variable: the last thing that happened to the variable in the block. - // It may be a Flush, PhantomLocal, GetLocal, SetLocal, or SetArgument. + // It may be a Flush, PhantomLocal, GetLocal, SetLocal, SetArgument, or Phi. // SetArgument may only appear in the root block. Note that if there ever // was a GetLocal to the variable, and it was followed by PhantomLocals and // Flushes but not SetLocals, then the tail variable will be the GetLocal. // This reflects the fact that you only care that the tail variable is a - // Flush or PhantomLocal if nothing else interesting happened. + // Flush or PhantomLocal if nothing else interesting happened. Likewise, if + // there ever was a SetLocal and it was followed by Flushes, then the tail + // variable will be a SetLocal and not those subsequent Flushes. // - // Child of GetLocal: the operation that the GetLocal keeps alive. For - // uncaptured locals, it may be a Phi from the current block. For arguments, - // it may be a SetArgument. For captured locals and arguments it may also be - // a SetLocal. + // Child of GetLocal: the operation that the GetLocal keeps alive. It may be + // a Phi from the current block. For arguments, it may be a SetArgument. // // Child of SetLocal: must be a value producing node. // @@ -362,7 +338,7 @@ private: break; case SetLocal: - canonicalizeSetLocal(node); + canonicalizeSet(node); break; case Flush: @@ -374,7 +350,7 @@ private: break; case SetArgument: - canonicalizeSetArgument(node); + canonicalizeSet(node); break; default: @@ -387,12 +363,22 @@ private: { SamplingRegion samplingRegion("DFG CPS Rethreading: canonicalizeLocalsInBlocks"); - for (m_blockIndex = m_graph.m_blocks.size(); m_blockIndex--;) { - m_block = m_graph.m_blocks[m_blockIndex].get(); + for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { + m_block = m_graph.block(blockIndex); canonicalizeLocalsInBlock(); } } + void specialCaseArguments() + { + // Normally, a SetArgument denotes the start of a live range for a local's value on the stack. + // But those SetArguments used for the actual arguments to the machine CodeBlock get + // special-cased. We could have instead used two different node types - one for the arguments + // at the prologue case, and another for the other uses. But this seemed like IR overkill. + for (unsigned i = m_graph.m_arguments.size(); i--;) + m_graph.block(0)->variablesAtHead.setArgumentFirstTime(i, m_graph.m_arguments[i]); + } + template<OperandKind operandKind> void propagatePhis() { @@ -402,24 +388,23 @@ private: // Ensure that attempts to use this fail instantly. m_block = 0; - m_blockIndex = NoBlock; while (!phiStack.isEmpty()) { PhiStackEntry entry = phiStack.last(); phiStack.removeLast(); BasicBlock* block = entry.m_block; - PredecessorList& predecessors = block->m_predecessors; + PredecessorList& predecessors = block->predecessors; Node* currentPhi = entry.m_phi; VariableAccessData* variable = currentPhi->variableAccessData(); size_t index = entry.m_index; for (size_t i = predecessors.size(); i--;) { - BasicBlock* predecessorBlock = m_graph.m_blocks[predecessors[i]].get(); + BasicBlock* predecessorBlock = predecessors[i]; Node* variableInPrevious = predecessorBlock->variablesAtTail.atFor<operandKind>(index); if (!variableInPrevious) { - variableInPrevious = addPhi<operandKind>(predecessorBlock, currentPhi->codeOrigin, variable, index); + variableInPrevious = addPhi<operandKind>(predecessorBlock, currentPhi->origin, variable, index); predecessorBlock->variablesAtTail.atFor<operandKind>(index) = variableInPrevious; predecessorBlock->variablesAtHead.atFor<operandKind>(index) = variableInPrevious; } else { @@ -453,7 +438,7 @@ private: continue; } - Node* newPhi = addPhiSilently(block, currentPhi->codeOrigin, variable); + Node* newPhi = addPhiSilently(block, currentPhi->origin, variable); newPhi->children = currentPhi->children; currentPhi->children.initialize(newPhi, variableInPrevious, 0); } @@ -481,10 +466,56 @@ private: return m_localPhiStack; } - BlockIndex m_blockIndex; + void computeIsFlushed() + { + m_graph.clearFlagsOnAllNodes(NodeIsFlushed); + + for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { + BasicBlock* block = m_graph.block(blockIndex); + if (!block) + continue; + for (unsigned nodeIndex = block->size(); nodeIndex--;) { + Node* node = block->at(nodeIndex); + if (node->op() != Flush) + continue; + addFlushedLocalOp(node); + } + } + while (!m_flushedLocalOpWorklist.isEmpty()) { + Node* node = m_flushedLocalOpWorklist.takeLast(); + switch (node->op()) { + case SetLocal: + case SetArgument: + break; + + case Flush: + case Phi: + ASSERT(node->flags() & NodeIsFlushed); + DFG_NODE_DO_TO_CHILDREN(m_graph, node, addFlushedLocalEdge); + break; + + default: + DFG_CRASH(m_graph, node, "Invalid node in flush graph"); + break; + } + } + } + + void addFlushedLocalOp(Node* node) + { + if (node->mergeFlags(NodeIsFlushed)) + m_flushedLocalOpWorklist.append(node); + } + + void addFlushedLocalEdge(Node*, Edge edge) + { + addFlushedLocalOp(edge.node()); + } + BasicBlock* m_block; Vector<PhiStackEntry, 128> m_argumentPhiStack; Vector<PhiStackEntry, 128> m_localPhiStack; + Vector<Node*, 128> m_flushedLocalOpWorklist; }; bool performCPSRethreading(Graph& graph) |