Changeset 145299 in webkit
- Timestamp:
- Mar 8, 2013, 6:51:06 PM (12 years ago)
- Location:
- trunk
- Files:
-
- 8 added
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r145298 r145299 1 2013-03-08 Filip Pizlo <[email protected]> 2 3 DFG overflow check elimination is too smart for its own good 4 https://bugs.webkit.org/show_bug.cgi?id=111832 5 6 Reviewed by Oliver Hunt and Gavin Barraclough. 7 8 * fast/js/dfg-arith-add-overflow-check-elimination-predicted-but-not-proven-int-expected.txt: Added. 9 * fast/js/dfg-arith-add-overflow-check-elimination-predicted-but-not-proven-int.html: Added. 10 * fast/js/dfg-arith-add-overflow-check-elimination-tower-of-large-numbers-expected.txt: Added. 11 * fast/js/dfg-arith-add-overflow-check-elimination-tower-of-large-numbers.html: Added. 12 * fast/js/jsc-test-list: 13 * fast/js/script-tests/dfg-arith-add-overflow-check-elimination-predicted-but-not-proven-int.js: Added. 14 (foo): 15 (bar): 16 * fast/js/script-tests/dfg-arith-add-overflow-check-elimination-tower-of-large-numbers.js: Added. 17 (foo): 18 (bar): 19 1 20 2013-03-08 James Robinson <[email protected]> 2 21 -
trunk/LayoutTests/fast/js/jsc-test-list
r145145 r145299 83 83 fast/js/dfg-arguments-out-of-bounds 84 84 fast/js/dfg-arguments-unexpected-escape 85 fast/js/dfg-arith-add-overflow-check-elimination-tower-of-large-numbers 86 fast/js/dfg-arith-add-overflow-check-elimination-predicted-but-not-proven-int 85 87 fast/js/dfg-arrayify-elimination 86 88 fast/js/dfg-arrayify-when-late-prevent-extensions -
trunk/Source/JavaScriptCore/CMakeLists.txt
r145119 r145299 79 79 dfg/DFGArrayMode.cpp 80 80 dfg/DFGAssemblyHelpers.cpp 81 dfg/DFGBackwardsPropagationPhase.cpp 81 82 dfg/DFGByteCodeParser.cpp 82 83 dfg/DFGCapabilities.cpp -
trunk/Source/JavaScriptCore/ChangeLog
r145247 r145299 1 2013-03-08 Filip Pizlo <[email protected]> 2 3 DFG overflow check elimination is too smart for its own good 4 https://bugs.webkit.org/show_bug.cgi?id=111832 5 6 Reviewed by Oliver Hunt and Gavin Barraclough. 7 8 This improves overflow check elimination in three ways: 9 10 1) It reduces the amount of time the compiler will spend doing it. 11 12 2) It fixes bugs where overflow check elimination was overzealous. Precisely, for a binary operation 13 over @a and @b where both @a and @b will type check that their inputs (@a->children, @b->children) 14 are int32's and then perform a possibly-overflowing operation, we must be careful not to assume 15 that @a's non-int32 parts don't matter if at the point that @a runs we have as yet not proved that 16 @b->children are int32's and that hence @b might produce a large enough result that doubles would 17 start chopping low bits. The specific implication of this is that for a binary operation to not 18 propagate that it cares about non-int32 parts (NodeUsedAsNumber), we must prove that at least one 19 of the inputs is guaranteed to produce a result within 2^32 and that there won't be a tower of such 20 operations large enough to ultimately produce a double greater than 2^52 (roughly). We achieve the 21 latter by disabling this optimization for very large basic blocks. It's noteworthy that blocks that 22 large won't even make it into the DFG currently. 23 24 3) It makes the overflow check elimination more precise for cases where the inputs to an Add or Sub 25 are the outputs of a bit-op. For example in (@a + (@b | 0)) | 0, we don't need to propagate 26 NodeUsedAsNumber to either @a or @b. 27 28 This is neutral on V8v7 and a slight speed-up on compile time benchmarks. 29 30 * CMakeLists.txt: 31 * GNUmakefile.list.am: 32 * JavaScriptCore.xcodeproj/project.pbxproj: 33 * Target.pri: 34 * dfg/DFGArrayMode.cpp: 35 (JSC::DFG::ArrayMode::refine): 36 * dfg/DFGBackwardsPropagationPhase.cpp: Added. 37 (DFG): 38 (BackwardsPropagationPhase): 39 (JSC::DFG::BackwardsPropagationPhase::BackwardsPropagationPhase): 40 (JSC::DFG::BackwardsPropagationPhase::run): 41 (JSC::DFG::BackwardsPropagationPhase::isNotNegZero): 42 (JSC::DFG::BackwardsPropagationPhase::isNotZero): 43 (JSC::DFG::BackwardsPropagationPhase::isWithinPowerOfTwoForConstant): 44 (JSC::DFG::BackwardsPropagationPhase::isWithinPowerOfTwoNonRecursive): 45 (JSC::DFG::BackwardsPropagationPhase::isWithinPowerOfTwo): 46 (JSC::DFG::BackwardsPropagationPhase::mergeDefaultFlags): 47 (JSC::DFG::BackwardsPropagationPhase::propagate): 48 (JSC::DFG::performBackwardsPropagation): 49 * dfg/DFGBackwardsPropagationPhase.h: Added. 50 (DFG): 51 * dfg/DFGCPSRethreadingPhase.cpp: 52 (JSC::DFG::CPSRethreadingPhase::run): 53 (JSC::DFG::CPSRethreadingPhase::clearIsLoadedFrom): 54 (CPSRethreadingPhase): 55 (JSC::DFG::CPSRethreadingPhase::canonicalizeGetLocalFor): 56 (JSC::DFG::CPSRethreadingPhase::canonicalizeFlushOrPhantomLocalFor): 57 * dfg/DFGDriver.cpp: 58 (JSC::DFG::compile): 59 * dfg/DFGGraph.cpp: 60 (JSC::DFG::Graph::dump): 61 * dfg/DFGNodeFlags.cpp: 62 (JSC::DFG::dumpNodeFlags): 63 (DFG): 64 * dfg/DFGNodeFlags.h: 65 (DFG): 66 * dfg/DFGPredictionPropagationPhase.cpp: 67 (PredictionPropagationPhase): 68 (JSC::DFG::PredictionPropagationPhase::propagate): 69 * dfg/DFGUnificationPhase.cpp: 70 (JSC::DFG::UnificationPhase::run): 71 * dfg/DFGVariableAccessData.h: 72 (JSC::DFG::VariableAccessData::VariableAccessData): 73 (JSC::DFG::VariableAccessData::mergeIsLoadedFrom): 74 (VariableAccessData): 75 (JSC::DFG::VariableAccessData::setIsLoadedFrom): 76 (JSC::DFG::VariableAccessData::isLoadedFrom): 77 1 78 2013-03-08 Roger Fong <[email protected]> 2 79 -
trunk/Source/JavaScriptCore/GNUmakefile.list.am
r145119 r145299 185 185 Source/JavaScriptCore/dfg/DFGAssemblyHelpers.cpp \ 186 186 Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h \ 187 Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp \ 188 Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.h \ 187 189 Source/JavaScriptCore/dfg/DFGBasicBlock.h \ 188 190 Source/JavaScriptCore/dfg/DFGBasicBlockInlines.h \ -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r145119 r145299 164 164 0F66E16B14DF3F1600B7B2E4 /* DFGAdjacencyList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */; settings = {ATTRIBUTES = (Private, ); }; }; 165 165 0F66E16C14DF3F1600B7B2E4 /* DFGEdge.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */; settings = {ATTRIBUTES = (Private, ); }; }; 166 0F714CA416EA92F000F3EBEB /* DFGBackwardsPropagationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F714CA116EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.cpp */; }; 167 0F714CA516EA92F200F3EBEB /* DFGBackwardsPropagationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F714CA216EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 166 168 0F73D7AE165A142D00ACAB71 /* ClosureCallStubRoutine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F73D7AB165A142A00ACAB71 /* ClosureCallStubRoutine.cpp */; }; 167 169 0F73D7AF165A143000ACAB71 /* ClosureCallStubRoutine.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F73D7AC165A142A00ACAB71 /* ClosureCallStubRoutine.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 1064 1066 0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAdjacencyList.h; path = dfg/DFGAdjacencyList.h; sourceTree = "<group>"; }; 1065 1067 0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGEdge.h; path = dfg/DFGEdge.h; sourceTree = "<group>"; }; 1068 0F714CA116EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGBackwardsPropagationPhase.cpp; path = dfg/DFGBackwardsPropagationPhase.cpp; sourceTree = "<group>"; }; 1069 0F714CA216EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBackwardsPropagationPhase.h; path = dfg/DFGBackwardsPropagationPhase.h; sourceTree = "<group>"; }; 1066 1070 0F73D7AB165A142A00ACAB71 /* ClosureCallStubRoutine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClosureCallStubRoutine.cpp; sourceTree = "<group>"; }; 1067 1071 0F73D7AC165A142A00ACAB71 /* ClosureCallStubRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClosureCallStubRoutine.h; sourceTree = "<group>"; }; … … 2637 2641 0FC0976B1468AB4A00CF2442 /* DFGAssemblyHelpers.cpp */, 2638 2642 0FC0976C1468AB4A00CF2442 /* DFGAssemblyHelpers.h */, 2643 0F714CA116EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.cpp */, 2644 0F714CA216EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.h */, 2639 2645 0F620170143FCD2F0068B77C /* DFGBasicBlock.h */, 2640 2646 0FD5652216AB780A00197653 /* DFGBasicBlockInlines.h */, … … 3409 3415 0FFB922016D033B70055A5DB /* NodeConstructors.h in Headers */, 3410 3416 0FCCAE4516D0CF7400D0C65B /* ParserError.h in Headers */, 3417 0F714CA516EA92F200F3EBEB /* DFGBackwardsPropagationPhase.h in Headers */, 3411 3418 ); 3412 3419 runOnlyForDeploymentPostprocessing = 0; … … 4052 4059 0F493AFA16D0CAD30084508B /* SourceProvider.cpp in Sources */, 4053 4060 ADE39FFF16DD144B0003CD4A /* PropertyTable.cpp in Sources */, 4061 0F714CA416EA92F000F3EBEB /* DFGBackwardsPropagationPhase.cpp in Sources */, 4054 4062 ); 4055 4063 runOnlyForDeploymentPostprocessing = 0; -
trunk/Source/JavaScriptCore/Target.pri
r145119 r145299 115 115 dfg/DFGArrayMode.cpp \ 116 116 dfg/DFGAssemblyHelpers.cpp \ 117 dfg/DFGBackwardsPropagationPhase.cpp \ 117 118 dfg/DFGByteCodeParser.cpp \ 118 119 dfg/DFGCapabilities.cpp \ -
trunk/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
r141069 r145299 168 168 169 169 case Array::Double: 170 if (flags & NodeUsedAsInt Locally)170 if (flags & NodeUsedAsInt) 171 171 return withTypeAndConversion(Array::Contiguous, Array::RageConvert); 172 172 if (!value || isNumberSpeculation(value)) … … 175 175 176 176 case Array::Contiguous: 177 if (doesConversion() && (flags & NodeUsedAsInt Locally))177 if (doesConversion() && (flags & NodeUsedAsInt)) 178 178 return withConversion(Array::RageConvert); 179 179 return *this; -
trunk/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp
r144862 r145299 48 48 return false; 49 49 50 clearIsLoadedFrom(); 50 51 freeUnnecessaryNodes(); 51 52 canonicalizeLocalsInBlocks(); … … 58 59 59 60 private: 61 62 void clearIsLoadedFrom() 63 { 64 for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) 65 m_graph.m_variableAccessData[i].setIsLoadedFrom(false); 66 } 60 67 61 68 void freeUnnecessaryNodes() … … 171 178 172 179 if (otherNode->op() == SetArgument) { 180 variable->setIsLoadedFrom(true); 173 181 node->children.setChild1(Edge(otherNode)); 174 182 m_block->variablesAtTail.atFor<operandKind>(idx) = node; … … 177 185 178 186 if (variable->isCaptured()) { 187 variable->setIsLoadedFrom(true); 179 188 if (otherNode->op() == GetLocal) 180 189 otherNode = otherNode->child1().node(); … … 201 210 } 202 211 212 variable->setIsLoadedFrom(true); 203 213 Node* phi = addPhi<operandKind>(node->codeOrigin, variable, idx); 204 214 node->children.setChild1(Edge(phi)); … … 257 267 } 258 268 269 variable->setIsLoadedFrom(true); 259 270 // There is nothing wrong with having redundant Flush's. It just needs to 260 271 // be linked appropriately. Note that if there had already been a previous … … 267 278 } 268 279 280 variable->setIsLoadedFrom(true); 269 281 node->children.setChild1(Edge(addPhi<operandKind>(node->codeOrigin, variable, idx))); 270 282 m_block->variablesAtHead.atFor<operandKind>(idx) = node; -
trunk/Source/JavaScriptCore/dfg/DFGDriver.cpp
r145143 r145299 34 34 35 35 #include "DFGArgumentsSimplificationPhase.h" 36 #include "DFGBackwardsPropagationPhase.h" 36 37 #include "DFGByteCodeParser.h" 37 38 #include "DFGCFAPhase.h" … … 123 124 validate(dfg); 124 125 126 performBackwardsPropagation(dfg); 125 127 performPredictionPropagation(dfg); 126 128 performFixup(dfg); -
trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp
r144862 r145299 180 180 } 181 181 182 if ( strlen(nodeFlagsAsString(node->flags())))183 out.print(comma, nodeFlagsAsString(node->flags()));182 if (toCString(NodeFlagsDump(node->flags())) != "<empty>") 183 out.print(comma, NodeFlagsDump(node->flags())); 184 184 if (node->hasArrayMode()) 185 185 out.print(comma, node->arrayMode()); -
trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp
r144362 r145299 29 29 #if ENABLE(DFG_JIT) 30 30 31 #include <wtf/ BoundsCheckedPointer.h>31 #include <wtf/CommaPrinter.h> 32 32 33 33 namespace JSC { namespace DFG { 34 34 35 const char* nodeFlagsAsString(NodeFlags flags)35 void dumpNodeFlags(PrintStream& out, NodeFlags flags) 36 36 { 37 if (!(flags ^ NodeDoesNotExit)) 38 return "<empty>"; 37 if (!(flags ^ NodeDoesNotExit)) { 38 out.print("<empty>"); 39 return; 40 } 39 41 40 static const int size = 128; 41 static char description[size]; 42 BoundsCheckedPointer<char> ptr(description, size); 43 44 bool hasPrinted = false; 42 CommaPrinter comma("|"); 45 43 46 44 if (flags & NodeResultMask) { 47 45 switch (flags & NodeResultMask) { 48 46 case NodeResultJS: 49 ptr.strcat("JS");47 out.print(comma, "JS"); 50 48 break; 51 49 case NodeResultNumber: 52 ptr.strcat("Number");50 out.print(comma, "Number"); 53 51 break; 54 52 case NodeResultInt32: 55 ptr.strcat("Int32");53 out.print(comma, "Int32"); 56 54 break; 57 55 case NodeResultBoolean: 58 ptr.strcat("Boolean");56 out.print(comma, "Boolean"); 59 57 break; 60 58 case NodeResultStorage: 61 ptr.strcat("Storage");59 out.print(comma, "Storage"); 62 60 break; 63 61 default: … … 65 63 break; 66 64 } 67 hasPrinted = true;68 65 } 69 66 70 if (flags & NodeMustGenerate) { 71 if (hasPrinted) 72 ptr.strcat("|"); 73 ptr.strcat("MustGen"); 74 hasPrinted = true; 67 if (flags & NodeMustGenerate) 68 out.print(comma, "MustGen"); 69 70 if (flags & NodeHasVarArgs) 71 out.print(comma, "VarArgs"); 72 73 if (flags & NodeClobbersWorld) 74 out.print(comma, "Clobbers"); 75 76 if (flags & NodeMightClobber) 77 out.print(comma, "MightClobber"); 78 79 if (flags & NodeResultMask) { 80 if (!(flags & NodeUsedAsNumber) && !(flags & NodeNeedsNegZero)) 81 out.print(comma, "PureInt"); 82 else if (!(flags & NodeUsedAsNumber)) 83 out.print(comma, "PureInt(w/ neg zero)"); 84 else if (!(flags & NodeNeedsNegZero)) 85 out.print(comma, "PureNum"); 86 if (flags & NodeUsedAsOther) 87 out.print(comma, "UseAsOther"); 75 88 } 76 89 77 if (flags & NodeHasVarArgs) { 78 if (hasPrinted) 79 ptr.strcat("|"); 80 ptr.strcat("VarArgs"); 81 hasPrinted = true; 82 } 90 if (flags & NodeMayOverflow) 91 out.print(comma, "MayOverflow"); 83 92 84 if (flags & NodeClobbersWorld) { 85 if (hasPrinted) 86 ptr.strcat("|"); 87 ptr.strcat("Clobbers"); 88 hasPrinted = true; 89 } 93 if (flags & NodeMayNegZero) 94 out.print(comma, "MayNegZero"); 90 95 91 if (flags & NodeMightClobber) { 92 if (hasPrinted) 93 ptr.strcat("|"); 94 ptr.strcat("MightClobber"); 95 hasPrinted = true; 96 } 96 if (flags & NodeUsedAsInt) 97 out.print(comma, "UseAsInt"); 97 98 98 if (flags & NodeResultMask) { 99 if (!(flags & NodeUsedAsNumber) && !(flags & NodeNeedsNegZero)) { 100 if (hasPrinted) 101 ptr.strcat("|"); 102 ptr.strcat("PureInt"); 103 hasPrinted = true; 104 } else if (!(flags & NodeUsedAsNumber)) { 105 if (hasPrinted) 106 ptr.strcat("|"); 107 ptr.strcat("PureInt(w/ neg zero)"); 108 hasPrinted = true; 109 } else if (!(flags & NodeNeedsNegZero)) { 110 if (hasPrinted) 111 ptr.strcat("|"); 112 ptr.strcat("PureNum"); 113 hasPrinted = true; 114 } 115 if (flags & NodeUsedAsOther) { 116 if (hasPrinted) 117 ptr.strcat("|"); 118 ptr.strcat("UseAsOther"); 119 hasPrinted = true; 120 } 121 } 99 if (!(flags & NodeDoesNotExit)) 100 out.print(comma, "CanExit"); 122 101 123 if (flags & NodeMayOverflow) { 124 if (hasPrinted) 125 ptr.strcat("|"); 126 ptr.strcat("MayOverflow"); 127 hasPrinted = true; 128 } 129 130 if (flags & NodeMayNegZero) { 131 if (hasPrinted) 132 ptr.strcat("|"); 133 ptr.strcat("MayNegZero"); 134 hasPrinted = true; 135 } 136 137 if (flags & NodeUsedAsInt) { 138 if (hasPrinted) 139 ptr.strcat("|"); 140 ptr.strcat("UseAsInt"); 141 hasPrinted = true; 142 } 143 144 if (!(flags & NodeDoesNotExit)) { 145 if (hasPrinted) 146 ptr.strcat("|"); 147 ptr.strcat("CanExit"); 148 hasPrinted = true; 149 } 150 151 if (flags & NodeExitsForward) { 152 if (hasPrinted) 153 ptr.strcat("|"); 154 ptr.strcat("NodeExitsForward"); 155 hasPrinted = true; 156 } 157 158 *ptr++ = 0; 159 160 return description; 102 if (flags & NodeExitsForward) 103 out.print(comma, "NodeExitsForward"); 161 104 } 162 163 105 164 106 } } // namespace JSC::DFG -
trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.h
r144362 r145299 31 31 #if ENABLE(DFG_JIT) 32 32 33 #include <wtf/PrintStream.h> 33 34 #include <wtf/StdLibExtras.h> 34 35 … … 60 61 #define NodeUsedAsValue (NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther) 61 62 #define NodeUsedAsInt 0x1000 // The result of this computation is known to be used in a context that prefers, but does not require, integer values. 62 #define NodeUsedAsIntLocally 0x2000 // Same as NodeUsedAsInt, but within the same basic block.63 63 64 64 #define NodeArithFlagsMask (NodeBehaviorMask | NodeBackPropMask) 65 65 66 #define NodeDoesNotExit 0x 4000 // This flag is negated to make it natural for the default to be that a node does exit.66 #define NodeDoesNotExit 0x2000 // This flag is negated to make it natural for the default to be that a node does exit. 67 67 68 #define NodeRelevantToOSR 0x 800068 #define NodeRelevantToOSR 0x4000 69 69 70 #define NodeExitsForward 0x1000070 #define NodeExitsForward 0x8000 71 71 72 72 typedef uint32_t NodeFlags; … … 103 103 } 104 104 105 const char* nodeFlagsAsString(NodeFlags); 105 void dumpNodeFlags(PrintStream&, NodeFlags); 106 MAKE_PRINT_ADAPTOR(NodeFlagsDump, NodeFlags, dumpNodeFlags); 106 107 107 108 } } // namespace JSC::DFG -
trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r144939 r145299 107 107 } 108 108 109 bool isNotNegZero(Node* node)110 {111 if (!m_graph.isNumberConstant(node))112 return false;113 double value = m_graph.valueOfNumberConstant(node);114 return !value && 1.0 / value < 0.0;115 }116 117 bool isNotZero(Node* node)118 {119 if (!m_graph.isNumberConstant(node))120 return false;121 return !!m_graph.valueOfNumberConstant(node);122 }123 124 bool isWithinPowerOfTwoForConstant(Node* node, int power)125 {126 JSValue immediateValue = node->valueOfJSConstant(codeBlock());127 if (!immediateValue.isInt32())128 return false;129 int32_t intImmediate = immediateValue.asInt32();130 return intImmediate > -(1 << power) && intImmediate < (1 << power);131 }132 133 bool isWithinPowerOfTwoNonRecursive(Node* node, int power)134 {135 if (node->op() != JSConstant)136 return false;137 return isWithinPowerOfTwoForConstant(node, power);138 }139 140 bool isWithinPowerOfTwo(Node* node, int power)141 {142 switch (node->op()) {143 case JSConstant: {144 return isWithinPowerOfTwoForConstant(node, power);145 }146 147 case BitAnd: {148 return isWithinPowerOfTwoNonRecursive(node->child1().node(), power)149 || isWithinPowerOfTwoNonRecursive(node->child2().node(), power);150 }151 152 case BitRShift:153 case BitURShift: {154 Node* shiftAmount = node->child2().node();155 if (shiftAmount->op() != JSConstant)156 return false;157 JSValue immediateValue = shiftAmount->valueOfJSConstant(codeBlock());158 if (!immediateValue.isInt32())159 return false;160 return immediateValue > 32 - power;161 }162 163 default:164 return false;165 }166 }167 168 109 SpeculatedType speculatedDoubleTypeForPrediction(SpeculatedType value) 169 110 { … … 183 124 { 184 125 NodeType op = node->op(); 185 NodeFlags flags = node->flags() & NodeBackPropMask;186 126 187 127 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) 188 dataLog(" ", Graph::opName(op), " ", m_currentNode, ": ", nodeFlagsAsString(flags), " ");128 dataLog(" ", Graph::opName(op), " ", m_currentNode, ": ", NodeFlagsDump(node->flags()), " "); 189 129 #endif 190 130 … … 203 143 if (prediction) 204 144 changed |= mergePrediction(prediction); 205 206 // Assume conservatively that a SetLocal implies that the value may flow through a loop,207 // and so we would have overflow leading to the program "observing" numbers even if all208 // users of the value are doing toInt32. It might be worthwhile to revisit this at some209 // point and actually check if the data flow involves loops, but right now I don't think210 // we have evidence that this would be beneficial for benchmarks.211 212 changed |= variableAccessData->mergeFlags((flags & ~NodeUsedAsIntLocally) | NodeUsedAsNumber);213 145 break; 214 146 } … … 217 149 VariableAccessData* variableAccessData = node->variableAccessData(); 218 150 changed |= variableAccessData->predict(node->child1()->prediction()); 219 220 changed |= node->child1()->mergeFlags(variableAccessData->flags());221 break;222 }223 224 case Flush: {225 // Make sure that the analysis knows that flushed locals escape.226 VariableAccessData* variableAccessData = node->variableAccessData();227 changed |= variableAccessData->mergeFlags(NodeUsedAsValue);228 151 break; 229 152 } … … 236 159 case BitURShift: { 237 160 changed |= setPrediction(SpecInt32); 238 flags |= NodeUsedAsInt | NodeUsedAsIntLocally;239 flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther);240 changed |= node->child1()->mergeFlags(flags);241 changed |= node->child2()->mergeFlags(flags);242 161 break; 243 162 } … … 245 164 case ValueToInt32: { 246 165 changed |= setPrediction(SpecInt32); 247 flags |= NodeUsedAsInt | NodeUsedAsIntLocally; 248 flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther); 249 changed |= node->child1()->mergeFlags(flags); 250 break; 251 } 252 253 case ArrayPop: { 254 changed |= mergePrediction(node->getHeapPrediction()); 255 changed |= mergeDefaultFlags(node); 256 break; 257 } 258 259 case ArrayPush: { 260 changed |= mergePrediction(node->getHeapPrediction()); 261 changed |= node->child1()->mergeFlags(NodeUsedAsValue); 262 changed |= node->child2()->mergeFlags(NodeUsedAsValue); 263 break; 264 } 265 166 break; 167 } 168 169 case ArrayPop: 170 case ArrayPush: 266 171 case RegExpExec: 267 case RegExpTest: { 268 changed |= mergePrediction(node->getHeapPrediction()); 269 changed |= mergeDefaultFlags(node); 172 case RegExpTest: 173 case GetById: 174 case GetByIdFlush: 175 case GetMyArgumentByValSafe: 176 case GetByOffset: 177 case Call: 178 case Construct: 179 case GetGlobalVar: 180 case GetScopedVar: 181 case Resolve: 182 case ResolveBase: 183 case ResolveBaseStrictPut: 184 case ResolveGlobal: { 185 changed |= setPrediction(node->getHeapPrediction()); 270 186 break; 271 187 } 272 188 273 189 case StringCharCodeAt: { 274 changed |= mergePrediction(SpecInt32); 275 changed |= node->child1()->mergeFlags(NodeUsedAsValue); 276 changed |= node->child2()->mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt | NodeUsedAsIntLocally); 190 changed |= setPrediction(SpecInt32); 277 191 break; 278 192 } … … 283 197 else 284 198 changed |= mergePrediction(SpecNumber); 285 286 changed |= node->child1()->mergeFlags(flags);287 199 break; 288 200 } … … 291 203 SpeculatedType left = node->child1()->prediction(); 292 204 SpeculatedType right = node->child2()->prediction(); 293 294 AddSpeculationMode mode = DontSpeculateInteger;295 205 296 206 if (left && right) { 297 207 if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right)) { 298 if ( (mode = m_graph.addSpeculationMode(node)) != DontSpeculateInteger)208 if (m_graph.addSpeculationMode(node) != DontSpeculateInteger) 299 209 changed |= mergePrediction(SpecInt32); 300 210 else … … 306 216 changed |= mergePrediction(SpecString | SpecInt32 | SpecDouble); 307 217 } 308 309 if (isNotNegZero(node->child1().node()) || isNotNegZero(node->child2().node()))310 flags &= ~NodeNeedsNegZero;311 if (node->child1()->hasNumberResult() || node->child2()->hasNumberResult())312 flags &= ~NodeUsedAsOther;313 314 if (mode != SpeculateInteger)315 flags |= NodeUsedAsNumber;316 317 changed |= node->child1()->mergeFlags(flags);318 changed |= node->child2()->mergeFlags(flags);319 218 break; 320 219 } … … 324 223 SpeculatedType right = node->child2()->prediction(); 325 224 326 AddSpeculationMode mode = DontSpeculateInteger;327 328 225 if (left && right) { 329 if ( (mode = m_graph.addSpeculationMode(node)) != DontSpeculateInteger)226 if (m_graph.addSpeculationMode(node) != DontSpeculateInteger) 330 227 changed |= mergePrediction(SpecInt32); 331 228 else 332 229 changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); 333 230 } 334 335 if (isNotNegZero(node->child1().node()) || isNotNegZero(node->child2().node()))336 flags &= ~NodeNeedsNegZero;337 flags &= ~NodeUsedAsOther;338 339 if (mode != SpeculateInteger)340 flags |= NodeUsedAsNumber;341 342 changed |= node->child1()->mergeFlags(flags);343 changed |= node->child2()->mergeFlags(flags);344 231 break; 345 232 } … … 349 236 SpeculatedType right = node->child2()->prediction(); 350 237 351 AddSpeculationMode mode = DontSpeculateInteger;352 353 238 if (left && right) { 354 if ( (mode = m_graph.addSpeculationMode(node)) != DontSpeculateInteger)239 if (m_graph.addSpeculationMode(node) != DontSpeculateInteger) 355 240 changed |= mergePrediction(SpecInt32); 356 241 else 357 242 changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); 358 243 } 359 360 if (isNotZero(node->child1().node()) || isNotZero(node->child2().node()))361 flags &= ~NodeNeedsNegZero;362 flags &= ~NodeUsedAsOther;363 364 if (mode != SpeculateInteger)365 flags |= NodeUsedAsNumber;366 367 changed |= node->child1()->mergeFlags(flags);368 changed |= node->child2()->mergeFlags(flags);369 244 break; 370 245 } … … 377 252 changed |= mergePrediction(speculatedDoubleTypeForPrediction(node->child1()->prediction())); 378 253 } 379 380 flags &= ~NodeUsedAsOther;381 382 changed |= node->child1()->mergeFlags(flags);383 254 break; 384 255 … … 395 266 changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); 396 267 } 397 398 flags |= NodeUsedAsNumber;399 flags &= ~NodeUsedAsOther;400 401 changed |= node->child1()->mergeFlags(flags);402 changed |= node->child2()->mergeFlags(flags);403 268 break; 404 269 } … … 414 279 changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); 415 280 } 416 417 // As soon as a multiply happens, we can easily end up in the part418 // of the double domain where the point at which you do truncation419 // can change the outcome. So, ArithMul always forces its inputs to420 // check for overflow. Additionally, it will have to check for overflow421 // itself unless we can prove that there is no way for the values422 // produced to cause double rounding.423 424 if (!isWithinPowerOfTwo(node->child1().node(), 22)425 && !isWithinPowerOfTwo(node->child2().node(), 22))426 flags |= NodeUsedAsNumber;427 428 changed |= node->mergeFlags(flags);429 430 flags |= NodeUsedAsNumber | NodeNeedsNegZero;431 flags &= ~NodeUsedAsOther;432 433 changed |= node->child1()->mergeFlags(flags);434 changed |= node->child2()->mergeFlags(flags);435 281 break; 436 282 } … … 447 293 changed |= mergePrediction(SpecDouble); 448 294 } 449 450 // As soon as a multiply happens, we can easily end up in the part451 // of the double domain where the point at which you do truncation452 // can change the outcome. So, ArithDiv always checks for overflow453 // no matter what, and always forces its inputs to check as well.454 455 flags |= NodeUsedAsNumber | NodeNeedsNegZero;456 flags &= ~NodeUsedAsOther;457 458 changed |= node->child1()->mergeFlags(flags);459 changed |= node->child2()->mergeFlags(flags);460 295 break; 461 296 } … … 472 307 changed |= mergePrediction(SpecDouble); 473 308 } 474 475 flags |= NodeUsedAsNumber | NodeNeedsNegZero;476 flags &= ~NodeUsedAsOther;477 478 changed |= node->child1()->mergeFlags(flags);479 changed |= node->child2()->mergeFlags(flags);480 309 break; 481 310 } … … 483 312 case ArithSqrt: { 484 313 changed |= setPrediction(SpecDouble); 485 flags |= NodeUsedAsNumber | NodeNeedsNegZero;486 flags &= ~NodeUsedAsOther;487 changed |= node->child1()->mergeFlags(flags);488 314 break; 489 315 } … … 496 322 else 497 323 changed |= mergePrediction(speculatedDoubleTypeForPrediction(child)); 498 499 changed |= node->child1()->mergeFlags(flags);500 324 break; 501 325 } … … 518 342 case IsFunction: { 519 343 changed |= setPrediction(SpecBoolean); 520 changed |= mergeDefaultFlags(node);521 344 break; 522 345 } … … 524 347 case TypeOf: { 525 348 changed |= setPrediction(SpecString); 526 changed |= mergeDefaultFlags(node); 527 break; 528 } 529 530 case GetById: { 531 changed |= mergePrediction(node->getHeapPrediction()); 532 changed |= mergeDefaultFlags(node); 533 break; 534 } 535 536 case GetByIdFlush: 537 changed |= mergePrediction(node->getHeapPrediction()); 538 changed |= mergeDefaultFlags(node); 539 break; 540 349 break; 350 } 351 541 352 case GetByVal: { 542 353 if (node->child1()->shouldSpeculateFloat32Array() … … 545 356 else 546 357 changed |= mergePrediction(node->getHeapPrediction()); 547 548 changed |= node->child1()->mergeFlags(NodeUsedAsValue);549 changed |= node->child2()->mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt | NodeUsedAsIntLocally);550 break;551 }552 553 case GetMyArgumentByValSafe: {554 changed |= mergePrediction(node->getHeapPrediction());555 changed |= node->child1()->mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt | NodeUsedAsIntLocally);556 358 break; 557 359 } … … 568 370 case ReallocatePropertyStorage: { 569 371 changed |= setPrediction(SpecOther); 570 changed |= mergeDefaultFlags(node); 571 break; 572 } 573 574 case GetByOffset: { 575 changed |= mergePrediction(node->getHeapPrediction()); 576 changed |= mergeDefaultFlags(node); 577 break; 578 } 579 580 case Call: 581 case Construct: { 582 changed |= mergePrediction(node->getHeapPrediction()); 583 for (unsigned childIdx = node->firstChild(); 584 childIdx < node->firstChild() + node->numChildren(); 585 ++childIdx) 586 changed |= m_graph.m_varArgChildren[childIdx]->mergeFlags(NodeUsedAsValue); 587 break; 588 } 589 372 break; 373 } 374 590 375 case ConvertThis: { 591 376 SpeculatedType prediction = node->child1()->prediction(); … … 597 382 changed |= mergePrediction(prediction); 598 383 } 599 changed |= mergeDefaultFlags(node);600 break;601 }602 603 case GetGlobalVar: {604 changed |= mergePrediction(node->getHeapPrediction());605 break;606 }607 608 case PutGlobalVar:609 case PutGlobalVarCheck: {610 changed |= node->child1()->mergeFlags(NodeUsedAsValue);611 break;612 }613 614 case GetScopedVar:615 case Resolve:616 case ResolveBase:617 case ResolveBaseStrictPut:618 case ResolveGlobal: {619 SpeculatedType prediction = node->getHeapPrediction();620 changed |= mergePrediction(prediction);621 384 break; 622 385 } … … 637 400 case NewObject: { 638 401 changed |= setPrediction(SpecFinalObject); 639 changed |= mergeDefaultFlags(node); 640 break; 641 } 642 643 case NewArray: { 644 changed |= setPrediction(SpecArray); 645 for (unsigned childIdx = node->firstChild(); 646 childIdx < node->firstChild() + node->numChildren(); 647 ++childIdx) 648 changed |= m_graph.m_varArgChildren[childIdx]->mergeFlags(NodeUsedAsValue); 649 break; 650 } 651 652 case NewArrayWithSize: { 653 changed |= setPrediction(SpecArray); 654 changed |= node->child1()->mergeFlags(NodeUsedAsValue | NodeUsedAsInt | NodeUsedAsIntLocally); 655 break; 656 } 657 402 break; 403 } 404 405 case NewArray: 406 case NewArrayWithSize: 658 407 case NewArrayBuffer: { 659 408 changed |= setPrediction(SpecArray); … … 661 410 } 662 411 663 case NewRegexp: { 412 case NewRegexp: 413 case CreateActivation: { 664 414 changed |= setPrediction(SpecObjectOther); 665 415 break; 666 416 } 667 417 668 case StringCharAt: { 669 changed |= setPrediction(SpecString); 670 changed |= node->child1()->mergeFlags(NodeUsedAsValue); 671 changed |= node->child2()->mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt | NodeUsedAsIntLocally); 672 break; 673 } 674 418 case StringCharAt: 675 419 case StrCat: { 676 420 changed |= setPrediction(SpecString); 677 for (unsigned childIdx = node->firstChild();678 childIdx < node->firstChild() + node->numChildren();679 ++childIdx)680 changed |= m_graph.m_varArgChildren[childIdx]->mergeFlags(NodeUsedAsNumber | NodeUsedAsOther);681 421 break; 682 422 } … … 700 440 changed |= mergePrediction(child); 701 441 } 702 changed |= node->child1()->mergeFlags(flags);703 break;704 }705 706 case CreateActivation: {707 changed |= setPrediction(SpecObjectOther);708 442 break; 709 443 } … … 744 478 } 745 479 746 case PutByVal:747 changed |= m_graph.varArgChild(node, 0)->mergeFlags(NodeUsedAsValue);748 changed |= m_graph.varArgChild(node, 1)->mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt | NodeUsedAsIntLocally);749 changed |= m_graph.varArgChild(node, 2)->mergeFlags(NodeUsedAsValue);750 break;751 752 case PutScopedVar:753 changed |= node->child1()->mergeFlags(NodeUsedAsValue);754 changed |= node->child3()->mergeFlags(NodeUsedAsValue);755 break;756 757 case Return:758 case Throw:759 changed |= node->child1()->mergeFlags(NodeUsedAsValue);760 break;761 762 case PutById:763 case PutByIdDirect:764 changed |= node->child1()->mergeFlags(NodeUsedAsValue);765 changed |= node->child2()->mergeFlags(NodeUsedAsValue);766 break;767 768 case PutByOffset:769 changed |= node->child1()->mergeFlags(NodeUsedAsValue);770 changed |= node->child3()->mergeFlags(NodeUsedAsValue);771 break;772 773 480 case Phi: 774 481 // Phis should not be visible here since we're iterating the all-but-Phi's … … 777 484 break; 778 485 486 case GetScope: 487 changed |= setPrediction(SpecCellOther); 488 break; 489 490 #ifndef NDEBUG 491 // These get ignored because they don't return anything. 492 case PutByVal: 493 case PutScopedVar: 494 case Return: 495 case Throw: 496 case PutById: 497 case PutByIdDirect: 498 case PutByOffset: 779 499 case SetCallee: 780 500 case SetMyScope: 781 changed |= node->child1()->mergeFlags(NodeUsedAsValue);782 break;783 784 case GetScope:785 changed |= node->child1()->mergeFlags(NodeUsedAsValue);786 changed |= setPrediction(SpecCellOther);787 break;788 789 #ifndef NDEBUG790 // These get ignored because they don't return anything.791 501 case DFG::Jump: 792 502 case Branch: … … 810 520 case AllocationProfileWatchpoint: 811 521 case Phantom: 812 changed |= mergeDefaultFlags(node); 522 case PutGlobalVar: 523 case PutGlobalVarCheck: 813 524 break; 814 525 … … 818 529 case CountExecution: 819 530 case PhantomLocal: 531 case Flush: 820 532 break; 821 533 … … 825 537 #else 826 538 default: 827 changed |= mergeDefaultFlags(node);828 539 break; 829 540 #endif … … 837 548 } 838 549 839 bool mergeDefaultFlags(Node* node)840 {841 bool changed = false;842 if (node->flags() & NodeHasVarArgs) {843 for (unsigned childIdx = node->firstChild();844 childIdx < node->firstChild() + node->numChildren();845 childIdx++) {846 if (!!m_graph.m_varArgChildren[childIdx])847 changed |= m_graph.m_varArgChildren[childIdx]->mergeFlags(NodeUsedAsValue);848 }849 } else {850 if (!node->child1())851 return changed;852 changed |= node->child1()->mergeFlags(NodeUsedAsValue);853 if (!node->child2())854 return changed;855 changed |= node->child2()->mergeFlags(NodeUsedAsValue);856 if (!node->child3())857 return changed;858 changed |= node->child3()->mergeFlags(NodeUsedAsValue);859 }860 return changed;861 }862 863 550 void propagateForward() 864 551 { -
trunk/Source/JavaScriptCore/dfg/DFGUnificationPhase.cpp
r143955 r145299 74 74 data->find()->mergeStructureCheckHoistingFailed(data->structureCheckHoistingFailed()); 75 75 data->find()->mergeShouldNeverUnbox(data->shouldNeverUnbox()); 76 data->find()->mergeIsLoadedFrom(data->isLoadedFrom()); 76 77 } 77 78 -
trunk/Source/JavaScriptCore/dfg/DFGVariableAccessData.h
r144131 r145299 52 52 , m_structureCheckHoistingFailed(false) 53 53 , m_isProfitableToUnbox(false) 54 , m_isLoadedFrom(false) 54 55 , m_doubleFormatState(EmptyDoubleFormatState) 55 56 { … … 150 151 } 151 152 153 bool mergeIsLoadedFrom(bool isLoadedFrom) 154 { 155 return checkAndSet(m_isLoadedFrom, m_isLoadedFrom | isLoadedFrom); 156 } 157 158 void setIsLoadedFrom(bool isLoadedFrom) 159 { 160 m_isLoadedFrom = isLoadedFrom; 161 } 162 163 bool isLoadedFrom() 164 { 165 return m_isLoadedFrom; 166 } 167 152 168 bool predict(SpeculatedType prediction) 153 169 { … … 307 323 bool m_structureCheckHoistingFailed; 308 324 bool m_isProfitableToUnbox; 325 bool m_isLoadedFrom; 309 326 310 327 float m_votes[2]; // Used primarily for double voting but may be reused for other purposes.
Note:
See TracChangeset
for help on using the changeset viewer.