Changeset 161126 in webkit
- Timestamp:
- Dec 29, 2013 1:50:55 PM (10 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 2 added
- 43 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r161077 r161126 1 2013-12-28 Filip Pizlo <fpizlo@apple.com> 2 3 Get rid of DFG forward exiting 4 https://bugs.webkit.org/show_bug.cgi?id=125531 5 6 Reviewed by Oliver Hunt. 7 8 This finally gets rid of forward exiting. Forward exiting was always a fragile concept 9 since it involved the compiler trying to figure out how to "roll forward" the 10 execution from some DFG node to the next bytecode index. It was always easy to find 11 counterexamples where it broke, and it has always served as an obstacle to adding 12 compiler improvements - the latest being http://webkit.org/b/125523, which tried to 13 make DCE work for more things. 14 15 This change finishes the work of removing forward exiting. A lot of forward exiting 16 was already removed in some other bugs, but SetLocal still did forward exits. SetLocal 17 is in many ways the hardest to remove, since the forward exiting of SetLocal also 18 implied that any conversion nodes inserted before the SetLocal would then also be 19 marked as forward-exiting. Hence SetLocal's forward-exiting made a bunch of other 20 things also forward-exiting, and this was always a source of weirdo bugs. 21 22 SetLocal must be able to exit in case it performs a hoisted type speculation. Nodes 23 inserted just before SetLocal must also be able to exit - for example type check 24 hoisting may insert a CheckStructure, or fixup phase may insert something like 25 Int32ToDouble. But if any of those nodes tried to backward exit, then this could lead 26 to the reexecution of a side-effecting operation, for example: 27 28 a: Call(...) 29 b: SetLocal(@a, r1) 30 31 For a long time it seemed like SetLocal *had* to exit forward because of this. But 32 this change side-steps the problem by changing the ByteCodeParser to always emit a 33 kind of "two-phase commit" for stores to local variables. Now when the ByteCodeParser 34 wishes to store to a local, it first emits a MovHint and then enqueues a SetLocal. 35 The SetLocal isn't actually emitted until the beginning of the next bytecode 36 instruction (which the exception of op_enter and op_ret, which emit theirs immediately 37 since it's always safe to reexecute those bytecode instructions and since deferring 38 SetLocals would be weird there - op_enter has many SetLocals and op_ret is a set 39 followed by a jump in case of inlining, so we'd have to emit the SetLocal "after" the 40 jump and that would be awkward). This means that the above IR snippet would look 41 something like: 42 43 a: Call(..., bc#42) 44 b: MovHint(@a, r1, bc#42) 45 c: SetLocal(@a, r1, bc#47) 46 47 Where the SetLocal exits "backwards" but appears at the beginning of the next bytecode 48 instruction. This means that by the time we get to that SetLocal, the OSR exit 49 analysis already knows that r1 is associated with @a, and it means that the SetLocal 50 or anything hoisted above it can exit backwards as normal. 51 52 This change also means that the "forward rewiring" can be killed. Previously, we might 53 have inserted a conversion node on SetLocal and then the SetLocal died (i.e. turned 54 into a MovHint) and the conversion node either died completely or had its lifetime 55 truncated to be less than the actual value's bytecode lifetime. This no longer happens 56 since conversion nodes are only inserted at SetLocals. 57 58 More precisely, this change introduces two laws that we were basically already 59 following anyway: 60 61 1) A MovHint's child should never be changed except if all other uses of that child 62 are also replaced. Specifically, this prohibits insertion of conversion nodes at 63 MovHints. 64 65 2) Anytime any child is replaced with something else, and all other uses aren't also 66 replaced, we must insert a Phantom use of the original child. 67 68 This is a slight compile-time regression but has no effect on code-gen. It unlocks a 69 bunch of optimization opportunities so I think it's worth it. 70 71 * bytecode/CodeBlock.cpp: 72 (JSC::CodeBlock::dumpAssumingJITType): 73 * bytecode/CodeBlock.h: 74 (JSC::CodeBlock::instructionCount): 75 * dfg/DFGAbstractInterpreterInlines.h: 76 (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): 77 * dfg/DFGArgumentsSimplificationPhase.cpp: 78 (JSC::DFG::ArgumentsSimplificationPhase::run): 79 * dfg/DFGArrayifySlowPathGenerator.h: 80 (JSC::DFG::ArrayifySlowPathGenerator::ArrayifySlowPathGenerator): 81 * dfg/DFGBackwardsPropagationPhase.cpp: 82 (JSC::DFG::BackwardsPropagationPhase::propagate): 83 * dfg/DFGByteCodeParser.cpp: 84 (JSC::DFG::ByteCodeParser::setDirect): 85 (JSC::DFG::ByteCodeParser::DelayedSetLocal::DelayedSetLocal): 86 (JSC::DFG::ByteCodeParser::DelayedSetLocal::execute): 87 (JSC::DFG::ByteCodeParser::handleInlining): 88 (JSC::DFG::ByteCodeParser::parseBlock): 89 * dfg/DFGCSEPhase.cpp: 90 (JSC::DFG::CSEPhase::eliminate): 91 * dfg/DFGClobberize.h: 92 (JSC::DFG::clobberize): 93 * dfg/DFGCommon.h: 94 * dfg/DFGConstantFoldingPhase.cpp: 95 (JSC::DFG::ConstantFoldingPhase::foldConstants): 96 * dfg/DFGDCEPhase.cpp: 97 (JSC::DFG::DCEPhase::run): 98 (JSC::DFG::DCEPhase::fixupBlock): 99 (JSC::DFG::DCEPhase::cleanVariables): 100 * dfg/DFGFixupPhase.cpp: 101 (JSC::DFG::FixupPhase::fixupNode): 102 (JSC::DFG::FixupPhase::fixEdge): 103 (JSC::DFG::FixupPhase::injectInt32ToDoubleNode): 104 * dfg/DFGLICMPhase.cpp: 105 (JSC::DFG::LICMPhase::run): 106 (JSC::DFG::LICMPhase::attemptHoist): 107 * dfg/DFGMinifiedNode.cpp: 108 (JSC::DFG::MinifiedNode::fromNode): 109 * dfg/DFGMinifiedNode.h: 110 (JSC::DFG::belongsInMinifiedGraph): 111 (JSC::DFG::MinifiedNode::constantNumber): 112 (JSC::DFG::MinifiedNode::weakConstant): 113 * dfg/DFGNode.cpp: 114 (JSC::DFG::Node::hasVariableAccessData): 115 * dfg/DFGNode.h: 116 (JSC::DFG::Node::convertToPhantom): 117 (JSC::DFG::Node::convertToPhantomUnchecked): 118 (JSC::DFG::Node::convertToIdentity): 119 (JSC::DFG::Node::containsMovHint): 120 (JSC::DFG::Node::hasUnlinkedLocal): 121 (JSC::DFG::Node::willHaveCodeGenOrOSR): 122 * dfg/DFGNodeFlags.cpp: 123 (JSC::DFG::dumpNodeFlags): 124 * dfg/DFGNodeFlags.h: 125 * dfg/DFGNodeType.h: 126 * dfg/DFGOSRAvailabilityAnalysisPhase.cpp: 127 (JSC::DFG::OSRAvailabilityAnalysisPhase::run): 128 * dfg/DFGOSREntrypointCreationPhase.cpp: 129 (JSC::DFG::OSREntrypointCreationPhase::run): 130 * dfg/DFGOSRExit.cpp: 131 * dfg/DFGOSRExit.h: 132 * dfg/DFGOSRExitBase.cpp: 133 * dfg/DFGOSRExitBase.h: 134 (JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSite): 135 * dfg/DFGPredictionPropagationPhase.cpp: 136 (JSC::DFG::PredictionPropagationPhase::propagate): 137 (JSC::DFG::PredictionPropagationPhase::doDoubleVoting): 138 * dfg/DFGSSAConversionPhase.cpp: 139 (JSC::DFG::SSAConversionPhase::run): 140 * dfg/DFGSafeToExecute.h: 141 (JSC::DFG::safeToExecute): 142 * dfg/DFGSpeculativeJIT.cpp: 143 (JSC::DFG::SpeculativeJIT::speculationCheck): 144 (JSC::DFG::SpeculativeJIT::emitInvalidationPoint): 145 (JSC::DFG::SpeculativeJIT::typeCheck): 146 (JSC::DFG::SpeculativeJIT::compileMovHint): 147 (JSC::DFG::SpeculativeJIT::compileCurrentBlock): 148 (JSC::DFG::SpeculativeJIT::checkArgumentTypes): 149 (JSC::DFG::SpeculativeJIT::compileInt32ToDouble): 150 * dfg/DFGSpeculativeJIT.h: 151 (JSC::DFG::SpeculativeJIT::detectPeepHoleBranch): 152 (JSC::DFG::SpeculativeJIT::needsTypeCheck): 153 * dfg/DFGSpeculativeJIT32_64.cpp: 154 (JSC::DFG::SpeculativeJIT::compile): 155 * dfg/DFGSpeculativeJIT64.cpp: 156 (JSC::DFG::SpeculativeJIT::compile): 157 * dfg/DFGTypeCheckHoistingPhase.cpp: 158 (JSC::DFG::TypeCheckHoistingPhase::run): 159 (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks): 160 (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks): 161 * dfg/DFGValidate.cpp: 162 (JSC::DFG::Validate::validateCPS): 163 * dfg/DFGVariableAccessData.h: 164 (JSC::DFG::VariableAccessData::VariableAccessData): 165 * dfg/DFGVariableEventStream.cpp: 166 (JSC::DFG::VariableEventStream::reconstruct): 167 * ftl/FTLCapabilities.cpp: 168 (JSC::FTL::canCompile): 169 * ftl/FTLLowerDFGToLLVM.cpp: 170 (JSC::FTL::LowerDFGToLLVM::compileNode): 171 (JSC::FTL::LowerDFGToLLVM::compileGetArgument): 172 (JSC::FTL::LowerDFGToLLVM::compileSetLocal): 173 (JSC::FTL::LowerDFGToLLVM::compileMovHint): 174 (JSC::FTL::LowerDFGToLLVM::compileZombieHint): 175 (JSC::FTL::LowerDFGToLLVM::compileInt32ToDouble): 176 (JSC::FTL::LowerDFGToLLVM::speculate): 177 (JSC::FTL::LowerDFGToLLVM::typeCheck): 178 (JSC::FTL::LowerDFGToLLVM::appendTypeCheck): 179 (JSC::FTL::LowerDFGToLLVM::appendOSRExit): 180 (JSC::FTL::LowerDFGToLLVM::emitOSRExitCall): 181 * ftl/FTLOSRExit.cpp: 182 * ftl/FTLOSRExit.h: 183 * tests/stress/dead-int32-to-double.js: Added. 184 (foo): 185 * tests/stress/dead-uint32-to-number.js: Added. 186 (foo): 187 1 188 2013-12-25 Commit Queue <commit-queue@webkit.org> 2 189 -
trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp
r160587 r161126 136 136 if (codeType() == FunctionCode) 137 137 out.print(specializationKind()); 138 out.print(", ", instructionCount()); 138 139 if (this->jitType() == JITCode::BaselineJIT && m_shouldAlwaysBeInlined) 139 140 out.print(" (SABI)"); -
trunk/Source/JavaScriptCore/bytecode/CodeBlock.h
r159943 r161126 245 245 bool usesOpcode(OpcodeID); 246 246 247 unsigned instructionCount() { return m_instructions.size(); }247 unsigned instructionCount() const { return m_instructions.size(); } 248 248 249 249 int argumentIndexAfterCapture(size_t argument); -
trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r160796 r161126 196 196 } 197 197 198 case MovHint: 199 case MovHintAndCheck: {200 // Don't need to do anything. A MovHint is effectively a promise that the SetLocal201 // was dead.198 case MovHint: { 199 // Don't need to do anything. A MovHint only informs us about what would have happened 200 // in bytecode, but this code is just concerned with what is actually happening during 201 // DFG execution. 202 202 break; 203 203 } … … 1584 1584 1585 1585 case Phantom: 1586 case Check: 1586 1587 case CountExecution: 1587 1588 case CheckTierUpInLoop: -
trunk/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
r161072 r161126 334 334 break; 335 335 336 case MovHint: 337 // We don't care about MovHints at all, since they represent what happens 338 // in bytecode. We rematerialize arguments objects on OSR exit anyway. 339 break; 340 336 341 default: 337 342 observeBadArgumentsUses(node); -
trunk/Source/JavaScriptCore/dfg/DFGArrayifySlowPathGenerator.h
r157044 r161126 64 64 case Array::Double: 65 65 case Array::Contiguous: 66 m_badPropertyJump = jit-> backwardSpeculationCheck(Uncountable, JSValueRegs(), 0);66 m_badPropertyJump = jit->speculationCheck(Uncountable, JSValueRegs(), 0); 67 67 break; 68 68 default: … … 70 70 } 71 71 } 72 m_badIndexingTypeJump = jit-> backwardSpeculationCheck(BadIndexingType, JSValueSource::unboxedCell(m_baseGPR), 0);72 m_badIndexingTypeJump = jit->speculationCheck(BadIndexingType, JSValueSource::unboxedCell(m_baseGPR), 0); 73 73 } 74 74 -
trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
r158384 r161126 188 188 } 189 189 190 case MovHint: 191 case Check: 192 break; 193 190 194 case BitAnd: 191 195 case BitOr: -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r160587 r161126 233 233 } 234 234 235 enum SetMode { NormalSet, SetOnEntry};235 enum SetMode { NormalSet, ImmediateSet }; 236 236 Node* setDirect(VirtualRegister operand, Node* value, SetMode setMode = NormalSet) 237 237 { 238 // Is this an argument? 239 if (operand.isArgument()) 240 return setArgument(operand, value, setMode); 241 242 // Must be a local. 243 return setLocal(operand, value, setMode); 238 addToGraph(MovHint, OpInfo(operand.offset()), value); 239 240 DelayedSetLocal delayed = DelayedSetLocal(operand, value); 241 242 if (setMode == NormalSet) { 243 m_setLocalQueue.append(delayed); 244 return 0; 245 } 246 247 return delayed.execute(this, setMode); 244 248 } 245 249 … … 1122 1126 1123 1127 InlineStackEntry* m_inlineStackTop; 1128 1129 struct DelayedSetLocal { 1130 VirtualRegister m_operand; 1131 Node* m_value; 1132 1133 DelayedSetLocal() { } 1134 DelayedSetLocal(VirtualRegister operand, Node* value) 1135 : m_operand(operand) 1136 , m_value(value) 1137 { 1138 } 1139 1140 Node* execute(ByteCodeParser* parser, SetMode setMode = NormalSet) 1141 { 1142 if (m_operand.isArgument()) 1143 return parser->setArgument(m_operand, m_value, setMode); 1144 return parser->setLocal(m_operand, m_value, setMode); 1145 } 1146 }; 1147 1148 Vector<DelayedSetLocal, 2> m_setLocalQueue; 1124 1149 1125 1150 // Have we built operand maps? We initialize them lazily, and only when doing … … 1326 1351 if (callLinkStatus.isClosureCall()) { 1327 1352 VariableAccessData* calleeVariable = 1328 set(VirtualRegister(JSStack::Callee), callTargetNode )->variableAccessData();1353 set(VirtualRegister(JSStack::Callee), callTargetNode, ImmediateSet)->variableAccessData(); 1329 1354 VariableAccessData* scopeVariable = 1330 set(VirtualRegister(JSStack::ScopeChain), addToGraph(GetScope, callTargetNode) )->variableAccessData();1355 set(VirtualRegister(JSStack::ScopeChain), addToGraph(GetScope, callTargetNode), ImmediateSet)->variableAccessData(); 1331 1356 1332 1357 calleeVariable->mergeShouldNeverUnbox(true); … … 1873 1898 1874 1899 while (true) { 1900 for (unsigned i = 0; i < m_setLocalQueue.size(); ++i) 1901 m_setLocalQueue[i].execute(this); 1902 m_setLocalQueue.resize(0); 1903 1875 1904 // Don't extend over jump destinations. 1876 1905 if (m_currentIndex == limit) { … … 1904 1933 // Initialize all locals to undefined. 1905 1934 for (int i = 0; i < m_inlineStackTop->m_codeBlock->m_numVars; ++i) 1906 set(virtualRegisterForLocal(i), constantUndefined(), SetOnEntry);1935 set(virtualRegisterForLocal(i), constantUndefined(), ImmediateSet); 1907 1936 NEXT_OPCODE(op_enter); 1908 1937 … … 2909 2938 if (inlineCallFrame()) { 2910 2939 ASSERT(m_inlineStackTop->m_returnValue.isValid()); 2911 setDirect(m_inlineStackTop->m_returnValue, get(VirtualRegister(currentInstruction[1].u.operand)) );2940 setDirect(m_inlineStackTop->m_returnValue, get(VirtualRegister(currentInstruction[1].u.operand)), ImmediateSet); 2912 2941 m_inlineStackTop->m_didReturn = true; 2913 2942 if (m_inlineStackTop->m_unlinkedBlocks.isEmpty()) { -
trunk/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
r160407 r161126 1052 1052 return; 1053 1053 ASSERT(node->mustGenerate()); 1054 node->setOpAndDefault NonExitFlags(phantomType);1054 node->setOpAndDefaultFlags(phantomType); 1055 1055 if (phantomType == Phantom) 1056 1056 eliminateIrrelevantPhantomChildren(node); -
trunk/Source/JavaScriptCore/dfg/DFGClobberize.h
r160796 r161126 130 130 case UInt32ToNumber: 131 131 case DoubleAsInt32: 132 return;133 134 case MovHintAndCheck:132 case Check: 133 return; 134 135 135 case MovHint: 136 136 case ZombieHint: -
trunk/Source/JavaScriptCore/dfg/DFGCommon.h
r159886 r161126 182 182 183 183 enum OperandSpeculationMode { AutomaticOperandSpeculation, ManualOperandSpeculation }; 184 185 enum SpeculationDirection { ForwardSpeculation, BackwardSpeculation };186 184 187 185 enum ProofStatus { NeedsCheck, IsProved }; -
trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
r160796 r161126 111 111 AdjacencyList children = node->children; 112 112 children.removeEdge(0); 113 if (!!children.child1()) { 114 Node phantom(Phantom, node->codeOrigin, children); 115 if (node->flags() & NodeExitsForward) 116 phantom.mergeFlags(NodeExitsForward); 117 m_insertionSet.insertNode(indexInBlock, SpecNone, phantom); 118 } 113 if (!!children.child1()) 114 m_insertionSet.insertNode(indexInBlock, SpecNone, Phantom, node->codeOrigin, children); 119 115 node->children.setChild2(Edge()); 120 116 node->children.setChild3(Edge()); -
trunk/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp
r156047 r161126 114 114 fixupBlock(depthFirst[i]); 115 115 } else { 116 RELEASE_ASSERT(m_graph.m_form == ThreadedCPS); 117 116 118 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) 117 119 fixupBlock(m_graph.block(blockIndex)); 120 121 cleanVariables(m_graph.m_arguments); 118 122 } 119 123 … … 153 157 if (!block) 154 158 return; 159 160 switch (m_graph.m_form) { 161 case SSA: 162 break; 163 164 case ThreadedCPS: { 165 // Clean up variable links for the block. We need to do this before the actual DCE 166 // because we need to see GetLocals, so we can bypass them in situations where the 167 // vars-at-tail point to a GetLocal, the GetLocal is dead, but the Phi it points 168 // to is alive. 169 170 for (unsigned phiIndex = 0; phiIndex < block->phis.size(); ++phiIndex) { 171 if (!block->phis[phiIndex]->shouldGenerate()) { 172 // FIXME: We could actually free nodes here. Except that it probably 173 // doesn't matter, since we don't add any nodes after this phase. 174 // https://bugs.webkit.org/show_bug.cgi?id=126239 175 block->phis[phiIndex--] = block->phis.last(); 176 block->phis.removeLast(); 177 } 178 } 179 180 cleanVariables(block->variablesAtHead); 181 cleanVariables(block->variablesAtTail); 182 break; 183 } 184 185 default: 186 RELEASE_ASSERT_NOT_REACHED(); 187 return; 188 } 155 189 156 190 for (unsigned indexInBlock = block->size(); indexInBlock--;) { … … 160 194 161 195 switch (node->op()) { 162 case SetLocal:163 196 case MovHint: { 164 ASSERT((node->op() == SetLocal) == (m_graph.m_form == ThreadedCPS)); 165 if (node->child1().willNotHaveCheck()) { 166 // Consider the possibility that UInt32ToNumber is dead but its 167 // child isn't; if so then we should MovHint the child. 168 if (!node->child1()->shouldGenerate() 169 && permitsOSRBackwardRewiring(node->child1()->op())) 170 node->child1() = node->child1()->child1(); 171 172 if (!node->child1()->shouldGenerate()) { 173 node->setOpAndDefaultFlags(ZombieHint); 174 node->child1() = Edge(); 175 break; 176 } 177 node->setOpAndDefaultFlags(MovHint); 197 ASSERT(node->child1().useKind() == UntypedUse); 198 if (!node->child1()->shouldGenerate()) { 199 node->setOpAndDefaultFlags(ZombieHint); 200 node->child1() = Edge(); 178 201 break; 179 202 } 180 node->setOpAndDefaultFlags(MovHintAndCheck); 181 node->setRefCount(1); 203 node->setOpAndDefaultFlags(MovHint); 182 204 break; 183 205 } 184 185 case GetLocal: 186 case SetArgument: { 187 if (m_graph.m_form == ThreadedCPS) { 188 // Leave them as not shouldGenerate. 189 break; 190 } 191 } 192 206 207 case ZombieHint: { 208 // Currently we assume that DCE runs only once. 209 RELEASE_ASSERT_NOT_REACHED(); 210 break; 211 } 212 193 213 default: { 194 214 if (node->flags() & NodeHasVarArgs) { … … 229 249 } 230 250 251 template<typename VariablesVectorType> 252 void cleanVariables(VariablesVectorType& variables) 253 { 254 for (unsigned i = variables.size(); i--;) { 255 Node* node = variables[i]; 256 if (!node) 257 continue; 258 if (node->op() != Phantom && node->shouldGenerate()) 259 continue; 260 if (node->op() == GetLocal) { 261 node = node->child1().node(); 262 ASSERT(node->op() == Phi); 263 if (node->shouldGenerate()) { 264 variables[i] = node; 265 continue; 266 } 267 } 268 variables[i] = 0; 269 } 270 } 271 231 272 Vector<Node*, 128> m_worklist; 232 273 InsertionSet m_insertionSet; -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r160796 r161126 887 887 888 888 case Phantom: 889 case Identity: { 889 case Identity: 890 case Check: { 890 891 switch (node->child1().useKind()) { 891 892 case NumberUse: … … 908 909 case GetTypedArrayByteOffset: 909 910 case LastNodeType: 910 case MovHint:911 case MovHintAndCheck:912 case ZombieHint:913 911 case CheckTierUpInLoop: 914 912 case CheckTierUpAtReturn: … … 952 950 } 953 951 break; 954 952 955 953 #if !ASSERT_DISABLED 956 954 // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes. … … 1006 1004 case FunctionReentryWatchpoint: 1007 1005 case TypedArrayWatchpoint: 1006 case MovHint: 1007 case ZombieHint: 1008 1008 break; 1009 1009 #else … … 1013 1013 } 1014 1014 1015 DFG_NODE_DO_TO_CHILDREN(m_graph, node, observeUntypedEdge); 1015 if (!node->containsMovHint()) 1016 DFG_NODE_DO_TO_CHILDREN(m_graph, node, observeUntypedEdge); 1016 1017 } 1017 1018 … … 1479 1480 if (isDouble(useKind)) { 1480 1481 if (edge->shouldSpeculateInt32ForArithmetic()) { 1481 injectInt32ToDoubleNode(edge, useKind , m_currentNode->speculationDirection());1482 injectInt32ToDoubleNode(edge, useKind); 1482 1483 return; 1483 1484 } … … 1492 1493 m_indexInBlock, SpecInt52AsDouble, Int52ToDouble, 1493 1494 m_currentNode->codeOrigin, Edge(edge.node(), NumberUse)); 1494 result->setSpeculationDirection(m_currentNode->speculationDirection());1495 1495 edge = Edge(result, useKind); 1496 1496 return; … … 1546 1546 m_indexInBlock, SpecInt52, Int52ToValue, 1547 1547 m_currentNode->codeOrigin, Edge(edge.node(), UntypedUse)); 1548 result->setSpeculationDirection(m_currentNode->speculationDirection());1549 1548 edge = Edge(result, useKind); 1550 1549 return; … … 1588 1587 } 1589 1588 1590 void injectInt32ToDoubleNode(Edge& edge, UseKind useKind = NumberUse , SpeculationDirection direction = BackwardSpeculation)1589 void injectInt32ToDoubleNode(Edge& edge, UseKind useKind = NumberUse) 1591 1590 { 1592 1591 Node* result = m_insertionSet.insertNode( 1593 1592 m_indexInBlock, SpecInt52AsDouble, Int32ToDouble, 1594 1593 m_currentNode->codeOrigin, Edge(edge.node(), NumberUse)); 1595 if (direction == ForwardSpeculation)1596 result->mergeFlags(NodeExitsForward);1597 1594 1598 1595 edge = Edge(result, useKind); -
trunk/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp
r155281 r161126 129 129 // 130 130 // Also, we need to remember to: 131 // - Clear NodeExitsForward for any nodes we hoisted.132 131 // - Update the state-at-tail with the node we hoisted, so future hoist candidates 133 132 // know about any type checks we hoisted. … … 231 230 data.preHeader->insertBeforeLast(node); 232 231 node->misc.owner = data.preHeader; 233 NodeFlags didExitForward = node->flags() & NodeExitsForward;234 node->clearFlags(NodeExitsForward);235 232 node->codeOriginForExitTarget = data.preHeader->last()->codeOriginForExitTarget; 236 233 … … 257 254 258 255 nodeRef = m_graph.addNode(SpecNone, Phantom, node->codeOrigin, node->children); 259 nodeRef->mergeFlags(didExitForward);260 256 261 257 return true; -
trunk/Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp
r141069 r161126 39 39 result.m_id = MinifiedID(node); 40 40 result.m_op = node->op(); 41 if (hasChild(node->op())) 42 result.m_childOrInfo = MinifiedID(node->child1().node()).m_id; 43 else if (hasConstantNumber(node->op())) 44 result.m_childOrInfo = node->constantNumber(); 41 if (hasConstantNumber(node->op())) 42 result.m_info = node->constantNumber(); 45 43 else if (hasWeakConstant(node->op())) 46 result.m_ childOrInfo = bitwise_cast<uintptr_t>(node->weakConstant());44 result.m_info = bitwise_cast<uintptr_t>(node->weakConstant()); 47 45 else { 48 46 ASSERT(node->op() == PhantomArguments); 49 result.m_ childOrInfo = 0;47 result.m_info = 0; 50 48 } 51 49 return result; -
trunk/Source/JavaScriptCore/dfg/DFGMinifiedNode.h
r156047 r161126 44 44 case JSConstant: 45 45 case WeakJSConstant: 46 case ValueToInt32:47 case Int32ToDouble:48 case UInt32ToNumber:49 case DoubleAsInt32:50 46 case PhantomArguments: 51 case Int52ToValue:52 case Int52ToDouble:53 47 return true; 54 48 default: 55 ASSERT(!permitsOSRBackwardRewiring(type) && !permitsOSRForwardRewiring(type));56 49 return false; 57 50 } … … 67 60 NodeType op() const { return m_op; } 68 61 69 bool hasChild1() const { return hasChild(m_op); }70 71 MinifiedID child1() const72 {73 ASSERT(hasChild(m_op));74 return MinifiedID::fromBits(m_childOrInfo);75 }76 77 62 bool hasConstant() const { return hasConstantNumber() || hasWeakConstant(); } 78 63 … … 82 67 { 83 68 ASSERT(hasConstantNumber(m_op)); 84 return m_ childOrInfo;69 return m_info; 85 70 } 86 71 … … 90 75 { 91 76 ASSERT(hasWeakConstant(m_op)); 92 return bitwise_cast<JSCell*>(m_ childOrInfo);77 return bitwise_cast<JSCell*>(m_info); 93 78 } 94 79 … … 100 85 101 86 private: 102 static bool hasChild(NodeType type)103 {104 switch (type) {105 case ValueToInt32:106 case Int32ToDouble:107 case UInt32ToNumber:108 case DoubleAsInt32:109 case Int52ToDouble:110 case Int52ToValue:111 return true;112 default:113 return false;114 }115 }116 87 static bool hasConstantNumber(NodeType type) 117 88 { … … 124 95 125 96 MinifiedID m_id; 126 uintptr_t m_ childOrInfo; // Nodes in the minified graph have only one child each.97 uintptr_t m_info; 127 98 NodeType m_op; 128 99 }; -
trunk/Source/JavaScriptCore/dfg/DFGNode.cpp
r153274 r161126 47 47 case GetArgument: 48 48 case SetLocal: 49 case MovHint:50 case MovHintAndCheck:51 case ZombieHint:52 49 case SetArgument: 53 50 case Flush: -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r160796 r161126 275 275 } 276 276 277 SpeculationDirection speculationDirection()278 {279 if (flags() & NodeExitsForward)280 return ForwardSpeculation;281 return BackwardSpeculation;282 }283 284 void setSpeculationDirection(SpeculationDirection direction)285 {286 switch (direction) {287 case ForwardSpeculation:288 mergeFlags(NodeExitsForward);289 return;290 case BackwardSpeculation:291 clearFlags(NodeExitsForward);292 return;293 }294 RELEASE_ASSERT_NOT_REACHED();295 }296 297 277 void setOpAndDefaultFlags(NodeType op) 298 278 { … … 301 281 } 302 282 303 void setOpAndDefaultNonExitFlags(NodeType op)304 {305 ASSERT(!(m_flags & NodeHasVarArgs));306 setOpAndDefaultNonExitFlagsUnchecked(op);307 }308 309 void setOpAndDefaultNonExitFlagsUnchecked(NodeType op)310 {311 m_op = op;312 m_flags = (defaultFlags(op) & ~NodeExitsForward) | (m_flags & NodeExitsForward);313 }314 315 283 void convertToPhantom() 316 284 { 317 setOpAndDefault NonExitFlags(Phantom);285 setOpAndDefaultFlags(Phantom); 318 286 } 319 287 320 288 void convertToPhantomUnchecked() 321 289 { 322 setOpAndDefault NonExitFlagsUnchecked(Phantom);290 setOpAndDefaultFlags(Phantom); 323 291 } 324 292 … … 327 295 RELEASE_ASSERT(child1()); 328 296 RELEASE_ASSERT(!child2()); 329 setOpAndDefault NonExitFlags(Identity);297 setOpAndDefaultFlags(Identity); 330 298 } 331 299 … … 532 500 { 533 501 switch (op()) { 534 case SetLocal:535 502 case MovHint: 536 case MovHintAndCheck:537 503 case ZombieHint: 538 504 return true; … … 568 534 case GetLocalUnlinked: 569 535 case ExtractOSREntryLocal: 536 case MovHint: 537 case ZombieHint: 570 538 return true; 571 539 default: … … 1191 1159 case MovHint: 1192 1160 case ZombieHint: 1193 case MovHintAndCheck:1194 case Int32ToDouble:1195 case ValueToInt32:1196 case UInt32ToNumber:1197 case DoubleAsInt32:1198 1161 case PhantomArguments: 1199 1162 return true; -
trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp
r156984 r161126 97 97 out.print(comma, "CanExit"); 98 98 99 if (flags & NodeExitsForward)100 out.print(comma, "NodeExitsForward");101 102 99 CString string = out.toCString(); 103 100 if (!string.length()) -
trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.h
r159545 r161126 69 69 #define NodeRelevantToOSR 0x4000 70 70 71 #define NodeExitsForward 0x8000 72 73 #define NodeIsStaticConstant 0x10000 // Used only by the parser, to determine if a constant arose statically and hence could be folded at parse-time. 71 #define NodeIsStaticConstant 0x8000 // Used only by the parser, to determine if a constant arose statically and hence could be folded at parse-time. 74 72 75 73 typedef uint32_t NodeFlags; -
trunk/Source/JavaScriptCore/dfg/DFGNodeType.h
r160796 r161126 58 58 /* VariableAccessData, and thus will share predictions. */\ 59 59 macro(GetLocal, NodeResultJS) \ 60 macro(SetLocal, NodeExitsForward) \ 61 macro(MovHintAndCheck, NodeMustGenerate | NodeExitsForward) \ 60 macro(SetLocal, 0) \ 62 61 macro(MovHint, NodeDoesNotExit) \ 63 62 macro(ZombieHint, NodeDoesNotExit) \ 64 63 macro(GetArgument, NodeResultJS | NodeMustGenerate) \ 65 64 macro(Phantom, NodeMustGenerate) \ 65 macro(Check, 0) /* Used if we want just a type check but not liveness. DCE eithers kills this or converts it to Phantom. */\ 66 66 macro(Upsilon, NodeDoesNotExit | NodeRelevantToOSR) \ 67 67 macro(Phi, NodeDoesNotExit | NodeRelevantToOSR) \ … … 319 319 } 320 320 321 inline bool permitsOSRBackwardRewiring(NodeType op)322 {323 switch (op) {324 case Identity:325 RELEASE_ASSERT_NOT_REACHED();326 return true;327 case UInt32ToNumber:328 case Int52ToValue:329 case Int52ToDouble:330 // These are the only node where we do:331 //332 // b: UInt32ToNumber(@a)333 // c: SetLocal(@b)334 //335 // and then also have some uses of @a without Phantom'ing @b.336 return true;337 default:338 return false;339 }340 }341 342 // Returns the priority with which we should select the given node for forward343 // rewiring. Higher is better. Zero means that the node is not useful for rewiring.344 // By convention, we use 100 to mean that the node is totally equivalent to its345 // input with no information loss.346 inline unsigned forwardRewiringSelectionScore(NodeType op)347 {348 switch (op) {349 case Identity:350 // We shouldn't see these by the time we get to OSR even though it clearly351 // is a perfect identity function.352 RELEASE_ASSERT_NOT_REACHED();353 return 100;354 355 case DoubleAsInt32:356 // This speculates that the incoming double is convertible to an int32. So357 // its result is totally equivalent.358 return 100;359 360 case Int32ToDouble:361 // This converts an int32 to a double, but that loses a bit of information.362 // OTOH it's still an equivalent number.363 return 75;364 365 case UInt32ToNumber:366 // It's completely fine to use this for OSR exit, since the uint32 isn't367 // actually representable in bytecode.368 return 100;369 370 case ValueToInt32:371 // This loses information. Only use it if there are no better alternatives.372 return 25;373 374 case Int52ToValue:375 // Loses no information. It just boxes the value, which is what OSR wants376 // to do anyway.377 return 100;378 379 case Int52ToDouble:380 // This is like Int32ToDouble; we can use it because it gives a semantically381 // equivalent value but that value may be an int32 in a double, so we'd382 // rather not if we can avoid it.383 return 75;384 385 default:386 return 0;387 }388 }389 390 inline bool permitsOSRForwardRewiring(NodeType op)391 {392 return forwardRewiringSelectionScore(op) > 0;393 }394 395 321 } } // namespace JSC::DFG 396 322 -
trunk/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp
r159394 r161126 104 104 } 105 105 106 case MovHint: 107 case MovHintAndCheck: { 108 VariableAccessData* variable = node->variableAccessData(); 109 availability.operand(variable->local()) = 106 case MovHint: { 107 availability.operand(node->unlinkedLocal()) = 110 108 Availability(node->child1().node()); 111 109 break; … … 113 111 114 112 case ZombieHint: { 115 VariableAccessData* variable = node->variableAccessData();116 availability.operand(variable->local()) =Availability::unavailable();113 availability.operand(node->unlinkedLocal()) = 114 Availability::unavailable(); 117 115 break; 118 116 } -
trunk/Source/JavaScriptCore/dfg/DFGOSREntrypointCreationPhase.cpp
r156677 r161126 105 105 OpInfo(variable->local().offset())); 106 106 107 // Create a MovHint. We can't use MovHint's directly at this stage of 108 // compilation, so we cook one up by creating a new VariableAccessData 109 // that isn't unified with any of the others. This ensures that this 110 // SetLocal will turn into a MovHint and will not have any type checks. 111 m_graph.m_variableAccessData.append( 112 VariableAccessData(variable->local(), variable->isCaptured())); 113 VariableAccessData* newVariable = &m_graph.m_variableAccessData.last(); 114 Node* setLocal = newRoot->appendNode( 115 m_graph, SpecNone, SetLocal, codeOrigin, OpInfo(newVariable), 107 newRoot->appendNode( 108 m_graph, SpecNone, MovHint, codeOrigin, OpInfo(variable->local().offset()), 116 109 Edge(locals[local])); 117 setLocal->setSpeculationDirection(BackwardSpeculation);118 110 } 119 111 for (int local = 0; local < baseline->m_numCalleeRegisters; ++local) { … … 123 115 VariableAccessData* variable = previousHead->variableAccessData(); 124 116 Node* node = locals[local]; 125 Node* setLocal =newRoot->appendNode(117 newRoot->appendNode( 126 118 m_graph, SpecNone, SetLocal, codeOrigin, OpInfo(variable), Edge(node)); 127 setLocal->setSpeculationDirection(BackwardSpeculation);128 119 } 129 120 -
trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp
r159091 r161126 69 69 } 70 70 71 void OSRExit::convertToForward(BasicBlock* block, Node* currentNode, unsigned nodeIndex, const ValueRecovery& valueRecovery)72 {73 Node* node;74 Node* lastMovHint;75 if (!doSearchForForwardConversion(block, currentNode, nodeIndex, !!valueRecovery, node, lastMovHint))76 return;77 78 ASSERT(node->codeOrigin != currentNode->codeOrigin);79 80 m_codeOrigin = node->codeOrigin;81 82 if (!valueRecovery)83 return;84 85 ASSERT(lastMovHint);86 ASSERT(lastMovHint->child1() == currentNode);87 m_valueRecoveryOverride = adoptRef(88 new ValueRecoveryOverride(lastMovHint->local(), valueRecovery));89 }90 91 71 } } // namespace JSC::DFG 92 72 -
trunk/Source/JavaScriptCore/dfg/DFGOSRExit.h
r159091 r161126 102 102 CodeLocationJump codeLocationForRepatch(CodeBlock*) const; 103 103 void correctJump(LinkBuffer&); 104 105 void convertToForward(BasicBlock*, Node*, unsigned nodeIndex, const ValueRecovery&);106 104 107 105 unsigned m_streamIndex; -
trunk/Source/JavaScriptCore/dfg/DFGOSRExitBase.cpp
r158459 r161126 47 47 } 48 48 49 bool OSRExitBase::doSearchForForwardConversion(50 BasicBlock* block, Node* currentNode, unsigned nodeIndex, bool hasValueRecovery,51 Node*& node, Node*& lastMovHint)52 {53 // Check that either the current node is a SetLocal, or the preceding node was a54 // SetLocal with the same code origin, or that we've provided a valueRecovery.55 if (!ASSERT_DISABLED56 && !hasValueRecovery57 && !currentNode->containsMovHint()) {58 Node* setLocal = block->at(nodeIndex - 1);59 ASSERT_UNUSED(setLocal, setLocal->containsMovHint());60 ASSERT_UNUSED(setLocal, setLocal->codeOriginForExitTarget == currentNode->codeOriginForExitTarget);61 }62 63 // Find the first node for the next bytecode instruction. Also track the last mov hint64 // on this node.65 unsigned indexInBlock = nodeIndex + 1;66 node = 0;67 lastMovHint = 0;68 for (;;) {69 if (indexInBlock == block->size()) {70 // This is an inline return. Give up and do a backwards speculation. This is safe71 // because an inline return has its own bytecode index and it's always safe to72 // reexecute that bytecode.73 ASSERT(node->op() == Jump);74 return false;75 }76 node = block->at(indexInBlock);77 if (node->containsMovHint() && node->child1() == currentNode)78 lastMovHint = node;79 if (node->codeOriginForExitTarget != currentNode->codeOriginForExitTarget)80 break;81 indexInBlock++;82 }83 84 ASSERT(node->codeOriginForExitTarget != currentNode->codeOriginForExitTarget);85 return true;86 }87 88 49 } } // namespace JSC::DFG 89 50 -
trunk/Source/JavaScriptCore/dfg/DFGOSRExitBase.h
r160348 r161126 65 65 return considerAddingAsFrequentExitSiteSlow(profiledCodeBlock); 66 66 } 67 68 // Returns true if the forward conversion is really needed.69 bool doSearchForForwardConversion(70 BasicBlock*, Node* currentNode, unsigned nodeIndex, bool hasValueRecovery,71 Node*& nextBCNode, Node*& lastMovHint);72 67 73 68 private: -
trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r160796 r161126 505 505 case Arrayify: 506 506 case ArrayifyToStructure: 507 case MovHint:508 case MovHintAndCheck:509 case ZombieHint:510 507 case CheckTierUpInLoop: 511 508 case CheckTierUpAtReturn: … … 578 575 case AllocationProfileWatchpoint: 579 576 case Phantom: 577 case Check: 580 578 case PutGlobalVar: 581 579 case CheckWatchdogTimer: … … 586 584 case TypedArrayWatchpoint: 587 585 case ConstantStoragePointer: 586 case MovHint: 587 case ZombieHint: 588 588 break; 589 589 … … 745 745 } 746 746 747 case MovHint: 748 // Ignore these since they have no effect on in-DFG execution. 749 break; 750 747 751 default: 748 752 m_graph.voteChildren(node, VoteValue); -
trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp
r160613 r161126 187 187 } else { 188 188 m_insertionSet.insertNode( 189 0, SpecNone, MovHint, CodeOrigin(), OpInfo(variable),190 Edge(node));189 0, SpecNone, MovHint, CodeOrigin(), 190 OpInfo(variable->local().offset()), Edge(node)); 191 191 } 192 192 } … … 270 270 // to the node specified by variablesAtHead. 271 271 // - SetLocal gets NodeMustGenerate if it's flushed, or turns into a 272 // MovHintotherwise.272 // Check otherwise. 273 273 // - Flush loses its children but remains, because we want to know when a 274 274 // flushed SetLocal's value is no longer needed. This also makes it simpler … … 309 309 node->mergeFlags(NodeMustGenerate); 310 310 else 311 node->setOpAndDefaultFlags( MovHint);311 node->setOpAndDefaultFlags(Check); 312 312 node->misc.replacement = node->child1().node(); // Only for Upsilons. 313 313 break; -
trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
r160796 r161126 119 119 case GetLocal: 120 120 case SetLocal: 121 case MovHintAndCheck:122 121 case MovHint: 123 122 case ZombieHint: … … 251 250 case CheckInBounds: 252 251 case ConstantStoragePointer: 252 case Check: 253 253 return true; 254 254 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r161072 r161126 107 107 } 108 108 109 void SpeculativeJIT:: backwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail)109 void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail) 110 110 { 111 111 if (!m_compileOkay) … … 116 116 } 117 117 118 void SpeculativeJIT:: backwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, const MacroAssembler::JumpList& jumpsToFail)118 void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, const MacroAssembler::JumpList& jumpsToFail) 119 119 { 120 120 if (!m_compileOkay) … … 125 125 } 126 126 127 void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail) 128 { 129 if (!m_compileOkay) 130 return; 131 backwardSpeculationCheck(kind, jsValueSource, node, jumpToFail); 132 if (m_speculationDirection == ForwardSpeculation) 133 convertLastOSRExitToForward(); 134 } 135 136 void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail) 137 { 138 ASSERT(m_isCheckingArgumentTypes || m_canExit); 139 speculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail); 140 } 141 142 OSRExitJumpPlaceholder SpeculativeJIT::backwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node) 127 OSRExitJumpPlaceholder SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node) 143 128 { 144 129 if (!m_compileOkay) … … 151 136 } 152 137 153 OSRExitJumpPlaceholder SpeculativeJIT:: backwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse)138 OSRExitJumpPlaceholder SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse) 154 139 { 155 140 ASSERT(m_isCheckingArgumentTypes || m_canExit); 156 return backwardSpeculationCheck(kind, jsValueSource, nodeUse.node()); 157 } 158 159 void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, const MacroAssembler::JumpList& jumpsToFail) 160 { 161 if (!m_compileOkay) 162 return; 163 backwardSpeculationCheck(kind, jsValueSource, node, jumpsToFail); 164 if (m_speculationDirection == ForwardSpeculation) 165 convertLastOSRExitToForward(); 141 return speculationCheck(kind, jsValueSource, nodeUse.node()); 142 } 143 144 void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail) 145 { 146 ASSERT(m_isCheckingArgumentTypes || m_canExit); 147 speculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail); 166 148 } 167 149 … … 172 154 } 173 155 174 void SpeculativeJIT:: backwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)156 void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery) 175 157 { 176 158 if (!m_compileOkay) … … 182 164 } 183 165 184 void SpeculativeJIT:: backwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)166 void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery) 185 167 { 186 168 ASSERT(m_isCheckingArgumentTypes || m_canExit); 187 backwardSpeculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail, recovery);188 } 189 190 void SpeculativeJIT:: speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)169 speculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail, recovery); 170 } 171 172 void SpeculativeJIT::emitInvalidationPoint(Node* node) 191 173 { 192 174 if (!m_compileOkay) 193 175 return; 194 backwardSpeculationCheck(kind, jsValueSource, node, jumpToFail, recovery);195 if (m_speculationDirection == ForwardSpeculation)196 convertLastOSRExitToForward();197 }198 199 void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge edge, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)200 {201 speculationCheck(kind, jsValueSource, edge.node(), jumpToFail, recovery);202 }203 204 void SpeculativeJIT::emitInvalidationPoint(Node* node)205 {206 if (!m_compileOkay)207 return;208 176 ASSERT(m_canExit); 209 ASSERT(m_speculationDirection == BackwardSpeculation);210 177 OSRExitCompilationInfo& info = m_jit.appendExitInfo(JITCompiler::JumpList()); 211 178 m_jit.jitCode()->appendOSRExit(OSRExit( … … 218 185 } 219 186 220 void SpeculativeJIT::convertLastOSRExitToForward(const ValueRecovery& valueRecovery)221 {222 m_jit.jitCode()->lastOSRExit().convertToForward(223 m_block, m_currentNode, m_indexInBlock, valueRecovery);224 }225 226 void SpeculativeJIT::forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail, const ValueRecovery& valueRecovery)227 {228 ASSERT(m_isCheckingArgumentTypes || m_canExit);229 backwardSpeculationCheck(kind, jsValueSource, node, jumpToFail);230 convertLastOSRExitToForward(valueRecovery);231 }232 233 void SpeculativeJIT::forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, const MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& valueRecovery)234 {235 ASSERT(m_isCheckingArgumentTypes || m_canExit);236 backwardSpeculationCheck(kind, jsValueSource, node, jumpsToFail);237 convertLastOSRExitToForward(valueRecovery);238 }239 240 187 void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, Node* node) 241 188 { … … 253 200 } 254 201 255 void SpeculativeJIT:: backwardTypeCheck(JSValueSource source, Edge edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail)202 void SpeculativeJIT::typeCheck(JSValueSource source, Edge edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail) 256 203 { 257 204 ASSERT(needsTypeCheck(edge, typesPassedThrough)); 258 205 m_interpreter.filter(edge, typesPassedThrough); 259 backwardSpeculationCheck(BadType, source, edge.node(), jumpToFail); 260 } 261 262 void SpeculativeJIT::typeCheck(JSValueSource source, Edge edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail) 263 { 264 backwardTypeCheck(source, edge, typesPassedThrough, jumpToFail); 265 if (m_speculationDirection == ForwardSpeculation) 266 convertLastOSRExitToForward(); 267 } 268 269 void SpeculativeJIT::forwardTypeCheck(JSValueSource source, Edge edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail, const ValueRecovery& valueRecovery) 270 { 271 backwardTypeCheck(source, edge, typesPassedThrough, jumpToFail); 272 convertLastOSRExitToForward(valueRecovery); 206 speculationCheck(BadType, source, edge.node(), jumpToFail); 273 207 } 274 208 … … 1381 1315 noticeOSRBirth(child); 1382 1316 1383 m_stream->appendAndLog(VariableEvent::movHint(MinifiedID(child), node->local())); 1384 } 1385 1386 void SpeculativeJIT::compileMovHintAndCheck(Node* node) 1387 { 1388 compileMovHint(node); 1389 speculate(node, node->child1()); 1390 noResult(node); 1317 m_stream->appendAndLog(VariableEvent::movHint(MinifiedID(child), node->unlinkedLocal())); 1391 1318 } 1392 1319 … … 1483 1410 1484 1411 case ZombieHint: { 1485 recordSetLocal( DataFormatDead);1412 recordSetLocal(m_currentNode->unlinkedLocal(), VirtualRegister(), DataFormatDead); 1486 1413 break; 1487 1414 } … … 1502 1429 } 1503 1430 1504 m_speculationDirection = (m_currentNode->flags() & NodeExitsForward) ? ForwardSpeculation : BackwardSpeculation;1505 1506 1431 compile(m_currentNode); 1507 1432 … … 1541 1466 ASSERT(!m_currentNode); 1542 1467 m_isCheckingArgumentTypes = true; 1543 m_speculationDirection = BackwardSpeculation;1544 1468 m_codeOriginForExitTarget = CodeOrigin(0); 1545 1469 m_codeOriginForExitProfile = CodeOrigin(0); … … 1547 1471 for (int i = 0; i < m_jit.codeBlock()->numParameters(); ++i) { 1548 1472 Node* node = m_jit.graph().m_arguments[i]; 1549 ASSERT(node->op() == SetArgument); 1550 if (!node->shouldGenerate()) { 1473 if (!node) { 1551 1474 // The argument is dead. We don't do any checks for such arguments. 1552 1475 continue; 1553 1476 } 1554 1477 1478 ASSERT(node->op() == SetArgument); 1479 ASSERT(node->shouldGenerate()); 1480 1555 1481 VariableAccessData* variableAccessData = node->variableAccessData(); 1556 1482 FlushFormat format = variableAccessData->flushFormat(); … … 2168 2094 2169 2095 if (needsTypeCheck(node->child1(), SpecFullNumber)) { 2170 if (node->flags() & NodeExitsForward) { 2171 forwardTypeCheck( 2172 JSValueRegs(op1GPR), node->child1(), SpecFullNumber, 2173 m_jit.branchTest64(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister), 2174 ValueRecovery::inGPR(op1GPR, DataFormatJS)); 2175 } else { 2176 backwardTypeCheck( 2177 JSValueRegs(op1GPR), node->child1(), SpecFullNumber, 2178 m_jit.branchTest64(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister)); 2179 } 2096 typeCheck( 2097 JSValueRegs(op1GPR), node->child1(), SpecFullNumber, 2098 m_jit.branchTest64(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister)); 2180 2099 } 2181 2100 … … 2199 2118 2200 2119 if (needsTypeCheck(node->child1(), SpecFullNumber)) { 2201 if (node->flags() & NodeExitsForward) { 2202 forwardTypeCheck( 2203 JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecFullNumber, 2204 m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag)), 2205 ValueRecovery::inPair(op1TagGPR, op1PayloadGPR)); 2206 } else { 2207 backwardTypeCheck( 2208 JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecFullNumber, 2209 m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag))); 2210 } 2120 typeCheck( 2121 JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecFullNumber, 2122 m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag))); 2211 2123 } 2212 2124 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r160919 r161126 698 698 for (unsigned index = m_indexInBlock + 1; index < m_block->size() - 1; ++index) { 699 699 Node* node = m_block->at(index); 700 if (node->shouldGenerate()) 701 return UINT_MAX; 700 if (!node->shouldGenerate()) 701 continue; 702 // Check if it's a Phantom that can be safely ignored. 703 if (node->op() == Phantom && !node->child1()) 704 continue; 705 return UINT_MAX; 702 706 } 703 707 … … 2144 2148 #endif 2145 2149 2146 // Add a backward speculation check. 2147 void backwardSpeculationCheck(ExitKind, JSValueSource, Node*, MacroAssembler::Jump jumpToFail); 2148 void backwardSpeculationCheck(ExitKind, JSValueSource, Node*, const MacroAssembler::JumpList& jumpsToFail); 2149 2150 // Add a speculation check without additional recovery. 2150 // Add a speculation check. 2151 2151 void speculationCheck(ExitKind, JSValueSource, Node*, MacroAssembler::Jump jumpToFail); 2152 void speculationCheck(ExitKind, JSValueSource, Node*, const MacroAssembler::JumpList& jumpsToFail); 2153 2154 // Add a speculation check without additional recovery, and with a promise to supply a jump later. 2155 OSRExitJumpPlaceholder speculationCheck(ExitKind, JSValueSource, Node*); 2156 OSRExitJumpPlaceholder speculationCheck(ExitKind, JSValueSource, Edge); 2152 2157 void speculationCheck(ExitKind, JSValueSource, Edge, MacroAssembler::Jump jumpToFail); 2153 // Add a speculation check without additional recovery, and with a promise to supply a jump later.2154 OSRExitJumpPlaceholder backwardSpeculationCheck(ExitKind, JSValueSource, Node*);2155 OSRExitJumpPlaceholder backwardSpeculationCheck(ExitKind, JSValueSource, Edge);2156 // Add a set of speculation checks without additional recovery.2157 void speculationCheck(ExitKind, JSValueSource, Node*, const MacroAssembler::JumpList& jumpsToFail);2158 2158 void speculationCheck(ExitKind, JSValueSource, Edge, const MacroAssembler::JumpList& jumpsToFail); 2159 2159 // Add a speculation check with additional recovery. 2160 void backwardSpeculationCheck(ExitKind, JSValueSource, Node*, MacroAssembler::Jump jumpToFail, const SpeculationRecovery&);2161 void backwardSpeculationCheck(ExitKind, JSValueSource, Edge, MacroAssembler::Jump jumpToFail, const SpeculationRecovery&);2162 2163 void emitInvalidationPoint(Node*);2164 2165 // It is generally a good idea to not use this directly.2166 void convertLastOSRExitToForward(const ValueRecovery& = ValueRecovery());2167 2168 // Note: not specifying the valueRecovery argument (leaving it as ValueRecovery()) implies2169 // that you've ensured that there exists a MovHint prior to your use of forwardSpeculationCheck().2170 void forwardSpeculationCheck(ExitKind, JSValueSource, Node*, MacroAssembler::Jump jumpToFail, const ValueRecovery& = ValueRecovery());2171 void forwardSpeculationCheck(ExitKind, JSValueSource, Node*, const MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& = ValueRecovery());2172 2160 void speculationCheck(ExitKind, JSValueSource, Node*, MacroAssembler::Jump jumpToFail, const SpeculationRecovery&); 2173 2161 void speculationCheck(ExitKind, JSValueSource, Edge, MacroAssembler::Jump jumpToFail, const SpeculationRecovery&); 2162 2163 void emitInvalidationPoint(Node*); 2164 2174 2165 // Called when we statically determine that a speculation will fail. 2175 2166 void terminateSpeculativeExecution(ExitKind, JSValueRegs, Node*); … … 2178 2169 // Helpers for performing type checks on an edge stored in the given registers. 2179 2170 bool needsTypeCheck(Edge edge, SpeculatedType typesPassedThrough) { return m_interpreter.needsTypeCheck(edge, typesPassedThrough); } 2180 void backwardTypeCheck(JSValueSource, Edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail);2181 2171 void typeCheck(JSValueSource, Edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail); 2182 void forwardTypeCheck(JSValueSource, Edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail, const ValueRecovery&);2183 2172 2184 2173 void speculateInt32(Edge); … … 2253 2242 BasicBlock* m_block; 2254 2243 Node* m_currentNode; 2255 SpeculationDirection m_speculationDirection;2256 2244 bool m_canExit; 2257 2245 unsigned m_indexInBlock; -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r161072 r161126 1922 1922 } 1923 1923 1924 case MovHintAndCheck: {1925 compileMovHintAndCheck(node);1926 break;1927 }1928 1929 1924 case MovHint: 1930 case ZombieHint: { 1925 case ZombieHint: 1926 case Check: { 1931 1927 RELEASE_ASSERT_NOT_REACHED(); 1932 1928 break; … … 1934 1930 1935 1931 case SetLocal: { 1936 // SetLocal doubles as a hint as to where a node will be stored and1937 // as a speculation point. So before we speculate make sure that we1938 // know where the child of this node needs to go in the virtual1939 // stack.1940 compileMovHint(node);1941 1942 1932 switch (node->variableAccessData()->flushFormat()) { 1943 1933 case FlushedDouble: { -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r161072 r161126 2237 2237 } 2238 2238 2239 case MovHintAndCheck: {2240 compileMovHintAndCheck(node);2241 break;2242 }2243 2244 2239 case MovHint: 2245 case ZombieHint: { 2240 case ZombieHint: 2241 case Check: { 2246 2242 RELEASE_ASSERT_NOT_REACHED(); 2247 2243 break; … … 2249 2245 2250 2246 case SetLocal: { 2251 // SetLocal doubles as a hint as to where a node will be stored and2252 // as a speculation point. So before we speculate make sure that we2253 // know where the child of this node needs to go in the virtual2254 // stack.2255 compileMovHint(node);2256 2257 2247 switch (node->variableAccessData()->flushFormat()) { 2258 2248 case FlushedDouble: { … … 2305 2295 m_jit.store64(value.gpr(), JITCompiler::addressFor(node->machineLocal())); 2306 2296 noResult(node); 2307 2308 2297 recordSetLocal(DataFormatJS); 2309 2298 break; -
trunk/Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp
r157656 r161126 164 164 break; 165 165 166 // First insert a dead SetLocal to tell OSR that the child's value should167 // be dropped into this bytecode variable if the CheckStructure decides168 // to exit.169 170 166 CodeOrigin codeOrigin = node->codeOrigin; 171 167 Edge child1 = node->child1(); 172 168 173 insertionSet.insertNode(174 indexInBlock, SpecNone, SetLocal, codeOrigin, OpInfo(variable), child1);175 176 // Use NodeExitsForward to indicate that we should exit to the next177 // bytecode instruction rather than reexecuting the current one.178 Node* newNode = 0;179 169 if (iter->value.m_structure) { 180 newNode =insertionSet.insertNode(170 insertionSet.insertNode( 181 171 indexInBlock, SpecNone, CheckStructure, codeOrigin, 182 172 OpInfo(m_graph.addStructureSet(iter->value.m_structure)), … … 184 174 } else if (iter->value.m_arrayModeIsValid) { 185 175 ASSERT(iter->value.m_arrayModeHoistingOkay); 186 newNode =insertionSet.insertNode(176 insertionSet.insertNode( 187 177 indexInBlock, SpecNone, CheckArray, codeOrigin, 188 178 OpInfo(iter->value.m_arrayMode.asWord()), … … 190 180 } else 191 181 RELEASE_ASSERT_NOT_REACHED(); 192 newNode->mergeFlags(NodeExitsForward);193 182 changed = true; 194 183 break; … … 229 218 case CheckStructure: 230 219 case StructureTransitionWatchpoint: { 231 // We currently rely on the fact that we're the only ones who would232 // insert these nodes with NodeExitsForward.233 RELEASE_ASSERT(!(node->flags() & NodeExitsForward));234 220 Node* child = node->child1().node(); 235 221 if (child->op() != GetLocal) … … 258 244 case GetTypedArrayByteOffset: 259 245 case Phantom: 246 case MovHint: 260 247 // Don't count these uses. 261 248 break; … … 330 317 switch (node->op()) { 331 318 case CheckArray: { 332 // We currently rely on the fact that we're the only ones who would333 // insert these nodes with NodeExitsForward.334 RELEASE_ASSERT(!(node->flags() & NodeExitsForward));335 319 Node* child = node->child1().node(); 336 320 if (child->op() != GetLocal) … … 358 342 case GetIndexedPropertyStorage: 359 343 case Phantom: 344 case MovHint: 360 345 // Don't count these uses. 361 346 break; -
trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp
r160348 r161126 246 246 || edge->op() == SetArgument 247 247 || edge->op() == Flush 248 || edge->op() == Phi 249 || edge->op() == ZombieHint 250 || edge->op() == MovHint 251 || edge->op() == MovHintAndCheck); 248 || edge->op() == Phi); 252 249 253 250 if (phisInThisBlock.contains(edge.node())) … … 258 255 (node, edge), 259 256 edge->op() == SetLocal 260 || edge->op() == ZombieHint261 || edge->op() == MovHint262 || edge->op() == MovHintAndCheck263 257 || edge->op() == SetArgument 264 258 || edge->op() == Flush); … … 293 287 (local, block->predecessors[k], prevNode), 294 288 prevNode->op() == SetLocal 295 || prevNode->op() == MovHint296 || prevNode->op() == MovHintAndCheck297 || prevNode->op() == ZombieHint298 289 || prevNode->op() == SetArgument 299 290 || prevNode->op() == Phi); -
trunk/Source/JavaScriptCore/dfg/DFGVariableAccessData.h
r161072 r161126 75 75 , m_checkArrayHoistingFailed(false) 76 76 , m_isProfitableToUnbox(false) 77 , m_isLoadedFrom(false) 77 78 , m_doubleFormatState(EmptyDoubleFormatState) 78 79 { -
trunk/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp
r159886 r161126 193 193 MinifiedGenerationInfo info = generationInfos.get(source.id()); 194 194 if (info.format == DataFormatNone) { 195 // Try to see if there is an alternate node that would contain the value we want. 196 // 197 // Backward rewiring refers to: 198 // 199 // a: Something(...) 200 // b: Id(@a) // some identity function 201 // c: SetLocal(@b) 202 // 203 // Where we find @b being dead, but @a is still alive. 204 // 205 // Forward rewiring refers to: 206 // 207 // a: Something(...) 208 // b: SetLocal(@a) 209 // c: Id(@a) // some identity function 210 // 211 // Where we find @a being dead, but @b is still alive. 212 213 bool found = false; 214 215 if (node && permitsOSRBackwardRewiring(node->op())) { 216 MinifiedID id = node->child1(); 217 if (tryToSetConstantRecovery(valueRecoveries[i], codeBlock, graph.at(id))) 218 continue; 219 info = generationInfos.get(id); 220 if (info.format != DataFormatNone) 221 found = true; 222 } 223 224 if (!found) { 225 MinifiedID bestID; 226 unsigned bestScore = 0; 227 228 HashMap<MinifiedID, MinifiedGenerationInfo>::iterator iter = generationInfos.begin(); 229 HashMap<MinifiedID, MinifiedGenerationInfo>::iterator end = generationInfos.end(); 230 for (; iter != end; ++iter) { 231 MinifiedID id = iter->key; 232 node = graph.at(id); 233 if (!node) 234 continue; 235 if (!node->hasChild1()) 236 continue; 237 if (node->child1() != source.id()) 238 continue; 239 if (iter->value.format == DataFormatNone) 240 continue; 241 unsigned myScore = forwardRewiringSelectionScore(node->op()); 242 if (myScore <= bestScore) 243 continue; 244 bestID = id; 245 bestScore = myScore; 246 } 247 248 if (!!bestID) { 249 info = generationInfos.get(bestID); 250 ASSERT(info.format != DataFormatNone); 251 found = true; 252 } 253 } 254 255 if (!found) { 256 valueRecoveries[i] = ValueRecovery::constant(jsUndefined()); 257 continue; 258 } 195 valueRecoveries[i] = ValueRecovery::constant(jsUndefined()); 196 continue; 259 197 } 260 198 -
trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
r160347 r161126 43 43 case GetLocal: 44 44 case SetLocal: 45 case MovHintAndCheck:46 45 case MovHint: 47 46 case ZombieHint: … … 112 111 case CheckInBounds: 113 112 case ConstantStoragePointer: 113 case Check: 114 114 // These are OK. 115 115 break; -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
r161072 r161126 229 229 bool shouldExecuteEffects = m_interpreter.startExecuting(m_node); 230 230 231 m_direction = (m_node->flags() & NodeExitsForward) ? ForwardSpeculation : BackwardSpeculation;232 233 231 switch (m_node->op()) { 234 232 case Upsilon: … … 260 258 case ZombieHint: 261 259 compileZombieHint(); 262 break;263 case MovHintAndCheck:264 compileMovHintAndCheck();265 260 break; 266 261 case Phantom: … … 658 653 switch (useKindFor(variable->flushFormat())) { 659 654 case Int32Use: 660 speculate Backward(BadType, jsValueValue(jsValue), m_node, isNotInt32(jsValue));655 speculate(BadType, jsValueValue(jsValue), m_node, isNotInt32(jsValue)); 661 656 setInt32(unboxInt32(jsValue)); 662 657 break; 663 658 case CellUse: 664 speculate Backward(BadType, jsValueValue(jsValue), m_node, isNotCell(jsValue));659 speculate(BadType, jsValueValue(jsValue), m_node, isNotCell(jsValue)); 665 660 setJSValue(jsValue); 666 661 break; 667 662 case BooleanUse: 668 speculate Backward(BadType, jsValueValue(jsValue), m_node, isNotBoolean(jsValue));663 speculate(BadType, jsValueValue(jsValue), m_node, isNotBoolean(jsValue)); 669 664 setBoolean(unboxBoolean(jsValue)); 670 665 break; … … 702 697 void compileSetLocal() 703 698 { 704 observeMovHint(m_node);705 706 699 VariableAccessData* variable = m_node->variableAccessData(); 707 700 switch (variable->flushFormat()) { … … 754 747 void compileMovHint() 755 748 { 756 observeMovHint(m_node); 749 ASSERT(m_node->containsMovHint()); 750 ASSERT(m_node->op() != ZombieHint); 751 752 VirtualRegister operand = m_node->unlinkedLocal(); 753 m_availability.operand(operand) = Availability(m_node->child1().node()); 757 754 } 758 755 759 756 void compileZombieHint() 760 757 { 761 VariableAccessData* data = m_node->variableAccessData(); 762 m_availability.operand(data->local()) = Availability::unavailable(); 763 } 764 765 void compileMovHintAndCheck() 766 { 767 observeMovHint(m_node); 768 speculate(m_node->child1()); 758 m_availability.operand(m_node->unlinkedLocal()) = Availability::unavailable(); 769 759 } 770 760 … … 1178 1168 void compileInt32ToDouble() 1179 1169 { 1180 if (!m_interpreter.needsTypeCheck(m_node->child1(), SpecFullNumber) 1181 || m_node->speculationDirection() == BackwardSpeculation) { 1182 setDouble(lowDouble(m_node->child1())); 1183 return; 1184 } 1185 1186 LValue boxedValue = lowJSValue(m_node->child1(), ManualOperandSpeculation); 1187 1188 LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("Double unboxing int case")); 1189 LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("Double unboxing double case")); 1190 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Double unboxing continuation")); 1191 1192 m_out.branch(isNotInt32(boxedValue), doubleCase, intCase); 1193 1194 LBasicBlock lastNext = m_out.appendTo(intCase, doubleCase); 1195 1196 ValueFromBlock intToDouble = m_out.anchor( 1197 m_out.intToDouble(unboxInt32(boxedValue))); 1198 m_out.jump(continuation); 1199 1200 m_out.appendTo(doubleCase, continuation); 1201 1202 forwardTypeCheck( 1203 jsValueValue(boxedValue), m_node->child1(), SpecFullNumber, 1204 isCellOrMisc(boxedValue), jsValueValue(boxedValue)); 1205 1206 ValueFromBlock unboxedDouble = m_out.anchor(unboxDouble(boxedValue)); 1207 m_out.jump(continuation); 1208 1209 m_out.appendTo(continuation, lastNext); 1210 1211 LValue result = m_out.phi(m_out.doubleType, intToDouble, unboxedDouble); 1212 1213 setDouble(result); 1170 setDouble(lowDouble(m_node->child1())); 1214 1171 } 1215 1172 … … 3197 3154 } 3198 3155 3199 void speculateBackward(3200 ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition)3201 {3202 appendOSRExit(3203 kind, lowValue, highValue, failCondition, BackwardSpeculation, FormattedValue());3204 }3205 3206 void speculateForward(3207 ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition,3208 const FormattedValue& recovery)3209 {3210 appendOSRExit(3211 kind, lowValue, highValue, failCondition, ForwardSpeculation, recovery);3212 }3213 3214 3156 void speculate( 3215 3157 ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition) 3216 3158 { 3217 appendOSRExit( 3218 kind, lowValue, highValue, failCondition, m_direction, FormattedValue()); 3159 appendOSRExit(kind, lowValue, highValue, failCondition); 3219 3160 } 3220 3161 … … 3222 3163 { 3223 3164 speculate(kind, noValue(), 0, m_out.booleanTrue); 3224 }3225 3226 void backwardTypeCheck(3227 FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,3228 LValue failCondition)3229 {3230 appendTypeCheck(3231 lowValue, highValue, typesPassedThrough, failCondition, BackwardSpeculation,3232 FormattedValue());3233 }3234 3235 void forwardTypeCheck(3236 FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,3237 LValue failCondition, const FormattedValue& recovery)3238 {3239 appendTypeCheck(3240 lowValue, highValue, typesPassedThrough, failCondition, ForwardSpeculation,3241 recovery);3242 3165 } 3243 3166 … … 3246 3169 LValue failCondition) 3247 3170 { 3248 appendTypeCheck( 3249 lowValue, highValue, typesPassedThrough, failCondition, m_direction, 3250 FormattedValue()); 3171 appendTypeCheck(lowValue, highValue, typesPassedThrough, failCondition); 3251 3172 } 3252 3173 3253 3174 void appendTypeCheck( 3254 3175 FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough, 3255 LValue failCondition , SpeculationDirection direction, FormattedValue recovery)3176 LValue failCondition) 3256 3177 { 3257 3178 if (!m_interpreter.needsTypeCheck(highValue, typesPassedThrough)) 3258 3179 return; 3259 3180 ASSERT(mayHaveTypeCheck(highValue.useKind())); 3260 appendOSRExit(BadType, lowValue, highValue.node(), failCondition , direction, recovery);3181 appendOSRExit(BadType, lowValue, highValue.node(), failCondition); 3261 3182 m_interpreter.filter(highValue, typesPassedThrough); 3262 3183 } … … 4093 4014 4094 4015 void appendOSRExit( 4095 ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition, 4096 SpeculationDirection direction, FormattedValue recovery) 4016 ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition) 4097 4017 { 4098 4018 if (verboseCompilationEnabled()) … … 4119 4039 lastNext = m_out.appendTo(failCase, continuation); 4120 4040 4121 emitOSRExitCall(exit, lowValue , direction, recovery);4041 emitOSRExitCall(exit, lowValue); 4122 4042 4123 4043 m_out.unreachable(); … … 4126 4046 } 4127 4047 4128 void emitOSRExitCall( 4129 OSRExit& exit, FormattedValue lowValue, SpeculationDirection direction, 4130 FormattedValue recovery) 4048 void emitOSRExitCall(OSRExit& exit, FormattedValue lowValue) 4131 4049 { 4132 4050 ExitArgumentList arguments; … … 4134 4052 CodeOrigin codeOrigin = exit.m_codeOrigin; 4135 4053 4136 if (direction == BackwardSpeculation) 4137 buildExitArguments(exit, arguments, lowValue, codeOrigin); 4138 else { 4139 ASSERT(direction == ForwardSpeculation); 4140 if (!recovery) { 4141 for (unsigned nodeIndex = m_nodeIndex; nodeIndex < m_highBlock->size(); ++nodeIndex) { 4142 Node* node = m_highBlock->at(nodeIndex); 4143 if (node->codeOriginForExitTarget == codeOrigin) 4144 continue; 4145 codeOrigin = node->codeOriginForExitTarget; 4146 break; 4147 } 4148 } 4149 4150 buildExitArguments(exit, arguments, lowValue, codeOrigin); 4151 exit.convertToForward(m_highBlock, m_node, m_nodeIndex, recovery, arguments); 4152 } 4054 buildExitArguments(exit, arguments, lowValue, codeOrigin); 4153 4055 4154 4056 callStackmap(exit, arguments); … … 4310 4212 } 4311 4213 4312 void observeMovHint(Node* node)4313 {4314 ASSERT(node->containsMovHint());4315 ASSERT(node->op() != ZombieHint);4316 4317 VirtualRegister operand = node->local();4318 4319 m_availability.operand(operand) = Availability(node->child1().node());4320 }4321 4322 4214 void setInt32(Node* node, LValue value) 4323 4215 { … … 4490 4382 unsigned m_nodeIndex; 4491 4383 Node* m_node; 4492 SpeculationDirection m_direction;4493 4384 4494 4385 uint32_t m_stackmapIDs; -
trunk/Source/JavaScriptCore/ftl/FTLOSRExit.cpp
r159091 r161126 62 62 } 63 63 64 void OSRExit::convertToForward(65 BasicBlock* block, Node* currentNode, unsigned nodeIndex,66 const FormattedValue &value, ExitArgumentList& arguments)67 {68 Node* node;69 Node* lastMovHint;70 if (!doSearchForForwardConversion(block, currentNode, nodeIndex, !!value, node, lastMovHint))71 return;72 73 ASSERT(node->codeOrigin != currentNode->codeOrigin);74 75 m_codeOrigin = node->codeOrigin;76 77 if (!value)78 return;79 80 VirtualRegister overriddenOperand = lastMovHint->local();81 82 // Is the value for this operand being passed as an argument to the exit, or is83 // it something else? If it's an argument already, then replace that argument;84 // otherwise add another argument.85 if (m_values.operand(overriddenOperand).isArgument()) {86 ExitArgument exitArgument = m_values.operand(overriddenOperand).exitArgument();87 arguments[exitArgument.argument()] = value.value();88 m_values.operand(overriddenOperand) = ExitValue::exitArgument(89 exitArgument.withFormat(value.format()));90 return;91 }92 93 unsigned argument = arguments.size();94 arguments.append(value.value());95 m_values.operand(overriddenOperand) = ExitValue::exitArgument(96 ExitArgument(value.format(), argument));97 }98 99 64 } } // namespace JSC::FTL 100 65 -
trunk/Source/JavaScriptCore/ftl/FTLOSRExit.h
r159091 r161126 167 167 168 168 CodeLocationJump codeLocationForRepatch(CodeBlock* ftlCodeBlock) const; 169 170 void convertToForward(171 DFG::BasicBlock*, DFG::Node* currentNode, unsigned nodeIndex,172 const FormattedValue&, ExitArgumentList& arguments);173 169 }; 174 170
Note: See TracChangeset
for help on using the changeset viewer.