Changeset 96375 in webkit
- Timestamp:
- Sep 29, 2011 4:17:19 PM (13 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 3 added
- 19 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r96373 r96375 1 2011-09-28 Filip Pizlo <fpizlo@apple.com> 2 3 DFG JIT should infer which uses of a variable are not aliased 4 https://bugs.webkit.org/show_bug.cgi?id=68593 5 6 Reviewed by Oliver Hunt. 7 8 This separates how a variable is stored (i.e. its virtual register) 9 from how it's predicted. Each variable now takes a 10 VariableAccessData as its operand, instead of the virtual register. 11 The VariableAccessData stores the operand and the prediction. If 12 multiple uses of a variable are aliased, their VariableAccessDatas 13 are unified. 14 15 This also adds tracking of which argument values are used. It 16 correctly observes that an argument value is not used, if the 17 argument is assigned to inside the function before being used. 18 19 This also adds tracking of which variables are live at the head of 20 a basic block, and separates that from a variable being live at the 21 tail. 22 23 Finally, this communicates to both OSR entry and OSR exit code how 24 a variable is predicted at a particular point in the code, rather 25 than just communicating how it was predicted in the entire code 26 block (since with this patch there is no longer the notion of a 27 variable having just one prediction for a code block). 28 29 * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: 30 * JavaScriptCore.vcproj/WTF/WTF.vcproj: 31 * JavaScriptCore.xcodeproj/project.pbxproj: 32 * bytecode/ActionablePrediction.h: Added. 33 (JSC::actionablePredictionFromPredictedType): 34 (JSC::valueObeysPrediction): 35 (JSC::actionablePredictionToString): 36 (JSC::ActionablePredictions::ActionablePredictions): 37 (JSC::ActionablePredictions::setArgument): 38 (JSC::ActionablePredictions::argument): 39 (JSC::ActionablePredictions::setVariable): 40 (JSC::ActionablePredictions::variable): 41 (JSC::ActionablePredictions::argumentUpperBound): 42 (JSC::ActionablePredictions::variableUpperBound): 43 (JSC::ActionablePredictions::pack): 44 (JSC::ActionablePredictions::packVector): 45 * bytecode/CodeBlock.h: 46 * bytecode/PredictionTracker.h: 47 * dfg/DFGByteCodeParser.cpp: 48 (JSC::DFG::ByteCodeParser::newVariableAccessData): 49 (JSC::DFG::ByteCodeParser::getLocal): 50 (JSC::DFG::ByteCodeParser::setLocal): 51 (JSC::DFG::ByteCodeParser::getArgument): 52 (JSC::DFG::ByteCodeParser::setArgument): 53 (JSC::DFG::ByteCodeParser::parseBlock): 54 (JSC::DFG::ByteCodeParser::processPhiStack): 55 (JSC::DFG::ByteCodeParser::parse): 56 * dfg/DFGDriver.cpp: 57 (JSC::DFG::compile): 58 * dfg/DFGGraph.cpp: 59 (JSC::DFG::Graph::nameOfVariableAccessData): 60 (JSC::DFG::Graph::dump): 61 (JSC::DFG::Graph::predictArgumentTypes): 62 * dfg/DFGGraph.h: 63 (JSC::DFG::operandIsArgument): 64 (JSC::DFG::VariableRecord::setFirstTime): 65 (JSC::DFG::BasicBlock::BasicBlock): 66 (JSC::DFG::Graph::predict): 67 (JSC::DFG::Graph::getPrediction): 68 * dfg/DFGJITCompiler.h: 69 (JSC::DFG::JITCompiler::noticeOSREntry): 70 * dfg/DFGNode.h: 71 (JSC::DFG::Node::hasVariableAccessData): 72 (JSC::DFG::Node::hasLocal): 73 (JSC::DFG::Node::variableAccessData): 74 (JSC::DFG::Node::local): 75 * dfg/DFGOSREntry.cpp: 76 (JSC::DFG::prepareOSREntry): 77 * dfg/DFGOSREntry.h: 78 * dfg/DFGPropagator.cpp: 79 (JSC::DFG::Propagator::propagateNodePredictions): 80 * dfg/DFGSpeculativeJIT.cpp: 81 (JSC::DFG::ValueSource::dump): 82 (JSC::DFG::OSRExit::OSRExit): 83 (JSC::DFG::SpeculativeJIT::compile): 84 (JSC::DFG::SpeculativeJIT::checkArgumentTypes): 85 (JSC::DFG::SpeculativeJIT::computeValueRecoveryFor): 86 * dfg/DFGSpeculativeJIT.h: 87 (JSC::DFG::ValueSource::ValueSource): 88 (JSC::DFG::ValueSource::forPrediction): 89 (JSC::DFG::ValueSource::isSet): 90 (JSC::DFG::ValueSource::kind): 91 (JSC::DFG::ValueSource::nodeIndex): 92 (JSC::DFG::ValueSource::nodeIndexFromKind): 93 (JSC::DFG::ValueSource::kindFromNodeIndex): 94 (JSC::DFG::SpeculativeJIT::isKnownArray): 95 (JSC::DFG::SpeculativeJIT::computeValueRecoveryFor): 96 (JSC::DFG::SpeculativeJIT::SpeculativeJIT): 97 * dfg/DFGSpeculativeJIT32_64.cpp: 98 (JSC::DFG::OSRExit::OSRExit): 99 (JSC::DFG::SpeculativeJIT::compile): 100 (JSC::DFG::SpeculativeJIT::checkArgumentTypes): 101 (JSC::DFG::SpeculativeJIT::computeValueRecoveryFor): 102 * wtf/PackedIntVector.h: Added. 103 (WTF::PackedIntVector::PackedIntVector): 104 (WTF::PackedIntVector::operator=): 105 (WTF::PackedIntVector::size): 106 (WTF::PackedIntVector::ensureSize): 107 (WTF::PackedIntVector::resize): 108 (WTF::PackedIntVector::clearAll): 109 (WTF::PackedIntVector::get): 110 (WTF::PackedIntVector::set): 111 (WTF::PackedIntVector::mask): 112 * wtf/Platform.h: 113 * wtf/UnionFind.h: Added. 114 (WTF::UnionFind::UnionFind): 115 (WTF::UnionFind::find): 116 (WTF::UnionFind::unify): 117 1 118 2011-09-29 Oliver Hunt <oliver@apple.com> 2 119 -
trunk/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
r95751 r96375 1431 1431 > 1432 1432 <File 1433 RelativePath="..\..\bytecode\ActionablePrediction.h" 1434 > 1435 </File> 1436 <File 1433 1437 RelativePath="..\..\bytecode\CodeBlock.cpp" 1434 1438 > -
trunk/Source/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj
r95895 r96375 942 942 </File> 943 943 <File 944 RelativePath="..\..\wtf\PackedIntVector.h" 945 > 946 </File> 947 <File 944 948 RelativePath="..\..\wtf\PageAllocation.h" 945 949 > -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r96347 r96375 50 50 0BDFFAE10FC6193100D69EF4 /* OwnFastMallocPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BDFFAD10FC616EC00D69EF4 /* OwnFastMallocPtr.h */; settings = {ATTRIBUTES = (Private, ); }; }; 51 51 0BF28A2911A33DC300638F84 /* SizeLimits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0BF28A2811A33DC300638F84 /* SizeLimits.cpp */; }; 52 0F16D726142C39C000CF784A /* BitVector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F16D724142C39A200CF784A /* BitVector.cpp */; }; 52 53 0F242DA713F3B1E8007ADD4C /* WeakReferenceHarvester.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F242DA513F3B1BB007ADD4C /* WeakReferenceHarvester.h */; settings = {ATTRIBUTES = (Private, ); }; }; 53 0F604E8B142D696D009CEB92 /* BitVector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F604E8A142D6969009CEB92 /* BitVector.cpp */; }; 54 0F636DA0142D27D700B2E66A /* PackedIntVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F636D9F142D27D200B2E66A /* PackedIntVector.h */; }; 55 0F636DA2142D27F000B2E66A /* ActionablePrediction.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F636DA1142D27ED00B2E66A /* ActionablePrediction.h */; }; 54 56 0F7700921402FF3C0078EB39 /* SamplingCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7700911402FF280078EB39 /* SamplingCounter.cpp */; }; 55 57 0F963B2713F753BB0002D9B2 /* RedBlackTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F963B2613F753990002D9B2 /* RedBlackTree.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 66 68 0FD3C82714115D4F00FD81CB /* DFGPropagator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD3C82414115D2200FD81CB /* DFGPropagator.h */; }; 67 69 0FD3C82814115D4F00FD81CB /* DFGDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD3C82214115D0E00FD81CB /* DFGDriver.h */; }; 70 0FD52AAE143035A00026DC9F /* UnionFind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD52AAC1430359D0026DC9F /* UnionFind.h */; settings = {ATTRIBUTES = (Private, ); }; }; 68 71 0FD82E2114172CE300179C94 /* DFGCapabilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E1E14172C2F00179C94 /* DFGCapabilities.cpp */; }; 69 72 0FD82E39141AB14D00179C94 /* CompactJITCodeMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E37141AB14200179C94 /* CompactJITCodeMap.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 798 801 0BDFFAD40FC6171000D69EF4 /* CrossThreadRefCounted.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CrossThreadRefCounted.h; sourceTree = "<group>"; }; 799 802 0BF28A2811A33DC300638F84 /* SizeLimits.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SizeLimits.cpp; sourceTree = "<group>"; }; 803 0F16D724142C39A200CF784A /* BitVector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BitVector.cpp; sourceTree = "<group>"; }; 800 804 0F242DA513F3B1BB007ADD4C /* WeakReferenceHarvester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakReferenceHarvester.h; sourceTree = "<group>"; }; 801 0F604E8A142D6969009CEB92 /* BitVector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BitVector.cpp; sourceTree = "<group>"; }; 805 0F636D9F142D27D200B2E66A /* PackedIntVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PackedIntVector.h; sourceTree = "<group>"; }; 806 0F636DA1142D27ED00B2E66A /* ActionablePrediction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActionablePrediction.h; sourceTree = "<group>"; }; 802 807 0F77008E1402FDD60078EB39 /* SamplingCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SamplingCounter.h; sourceTree = "<group>"; }; 803 808 0F7700911402FF280078EB39 /* SamplingCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingCounter.cpp; sourceTree = "<group>"; }; … … 815 820 0FD3C82314115D1A00FD81CB /* DFGPropagator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGPropagator.cpp; path = dfg/DFGPropagator.cpp; sourceTree = "<group>"; }; 816 821 0FD3C82414115D2200FD81CB /* DFGPropagator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPropagator.h; path = dfg/DFGPropagator.h; sourceTree = "<group>"; }; 822 0FD52AAC1430359D0026DC9F /* UnionFind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnionFind.h; sourceTree = "<group>"; }; 817 823 0FD82E1E14172C2F00179C94 /* DFGCapabilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCapabilities.cpp; path = dfg/DFGCapabilities.cpp; sourceTree = "<group>"; }; 818 824 0FD82E1F14172C2F00179C94 /* DFGCapabilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCapabilities.h; path = dfg/DFGCapabilities.h; sourceTree = "<group>"; }; … … 1825 1831 isa = PBXGroup; 1826 1832 children = ( 1827 0F604E8A142D6969009CEB92 /* BitVector.cpp */, 1833 0FD52AAC1430359D0026DC9F /* UnionFind.h */, 1834 0F636D9F142D27D200B2E66A /* PackedIntVector.h */, 1835 0F16D724142C39A200CF784A /* BitVector.cpp */, 1828 1836 0FD82F491428069200179C94 /* BitVector.h */, 1829 1837 C22C524813FAF6EF00B7DC0D /* dtoa */, … … 2356 2364 isa = PBXGroup; 2357 2365 children = ( 2366 0F636DA1142D27ED00B2E66A /* ActionablePrediction.h */, 2358 2367 0FD82E8E14207A5100179C94 /* ValueProfile.cpp */, 2359 2368 0FD82E84141F3FDA00179C94 /* PredictedType.cpp */, … … 2839 2848 A70456B01427FB910037DA68 /* AllocationSpace.h in Headers */, 2840 2849 86FA9E92142BBB2E001773B7 /* JSBoundFunction.h in Headers */, 2850 0F636DA0142D27D700B2E66A /* PackedIntVector.h in Headers */, 2851 0F636DA2142D27F000B2E66A /* ActionablePrediction.h in Headers */, 2841 2852 A7521E131429169A003C8D0C /* CardSet.h in Headers */, 2853 0FD52AAE143035A00026DC9F /* UnionFind.h in Headers */, 2842 2854 86880F1E14328BB900B08D42 /* DFGJITCompilerInlineMethods.h in Headers */, 2843 2855 ); … … 3154 3166 buildActionMask = 2147483647; 3155 3167 files = ( 3168 0F16D726142C39C000CF784A /* BitVector.cpp in Sources */, 3156 3169 0FD82F2C1426CA7400179C94 /* JettisonedCodeBlocks.cpp in Sources */, 3157 3170 0FD82E9014207A5F00179C94 /* ValueProfile.cpp in Sources */, … … 3365 3378 A70456B11427FB950037DA68 /* AllocationSpace.cpp in Sources */, 3366 3379 86FA9E91142BBB2E001773B7 /* JSBoundFunction.cpp in Sources */, 3367 0F604E8B142D696D009CEB92 /* BitVector.cpp in Sources */,3368 3380 86880F1C14328BB900B08D42 /* DFGJITCodeGenerator32_64.cpp in Sources */, 3369 3381 86880F1D14328BB900B08D42 /* DFGJITCompiler32_64.cpp in Sources */, -
trunk/Source/JavaScriptCore/bytecode/CodeBlock.h
r95930 r96375 241 241 PassOwnPtr<CodeBlock> releaseAlternative() { return m_alternative.release(); } 242 242 243 void setPredictions(PassOwnPtr<PredictionTracker> predictions) { m_predictions = predictions; }244 PredictionTracker* predictions() const { return m_predictions.get(); }245 246 243 void visitAggregate(SlotVisitor&); 247 244 void visitWeakReferences(SlotVisitor&); … … 976 973 OwnPtr<CodeBlock> m_alternative; 977 974 978 OwnPtr<PredictionTracker> m_predictions;979 980 975 int32_t m_executeCounter; 981 976 uint32_t m_speculativeSuccessCounter; -
trunk/Source/JavaScriptCore/bytecode/PredictionTracker.h
r95930 r96375 29 29 #include "PredictedType.h" 30 30 #include <wtf/HashMap.h> 31 #include <wtf/Vector.h>32 31 33 32 namespace JSC { 34 35 // helper function to distinguish vars & temporaries from arguments.36 inline bool operandIsArgument(int operand) { return operand < 0; }37 33 38 34 struct PredictionSlot { … … 51 47 } 52 48 53 PredictionTracker(unsigned numArguments, unsigned numVariables)54 : m_arguments(numArguments)55 , m_variables(numVariables)56 {57 }58 59 void initializeSimilarTo(const PredictionTracker& other)60 {61 m_arguments.resize(other.numberOfArguments());62 m_variables.resize(other.numberOfVariables());63 }64 65 void copyLocalsFrom(const PredictionTracker& other)66 {67 m_arguments = other.m_arguments;68 m_variables = other.m_variables;69 }70 71 size_t numberOfArguments() const { return m_arguments.size(); }72 size_t numberOfVariables() const { return m_variables.size(); }73 74 unsigned argumentIndexForOperand(int operand) const { return operand + m_arguments.size() + RegisterFile::CallFrameHeaderSize; }75 76 bool predictArgument(unsigned argument, PredictedType prediction)77 {78 return mergePrediction(m_arguments[argument].m_value, prediction);79 }80 81 bool predict(int operand, PredictedType prediction)82 {83 if (operandIsArgument(operand))84 return predictArgument(argumentIndexForOperand(operand), prediction);85 if ((unsigned)operand >= m_variables.size()) {86 ASSERT(operand >= 0);87 m_variables.resize(operand + 1);88 }89 90 return mergePrediction(m_variables[operand].m_value, prediction);91 }92 93 49 bool predictGlobalVar(unsigned varNumber, PredictedType prediction) 94 50 { … … 103 59 } 104 60 105 PredictedType getArgumentPrediction(unsigned argument)106 {107 return m_arguments[argument].m_value;108 }109 110 PredictedType getPrediction(int operand)111 {112 if (operandIsArgument(operand))113 return getArgumentPrediction(argumentIndexForOperand(operand));114 if ((unsigned)operand < m_variables.size())115 return m_variables[operand].m_value;116 return PredictNone;117 }118 119 61 PredictedType getGlobalVarPrediction(unsigned varNumber) 120 62 { … … 126 68 127 69 private: 128 Vector<PredictionSlot, 16> m_arguments;129 Vector<PredictionSlot, 16> m_variables;130 70 HashMap<unsigned, PredictionSlot> m_globalVars; 131 71 }; -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r96189 r96375 84 84 // Add spill locations to nodes. 85 85 void allocateVirtualRegisters(); 86 86 87 VariableAccessData* newVariableAccessData(int operand) 88 { 89 ASSERT(operand < FirstConstantRegisterIndex); 90 91 m_graph.m_variableAccessData.append(VariableAccessData(static_cast<VirtualRegister>(operand))); 92 return &m_graph.m_variableAccessData.last(); 93 } 94 87 95 // Get/Set the operands/result of a bytecode instruction. 88 96 NodeIndex get(int operand) … … 117 125 NodeIndex getLocal(unsigned operand) 118 126 { 119 NodeIndex nodeIndex = m_currentBlock->m_locals [operand].value;127 NodeIndex nodeIndex = m_currentBlock->m_localsAtTail[operand].value; 120 128 121 129 if (nodeIndex != NoNode) { … … 130 138 // expand m_preservedVars to cover these. 131 139 m_preservedVars = std::max(m_preservedVars, operand + 1); 132 133 NodeIndex phi = addToGraph(Phi); 140 141 VariableAccessData* variableAccessData = newVariableAccessData(operand); 142 143 NodeIndex phi = addToGraph(Phi, OpInfo(variableAccessData)); 134 144 m_localPhiStack.append(PhiStackEntry(m_currentBlock, phi, operand)); 135 nodeIndex = addToGraph(GetLocal, OpInfo(operand), phi); 136 m_currentBlock->m_locals[operand].value = nodeIndex; 145 nodeIndex = addToGraph(GetLocal, OpInfo(variableAccessData), phi); 146 m_currentBlock->m_localsAtTail[operand].value = nodeIndex; 147 148 m_currentBlock->m_localsAtHead[operand].setFirstTime(nodeIndex); 149 137 150 return nodeIndex; 138 151 } 139 152 void setLocal(unsigned operand, NodeIndex value) 140 153 { 141 m_currentBlock->m_locals [operand].value = addToGraph(SetLocal, OpInfo(operand), value);154 m_currentBlock->m_localsAtTail[operand].value = addToGraph(SetLocal, OpInfo(newVariableAccessData(operand)), value); 142 155 } 143 156 … … 148 161 ASSERT(argument < m_numArguments); 149 162 150 NodeIndex nodeIndex = m_currentBlock->m_arguments [argument].value;163 NodeIndex nodeIndex = m_currentBlock->m_argumentsAtTail[argument].value; 151 164 152 165 if (nodeIndex != NoNode) { 153 166 Node& node = m_graph[nodeIndex]; 167 if (node.op == SetArgument) { 168 // We're getting an argument in the first basic block; link 169 // the GetLocal to the SetArgument. 170 ASSERT(node.local() == static_cast<VirtualRegister>(operand)); 171 nodeIndex = addToGraph(GetLocal, OpInfo(node.variableAccessData()), nodeIndex); 172 m_currentBlock->m_argumentsAtTail[argument].value = nodeIndex; 173 return nodeIndex; 174 } 175 154 176 if (node.op == GetLocal) 155 177 return nodeIndex; 178 156 179 ASSERT(node.op == SetLocal); 157 180 return node.child1(); 158 181 } 159 160 NodeIndex phi = addToGraph(Phi); 182 183 VariableAccessData* variableAccessData = newVariableAccessData(operand); 184 185 NodeIndex phi = addToGraph(Phi, OpInfo(variableAccessData)); 161 186 m_argumentPhiStack.append(PhiStackEntry(m_currentBlock, phi, argument)); 162 nodeIndex = addToGraph(GetLocal, OpInfo(operand), phi); 163 m_currentBlock->m_arguments[argument].value = nodeIndex; 187 nodeIndex = addToGraph(GetLocal, OpInfo(variableAccessData), phi); 188 m_currentBlock->m_argumentsAtTail[argument].value = nodeIndex; 189 190 m_currentBlock->m_argumentsAtHead[argument].setFirstTime(nodeIndex); 191 164 192 return nodeIndex; 165 193 } … … 169 197 ASSERT(argument < m_numArguments); 170 198 171 m_currentBlock->m_arguments [argument].value = addToGraph(SetLocal, OpInfo(operand), value);199 m_currentBlock->m_argumentsAtTail[argument].value = addToGraph(SetLocal, OpInfo(newVariableAccessData(operand)), value); 172 200 } 173 201 … … 688 716 for (unsigned i = 0; i < m_constants.size(); ++i) 689 717 m_constants[i] = ConstantRecord(); 718 } 719 720 // If we are the first basic block, introduce markers for arguments. This allows 721 // us to track if a use of an argument may use the actual argument passed, as 722 // opposed to using a value we set explicitly. 723 if (!m_currentIndex) { 724 m_graph.m_arguments.resize(m_numArguments); 725 for (unsigned argument = 0; argument < m_numArguments; ++argument) { 726 NodeIndex setArgument = addToGraph(SetArgument, OpInfo(newVariableAccessData(argument - m_codeBlock->m_numParameters - RegisterFile::CallFrameHeaderSize))); 727 m_graph.m_arguments[argument] = setArgument; 728 m_currentBlock->m_argumentsAtHead[argument].setFirstTime(setArgument); 729 m_currentBlock->m_argumentsAtTail[argument].setFirstTime(setArgument); 730 } 690 731 } 691 732 … … 1449 1490 PredecessorList& predecessors = entry.m_block->m_predecessors; 1450 1491 unsigned varNo = entry.m_varNo; 1492 VariableAccessData* dataForPhi = m_graph[entry.m_phi].variableAccessData(); 1451 1493 1452 1494 for (size_t i = 0; i < predecessors.size(); ++i) { 1453 1495 BasicBlock* predecessorBlock = m_graph.m_blocks[predecessors[i]].get(); 1454 1496 1455 VariableRecord& var = (stackType == ArgumentPhiStack) ? predecessorBlock->m_arguments [varNo] : predecessorBlock->m_locals[varNo];1497 VariableRecord& var = (stackType == ArgumentPhiStack) ? predecessorBlock->m_argumentsAtTail[varNo] : predecessorBlock->m_localsAtTail[varNo]; 1456 1498 1457 1499 NodeIndex valueInPredecessor = var.value; 1458 1500 if (valueInPredecessor == NoNode) { 1459 valueInPredecessor = addToGraph(Phi); 1460 var.value = valueInPredecessor; 1501 valueInPredecessor = addToGraph(Phi, OpInfo(newVariableAccessData(stackType == ArgumentPhiStack ? varNo - m_codeBlock->m_numParameters - RegisterFile::CallFrameHeaderSize : varNo))); 1502 var.setFirstTime(valueInPredecessor); 1503 if (stackType == ArgumentPhiStack) 1504 predecessorBlock->m_argumentsAtHead[varNo].setFirstTime(valueInPredecessor); 1505 else 1506 predecessorBlock->m_localsAtHead[varNo].setFirstTime(valueInPredecessor); 1461 1507 phiStack.append(PhiStackEntry(predecessorBlock, valueInPredecessor, varNo)); 1462 } else if (m_graph[valueInPredecessor].op == GetLocal) 1508 } else if (m_graph[valueInPredecessor].op == GetLocal) { 1509 // We want to ensure that the VariableAccessDatas are identical between the 1510 // GetLocal and its block-local Phi. Strictly speaking we only need the two 1511 // to be unified. But for efficiency, we want the code that creates GetLocals 1512 // and Phis to try to reuse VariableAccessDatas as much as possible. 1513 ASSERT(m_graph[valueInPredecessor].variableAccessData() == m_graph[m_graph[valueInPredecessor].child1()].variableAccessData()); 1514 1463 1515 valueInPredecessor = m_graph[valueInPredecessor].child1(); 1464 ASSERT(m_graph[valueInPredecessor].op == SetLocal || m_graph[valueInPredecessor].op == Phi); 1516 } 1517 ASSERT(m_graph[valueInPredecessor].op == SetLocal || m_graph[valueInPredecessor].op == Phi || (m_graph[valueInPredecessor].op == SetArgument && stackType == ArgumentPhiStack)); 1518 1519 VariableAccessData* dataForPredecessor = m_graph[valueInPredecessor].variableAccessData(); 1520 1521 dataForPredecessor->unify(dataForPhi); 1465 1522 1466 1523 Node* phiNode = &m_graph[entry.m_phi]; … … 1480 1537 continue; 1481 1538 } 1482 1483 NodeIndex newPhi = addToGraph(Phi );1539 1540 NodeIndex newPhi = addToGraph(Phi, OpInfo(dataForPhi)); 1484 1541 1485 1542 phiNode = &m_graph[entry.m_phi]; // reload after vector resize … … 1549 1606 1550 1607 m_graph.m_preservedVars = m_preservedVars; 1608 m_graph.m_localVars = m_numLocals; 1551 1609 m_graph.m_parameterSlots = m_parameterSlots; 1552 1610 -
trunk/Source/JavaScriptCore/dfg/DFGDriver.cpp
r95901 r96375 39 39 { 40 40 JSGlobalData* globalData = &exec->globalData(); 41 Graph dfg (codeBlock->m_numParameters, codeBlock->m_numVars);41 Graph dfg; 42 42 if (!parse(dfg, globalData, codeBlock)) 43 43 return false; … … 47 47 48 48 propagate(dfg, globalData, codeBlock); 49 50 // Save the predictions we've made, so that OSR entry can verify them. Predictions51 // are saved in the CodeBlock from which we will be doing OSR entry, since the52 // CodeBlock to which we are OSRing may be replaced at any time.53 OwnPtr<PredictionTracker> predictions = adoptPtr(new PredictionTracker());54 *predictions = dfg.predictions();55 ASSERT(codeBlock->alternative());56 ASSERT(codeBlock->alternative()->getJITType() == JITCode::BaselineJIT);57 codeBlock->alternative()->setPredictions(predictions.release());58 49 59 50 JITCompiler dataFlowJIT(globalData, dfg, codeBlock); -
trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp
r95930 r96375 45 45 { 46 46 return dfgOpNames[op & NodeIdMask]; 47 } 48 49 const char* Graph::nameOfVariableAccessData(VariableAccessData* variableAccessData) 50 { 51 // Variables are already numbered. For readability of IR dumps, this returns 52 // an alphabetic name for the variable access data, so that you don't have to 53 // reason about two numbers (variable number and live range number), but instead 54 // a number and a letter. 55 56 unsigned index = std::numeric_limits<unsigned>::max(); 57 for (unsigned i = 0; i < m_variableAccessData.size(); ++i) { 58 if (&m_variableAccessData[i] == variableAccessData) { 59 index = i; 60 break; 61 } 62 } 63 64 ASSERT(index != std::numeric_limits<unsigned>::max()); 65 66 if (!index) 67 return "A"; 68 69 static char buf[10]; 70 BoundsCheckedPointer<char> ptr(buf, sizeof(buf)); 71 72 while (index) { 73 *ptr++ = 'A' + (index % 26); 74 index /= 26; 75 } 76 77 *ptr++ = 0; 78 79 return buf; 47 80 } 48 81 … … 117 150 hasPrinted = true; 118 151 } 119 if (node.hasLocal()) { 120 int local = node.local(); 121 if (operandIsArgument(local)) 122 printf("%sarg%u", hasPrinted ? ", " : "", local - codeBlock->thisRegister()); 152 ASSERT(node.hasVariableAccessData() == node.hasLocal()); 153 if (node.hasVariableAccessData()) { 154 VariableAccessData* variableAccessData = node.variableAccessData(); 155 int operand = variableAccessData->operand(); 156 if (operandIsArgument(operand)) 157 printf("%sarg%u(%s)", hasPrinted ? ", " : "", operand - codeBlock->thisRegister(), nameOfVariableAccessData(variableAccessData)); 123 158 else 124 printf("%sr%u ", hasPrinted ? ", " : "", local);159 printf("%sr%u(%s)", hasPrinted ? ", " : "", operand, nameOfVariableAccessData(variableAccessData)); 125 160 hasPrinted = true; 126 161 } … … 146 181 147 182 if (!skipped) { 148 if (node.has Local())149 printf(" predicting %s", predictionToString( getPrediction(node.local())));183 if (node.hasVariableAccessData()) 184 printf(" predicting %s", predictionToString(node.variableAccessData()->prediction())); 150 185 else if (node.hasVarNumber()) 151 186 printf(" predicting %s", predictionToString(getGlobalVarPrediction(node.varNumber()))); … … 205 240 { 206 241 if (exec) { 207 size_t numberOfArguments = std::min(exec->argumentCountIncludingThis(), m_ predictions.numberOfArguments());242 size_t numberOfArguments = std::min(exec->argumentCountIncludingThis(), m_arguments.size()); 208 243 209 244 for (size_t arg = 1; arg < numberOfArguments; ++arg) 210 m_predictions.predictArgument(arg,predictionFromValue(exec->argument(arg - 1)));245 at(m_arguments[arg]).variableAccessData()->predict(predictionFromValue(exec->argument(arg - 1))); 211 246 } 212 247 … … 221 256 continue; 222 257 223 m_predictions.predictArgument(arg,profile->computeUpdatedPrediction());258 at(m_arguments[arg]).variableAccessData()->predict(profile->computeUpdatedPrediction()); 224 259 225 260 #if ENABLE(DFG_DEBUG_VERBOSE) 226 printf("Argument [%lu] prediction: %s\n", arg, predictionToString( m_predictions.getArgumentPrediction(arg)));261 printf("Argument [%lu] prediction: %s\n", arg, predictionToString(at(m_arguments[arg]).variableAccessData()->prediction())); 227 262 #endif 228 263 } -
trunk/Source/JavaScriptCore/dfg/DFGGraph.h
r95930 r96375 44 44 namespace DFG { 45 45 46 // helper function to distinguish vars & temporaries from arguments. 47 inline bool operandIsArgument(int operand) { return operand < 0; } 48 46 49 typedef uint32_t BlockIndex; 47 50 … … 53 56 : value(NoNode) 54 57 { 58 } 59 60 void setFirstTime(NodeIndex nodeIndex) 61 { 62 ASSERT(value == NoNode); 63 value = nodeIndex; 55 64 } 56 65 … … 111 120 , end(NoNode) 112 121 , isOSRTarget(false) 113 , m_arguments(numArguments) 114 , m_locals(numLocals) 122 , m_argumentsAtHead(numArguments) 123 , m_localsAtHead(numLocals) 124 , m_argumentsAtTail(numArguments) 125 , m_localsAtTail(numLocals) 115 126 { 116 127 } … … 127 138 128 139 PredecessorList m_predecessors; 129 Vector <VariableRecord, 8> m_arguments; 130 Vector <VariableRecord, 16> m_locals; 140 141 Vector<VariableRecord, 8> m_argumentsAtHead; 142 Vector<VariableRecord, 16> m_localsAtHead; 143 144 Vector<VariableRecord, 8> m_argumentsAtTail; 145 Vector<VariableRecord, 16> m_localsAtTail; 131 146 }; 132 147 … … 139 154 class Graph : public Vector<Node, 64> { 140 155 public: 141 Graph(unsigned numArguments, unsigned numVariables)142 : m_predictions(numArguments, numVariables)143 {144 }145 146 156 // Mark a node as being referenced. 147 157 void ref(NodeIndex nodeIndex) … … 172 182 } 173 183 174 PredictionTracker& predictions()175 {176 return m_predictions;177 }178 179 bool predict(int operand, PredictedType prediction)180 {181 return m_predictions.predict(operand, prediction);182 }183 184 184 bool predictGlobalVar(unsigned varNumber, PredictedType prediction) 185 185 { … … 191 191 switch (node.op) { 192 192 case GetLocal: 193 return predict(node.local(), prediction); 194 break; 193 case SetLocal: 194 case Phi: 195 case SetArgument: 196 return node.variableAccessData()->predict(prediction); 195 197 case GetGlobalVar: 196 198 return predictGlobalVar(node.varNumber(), prediction); 197 break;198 199 case GetById: 199 200 case GetMethod: … … 213 214 } 214 215 215 PredictedType getPrediction(int operand)216 {217 return m_predictions.getPrediction(operand);218 }219 220 216 PredictedType getGlobalVarPrediction(unsigned varNumber) 221 217 { … … 245 241 switch (nodePtr->op) { 246 242 case GetLocal: 247 return getPrediction(nodePtr->local()); 243 case SetLocal: 244 case SetArgument: 245 case Phi: 246 return nodePtr->variableAccessData()->prediction(); 248 247 case GetGlobalVar: 249 248 return getGlobalVarPrediction(nodePtr->varNumber()); … … 325 324 #ifndef NDEBUG 326 325 static const char *opName(NodeType); 326 327 // This is O(n), and should only be used for verbose dumps. 328 const char* nameOfVariableAccessData(VariableAccessData*); 327 329 #endif 328 330 … … 334 336 Vector<StorageAccessData> m_storageAccessData; 335 337 Vector<ResolveGlobalData> m_resolveGlobalData; 338 Vector<NodeIndex, 8> m_arguments; 339 SegmentedVector<VariableAccessData, 16> m_variableAccessData; 336 340 unsigned m_preservedVars; 341 unsigned m_localVars; 337 342 unsigned m_parameterSlots; 338 343 private: -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
r95933 r96375 577 577 // Link the code, populate data in CodeBlock data structures. 578 578 #if ENABLE(DFG_DEBUG_VERBOSE) 579 fprintf(stderr, "JIT code for %p start at [%p, %p) \n", m_codeBlock, linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) +linkBuffer.debugSize());579 fprintf(stderr, "JIT code for %p start at [%p, %p). Size = %lu.\n", m_codeBlock, linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize(), linkBuffer.debugSize()); 580 580 #endif 581 581 -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h
r96171 r96375 394 394 OSREntryData* entry = codeBlock()->appendDFGOSREntryData(basicBlock.bytecodeBegin, differenceBetween(m_startOfCode, label())); 395 395 396 unsigned lastLiveArgument = 0; 397 unsigned lastLiveLocal = 0; 396 ActionablePredictions actionablePredictions(basicBlock.m_argumentsAtHead.size(), basicBlock.m_localsAtHead.size()); 397 398 for (unsigned i = 0; i < basicBlock.m_argumentsAtHead.size(); ++i) { 399 NodeIndex nodeIndex = basicBlock.m_argumentsAtHead[i].value; 400 if (nodeIndex != NoNode) 401 actionablePredictions.setArgument(i, actionablePredictionFromPredictedType(m_graph[nodeIndex].variableAccessData()->prediction())); 402 } 398 403 399 for (unsigned i = 0; i < basicBlock.m_arguments.size(); ++i) { 400 if (basicBlock.m_arguments[i].value != NoNode) 401 lastLiveArgument = i; 404 for (unsigned i = 0; i < basicBlock.m_localsAtHead.size(); ++i) { 405 NodeIndex nodeIndex = basicBlock.m_localsAtHead[i].value; 406 if (nodeIndex != NoNode) 407 actionablePredictions.setVariable(i, actionablePredictionFromPredictedType(m_graph[nodeIndex].variableAccessData()->prediction())); 402 408 } 403 409 404 for (unsigned i = 0; i < basicBlock.m_locals.size(); ++i) { 405 if (basicBlock.m_locals[i].value != NoNode) 406 lastLiveLocal = i; 407 } 410 actionablePredictions.pack(); 408 411 409 if (lastLiveArgument) { 410 entry->m_liveArguments.resize(lastLiveArgument + 1); 411 entry->m_liveArguments.clearAll(); 412 413 for (unsigned i = 0; i <= lastLiveArgument; ++i) { 414 if (basicBlock.m_arguments[i].value != NoNode) 415 entry->m_liveArguments.set(i); 416 } 417 } else 418 entry->m_liveArguments.clearAll(); 419 420 if (lastLiveLocal) { 421 entry->m_liveVariables.resize(lastLiveLocal + 1); 422 entry->m_liveVariables.clearAll(); 423 424 for (unsigned i = 0; i <= lastLiveLocal; ++i) { 425 if (basicBlock.m_locals[i].value != NoNode) 426 entry->m_liveVariables.set(i); 427 } 428 } else 429 entry->m_liveVariables.clearAll(); 412 entry->m_predictions = actionablePredictions; 430 413 #else 431 414 UNUSED_PARAM(basicBlock); -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r96309 r96375 29 29 #include <wtf/BoundsCheckedPointer.h> 30 30 #include <wtf/Platform.h> 31 #include <wtf/UnionFind.h> 31 32 32 33 // Emit various logging information for debugging, including dumping the dataflow graphs. … … 109 110 }; 110 111 112 class VariableAccessData: public UnionFind<VariableAccessData> { 113 public: 114 VariableAccessData() 115 : m_local(static_cast<VirtualRegister>(std::numeric_limits<int>::min())) 116 , m_prediction(PredictNone) 117 { 118 } 119 120 VariableAccessData(VirtualRegister local) 121 : m_local(local) 122 , m_prediction(PredictNone) 123 { 124 } 125 126 VirtualRegister local() 127 { 128 ASSERT(m_local == find()->m_local); 129 return m_local; 130 } 131 132 int operand() 133 { 134 return static_cast<int>(local()); 135 } 136 137 bool predict(PredictedType prediction) 138 { 139 return mergePrediction(find()->m_prediction, prediction); 140 } 141 142 PredictedType prediction() 143 { 144 return find()->m_prediction; 145 } 146 147 private: 148 // This is slightly space-inefficient, since anything we're unified with 149 // will have the same operand and should have the same prediction. But 150 // putting them here simplifies the code, and we don't expect DFG space 151 // usage for variable access nodes do be significant. 152 153 VirtualRegister m_local; 154 PredictedType m_prediction; 155 }; 156 111 157 typedef unsigned ArithNodeFlags; 112 158 #define NodeUseBottom 0x00 … … 223 269 macro(Phantom, NodeMustGenerate) \ 224 270 macro(Phi, 0) \ 271 \ 272 /* Marker for arguments being set. */\ 273 macro(SetArgument, 0) \ 225 274 \ 226 275 /* Nodes for bitwise operations. */\ … … 465 514 } 466 515 516 bool hasVariableAccessData() 517 { 518 switch (op) { 519 case GetLocal: 520 case SetLocal: 521 case Phi: 522 case SetArgument: 523 return true; 524 default: 525 return false; 526 } 527 } 528 467 529 bool hasLocal() 468 530 { 469 return op == GetLocal || op == SetLocal; 470 } 471 531 return hasVariableAccessData(); 532 } 533 534 VariableAccessData* variableAccessData() 535 { 536 return reinterpret_cast<VariableAccessData*>(m_opInfo)->find(); 537 } 538 472 539 VirtualRegister local() 473 540 { 474 ASSERT(hasLocal()); 475 return (VirtualRegister)m_opInfo; 541 return variableAccessData()->local(); 476 542 } 477 543 -
trunk/Source/JavaScriptCore/dfg/DFGOSREntry.cpp
r95901 r96375 36 36 namespace JSC { namespace DFG { 37 37 38 inline bool predictionIsValid(JSGlobalData* globalData, JSValue value, PredictedType type)39 {40 // this takes into account only local variable predictions that get enforced41 // on SetLocal.42 43 if (isInt32Prediction(type))44 return value.isInt32();45 46 if (isArrayPrediction(type))47 return isJSArray(globalData, value);48 49 if (isBooleanPrediction(type))50 return value.isBoolean();51 52 return true;53 }54 55 38 void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIndex) 56 39 { … … 67 50 68 51 JSGlobalData* globalData = &exec->globalData(); 69 CodeBlock* baselineCodeBlock = codeBlock->alternative();70 52 OSREntryData* entry = codeBlock->dfgOSREntryDataForBytecodeIndex(bytecodeIndex); 71 53 … … 96 78 // OSR at this time. 97 79 98 PredictionTracker* predictions = baselineCodeBlock->predictions(); 99 100 if (predictions->numberOfArguments() > exec->argumentCountIncludingThis()) 101 return 0; 102 103 for (unsigned i = 1; i < predictions->numberOfArguments(); ++i) { 104 if (i < entry->m_liveArguments.size() && entry->m_liveArguments.get(i) 105 && !predictionIsValid(globalData, exec->argument(i - 1), predictions->getArgumentPrediction(i))) { 80 for (unsigned i = 1; i < entry->m_predictions.argumentUpperBound(); ++i) { 81 ActionablePrediction prediction = entry->m_predictions.argument(i); 82 if (prediction == NoActionablePrediction) 83 continue; 84 85 if (i >= exec->argumentCountIncludingThis()) { 106 86 #if ENABLE(JIT_VERBOSE_OSR) 107 printf(" OSR failed because argument %u is %s, expected %s.\n", i, exec->argument(i - 1).description(), predictionToString(predictions->getArgumentPrediction(i))); 87 printf(" OSR failed because argument %u was not passed, expected %s.\n", i, actionablePredictionToString(prediction)); 88 #endif 89 return 0; 90 } 91 92 if (!valueObeysPrediction(globalData, exec->argument(i - 1), prediction)) { 93 #if ENABLE(JIT_VERBOSE_OSR) 94 printf(" OSR failed because argument %u is %s, expected %s.\n", i, exec->argument(i - 1).description(), actionablePredictionToString(prediction)); 108 95 #endif 109 96 return 0; … … 111 98 } 112 99 113 for (unsigned i = 0; i < predictions->numberOfVariables(); ++i) { 114 if (i < entry->m_liveVariables.size() && entry->m_liveVariables.get(i) 115 && !predictionIsValid(globalData, exec->registers()[i].jsValue(), predictions->getPrediction(i))) { 100 for (unsigned i = 0; i < entry->m_predictions.variableUpperBound(); ++i) { 101 ActionablePrediction prediction = entry->m_predictions.variable(i); 102 if (prediction == NoActionablePrediction) 103 continue; 104 105 if (!valueObeysPrediction(globalData, exec->registers()[i].jsValue(), prediction)) { 116 106 #if ENABLE(JIT_VERBOSE_OSR) 117 printf(" OSR failed because variable %u is %s, expected %s.\n", i, exec->registers()[i].jsValue().description(), predictionToString(predictions->getPrediction(i)));107 printf(" OSR failed because variable %u is %s, expected %s.\n", i, exec->registers()[i].jsValue().description(), actionablePredictionToString(prediction)); 118 108 #endif 119 109 return 0; … … 130 120 if (!globalData->interpreter->registerFile().grow(&exec->registers()[codeBlock->m_numCalleeRegisters])) { 131 121 #if ENABLE(JIT_VERBOSE_OSR) 132 printf(" OSR failed because stack growth failed. .\n");122 printf(" OSR failed because stack growth failed.\n"); 133 123 #endif 134 124 return 0; -
trunk/Source/JavaScriptCore/dfg/DFGOSREntry.h
r95901 r96375 27 27 #define DFGOSREntry_h 28 28 29 #include <wtf/BitVector.h>29 #include "ActionablePrediction.h" 30 30 31 31 namespace JSC { … … 40 40 unsigned m_bytecodeIndex; 41 41 unsigned m_machineCodeOffset; 42 BitVector m_liveArguments; 43 BitVector m_liveVariables; 42 ActionablePredictions m_predictions; 44 43 }; 45 44 -
trunk/Source/JavaScriptCore/dfg/DFGPropagator.cpp
r96189 r96375 320 320 321 321 case GetLocal: { 322 PredictedType prediction = m_graph.getPrediction(node.local());322 PredictedType prediction = node.variableAccessData()->prediction(); 323 323 if (prediction) 324 324 changed |= mergePrediction(prediction); … … 327 327 328 328 case SetLocal: { 329 changed |= m_graph.predict(node.local(),m_predictions[node.child1()]);329 changed |= node.variableAccessData()->predict(m_predictions[node.child1()]); 330 330 break; 331 331 } … … 473 473 474 474 case ConvertThis: { 475 changed |= setPrediction(PredictObjectUnknown); 475 PredictedType prediction = m_predictions[node.child1()]; 476 if (prediction) { 477 if (prediction & ~PredictObjectMask) { 478 prediction &= ~PredictObjectMask; 479 prediction |= PredictObjectUnknown; 480 } 481 changed |= mergePrediction(prediction); 482 } 476 483 break; 477 484 } … … 572 579 case ThrowReferenceError: 573 580 case ForceOSRExit: 574 break; 575 576 // This gets ignored because it doesn't do anything. 577 case Phantom: 581 case SetArgument: 578 582 case PutByVal: 579 583 case PutByValAlias: 580 584 case PutById: 581 585 case PutByIdDirect: 586 break; 587 588 // This gets ignored because it doesn't do anything. 589 case Phantom: 582 590 break; 583 591 #else -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r96306 r96375 156 156 void ValueSource::dump(FILE* out) const 157 157 { 158 fprintf(out, "Node(%d)", m_nodeIndex); 158 switch (kind()) { 159 case SourceNotSet: 160 fprintf(out, "NotSet"); 161 break; 162 case ValueInRegisterFile: 163 fprintf(out, "InRegFile"); 164 break; 165 case Int32InRegisterFile: 166 fprintf(out, "Int32"); 167 break; 168 case HaveNode: 169 fprintf(out, "Node(%d)", m_nodeIndex); 170 break; 171 } 159 172 } 160 173 … … 204 217 ASSERT(m_bytecodeIndex != std::numeric_limits<uint32_t>::max()); 205 218 for (unsigned argument = 0; argument < m_arguments.size(); ++argument) 206 m_arguments[argument] = jit->computeValueRecoveryFor( operandForArgument(argument),jit->m_arguments[argument]);219 m_arguments[argument] = jit->computeValueRecoveryFor(jit->m_arguments[argument]); 207 220 for (unsigned variable = 0; variable < m_variables.size(); ++variable) 208 m_variables[variable] = jit->computeValueRecoveryFor( variable,jit->m_variables[variable]);221 m_variables[variable] = jit->computeValueRecoveryFor(jit->m_variables[variable]); 209 222 } 210 223 … … 723 736 724 737 case GetLocal: { 725 PredictedType prediction = m_jit.graph().getPrediction(node.local());738 PredictedType prediction = node.variableAccessData()->prediction(); 726 739 727 740 // If we have no prediction for this local, then don't attempt to compile. … … 798 811 m_bytecodeIndexForOSR = nextNode.codeOrigin.bytecodeIndex(); 799 812 800 PredictedType predictedType = m_jit.graph().getPrediction(node.local());813 PredictedType predictedType = node.variableAccessData()->prediction(); 801 814 if (isInt32Prediction(predictedType)) { 802 815 SpeculateIntegerOperand value(this, node.child1()); … … 821 834 // Indicate that it's no longer necessary to retrieve the value of 822 835 // this bytecode variable from registers or other locations in the register file. 823 valueSourceReferenceForOperand(node.local()) = ValueSource(); 824 break; 825 } 836 valueSourceReferenceForOperand(node.local()) = ValueSource::forPrediction(predictedType); 837 break; 838 } 839 840 case SetArgument: 841 // This is a no-op; it just marks the fact that the argument is being used. 842 // But it may be profitable to use this as a hook to run speculation checks 843 // on arguments, thereby allowing us to trivially eliminate such checks if 844 // the argument is not used. 845 break; 826 846 827 847 case BitAnd: … … 2202 2222 #endif 2203 2223 2204 for (size_t i = 0; i < m_arguments.size(); ++i) 2205 m_arguments[i] = ValueSource(); 2206 for (size_t i = 0; i < m_variables.size(); ++i) 2207 m_variables[i] = ValueSource(); 2224 ASSERT(m_arguments.size() == block.m_argumentsAtHead.size()); 2225 for (size_t i = 0; i < m_arguments.size(); ++i) { 2226 NodeIndex nodeIndex = block.m_argumentsAtHead[i].value; 2227 if (nodeIndex == NoNode) 2228 m_arguments[i] = ValueSource(ValueInRegisterFile); 2229 else 2230 m_arguments[i] = ValueSource::forPrediction(m_jit.graph()[nodeIndex].variableAccessData()->prediction()); 2231 } 2232 2233 ASSERT(m_variables.size() == block.m_localsAtHead.size()); 2234 for (size_t i = 0; i < m_variables.size(); ++i) { 2235 NodeIndex nodeIndex = block.m_localsAtHead[i].value; 2236 if (nodeIndex == NoNode) 2237 m_variables[i] = ValueSource(ValueInRegisterFile); 2238 else 2239 m_variables[i] = ValueSource::forPrediction(m_jit.graph()[nodeIndex].variableAccessData()->prediction()); 2240 } 2241 2208 2242 m_lastSetOperand = std::numeric_limits<int>::max(); 2209 2243 m_bytecodeIndexForOSR = std::numeric_limits<uint32_t>::max(); … … 2276 2310 ASSERT(!m_compileIndex); 2277 2311 m_bytecodeIndexForOSR = 0; 2312 2313 for (size_t i = 0; i < m_arguments.size(); ++i) 2314 m_arguments[i] = ValueSource(ValueInRegisterFile); 2315 for (size_t i = 0; i < m_variables.size(); ++i) 2316 m_variables[i] = ValueSource(ValueInRegisterFile); 2317 2278 2318 for (int i = 0; i < m_jit.codeBlock()->m_numParameters; ++i) { 2279 2319 VirtualRegister virtualRegister = (VirtualRegister)(m_jit.codeBlock()->thisRegister() + i); 2280 PredictedType predictedType = m_jit.graph() .getPrediction(virtualRegister);2320 PredictedType predictedType = m_jit.graph()[m_jit.graph().m_arguments[i]].variableAccessData()->prediction(); 2281 2321 if (isInt32Prediction(predictedType)) 2282 2322 speculationCheck(m_jit.branchPtr(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::tagTypeNumberRegister)); … … 2306 2346 } 2307 2347 2308 ValueRecovery SpeculativeJIT::computeValueRecoveryFor( int operand,const ValueSource& valueSource)2348 ValueRecovery SpeculativeJIT::computeValueRecoveryFor(const ValueSource& valueSource) 2309 2349 { 2310 if (!valueSource.isSet()) { 2311 if (m_bytecodeIndexForOSR && isInt32Prediction(m_jit.graph().getPrediction(operand))) 2312 return ValueRecovery::alreadyInRegisterFileAsUnboxedInt32(); 2350 switch (valueSource.kind()) { 2351 case ValueInRegisterFile: 2313 2352 return ValueRecovery::alreadyInRegisterFile(); 2314 } 2315 2316 if (m_jit.isConstant(valueSource.nodeIndex())) 2317 return ValueRecovery::constant(m_jit.valueOfJSConstant(valueSource.nodeIndex())); 2318 2319 Node* nodePtr = &m_jit.graph()[valueSource.nodeIndex()]; 2320 if (!nodePtr->shouldGenerate()) { 2321 // It's legitimately dead. As in, nobody will ever use this node, or operand, 2322 // ever. Set it to Undefined to make the GC happy after the OSR. 2323 return ValueRecovery::constant(jsUndefined()); 2324 } 2325 2326 GenerationInfo* infoPtr = &m_generationInfo[nodePtr->virtualRegister()]; 2327 if (!infoPtr->alive() || infoPtr->nodeIndex() != valueSource.nodeIndex()) { 2328 // Try to see if there is an alternate node that would contain the value we want. 2329 // There are four possibilities: 2330 // 2331 // ValueToNumber: If the only live version of the value is a ValueToNumber node 2332 // then it means that all remaining uses of the value would have performed a 2333 // ValueToNumber conversion anyway. Thus, we can substitute ValueToNumber. 2334 // 2335 // ValueToInt32: Likewise, if the only remaining live version of the value is 2336 // ValueToInt32, then we can use it. But if there is both a ValueToInt32 2337 // and a ValueToNumber, then we better go with ValueToNumber because it 2338 // means that some remaining uses would have converted to number while 2339 // others would have converted to Int32. 2340 // 2341 // UInt32ToNumber: If the only live version of the value is a UInt32ToNumber 2342 // then the only remaining uses are ones that want a properly formed number 2343 // rather than a UInt32 intermediate. 2344 // 2345 // The reverse of the above: This node could be a UInt32ToNumber, but its 2346 // alternative is still alive. This means that the only remaining uses of 2347 // the number would be fine with a UInt32 intermediate. 2348 2349 bool found = false; 2350 2351 if (nodePtr->op == UInt32ToNumber) { 2352 NodeIndex nodeIndex = nodePtr->child1(); 2353 nodePtr = &m_jit.graph()[nodeIndex]; 2354 infoPtr = &m_generationInfo[nodePtr->virtualRegister()]; 2355 if (infoPtr->alive() && infoPtr->nodeIndex() == nodeIndex) 2356 found = true; 2357 } 2358 2359 if (!found) { 2360 NodeIndex valueToNumberIndex = NoNode; 2361 NodeIndex valueToInt32Index = NoNode; 2362 NodeIndex uint32ToNumberIndex = NoNode; 2363 2364 for (unsigned virtualRegister = 0; virtualRegister < m_generationInfo.size(); ++virtualRegister) { 2365 GenerationInfo& info = m_generationInfo[virtualRegister]; 2366 if (!info.alive()) 2367 continue; 2368 if (info.nodeIndex() == NoNode) 2369 continue; 2370 Node& node = m_jit.graph()[info.nodeIndex()]; 2371 if (node.child1Unchecked() != valueSource.nodeIndex()) 2372 continue; 2373 switch (node.op) { 2374 case ValueToNumber: 2375 case ValueToDouble: 2376 valueToNumberIndex = info.nodeIndex(); 2377 break; 2378 case ValueToInt32: 2379 valueToInt32Index = info.nodeIndex(); 2380 break; 2381 case UInt32ToNumber: 2382 uint32ToNumberIndex = info.nodeIndex(); 2383 break; 2384 default: 2385 break; 2353 2354 case Int32InRegisterFile: 2355 return ValueRecovery::alreadyInRegisterFileAsUnboxedInt32(); 2356 2357 case HaveNode: { 2358 if (m_jit.isConstant(valueSource.nodeIndex())) 2359 return ValueRecovery::constant(m_jit.valueOfJSConstant(valueSource.nodeIndex())); 2360 2361 Node* nodePtr = &m_jit.graph()[valueSource.nodeIndex()]; 2362 if (!nodePtr->shouldGenerate()) { 2363 // It's legitimately dead. As in, nobody will ever use this node, or operand, 2364 // ever. Set it to Undefined to make the GC happy after the OSR. 2365 return ValueRecovery::constant(jsUndefined()); 2366 } 2367 2368 GenerationInfo* infoPtr = &m_generationInfo[nodePtr->virtualRegister()]; 2369 if (!infoPtr->alive() || infoPtr->nodeIndex() != valueSource.nodeIndex()) { 2370 // Try to see if there is an alternate node that would contain the value we want. 2371 // There are four possibilities: 2372 // 2373 // ValueToNumber: If the only live version of the value is a ValueToNumber node 2374 // then it means that all remaining uses of the value would have performed a 2375 // ValueToNumber conversion anyway. Thus, we can substitute ValueToNumber. 2376 // 2377 // ValueToInt32: Likewise, if the only remaining live version of the value is 2378 // ValueToInt32, then we can use it. But if there is both a ValueToInt32 2379 // and a ValueToNumber, then we better go with ValueToNumber because it 2380 // means that some remaining uses would have converted to number while 2381 // others would have converted to Int32. 2382 // 2383 // UInt32ToNumber: If the only live version of the value is a UInt32ToNumber 2384 // then the only remaining uses are ones that want a properly formed number 2385 // rather than a UInt32 intermediate. 2386 // 2387 // The reverse of the above: This node could be a UInt32ToNumber, but its 2388 // alternative is still alive. This means that the only remaining uses of 2389 // the number would be fine with a UInt32 intermediate. 2390 2391 bool found = false; 2392 2393 if (nodePtr->op == UInt32ToNumber) { 2394 NodeIndex nodeIndex = nodePtr->child1(); 2395 nodePtr = &m_jit.graph()[nodeIndex]; 2396 infoPtr = &m_generationInfo[nodePtr->virtualRegister()]; 2397 if (infoPtr->alive() && infoPtr->nodeIndex() == nodeIndex) 2398 found = true; 2399 } 2400 2401 if (!found) { 2402 NodeIndex valueToNumberIndex = NoNode; 2403 NodeIndex valueToInt32Index = NoNode; 2404 NodeIndex uint32ToNumberIndex = NoNode; 2405 2406 for (unsigned virtualRegister = 0; virtualRegister < m_generationInfo.size(); ++virtualRegister) { 2407 GenerationInfo& info = m_generationInfo[virtualRegister]; 2408 if (!info.alive()) 2409 continue; 2410 if (info.nodeIndex() == NoNode) 2411 continue; 2412 Node& node = m_jit.graph()[info.nodeIndex()]; 2413 if (node.child1Unchecked() != valueSource.nodeIndex()) 2414 continue; 2415 switch (node.op) { 2416 case ValueToNumber: 2417 case ValueToDouble: 2418 valueToNumberIndex = info.nodeIndex(); 2419 break; 2420 case ValueToInt32: 2421 valueToInt32Index = info.nodeIndex(); 2422 break; 2423 case UInt32ToNumber: 2424 uint32ToNumberIndex = info.nodeIndex(); 2425 break; 2426 default: 2427 break; 2428 } 2429 } 2430 2431 NodeIndex nodeIndexToUse; 2432 if (valueToNumberIndex != NoNode) 2433 nodeIndexToUse = valueToNumberIndex; 2434 else if (valueToInt32Index != NoNode) 2435 nodeIndexToUse = valueToInt32Index; 2436 else if (uint32ToNumberIndex != NoNode) 2437 nodeIndexToUse = uint32ToNumberIndex; 2438 else 2439 nodeIndexToUse = NoNode; 2440 2441 if (nodeIndexToUse != NoNode) { 2442 nodePtr = &m_jit.graph()[nodeIndexToUse]; 2443 infoPtr = &m_generationInfo[nodePtr->virtualRegister()]; 2444 ASSERT(infoPtr->alive() && infoPtr->nodeIndex() == nodeIndexToUse); 2445 found = true; 2386 2446 } 2387 2447 } 2388 2389 NodeIndex nodeIndexToUse; 2390 if (valueToNumberIndex != NoNode) 2391 nodeIndexToUse = valueToNumberIndex; 2392 else if (valueToInt32Index != NoNode) 2393 nodeIndexToUse = valueToInt32Index; 2394 else if (uint32ToNumberIndex != NoNode) 2395 nodeIndexToUse = uint32ToNumberIndex; 2396 else 2397 nodeIndexToUse = NoNode; 2398 2399 if (nodeIndexToUse != NoNode) { 2400 nodePtr = &m_jit.graph()[nodeIndexToUse]; 2401 infoPtr = &m_generationInfo[nodePtr->virtualRegister()]; 2402 ASSERT(infoPtr->alive() && infoPtr->nodeIndex() == nodeIndexToUse); 2403 found = true; 2404 } 2405 } 2406 2407 if (!found) 2408 return ValueRecovery::constant(jsUndefined()); 2409 } 2410 2411 ASSERT(infoPtr->alive()); 2412 2413 if (infoPtr->registerFormat() != DataFormatNone) { 2414 if (infoPtr->registerFormat() == DataFormatDouble) 2415 return ValueRecovery::inFPR(infoPtr->fpr()); 2416 return ValueRecovery::inGPR(infoPtr->gpr(), infoPtr->registerFormat()); 2417 } 2418 if (infoPtr->spillFormat() != DataFormatNone) 2419 return ValueRecovery::displacedInRegisterFile(static_cast<VirtualRegister>(nodePtr->virtualRegister())); 2420 2421 ASSERT_NOT_REACHED(); 2422 return ValueRecovery(); 2448 2449 if (!found) 2450 return ValueRecovery::constant(jsUndefined()); 2451 } 2452 2453 ASSERT(infoPtr->alive()); 2454 2455 if (infoPtr->registerFormat() != DataFormatNone) { 2456 if (infoPtr->registerFormat() == DataFormatDouble) 2457 return ValueRecovery::inFPR(infoPtr->fpr()); 2458 return ValueRecovery::inGPR(infoPtr->gpr(), infoPtr->registerFormat()); 2459 } 2460 if (infoPtr->spillFormat() != DataFormatNone) 2461 return ValueRecovery::displacedInRegisterFile(static_cast<VirtualRegister>(nodePtr->virtualRegister())); 2462 2463 ASSERT_NOT_REACHED(); 2464 return ValueRecovery(); 2465 } 2466 2467 default: 2468 ASSERT_NOT_REACHED(); 2469 return ValueRecovery(); 2470 } 2423 2471 } 2424 2472 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r96189 r96375 67 67 }; 68 68 69 enum ValueSourceKind { 70 SourceNotSet, 71 ValueInRegisterFile, 72 Int32InRegisterFile, 73 HaveNode 74 }; 75 69 76 class ValueSource { 70 77 public: 71 78 ValueSource() 72 : m_nodeIndex(NoNode) 73 { 79 : m_nodeIndex(nodeIndexFromKind(SourceNotSet)) 80 { 81 } 82 83 explicit ValueSource(ValueSourceKind valueSourceKind) 84 : m_nodeIndex(nodeIndexFromKind(valueSourceKind)) 85 { 86 ASSERT(kind() != SourceNotSet); 87 ASSERT(kind() != HaveNode); 74 88 } 75 89 … … 77 91 : m_nodeIndex(nodeIndex) 78 92 { 93 ASSERT(kind() == HaveNode); 94 } 95 96 static ValueSource forPrediction(PredictedType prediction) 97 { 98 if (isInt32Prediction(prediction)) 99 return ValueSource(Int32InRegisterFile); 100 return ValueSource(ValueInRegisterFile); 79 101 } 80 102 81 103 bool isSet() const 82 104 { 83 return m_nodeIndex != NoNode; 105 return kindFromNodeIndex(m_nodeIndex) != SourceNotSet; 106 } 107 108 ValueSourceKind kind() const 109 { 110 return kindFromNodeIndex(m_nodeIndex); 84 111 } 85 112 86 113 NodeIndex nodeIndex() const 87 114 { 88 ASSERT( isSet());115 ASSERT(kind() == HaveNode); 89 116 return m_nodeIndex; 90 117 } … … 95 122 96 123 private: 124 static NodeIndex nodeIndexFromKind(ValueSourceKind kind) 125 { 126 ASSERT(kind >= SourceNotSet && kind < HaveNode); 127 return NoNode - kind; 128 } 129 130 static ValueSourceKind kindFromNodeIndex(NodeIndex nodeIndex) 131 { 132 unsigned kind = static_cast<unsigned>(NoNode - nodeIndex); 133 if (kind >= static_cast<unsigned>(HaveNode)) 134 return HaveNode; 135 return static_cast<ValueSourceKind>(kind); 136 } 137 97 138 NodeIndex m_nodeIndex; 98 139 }; … … 518 559 switch (node.op) { 519 560 case GetLocal: 520 return isArrayPrediction( m_jit.graph().getPrediction(node.local()));561 return isArrayPrediction(node.variableAccessData()->prediction()); 521 562 522 563 case NewArray: … … 591 632 // Tracking for which nodes are currently holding the values of arguments and bytecode 592 633 // operand-indexed variables. 593 634 594 635 ValueSource valueSourceForOperand(int operand) 595 636 { … … 624 665 uint32_t m_bytecodeIndexForOSR; 625 666 626 ValueRecovery computeValueRecoveryFor( int operand,const ValueSource&);667 ValueRecovery computeValueRecoveryFor(const ValueSource&); 627 668 628 669 ValueRecovery computeValueRecoveryFor(int operand) 629 670 { 630 return computeValueRecoveryFor( operand,valueSourceForOperand(operand));671 return computeValueRecoveryFor(valueSourceForOperand(operand)); 631 672 } 632 673 }; … … 853 894 , m_compileOkay(true) 854 895 , m_arguments(jit.codeBlock()->m_numParameters) 855 , m_variables(jit. codeBlock()->m_numVars)896 , m_variables(jit.graph().m_localVars) 856 897 , m_lastSetOperand(std::numeric_limits<int>::max()) 857 898 , m_bytecodeIndexForOSR(std::numeric_limits<uint32_t>::max()) -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r96344 r96375 118 118 void ValueSource::dump(FILE* out) const 119 119 { 120 fprintf(out, "Node(%d)", m_nodeIndex); 120 switch (kind()) { 121 case SourceNotSet: 122 fprintf(out, "NotSet"); 123 break; 124 case ValueInRegisterFile: 125 fprintf(out, "InRegFile"); 126 break; 127 case Int32InRegisterFile: 128 fprintf(out, "Int32"); 129 break; 130 case HaveNode: 131 fprintf(out, "Node(%d)", m_nodeIndex); 132 break; 133 } 121 134 } 122 135 … … 171 184 ASSERT(m_bytecodeIndex != std::numeric_limits<uint32_t>::max()); 172 185 for (unsigned argument = 0; argument < m_arguments.size(); ++argument) 173 m_arguments[argument] = jit->computeValueRecoveryFor( operandForArgument(argument),jit->m_arguments[argument]);186 m_arguments[argument] = jit->computeValueRecoveryFor(jit->m_arguments[argument]); 174 187 for (unsigned variable = 0; variable < m_variables.size(); ++variable) 175 m_variables[variable] = jit->computeValueRecoveryFor( variable,jit->m_variables[variable]);188 m_variables[variable] = jit->computeValueRecoveryFor(jit->m_variables[variable]); 176 189 } 177 190 … … 632 645 633 646 case GetLocal: { 634 PredictedType prediction = m_jit.graph().getPrediction(node.local());647 PredictedType prediction = node.variableAccessData()->prediction(); 635 648 636 649 // If we have no prediction for this local, then don't attempt to compile. … … 706 719 m_bytecodeIndexForOSR = nextNode.codeOrigin.bytecodeIndex(); 707 720 708 PredictedType predictedType = m_jit.graph().getPrediction(node.local());721 PredictedType predictedType = node.variableAccessData()->prediction(); 709 722 if (isInt32Prediction(predictedType)) { 710 723 SpeculateIntegerOperand value(this, node.child1()); … … 726 739 // Indicate that it's no longer necessary to retrieve the value of 727 740 // this bytecode variable from registers or other locations in the register file. 728 valueSourceReferenceForOperand(node.local()) = ValueSource(); 729 break; 730 } 741 valueSourceReferenceForOperand(node.local()) = ValueSource::forPrediction(predictedType); 742 break; 743 } 744 745 case SetArgument: 746 // This is a no-op; it just marks the fact that the argument is being used. 747 // But it may be profitable to use this as a hook to run speculation checks 748 // on arguments, thereby allowing us to trivially eliminate such checks if 749 // the argument is not used. 750 break; 731 751 732 752 case BitAnd: … … 2135 2155 #endif 2136 2156 2137 for (size_t i = 0; i < m_arguments.size(); ++i) 2138 m_arguments[i] = ValueSource(); 2139 for (size_t i = 0; i < m_variables.size(); ++i) 2140 m_variables[i] = ValueSource(); 2157 ASSERT(m_arguments.size() == block.m_argumentsAtHead.size()); 2158 for (size_t i = 0; i < m_arguments.size(); ++i) { 2159 NodeIndex nodeIndex = block.m_argumentsAtHead[i].value; 2160 if (nodeIndex == NoNode) 2161 m_arguments[i] = ValueSource(ValueInRegisterFile); 2162 else 2163 m_arguments[i] = ValueSource::forPrediction(m_jit.graph()[nodeIndex].variableAccessData()->prediction()); 2164 } 2165 2166 ASSERT(m_variables.size() == block.m_localsAtHead.size()); 2167 for (size_t i = 0; i < m_variables.size(); ++i) { 2168 NodeIndex nodeIndex = block.m_localsAtHead[i].value; 2169 if (nodeIndex == NoNode) 2170 m_variables[i] = ValueSource(ValueInRegisterFile); 2171 else 2172 m_variables[i] = ValueSource::forPrediction(m_jit.graph()[nodeIndex].variableAccessData()->prediction()); 2173 } 2174 2141 2175 m_lastSetOperand = std::numeric_limits<int>::max(); 2142 2176 m_bytecodeIndexForOSR = std::numeric_limits<uint32_t>::max(); … … 2211 2245 ASSERT(!m_compileIndex); 2212 2246 m_bytecodeIndexForOSR = 0; 2247 2248 for (size_t i = 0; i < m_arguments.size(); ++i) 2249 m_arguments[i] = ValueSource(ValueInRegisterFile); 2250 for (size_t i = 0; i < m_variables.size(); ++i) 2251 m_variables[i] = ValueSource(ValueInRegisterFile); 2252 2213 2253 for (int i = 0; i < m_jit.codeBlock()->m_numParameters; ++i) { 2214 2254 VirtualRegister virtualRegister = (VirtualRegister)(m_jit.codeBlock()->thisRegister() + i); 2215 PredictedType predictedType = m_jit.graph() .getPrediction(virtualRegister);2255 PredictedType predictedType = m_jit.graph()[m_jit.graph().m_arguments[i]].variableAccessData()->prediction(); 2216 2256 if (isInt32Prediction(predictedType)) 2217 2257 speculationCheck(m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag))); … … 2237 2277 } 2238 2278 2239 ValueRecovery SpeculativeJIT::computeValueRecoveryFor( int operand,const ValueSource& valueSource)2279 ValueRecovery SpeculativeJIT::computeValueRecoveryFor(const ValueSource& valueSource) 2240 2280 { 2241 if (!valueSource.isSet()) { 2242 if (m_bytecodeIndexForOSR && isInt32Prediction(m_jit.graph().getPrediction(operand))) 2243 return ValueRecovery::alreadyInRegisterFileAsUnboxedInt32(); 2281 switch (valueSource.kind()) { 2282 case ValueInRegisterFile: 2244 2283 return ValueRecovery::alreadyInRegisterFile(); 2245 } 2246 2247 if (m_jit.isConstant(valueSource.nodeIndex())) 2248 return ValueRecovery::constant(m_jit.valueOfJSConstant(valueSource.nodeIndex())); 2249 2250 Node* nodePtr = &m_jit.graph()[valueSource.nodeIndex()]; 2251 if (!nodePtr->shouldGenerate()) { 2252 // It's legitimately dead. As in, nobody will ever use this node, or operand, 2253 // ever. Set it to Undefined to make the GC happy after the OSR. 2254 return ValueRecovery::constant(jsUndefined()); 2255 } 2256 2257 GenerationInfo* infoPtr = &m_generationInfo[nodePtr->virtualRegister()]; 2258 if (!infoPtr->alive() || infoPtr->nodeIndex() != valueSource.nodeIndex()) { 2259 // Try to see if there is an alternate node that would contain the value we want. 2260 // There are four possibilities: 2261 // 2262 // ValueToNumber: If the only live version of the value is a ValueToNumber node 2263 // then it means that all remaining uses of the value would have performed a 2264 // ValueToNumber conversion anyway. Thus, we can substitute ValueToNumber. 2265 // 2266 // ValueToInt32: Likewise, if the only remaining live version of the value is 2267 // ValueToInt32, then we can use it. But if there is both a ValueToInt32 2268 // and a ValueToNumber, then we better go with ValueToNumber because it 2269 // means that some remaining uses would have converted to number while 2270 // others would have converted to Int32. 2271 // 2272 // UInt32ToNumber: If the only live version of the value is a UInt32ToNumber 2273 // then the only remaining uses are ones that want a properly formed number 2274 // rather than a UInt32 intermediate. 2275 // 2276 // The reverse of the above: This node could be a UInt32ToNumber, but its 2277 // alternative is still alive. This means that the only remaining uses of 2278 // the number would be fine with a UInt32 intermediate. 2279 2280 bool found = false; 2281 2282 if (nodePtr->op == UInt32ToNumber) { 2283 NodeIndex nodeIndex = nodePtr->child1(); 2284 nodePtr = &m_jit.graph()[nodeIndex]; 2285 infoPtr = &m_generationInfo[nodePtr->virtualRegister()]; 2286 if (infoPtr->alive() && infoPtr->nodeIndex() == nodeIndex) 2287 found = true; 2288 } 2289 2290 if (!found) { 2291 NodeIndex valueToNumberIndex = NoNode; 2292 NodeIndex valueToInt32Index = NoNode; 2293 NodeIndex uint32ToNumberIndex = NoNode; 2294 2295 for (unsigned virtualRegister = 0; virtualRegister < m_generationInfo.size(); ++virtualRegister) { 2296 GenerationInfo& info = m_generationInfo[virtualRegister]; 2297 if (!info.alive()) 2298 continue; 2299 if (info.nodeIndex() == NoNode) 2300 continue; 2301 Node& node = m_jit.graph()[info.nodeIndex()]; 2302 if (node.child1Unchecked() != valueSource.nodeIndex()) 2303 continue; 2304 switch (node.op) { 2305 case ValueToNumber: 2306 case ValueToDouble: 2307 valueToNumberIndex = info.nodeIndex(); 2308 break; 2309 case ValueToInt32: 2310 valueToInt32Index = info.nodeIndex(); 2311 break; 2312 case UInt32ToNumber: 2313 uint32ToNumberIndex = info.nodeIndex(); 2314 break; 2315 default: 2316 break; 2284 2285 case Int32InRegisterFile: 2286 return ValueRecovery::alreadyInRegisterFileAsUnboxedInt32(); 2287 2288 case HaveNode: { 2289 if (m_jit.isConstant(valueSource.nodeIndex())) 2290 return ValueRecovery::constant(m_jit.valueOfJSConstant(valueSource.nodeIndex())); 2291 2292 Node* nodePtr = &m_jit.graph()[valueSource.nodeIndex()]; 2293 if (!nodePtr->shouldGenerate()) { 2294 // It's legitimately dead. As in, nobody will ever use this node, or operand, 2295 // ever. Set it to Undefined to make the GC happy after the OSR. 2296 return ValueRecovery::constant(jsUndefined()); 2297 } 2298 2299 GenerationInfo* infoPtr = &m_generationInfo[nodePtr->virtualRegister()]; 2300 if (!infoPtr->alive() || infoPtr->nodeIndex() != valueSource.nodeIndex()) { 2301 // Try to see if there is an alternate node that would contain the value we want. 2302 // There are four possibilities: 2303 // 2304 // ValueToNumber: If the only live version of the value is a ValueToNumber node 2305 // then it means that all remaining uses of the value would have performed a 2306 // ValueToNumber conversion anyway. Thus, we can substitute ValueToNumber. 2307 // 2308 // ValueToInt32: Likewise, if the only remaining live version of the value is 2309 // ValueToInt32, then we can use it. But if there is both a ValueToInt32 2310 // and a ValueToNumber, then we better go with ValueToNumber because it 2311 // means that some remaining uses would have converted to number while 2312 // others would have converted to Int32. 2313 // 2314 // UInt32ToNumber: If the only live version of the value is a UInt32ToNumber 2315 // then the only remaining uses are ones that want a properly formed number 2316 // rather than a UInt32 intermediate. 2317 // 2318 // The reverse of the above: This node could be a UInt32ToNumber, but its 2319 // alternative is still alive. This means that the only remaining uses of 2320 // the number would be fine with a UInt32 intermediate. 2321 2322 bool found = false; 2323 2324 if (nodePtr->op == UInt32ToNumber) { 2325 NodeIndex nodeIndex = nodePtr->child1(); 2326 nodePtr = &m_jit.graph()[nodeIndex]; 2327 infoPtr = &m_generationInfo[nodePtr->virtualRegister()]; 2328 if (infoPtr->alive() && infoPtr->nodeIndex() == nodeIndex) 2329 found = true; 2330 } 2331 2332 if (!found) { 2333 NodeIndex valueToNumberIndex = NoNode; 2334 NodeIndex valueToInt32Index = NoNode; 2335 NodeIndex uint32ToNumberIndex = NoNode; 2336 2337 for (unsigned virtualRegister = 0; virtualRegister < m_generationInfo.size(); ++virtualRegister) { 2338 GenerationInfo& info = m_generationInfo[virtualRegister]; 2339 if (!info.alive()) 2340 continue; 2341 if (info.nodeIndex() == NoNode) 2342 continue; 2343 Node& node = m_jit.graph()[info.nodeIndex()]; 2344 if (node.child1Unchecked() != valueSource.nodeIndex()) 2345 continue; 2346 switch (node.op) { 2347 case ValueToNumber: 2348 case ValueToDouble: 2349 valueToNumberIndex = info.nodeIndex(); 2350 break; 2351 case ValueToInt32: 2352 valueToInt32Index = info.nodeIndex(); 2353 break; 2354 case UInt32ToNumber: 2355 uint32ToNumberIndex = info.nodeIndex(); 2356 break; 2357 default: 2358 break; 2359 } 2360 } 2361 2362 NodeIndex nodeIndexToUse; 2363 if (valueToNumberIndex != NoNode) 2364 nodeIndexToUse = valueToNumberIndex; 2365 else if (valueToInt32Index != NoNode) 2366 nodeIndexToUse = valueToInt32Index; 2367 else if (uint32ToNumberIndex != NoNode) 2368 nodeIndexToUse = uint32ToNumberIndex; 2369 else 2370 nodeIndexToUse = NoNode; 2371 2372 if (nodeIndexToUse != NoNode) { 2373 nodePtr = &m_jit.graph()[nodeIndexToUse]; 2374 infoPtr = &m_generationInfo[nodePtr->virtualRegister()]; 2375 ASSERT(infoPtr->alive() && infoPtr->nodeIndex() == nodeIndexToUse); 2376 found = true; 2317 2377 } 2318 2378 } 2319 2320 NodeIndex nodeIndexToUse; 2321 if (valueToNumberIndex != NoNode) 2322 nodeIndexToUse = valueToNumberIndex; 2323 else if (valueToInt32Index != NoNode) 2324 nodeIndexToUse = valueToInt32Index; 2325 else if (uint32ToNumberIndex != NoNode) 2326 nodeIndexToUse = uint32ToNumberIndex; 2327 else 2328 nodeIndexToUse = NoNode; 2329 2330 if (nodeIndexToUse != NoNode) { 2331 nodePtr = &m_jit.graph()[nodeIndexToUse]; 2332 infoPtr = &m_generationInfo[nodePtr->virtualRegister()]; 2333 ASSERT(infoPtr->alive() && infoPtr->nodeIndex() == nodeIndexToUse); 2334 found = true; 2335 } 2336 } 2337 2338 if (!found) 2339 return ValueRecovery::constant(jsUndefined()); 2340 } 2341 2342 ASSERT(infoPtr->alive()); 2343 2344 if (infoPtr->registerFormat() != DataFormatNone) { 2345 if (infoPtr->registerFormat() == DataFormatDouble) 2346 return ValueRecovery::inFPR(infoPtr->fpr()); 2347 if (infoPtr->registerFormat() & DataFormatJS) 2348 return ValueRecovery::inPair(infoPtr->tagGPR(), infoPtr->payloadGPR()); 2349 return ValueRecovery::inGPR(infoPtr->gpr(), infoPtr->registerFormat()); 2350 } 2351 if (infoPtr->spillFormat() != DataFormatNone) 2352 return ValueRecovery::displacedInRegisterFile(static_cast<VirtualRegister>(nodePtr->virtualRegister())); 2353 2354 ASSERT_NOT_REACHED(); 2355 return ValueRecovery(); 2379 2380 if (!found) 2381 return ValueRecovery::constant(jsUndefined()); 2382 } 2383 2384 ASSERT(infoPtr->alive()); 2385 2386 if (infoPtr->registerFormat() != DataFormatNone) { 2387 if (infoPtr->registerFormat() == DataFormatDouble) 2388 return ValueRecovery::inFPR(infoPtr->fpr()); 2389 if (infoPtr->registerFormat() & DataFormatJS) 2390 return ValueRecovery::inPair(infoPtr->tagGPR(), infoPtr->payloadGPR()); 2391 return ValueRecovery::inGPR(infoPtr->gpr(), infoPtr->registerFormat()); 2392 } 2393 if (infoPtr->spillFormat() != DataFormatNone) 2394 return ValueRecovery::displacedInRegisterFile(static_cast<VirtualRegister>(nodePtr->virtualRegister())); 2395 2396 ASSERT_NOT_REACHED(); 2397 return ValueRecovery(); 2398 } 2399 2400 default: 2401 ASSERT_NOT_REACHED(); 2402 return ValueRecovery(); 2403 } 2356 2404 } 2357 2405
Note: See TracChangeset
for help on using the changeset viewer.