diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGGraph.h')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGGraph.h | 584 |
1 files changed, 314 insertions, 270 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index b39845968..3e4e4b5bc 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,7 +35,10 @@ #include "DFGAssemblyHelpers.h" #include "DFGBasicBlock.h" #include "DFGDominators.h" +#include "DFGLongLivedState.h" #include "DFGNode.h" +#include "DFGNodeAllocator.h" +#include "DFGVariadicFunction.h" #include "JSStack.h" #include "MethodOfGettingAValueProfile.h" #include <wtf/BitVector.h> @@ -57,142 +60,126 @@ struct StorageAccessData { struct ResolveGlobalData { unsigned identifierNumber; - unsigned resolveOperationsIndex; - unsigned putToBaseOperationIndex; + ResolveOperations* resolveOperations; + PutToBaseOperation* putToBaseOperation; unsigned resolvePropertyIndex; }; struct ResolveOperationData { unsigned identifierNumber; - unsigned resolveOperationsIndex; - unsigned putToBaseOperationIndex; + ResolveOperations* resolveOperations; + PutToBaseOperation* putToBaseOperation; }; struct PutToBaseOperationData { - unsigned putToBaseOperationIndex; + PutToBaseOperation* putToBaseOperation; }; enum AddSpeculationMode { DontSpeculateInteger, - SpeculateIntegerButAlwaysWatchOverflow, + SpeculateIntegerAndTruncateConstants, SpeculateInteger }; - + // // === Graph === // -// The dataflow graph is an ordered vector of nodes. // The order may be significant for nodes with side-effects (property accesses, value conversions). // Nodes that are 'dead' remain in the vector with refCount 0. -class Graph : public Vector<Node, 64> { +class Graph { public: - Graph(JSGlobalData&, CodeBlock*, unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues); - - using Vector<Node, 64>::operator[]; - using Vector<Node, 64>::at; - - Node& operator[](Edge nodeUse) { return at(nodeUse.index()); } - const Node& operator[](Edge nodeUse) const { return at(nodeUse.index()); } - - Node& at(Edge nodeUse) { return at(nodeUse.index()); } - const Node& at(Edge nodeUse) const { return at(nodeUse.index()); } - - // Mark a node as being referenced. - void ref(NodeIndex nodeIndex) - { - Node& node = at(nodeIndex); - // If the value (before incrementing) was at refCount zero then we need to ref its children. - if (node.ref()) - refChildren(nodeIndex); - } - void ref(Edge nodeUse) - { - ref(nodeUse.index()); - } + Graph(VM&, CodeBlock*, unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues); + ~Graph(); - void deref(NodeIndex nodeIndex) - { - if (!at(nodeIndex).refCount()) - dump(); - if (at(nodeIndex).deref()) - derefChildren(nodeIndex); - } - void deref(Edge nodeUse) + void changeChild(Edge& edge, Node* newNode) { - deref(nodeUse.index()); + edge.setNode(newNode); } - void changeIndex(Edge& edge, NodeIndex newIndex, bool changeRef = true) + void changeEdge(Edge& edge, Edge newEdge) { - if (changeRef) { - ref(newIndex); - deref(edge.index()); - } - edge.setIndex(newIndex); - } - - void changeEdge(Edge& edge, Edge newEdge, bool changeRef = true) - { - if (changeRef) { - ref(newEdge); - deref(edge); - } edge = newEdge; } - void compareAndSwap(Edge& edge, NodeIndex oldIndex, NodeIndex newIndex, bool changeRef) + void compareAndSwap(Edge& edge, Node* oldNode, Node* newNode) { - if (edge.index() != oldIndex) + if (edge.node() != oldNode) return; - changeIndex(edge, newIndex, changeRef); + changeChild(edge, newNode); } - void compareAndSwap(Edge& edge, Edge oldEdge, Edge newEdge, bool changeRef) + void compareAndSwap(Edge& edge, Edge oldEdge, Edge newEdge) { if (edge != oldEdge) return; - changeEdge(edge, newEdge, changeRef); + changeEdge(edge, newEdge); } - void clearAndDerefChild1(Node& node) + void clearAndDerefChild(Node* node, unsigned index) { - if (!node.child1()) + if (!node->children.child(index)) return; - deref(node.child1()); - node.children.child1() = Edge(); + node->children.setChild(index, Edge()); } - - void clearAndDerefChild2(Node& node) + void clearAndDerefChild1(Node* node) { clearAndDerefChild(node, 0); } + void clearAndDerefChild2(Node* node) { clearAndDerefChild(node, 1); } + void clearAndDerefChild3(Node* node) { clearAndDerefChild(node, 2); } + + void performSubstitution(Node* node) { - if (!node.child2()) - return; - deref(node.child2()); - node.children.child2() = Edge(); + if (node->flags() & NodeHasVarArgs) { + for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++) + performSubstitutionForEdge(m_varArgChildren[childIdx]); + } else { + performSubstitutionForEdge(node->child1()); + performSubstitutionForEdge(node->child2()); + performSubstitutionForEdge(node->child3()); + } } - - void clearAndDerefChild3(Node& node) + + void performSubstitutionForEdge(Edge& child) { - if (!node.child3()) + // Check if this operand is actually unused. + if (!child) return; - deref(node.child3()); - node.children.child3() = Edge(); + + // Check if there is any replacement. + Node* replacement = child->replacement; + if (!replacement) + return; + + child.setNode(replacement); + + // There is definitely a replacement. Assert that the replacement does not + // have a replacement. + ASSERT(!child->replacement); } - // Call this if you've modified the reference counts of nodes that deal with - // local variables. This is necessary because local variable references can form - // cycles, and hence reference counting is not enough. This will reset the - // reference counts according to reachability. - void collectGarbage(); +#define DFG_DEFINE_ADD_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \ + templatePre typeParams templatePost Node* addNode(SpeculatedType type valueParamsComma valueParams) \ + { \ + Node* node = new (m_allocator) Node(valueArgs); \ + node->predict(type); \ + return node; \ + } + DFG_VARIADIC_TEMPLATE_FUNCTION(DFG_DEFINE_ADD_NODE) +#undef DFG_DEFINE_ADD_NODE + + void dethread(); - void convertToConstant(NodeIndex nodeIndex, unsigned constantNumber) + void convertToConstant(Node* node, unsigned constantNumber) { - at(nodeIndex).convertToConstant(constantNumber); + if (node->op() == GetLocal) + dethread(); + else + ASSERT(!node->hasVariableAccessData()); + node->convertToConstant(constantNumber); } - void convertToConstant(NodeIndex nodeIndex, JSValue value) + void convertToConstant(Node* node, JSValue value) { - convertToConstant(nodeIndex, m_codeBlock->addOrFindConstant(value)); + convertToConstant(node, m_codeBlock->addOrFindConstant(value)); } // CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names). @@ -200,107 +187,120 @@ public: enum PhiNodeDumpMode { DumpLivePhisOnly, DumpAllPhis }; void dumpBlockHeader(PrintStream&, const char* prefix, BlockIndex, PhiNodeDumpMode); void dump(PrintStream&, Edge); - void dump(PrintStream&, const char* prefix, NodeIndex); - static int amountOfNodeWhiteSpace(Node&); - static void printNodeWhiteSpace(PrintStream&, Node&); + void dump(PrintStream&, const char* prefix, Node*); + static int amountOfNodeWhiteSpace(Node*); + static void printNodeWhiteSpace(PrintStream&, Node*); // Dump the code origin of the given node as a diff from the code origin of the - // preceding node. - void dumpCodeOrigin(PrintStream&, const char* prefix, NodeIndex, NodeIndex); + // preceding node. Returns true if anything was printed. + bool dumpCodeOrigin(PrintStream&, const char* prefix, Node* previousNode, Node* currentNode); BlockIndex blockIndexForBytecodeOffset(Vector<BlockIndex>& blocks, unsigned bytecodeBegin); - SpeculatedType getJSConstantSpeculation(Node& node) + SpeculatedType getJSConstantSpeculation(Node* node) { - return speculationFromValue(node.valueOfJSConstant(m_codeBlock)); + return speculationFromValue(node->valueOfJSConstant(m_codeBlock)); } - AddSpeculationMode addSpeculationMode(Node& add) + AddSpeculationMode addSpeculationMode(Node* add, bool leftShouldSpeculateInteger, bool rightShouldSpeculateInteger) { - ASSERT(add.op() == ValueAdd || add.op() == ArithAdd || add.op() == ArithSub); + ASSERT(add->op() == ValueAdd || add->op() == ArithAdd || add->op() == ArithSub); - Node& left = at(add.child1()); - Node& right = at(add.child2()); + Node* left = add->child1().node(); + Node* right = add->child2().node(); - if (left.hasConstant()) - return addImmediateShouldSpeculateInteger(add, right, left); - if (right.hasConstant()) - return addImmediateShouldSpeculateInteger(add, left, right); + if (left->hasConstant()) + return addImmediateShouldSpeculateInteger(add, rightShouldSpeculateInteger, left); + if (right->hasConstant()) + return addImmediateShouldSpeculateInteger(add, leftShouldSpeculateInteger, right); - return (Node::shouldSpeculateIntegerExpectingDefined(left, right) && add.canSpeculateInteger()) ? SpeculateInteger : DontSpeculateInteger; + return (leftShouldSpeculateInteger && rightShouldSpeculateInteger && add->canSpeculateInteger()) ? SpeculateInteger : DontSpeculateInteger; } - bool addShouldSpeculateInteger(Node& add) + AddSpeculationMode valueAddSpeculationMode(Node* add) { - return addSpeculationMode(add) != DontSpeculateInteger; + return addSpeculationMode(add, add->child1()->shouldSpeculateIntegerExpectingDefined(), add->child2()->shouldSpeculateIntegerExpectingDefined()); } - bool mulShouldSpeculateInteger(Node& mul) + AddSpeculationMode arithAddSpeculationMode(Node* add) { - ASSERT(mul.op() == ArithMul); - - Node& left = at(mul.child1()); - Node& right = at(mul.child2()); + return addSpeculationMode(add, add->child1()->shouldSpeculateIntegerForArithmetic(), add->child2()->shouldSpeculateIntegerForArithmetic()); + } + + AddSpeculationMode addSpeculationMode(Node* add) + { + if (add->op() == ValueAdd) + return valueAddSpeculationMode(add); - return Node::shouldSpeculateIntegerForArithmetic(left, right) && mul.canSpeculateInteger(); + return arithAddSpeculationMode(add); + } + + bool addShouldSpeculateInteger(Node* add) + { + return addSpeculationMode(add) != DontSpeculateInteger; } - bool negateShouldSpeculateInteger(Node& negate) + bool mulShouldSpeculateInteger(Node* mul) { - ASSERT(negate.op() == ArithNegate); - return at(negate.child1()).shouldSpeculateIntegerForArithmetic() && negate.canSpeculateInteger(); + ASSERT(mul->op() == ArithMul); + + Node* left = mul->child1().node(); + Node* right = mul->child2().node(); + + return Node::shouldSpeculateIntegerForArithmetic(left, right) && mul->canSpeculateInteger(); } - bool addShouldSpeculateInteger(NodeIndex nodeIndex) + bool negateShouldSpeculateInteger(Node* negate) { - return addShouldSpeculateInteger(at(nodeIndex)); + ASSERT(negate->op() == ArithNegate); + return negate->child1()->shouldSpeculateIntegerForArithmetic() && negate->canSpeculateInteger(); } // Helper methods to check nodes for constants. - bool isConstant(NodeIndex nodeIndex) + bool isConstant(Node* node) { - return at(nodeIndex).hasConstant(); + return node->hasConstant(); } - bool isJSConstant(NodeIndex nodeIndex) + bool isJSConstant(Node* node) { - return at(nodeIndex).hasConstant(); + return node->hasConstant(); } - bool isInt32Constant(NodeIndex nodeIndex) + bool isInt32Constant(Node* node) { - return at(nodeIndex).isInt32Constant(m_codeBlock); + return node->isInt32Constant(m_codeBlock); } - bool isDoubleConstant(NodeIndex nodeIndex) + bool isDoubleConstant(Node* node) { - return at(nodeIndex).isDoubleConstant(m_codeBlock); + return node->isDoubleConstant(m_codeBlock); } - bool isNumberConstant(NodeIndex nodeIndex) + bool isNumberConstant(Node* node) { - return at(nodeIndex).isNumberConstant(m_codeBlock); + return node->isNumberConstant(m_codeBlock); } - bool isBooleanConstant(NodeIndex nodeIndex) + bool isBooleanConstant(Node* node) { - return at(nodeIndex).isBooleanConstant(m_codeBlock); + return node->isBooleanConstant(m_codeBlock); } - bool isCellConstant(NodeIndex nodeIndex) + bool isCellConstant(Node* node) { - if (!isJSConstant(nodeIndex)) + if (!isJSConstant(node)) return false; - JSValue value = valueOfJSConstant(nodeIndex); + JSValue value = valueOfJSConstant(node); return value.isCell() && !!value; } - bool isFunctionConstant(NodeIndex nodeIndex) + bool isFunctionConstant(Node* node) { - if (!isJSConstant(nodeIndex)) + if (!isJSConstant(node)) return false; - if (!getJSFunction(valueOfJSConstant(nodeIndex))) + if (!getJSFunction(valueOfJSConstant(node))) return false; return true; } - bool isInternalFunctionConstant(NodeIndex nodeIndex) + bool isInternalFunctionConstant(Node* node) { - if (!isJSConstant(nodeIndex)) + if (!isJSConstant(node)) return false; - JSValue value = valueOfJSConstant(nodeIndex); + JSValue value = valueOfJSConstant(node); if (!value.isCell() || !value) return false; JSCell* cell = value.asCell(); @@ -309,37 +309,31 @@ public: return true; } // Helper methods get constant values from nodes. - JSValue valueOfJSConstant(NodeIndex nodeIndex) + JSValue valueOfJSConstant(Node* node) { - return at(nodeIndex).valueOfJSConstant(m_codeBlock); + return node->valueOfJSConstant(m_codeBlock); } - int32_t valueOfInt32Constant(NodeIndex nodeIndex) + int32_t valueOfInt32Constant(Node* node) { - return valueOfJSConstant(nodeIndex).asInt32(); + return valueOfJSConstant(node).asInt32(); } - double valueOfNumberConstant(NodeIndex nodeIndex) + double valueOfNumberConstant(Node* node) { - return valueOfJSConstant(nodeIndex).asNumber(); + return valueOfJSConstant(node).asNumber(); } - bool valueOfBooleanConstant(NodeIndex nodeIndex) + bool valueOfBooleanConstant(Node* node) { - return valueOfJSConstant(nodeIndex).asBoolean(); + return valueOfJSConstant(node).asBoolean(); } - JSFunction* valueOfFunctionConstant(NodeIndex nodeIndex) + JSFunction* valueOfFunctionConstant(Node* node) { - JSCell* function = getJSFunction(valueOfJSConstant(nodeIndex)); + JSCell* function = getJSFunction(valueOfJSConstant(node)); ASSERT(function); return jsCast<JSFunction*>(function); } - InternalFunction* valueOfInternalFunctionConstant(NodeIndex nodeIndex) - { - return jsCast<InternalFunction*>(valueOfJSConstant(nodeIndex).asCell()); - } static const char *opName(NodeType); - void predictArgumentTypes(); - StructureSet* addStructureSet(const StructureSet& structureSet) { ASSERT(structureSet.size()); @@ -358,6 +352,12 @@ public: return m_codeBlock->globalObjectFor(codeOrigin); } + JSObject* globalThisObjectFor(CodeOrigin codeOrigin) + { + JSGlobalObject* object = globalObjectFor(codeOrigin); + return object->methodTable()->toThisObject(object, 0); + } + ExecutableBase* executableFor(InlineCallFrame* inlineCallFrame) { if (!inlineCallFrame) @@ -376,6 +376,16 @@ public: return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock); } + bool hasGlobalExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind) + { + return baselineCodeBlockFor(codeOrigin)->hasExitSite(FrequentExitSite(exitKind)); + } + + bool hasExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind) + { + return baselineCodeBlockFor(codeOrigin)->hasExitSite(FrequentExitSite(codeOrigin.bytecodeIndex, exitKind)); + } + int argumentsRegisterFor(const CodeOrigin& codeOrigin) { if (!codeOrigin.inlineCallFrame) @@ -400,51 +410,54 @@ public: codeOrigin.inlineCallFrame->stackOffset; } - int uncheckedActivationRegisterFor(const CodeOrigin& codeOrigin) + int uncheckedActivationRegisterFor(const CodeOrigin&) { - ASSERT_UNUSED(codeOrigin, !codeOrigin.inlineCallFrame); + // This will ignore CodeOrigin because we don't inline code that uses activations. + // Hence for inlined call frames it will return the outermost code block's + // activation register. This method is only used to compare the result to a local + // to see if we're mucking with the activation register. Hence if we return the + // "wrong" activation register for the frame then it will compare false, which is + // what we wanted. return m_codeBlock->uncheckedActivationRegister(); } - ValueProfile* valueProfileFor(NodeIndex nodeIndex) + ValueProfile* valueProfileFor(Node* node) { - if (nodeIndex == NoNode) + if (!node) return 0; - Node& node = at(nodeIndex); - CodeBlock* profiledBlock = baselineCodeBlockFor(node.codeOrigin); + CodeBlock* profiledBlock = baselineCodeBlockFor(node->codeOrigin); - if (node.hasLocal()) { - if (!operandIsArgument(node.local())) + if (node->hasLocal()) { + if (!operandIsArgument(node->local())) return 0; - int argument = operandToArgument(node.local()); - if (node.variableAccessData() != at(m_arguments[argument]).variableAccessData()) + int argument = operandToArgument(node->local()); + if (node->variableAccessData() != m_arguments[argument]->variableAccessData()) return 0; return profiledBlock->valueProfileForArgument(argument); } - if (node.hasHeapPrediction()) - return profiledBlock->valueProfileForBytecodeOffset(node.codeOrigin.bytecodeIndexForValueProfile()); + if (node->hasHeapPrediction()) + return profiledBlock->valueProfileForBytecodeOffset(node->codeOrigin.bytecodeIndexForValueProfile()); return 0; } - MethodOfGettingAValueProfile methodOfGettingAValueProfileFor(NodeIndex nodeIndex) + MethodOfGettingAValueProfile methodOfGettingAValueProfileFor(Node* node) { - if (nodeIndex == NoNode) + if (!node) return MethodOfGettingAValueProfile(); - Node& node = at(nodeIndex); - CodeBlock* profiledBlock = baselineCodeBlockFor(node.codeOrigin); + CodeBlock* profiledBlock = baselineCodeBlockFor(node->codeOrigin); - if (node.op() == GetLocal) { + if (node->op() == GetLocal) { return MethodOfGettingAValueProfile::fromLazyOperand( profiledBlock, LazyOperandValueProfileKey( - node.codeOrigin.bytecodeIndex, node.local())); + node->codeOrigin.bytecodeIndex, node->local())); } - return MethodOfGettingAValueProfile(valueProfileFor(nodeIndex)); + return MethodOfGettingAValueProfile(valueProfileFor(node)); } bool needsActivation() const @@ -457,33 +470,22 @@ public: return m_codeBlock->usesArguments(); } - bool isCreatedThisArgument(int operand) - { - if (!operandIsArgument(operand)) - return false; - if (operandToArgument(operand)) - return false; - return m_codeBlock->specializationKind() == CodeForConstruct; - } - unsigned numSuccessors(BasicBlock* block) { - return at(block->last()).numSuccessors(); + return block->last()->numSuccessors(); } BlockIndex successor(BasicBlock* block, unsigned index) { - return at(block->last()).successor(index); + return block->last()->successor(index); } BlockIndex successorForCondition(BasicBlock* block, bool condition) { - return at(block->last()).successorForCondition(condition); + return block->last()->successorForCondition(condition); } - bool isPredictedNumerical(Node& node) + bool isPredictedNumerical(Node* node) { - SpeculatedType left = at(node.child1()).prediction(); - SpeculatedType right = at(node.child2()).prediction(); - return isNumberSpeculation(left) && isNumberSpeculation(right); + return isNumerical(node->child1().useKind()) && isNumerical(node->child2().useKind()); } // Note that a 'true' return does not actually mean that the ByVal access clobbers nothing. @@ -492,23 +494,23 @@ public: // - PutByVal definitely changes the array it stores to, and may even change its length. // - PutByOffset definitely changes the object it stores to. // - and so on. - bool byValIsPure(Node& node) + bool byValIsPure(Node* node) { - switch (node.arrayMode().type()) { + switch (node->arrayMode().type()) { case Array::Generic: return false; case Array::Int32: case Array::Double: case Array::Contiguous: case Array::ArrayStorage: - return !node.arrayMode().isOutOfBounds(); + return !node->arrayMode().isOutOfBounds(); case Array::SlowPutArrayStorage: - return !node.arrayMode().mayStoreToHole(); + return !node->arrayMode().mayStoreToHole(); case Array::String: - return node.op() == GetByVal; + return node->op() == GetByVal; #if USE(JSVALUE32_64) case Array::Arguments: - if (node.op() == GetByVal) + if (node->op() == GetByVal) return true; return false; #endif // USE(JSVALUE32_64) @@ -517,13 +519,13 @@ public: } } - bool clobbersWorld(Node& node) + bool clobbersWorld(Node* node) { - if (node.flags() & NodeClobbersWorld) + if (node->flags() & NodeClobbersWorld) return true; - if (!(node.flags() & NodeMightClobber)) + if (!(node->flags() & NodeMightClobber)) return false; - switch (node.op()) { + switch (node->op()) { case ValueAdd: case CompareLess: case CompareLessEq: @@ -535,108 +537,119 @@ public: case PutByVal: case PutByValAlias: return !byValIsPure(node); + case ToString: + switch (node->child1().useKind()) { + case StringObjectUse: + case StringOrStringObjectUse: + return false; + case CellUse: + case UntypedUse: + return true; + default: + RELEASE_ASSERT_NOT_REACHED(); + return true; + } default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return true; // If by some oddity we hit this case in release build it's safer to have CSE assume the worst. } } - bool clobbersWorld(NodeIndex nodeIndex) - { - return clobbersWorld(at(nodeIndex)); - } - void determineReachability(); void resetReachability(); void resetExitStates(); - unsigned varArgNumChildren(Node& node) + unsigned varArgNumChildren(Node* node) { - ASSERT(node.flags() & NodeHasVarArgs); - return node.numChildren(); + ASSERT(node->flags() & NodeHasVarArgs); + return node->numChildren(); } - unsigned numChildren(Node& node) + unsigned numChildren(Node* node) { - if (node.flags() & NodeHasVarArgs) + if (node->flags() & NodeHasVarArgs) return varArgNumChildren(node); return AdjacencyList::Size; } - Edge& varArgChild(Node& node, unsigned index) + Edge& varArgChild(Node* node, unsigned index) { - ASSERT(node.flags() & NodeHasVarArgs); - return m_varArgChildren[node.firstChild() + index]; + ASSERT(node->flags() & NodeHasVarArgs); + return m_varArgChildren[node->firstChild() + index]; } - Edge& child(Node& node, unsigned index) + Edge& child(Node* node, unsigned index) { - if (node.flags() & NodeHasVarArgs) + if (node->flags() & NodeHasVarArgs) return varArgChild(node, index); - return node.children.child(index); + return node->children.child(index); } - void vote(Edge edge, unsigned ballot) + void voteNode(Node* node, unsigned ballot) { - switch (at(edge).op()) { + switch (node->op()) { case ValueToInt32: case UInt32ToNumber: - edge = at(edge).child1(); + node = node->child1().node(); break; default: break; } - if (at(edge).op() == GetLocal) - at(edge).variableAccessData()->vote(ballot); + if (node->op() == GetLocal) + node->variableAccessData()->vote(ballot); + } + + void voteNode(Edge edge, unsigned ballot) + { + voteNode(edge.node(), ballot); } - void vote(Node& node, unsigned ballot) + void voteChildren(Node* node, unsigned ballot) { - if (node.flags() & NodeHasVarArgs) { - for (unsigned childIdx = node.firstChild(); - childIdx < node.firstChild() + node.numChildren(); - childIdx++) { + if (node->flags() & NodeHasVarArgs) { + for (unsigned childIdx = node->firstChild(); + childIdx < node->firstChild() + node->numChildren(); + childIdx++) { if (!!m_varArgChildren[childIdx]) - vote(m_varArgChildren[childIdx], ballot); + voteNode(m_varArgChildren[childIdx], ballot); } return; } - if (!node.child1()) + if (!node->child1()) return; - vote(node.child1(), ballot); - if (!node.child2()) + voteNode(node->child1(), ballot); + if (!node->child2()) return; - vote(node.child2(), ballot); - if (!node.child3()) + voteNode(node->child2(), ballot); + if (!node->child3()) return; - vote(node.child3(), ballot); + voteNode(node->child3(), ballot); } - template<typename T> // T = NodeIndex or Edge + template<typename T> // T = Node* or Edge void substitute(BasicBlock& block, unsigned startIndexInBlock, T oldThing, T newThing) { for (unsigned indexInBlock = startIndexInBlock; indexInBlock < block.size(); ++indexInBlock) { - NodeIndex nodeIndex = block[indexInBlock]; - Node& node = at(nodeIndex); - if (node.flags() & NodeHasVarArgs) { - for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); ++childIdx) { + Node* node = block[indexInBlock]; + if (node->flags() & NodeHasVarArgs) { + for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); ++childIdx) { if (!!m_varArgChildren[childIdx]) - compareAndSwap(m_varArgChildren[childIdx], oldThing, newThing, node.shouldGenerate()); + compareAndSwap(m_varArgChildren[childIdx], oldThing, newThing); } continue; } - if (!node.child1()) + if (!node->child1()) continue; - compareAndSwap(node.children.child1(), oldThing, newThing, node.shouldGenerate()); - if (!node.child2()) + compareAndSwap(node->children.child1(), oldThing, newThing); + if (!node->child2()) continue; - compareAndSwap(node.children.child2(), oldThing, newThing, node.shouldGenerate()); - if (!node.child3()) + compareAndSwap(node->children.child2(), oldThing, newThing); + if (!node->child3()) continue; - compareAndSwap(node.children.child3(), oldThing, newThing, node.shouldGenerate()); + compareAndSwap(node->children.child3(), oldThing, newThing); } } @@ -644,29 +657,28 @@ public: // any GetLocals in the basic block. // FIXME: it may be appropriate, in the future, to generalize this to handle GetLocals // introduced anywhere in the basic block. - void substituteGetLocal(BasicBlock& block, unsigned startIndexInBlock, VariableAccessData* variableAccessData, NodeIndex newGetLocal) + void substituteGetLocal(BasicBlock& block, unsigned startIndexInBlock, VariableAccessData* variableAccessData, Node* newGetLocal) { if (variableAccessData->isCaptured()) { // Let CSE worry about this one. return; } for (unsigned indexInBlock = startIndexInBlock; indexInBlock < block.size(); ++indexInBlock) { - NodeIndex nodeIndex = block[indexInBlock]; - Node& node = at(nodeIndex); + Node* node = block[indexInBlock]; bool shouldContinue = true; - switch (node.op()) { + switch (node->op()) { case SetLocal: { - if (node.local() == variableAccessData->local()) + if (node->local() == variableAccessData->local()) shouldContinue = false; break; } case GetLocal: { - if (node.variableAccessData() != variableAccessData) + if (node->variableAccessData() != variableAccessData) continue; - substitute(block, indexInBlock, nodeIndex, newGetLocal); - NodeIndex oldTailIndex = block.variablesAtTail.operand(variableAccessData->local()); - if (oldTailIndex == nodeIndex) + substitute(block, indexInBlock, node, newGetLocal); + Node* oldTailNode = block.variablesAtTail.operand(variableAccessData->local()); + if (oldTailNode == node) block.variablesAtTail.operand(variableAccessData->local()) = newGetLocal; shouldContinue = false; break; @@ -680,9 +692,12 @@ public: } } - JSGlobalData& m_globalData; + VM& m_vm; CodeBlock* m_codeBlock; + RefPtr<Profiler::Compilation> m_compilation; CodeBlock* m_profiledBlock; + + NodeAllocator& m_allocator; Vector< OwnPtr<BasicBlock> , 8> m_blocks; Vector<Edge, 16> m_varArgChildren; @@ -690,7 +705,7 @@ public: Vector<ResolveGlobalData> m_resolveGlobalData; Vector<ResolveOperationData> m_resolveOperationsData; Vector<PutToBaseOperationData> m_putToBaseOperationData; - Vector<NodeIndex, 8> m_arguments; + Vector<Node*, 8> m_arguments; SegmentedVector<VariableAccessData, 16> m_variableAccessData; SegmentedVector<ArgumentPosition, 8> m_argumentPositions; SegmentedVector<StructureSet, 16> m_structureSet; @@ -706,41 +721,44 @@ public: Operands<JSValue> m_mustHandleValues; OptimizationFixpointState m_fixpointState; + GraphForm m_form; + UnificationState m_unificationState; + RefCountState m_refCountState; private: void handleSuccessor(Vector<BlockIndex, 16>& worklist, BlockIndex blockIndex, BlockIndex successorIndex); - AddSpeculationMode addImmediateShouldSpeculateInteger(Node& add, Node& variable, Node& immediate) + AddSpeculationMode addImmediateShouldSpeculateInteger(Node* add, bool variableShouldSpeculateInteger, Node* immediate) { - ASSERT(immediate.hasConstant()); + ASSERT(immediate->hasConstant()); - JSValue immediateValue = immediate.valueOfJSConstant(m_codeBlock); + JSValue immediateValue = immediate->valueOfJSConstant(m_codeBlock); if (!immediateValue.isNumber()) return DontSpeculateInteger; - if (!variable.shouldSpeculateIntegerExpectingDefined()) + if (!variableShouldSpeculateInteger) return DontSpeculateInteger; if (immediateValue.isInt32()) - return add.canSpeculateInteger() ? SpeculateInteger : DontSpeculateInteger; + return add->canSpeculateInteger() ? SpeculateInteger : DontSpeculateInteger; double doubleImmediate = immediateValue.asDouble(); const double twoToThe48 = 281474976710656.0; if (doubleImmediate < -twoToThe48 || doubleImmediate > twoToThe48) return DontSpeculateInteger; - return nodeCanTruncateInteger(add.arithNodeFlags()) ? SpeculateIntegerButAlwaysWatchOverflow : DontSpeculateInteger; + return nodeCanTruncateInteger(add->arithNodeFlags()) ? SpeculateIntegerAndTruncateConstants : DontSpeculateInteger; } - bool mulImmediateShouldSpeculateInteger(Node& mul, Node& variable, Node& immediate) + bool mulImmediateShouldSpeculateInteger(Node* mul, Node* variable, Node* immediate) { - ASSERT(immediate.hasConstant()); + ASSERT(immediate->hasConstant()); - JSValue immediateValue = immediate.valueOfJSConstant(m_codeBlock); + JSValue immediateValue = immediate->valueOfJSConstant(m_codeBlock); if (!immediateValue.isInt32()) return false; - if (!variable.shouldSpeculateIntegerForArithmetic()) + if (!variable->shouldSpeculateIntegerForArithmetic()) return false; int32_t intImmediate = immediateValue.asInt32(); @@ -751,14 +769,10 @@ private: // canSpeculateInteger() implies). const int32_t twoToThe22 = 1 << 22; if (intImmediate <= -twoToThe22 || intImmediate >= twoToThe22) - return mul.canSpeculateInteger() && !nodeMayOverflow(mul.arithNodeFlags()); + return mul->canSpeculateInteger() && !nodeMayOverflow(mul->arithNodeFlags()); - return mul.canSpeculateInteger(); + return mul->canSpeculateInteger(); } - - // When a node's refCount goes from 0 to 1, it must (logically) recursively ref all of its children, and vice versa. - void refChildren(NodeIndex); - void derefChildren(NodeIndex); }; class GetBytecodeBeginForBlock { @@ -779,9 +793,39 @@ private: inline BlockIndex Graph::blockIndexForBytecodeOffset(Vector<BlockIndex>& linkingTargets, unsigned bytecodeBegin) { - return *WTF::binarySearchWithFunctor<BlockIndex, unsigned>(linkingTargets.begin(), linkingTargets.size(), bytecodeBegin, WTF::KeyMustBePresentInArray, GetBytecodeBeginForBlock(*this)); + return *binarySearch<BlockIndex, unsigned>(linkingTargets, linkingTargets.size(), bytecodeBegin, GetBytecodeBeginForBlock(*this)); } +#define DFG_NODE_DO_TO_CHILDREN(graph, node, thingToDo) do { \ + Node* _node = (node); \ + if (_node->flags() & NodeHasVarArgs) { \ + for (unsigned _childIdx = _node->firstChild(); \ + _childIdx < _node->firstChild() + _node->numChildren(); \ + _childIdx++) { \ + if (!!(graph).m_varArgChildren[_childIdx]) \ + thingToDo(_node, (graph).m_varArgChildren[_childIdx]); \ + } \ + } else { \ + if (!_node->child1()) { \ + ASSERT( \ + !_node->child2() \ + && !_node->child3()); \ + break; \ + } \ + thingToDo(_node, _node->child1()); \ + \ + if (!_node->child2()) { \ + ASSERT(!_node->child3()); \ + break; \ + } \ + thingToDo(_node, _node->child2()); \ + \ + if (!_node->child3()) \ + break; \ + thingToDo(_node, _node->child3()); \ + } \ + } while (false) + } } // namespace JSC::DFG #endif |