diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp | 224 |
1 files changed, 146 insertions, 78 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp index 2f06646aa..bf651886e 100644 --- a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.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,17 +44,21 @@ public: bool run() { - for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { - BasicBlock* block = m_graph.m_blocks[blockIndex].get(); - if (!block) - continue; - - // Prevent a tower of overflowing additions from creating a value that is out of the - // safe 2^48 range. - m_allowNestedOverflowingAdditions = block->size() < (1 << 16); - - for (unsigned indexInBlock = block->size(); indexInBlock--;) - propagate(block->at(indexInBlock)); + m_changed = true; + while (m_changed) { + m_changed = false; + for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { + BasicBlock* block = m_graph.block(blockIndex); + if (!block) + continue; + + // Prevent a tower of overflowing additions from creating a value that is out of the + // safe 2^48 range. + m_allowNestedOverflowingAdditions = block->size() < (1 << 16); + + for (unsigned indexInBlock = block->size(); indexInBlock--;) + propagate(block->at(indexInBlock)); + } } return true; @@ -63,17 +67,17 @@ public: private: bool isNotNegZero(Node* node) { - if (!m_graph.isNumberConstant(node)) + if (!node->isNumberConstant()) return false; - double value = m_graph.valueOfNumberConstant(node); + double value = node->asNumber(); return (value || 1.0 / value > 0.0); } bool isNotPosZero(Node* node) { - if (!m_graph.isNumberConstant(node)) + if (!node->isNumberConstant()) return false; - double value = m_graph.valueOfNumberConstant(node); + double value = node->asNumber(); return (value || 1.0 / value < 0.0); } @@ -81,7 +85,7 @@ private: template<int power> bool isWithinPowerOfTwoForConstant(Node* node) { - JSValue immediateValue = node->valueOfJSConstant(codeBlock()); + JSValue immediateValue = node->asJSValue(); if (!immediateValue.isNumber()) return false; double immediate = immediateValue.asNumber(); @@ -91,7 +95,7 @@ private: template<int power> bool isWithinPowerOfTwoNonRecursive(Node* node) { - if (node->op() != JSConstant) + if (!node->isNumberConstant()) return false; return isWithinPowerOfTwoForConstant<power>(node); } @@ -100,7 +104,9 @@ private: bool isWithinPowerOfTwo(Node* node) { switch (node->op()) { - case JSConstant: { + case DoubleConstant: + case JSConstant: + case Int52Constant: { return isWithinPowerOfTwoForConstant<power>(node); } @@ -114,8 +120,7 @@ private: case BitOr: case BitXor: - case BitLShift: - case ValueToInt32: { + case BitLShift: { return power > 31; } @@ -125,9 +130,9 @@ private: return true; Node* shiftAmount = node->child2().node(); - if (shiftAmount->op() != JSConstant) + if (!node->isNumberConstant()) return false; - JSValue immediateValue = shiftAmount->valueOfJSConstant(codeBlock()); + JSValue immediateValue = shiftAmount->asJSValue(); if (!immediateValue.isInt32()) return false; return immediateValue.asInt32() > 32 - power; @@ -152,30 +157,31 @@ private: childIdx < node->firstChild() + node->numChildren(); childIdx++) { if (!!m_graph.m_varArgChildren[childIdx]) - changed |= m_graph.m_varArgChildren[childIdx]->mergeFlags(NodeUsedAsValue); + changed |= m_graph.m_varArgChildren[childIdx]->mergeFlags(NodeBytecodeUsesAsValue); } } else { if (!node->child1()) return changed; - changed |= node->child1()->mergeFlags(NodeUsedAsValue); + changed |= node->child1()->mergeFlags(NodeBytecodeUsesAsValue); if (!node->child2()) return changed; - changed |= node->child2()->mergeFlags(NodeUsedAsValue); + changed |= node->child2()->mergeFlags(NodeBytecodeUsesAsValue); if (!node->child3()) return changed; - changed |= node->child3()->mergeFlags(NodeUsedAsValue); + changed |= node->child3()->mergeFlags(NodeBytecodeUsesAsValue); } return changed; } void propagate(Node* node) { - NodeFlags flags = node->flags() & NodeBackPropMask; + NodeFlags flags = node->flags() & NodeBytecodeBackPropMask; switch (node->op()) { case GetLocal: { VariableAccessData* variableAccessData = node->variableAccessData(); - variableAccessData->mergeFlags(flags); + flags &= ~NodeBytecodeUsesAsInt; // We don't care about cross-block uses-as-int. + m_changed |= variableAccessData->mergeFlags(flags); break; } @@ -183,10 +189,23 @@ private: VariableAccessData* variableAccessData = node->variableAccessData(); if (!variableAccessData->isLoadedFrom()) break; - node->child1()->mergeFlags(NodeUsedAsValue); + flags = variableAccessData->flags(); + RELEASE_ASSERT(!(flags & ~NodeBytecodeBackPropMask)); + flags |= NodeBytecodeUsesAsNumber; // Account for the fact that control flow may cause overflows that our modeling can't handle. + node->child1()->mergeFlags(flags); break; } + case Flush: { + VariableAccessData* variableAccessData = node->variableAccessData(); + m_changed |= variableAccessData->mergeFlags(NodeBytecodeUsesAsValue); + break; + } + + case MovHint: + case Check: + break; + case BitAnd: case BitOr: case BitXor: @@ -194,27 +213,20 @@ private: case BitLShift: case BitURShift: case ArithIMul: { - flags |= NodeUsedAsInt; - flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther); + flags |= NodeBytecodeUsesAsInt; + flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther); + flags &= ~NodeBytecodeUsesAsArrayIndex; node->child1()->mergeFlags(flags); node->child2()->mergeFlags(flags); break; } - case ValueToInt32: { - flags |= NodeUsedAsInt; - flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther); - node->child1()->mergeFlags(flags); - break; - } - case StringCharCodeAt: { - node->child1()->mergeFlags(NodeUsedAsValue); - node->child2()->mergeFlags(NodeUsedAsValue | NodeUsedAsInt); + node->child1()->mergeFlags(NodeBytecodeUsesAsValue); + node->child2()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex); break; } - case Identity: case UInt32ToNumber: { node->child1()->mergeFlags(flags); break; @@ -222,39 +234,46 @@ private: case ValueAdd: { if (isNotNegZero(node->child1().node()) || isNotNegZero(node->child2().node())) - flags &= ~NodeNeedsNegZero; + flags &= ~NodeBytecodeNeedsNegZero; if (node->child1()->hasNumberResult() || node->child2()->hasNumberResult()) - flags &= ~NodeUsedAsOther; + flags &= ~NodeBytecodeUsesAsOther; if (!isWithinPowerOfTwo<32>(node->child1()) && !isWithinPowerOfTwo<32>(node->child2())) - flags |= NodeUsedAsNumber; + flags |= NodeBytecodeUsesAsNumber; if (!m_allowNestedOverflowingAdditions) - flags |= NodeUsedAsNumber; + flags |= NodeBytecodeUsesAsNumber; node->child1()->mergeFlags(flags); node->child2()->mergeFlags(flags); break; } - + case ArithAdd: { if (isNotNegZero(node->child1().node()) || isNotNegZero(node->child2().node())) - flags &= ~NodeNeedsNegZero; + flags &= ~NodeBytecodeNeedsNegZero; if (!isWithinPowerOfTwo<32>(node->child1()) && !isWithinPowerOfTwo<32>(node->child2())) - flags |= NodeUsedAsNumber; + flags |= NodeBytecodeUsesAsNumber; if (!m_allowNestedOverflowingAdditions) - flags |= NodeUsedAsNumber; + flags |= NodeBytecodeUsesAsNumber; node->child1()->mergeFlags(flags); node->child2()->mergeFlags(flags); break; } - + + case ArithClz32: { + flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther | ~NodeBytecodeUsesAsArrayIndex); + flags |= NodeBytecodeUsesAsInt; + node->child1()->mergeFlags(flags); + break; + } + case ArithSub: { if (isNotNegZero(node->child1().node()) || isNotPosZero(node->child2().node())) - flags &= ~NodeNeedsNegZero; + flags &= ~NodeBytecodeNeedsNegZero; if (!isWithinPowerOfTwo<32>(node->child1()) && !isWithinPowerOfTwo<32>(node->child2())) - flags |= NodeUsedAsNumber; + flags |= NodeBytecodeUsesAsNumber; if (!m_allowNestedOverflowingAdditions) - flags |= NodeUsedAsNumber; + flags |= NodeBytecodeUsesAsNumber; node->child1()->mergeFlags(flags); node->child2()->mergeFlags(flags); @@ -262,7 +281,7 @@ private: } case ArithNegate: { - flags &= ~NodeUsedAsOther; + flags &= ~NodeBytecodeUsesAsOther; node->child1()->mergeFlags(flags); break; @@ -278,12 +297,12 @@ private: if (!isWithinPowerOfTwo<22>(node->child1().node()) && !isWithinPowerOfTwo<22>(node->child2().node())) - flags |= NodeUsedAsNumber; + flags |= NodeBytecodeUsesAsNumber; node->mergeFlags(flags); - flags |= NodeUsedAsNumber | NodeNeedsNegZero; - flags &= ~NodeUsedAsOther; + flags |= NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero; + flags &= ~NodeBytecodeUsesAsOther; node->child1()->mergeFlags(flags); node->child2()->mergeFlags(flags); @@ -291,8 +310,8 @@ private: } case ArithDiv: { - flags |= NodeUsedAsNumber | NodeNeedsNegZero; - flags &= ~NodeUsedAsOther; + flags |= NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero; + flags &= ~NodeBytecodeUsesAsOther; node->child1()->mergeFlags(flags); node->child2()->mergeFlags(flags); @@ -300,38 +319,42 @@ private: } case ArithMod: { - flags |= NodeUsedAsNumber | NodeNeedsNegZero; - flags &= ~NodeUsedAsOther; + flags |= NodeBytecodeUsesAsNumber; + flags &= ~NodeBytecodeUsesAsOther; node->child1()->mergeFlags(flags); - node->child2()->mergeFlags(flags); + node->child2()->mergeFlags(flags & ~NodeBytecodeNeedsNegZero); break; } case GetByVal: { - node->child1()->mergeFlags(NodeUsedAsValue); - node->child2()->mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt); + node->child1()->mergeFlags(NodeBytecodeUsesAsValue); + node->child2()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex); break; } - case GetMyArgumentByValSafe: { - node->child1()->mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt); + case NewArrayWithSize: { + node->child1()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex); break; } - case NewArrayWithSize: { - node->child1()->mergeFlags(NodeUsedAsValue | NodeUsedAsInt); + case NewTypedArray: { + // Negative zero is not observable. NaN versus undefined are only observable + // in that you would get a different exception message. So, like, whatever: we + // claim here that NaN v. undefined is observable. + node->child1()->mergeFlags(NodeBytecodeUsesAsInt | NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsArrayIndex); break; } case StringCharAt: { - node->child1()->mergeFlags(NodeUsedAsValue); - node->child2()->mergeFlags(NodeUsedAsValue | NodeUsedAsInt); + node->child1()->mergeFlags(NodeBytecodeUsesAsValue); + node->child2()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex); break; } - case ToString: { - node->child1()->mergeFlags(NodeUsedAsNumber | NodeUsedAsOther); + case ToString: + case CallStringConstructor: { + node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther); break; } @@ -339,14 +362,58 @@ private: node->child1()->mergeFlags(flags); break; } - + + case PutByValDirect: case PutByVal: { - m_graph.varArgChild(node, 0)->mergeFlags(NodeUsedAsValue); - m_graph.varArgChild(node, 1)->mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt); - m_graph.varArgChild(node, 2)->mergeFlags(NodeUsedAsValue); + m_graph.varArgChild(node, 0)->mergeFlags(NodeBytecodeUsesAsValue); + m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex); + m_graph.varArgChild(node, 2)->mergeFlags(NodeBytecodeUsesAsValue); break; } + case Switch: { + SwitchData* data = node->switchData(); + switch (data->kind) { + case SwitchImm: + // We don't need NodeBytecodeNeedsNegZero because if the cases are all integers + // then -0 and 0 are treated the same. We don't need NodeBytecodeUsesAsOther + // because if all of the cases are integers then NaN and undefined are + // treated the same (i.e. they will take default). + node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsInt); + break; + case SwitchChar: { + // We don't need NodeBytecodeNeedsNegZero because if the cases are all strings + // then -0 and 0 are treated the same. We don't need NodeBytecodeUsesAsOther + // because if all of the cases are single-character strings then NaN + // and undefined are treated the same (i.e. they will take default). + node->child1()->mergeFlags(NodeBytecodeUsesAsNumber); + break; + } + case SwitchString: + // We don't need NodeBytecodeNeedsNegZero because if the cases are all strings + // then -0 and 0 are treated the same. + node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther); + break; + case SwitchCell: + // There is currently no point to being clever here since this is used for switching + // on objects. + mergeDefaultFlags(node); + break; + } + break; + } + + case Identity: + // This would be trivial to handle but we just assert that we cannot see these yet. + RELEASE_ASSERT_NOT_REACHED(); + break; + + // Note: ArithSqrt, ArithSin, and ArithCos and other math intrinsics don't have special + // rules in here because they are always followed by Phantoms to signify that if the + // method call speculation fails, the bytecode may use the arguments in arbitrary ways. + // This corresponds to that possibility of someone doing something like: + // Math.sin = function(x) { doArbitraryThingsTo(x); } + default: mergeDefaultFlags(node); break; @@ -354,6 +421,7 @@ private: } bool m_allowNestedOverflowingAdditions; + bool m_changed; }; bool performBackwardsPropagation(Graph& graph) |