Changeset 208560 in webkit
- Timestamp:
- Nov 10, 2016, 1:19:52 PM (9 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r208524 r208560 1 2016-11-10 Mark Lam <mark.lam@apple.com> 2 3 Graph::methodOfGettingAValueProfileFor() should be returning the profile for the operand node. 4 https://bugs.webkit.org/show_bug.cgi?id=164600 5 <rdar://problem/28828676> 6 7 Reviewed by Filip Pizlo. 8 9 * stress/osr-exit-on-op-negate-should-no-fail-assertions.js: Added. 10 1 11 2016-11-08 Yusuke Suzuki <utatane.tea@gmail.com> 2 12 -
trunk/Source/JavaScriptCore/ChangeLog
r208540 r208560 1 2016-11-10 Mark Lam <mark.lam@apple.com> 2 3 Graph::methodOfGettingAValueProfileFor() should be returning the profile for the operand node. 4 https://bugs.webkit.org/show_bug.cgi?id=164600 5 <rdar://problem/28828676> 6 7 Reviewed by Filip Pizlo. 8 9 Currently, Graph::methodOfGettingAValueProfileFor() assumes that the operand DFG 10 node that it is provided with always has a different origin than the node that is 11 using that operand. For example, in a DFG graph that looks like this: 12 13 a: ... 14 b: ArithAdd(@a, ...) 15 16 ... when emitting speculation checks on @a for the ArithAdd node at @b, 17 Graph::methodOfGettingAValueProfileFor() is passed @a, and expects @a's to 18 originate from a different bytecode than @b. The intent here is to get the 19 profile for @a so that the OSR exit ramp for @b can update @a's profile with the 20 observed result type from @a so that future type prediction on incoming args for 21 the ArithAdd node can take this into consideration. 22 23 However, op_negate can be compiled into the following series of nodes: 24 25 a: ... 26 b: BooleanToNumber(@a) 27 c: DoubleRep(@b) 28 d: ArithNegate(@c) 29 30 All 3 nodes @b, @c, and @d maps to the same op_negate bytecode i.e. they have the 31 same origin. When the speculativeJIT emits a speculationCheck for DoubleRep, it 32 calls Graph::methodOfGettingAValueProfileFor() to get the ArithProfile for the 33 BooleanToNumber node. But because all 3 nodes have the same origin, 34 Graph::methodOfGettingAValueProfileFor() erroneously returns the ArithProfile for 35 the op_negate. Subsequently, the OSR exit ramp will modify the ArithProfile of 36 the op_negate and corrupt its profile. Instead, what the OSR exit ramp should be 37 doing is update the ArithProfile of op_negate's operand i.e. BooleanToNumber's 38 operand @a in this case. 39 40 The fix is to always pass the current node we're generating code for (in addition 41 to the operand node) to Graph::methodOfGettingAValueProfileFor(). This way, we 42 know the profile is valid if and only if the current node and its operand node 43 does not have the same origin. 44 45 In this patch, we also fixed the following: 46 1. Teach Graph::methodOfGettingAValueProfileFor() to get the profile for 47 BooleanToNumber's operand if the operand node it is given is BooleanToNumber. 48 2. Change JITCompiler::appendExceptionHandlingOSRExit() to explicitly pass an 49 empty MethodOfGettingAValueProfile(). It was implicitly doing this before. 50 3. Change SpeculativeJIT::emitInvalidationPoint() to pass an empty 51 MethodOfGettingAValueProfile(). It has no child node. Hence, it doesn't 52 make sense to call Graph::methodOfGettingAValueProfileFor() for a child node 53 that does not exist. 54 55 * dfg/DFGGraph.cpp: 56 (JSC::DFG::Graph::methodOfGettingAValueProfileFor): 57 * dfg/DFGGraph.h: 58 * dfg/DFGJITCompiler.cpp: 59 (JSC::DFG::JITCompiler::appendExceptionHandlingOSRExit): 60 * dfg/DFGSpeculativeJIT.cpp: 61 (JSC::DFG::SpeculativeJIT::speculationCheck): 62 (JSC::DFG::SpeculativeJIT::emitInvalidationPoint): 63 * ftl/FTLLowerDFGToB3.cpp: 64 (JSC::FTL::DFG::LowerDFGToB3::appendOSRExitDescriptor): 65 1 66 2016-11-10 Aaron Chu <aaron_chu@apple.com> 2 67 -
trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp
r208524 r208560 1614 1614 } 1615 1615 1616 MethodOfGettingAValueProfile Graph::methodOfGettingAValueProfileFor(Node* node) 1617 { 1618 while (node) { 1619 CodeBlock* profiledBlock = baselineCodeBlockFor(node->origin.semantic); 1620 1621 if (node->accessesStack(*this)) { 1622 ValueProfile* result = [&] () -> ValueProfile* { 1623 if (!node->local().isArgument()) 1624 return nullptr; 1625 int argument = node->local().toArgument(); 1626 Node* argumentNode = m_arguments[argument]; 1627 if (!argumentNode) 1628 return nullptr; 1629 if (node->variableAccessData() != argumentNode->variableAccessData()) 1630 return nullptr; 1631 return profiledBlock->valueProfileForArgument(argument); 1632 }(); 1633 if (result) 1634 return result; 1635 1636 if (node->op() == GetLocal) { 1637 return MethodOfGettingAValueProfile::fromLazyOperand( 1638 profiledBlock, 1639 LazyOperandValueProfileKey( 1640 node->origin.semantic.bytecodeIndex, node->local())); 1616 MethodOfGettingAValueProfile Graph::methodOfGettingAValueProfileFor(Node* currentNode, Node* operandNode) 1617 { 1618 for (Node* node = operandNode; node;) { 1619 // currentNode is null when we're doing speculation checks for checkArgumentTypes(). 1620 if (!currentNode || node->origin != currentNode->origin) { 1621 CodeBlock* profiledBlock = baselineCodeBlockFor(node->origin.semantic); 1622 1623 if (node->accessesStack(*this)) { 1624 ValueProfile* result = [&] () -> ValueProfile* { 1625 if (!node->local().isArgument()) 1626 return nullptr; 1627 int argument = node->local().toArgument(); 1628 Node* argumentNode = m_arguments[argument]; 1629 if (!argumentNode) 1630 return nullptr; 1631 if (node->variableAccessData() != argumentNode->variableAccessData()) 1632 return nullptr; 1633 return profiledBlock->valueProfileForArgument(argument); 1634 }(); 1635 if (result) 1636 return result; 1637 1638 if (node->op() == GetLocal) { 1639 return MethodOfGettingAValueProfile::fromLazyOperand( 1640 profiledBlock, 1641 LazyOperandValueProfileKey( 1642 node->origin.semantic.bytecodeIndex, node->local())); 1643 } 1641 1644 } 1642 } 1643 1644 if (node->hasHeapPrediction()) 1645 return profiledBlock->valueProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex); 1646 1647 { 1645 1646 if (node->hasHeapPrediction()) 1647 return profiledBlock->valueProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex); 1648 1648 1649 if (profiledBlock->hasBaselineJITProfiling()) { 1649 1650 if (ArithProfile* result = profiledBlock->arithProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex)) … … 1651 1652 } 1652 1653 } 1653 1654 1654 1655 switch (node->op()) { 1656 case BooleanToNumber: 1655 1657 case Identity: 1656 1658 case ValueRep: -
trunk/Source/JavaScriptCore/dfg/DFGGraph.h
r208373 r208560 418 418 } 419 419 420 MethodOfGettingAValueProfile methodOfGettingAValueProfileFor(Node* );420 MethodOfGettingAValueProfile methodOfGettingAValueProfileFor(Node* currentNode, Node* operandNode); 421 421 422 422 BlockIndex numBlocks() const { return m_blocks.size(); } -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
r207475 r208560 589 589 void JITCompiler::appendExceptionHandlingOSRExit(ExitKind kind, unsigned eventStreamIndex, CodeOrigin opCatchOrigin, HandlerInfo* exceptionHandler, CallSiteIndex callSite, MacroAssembler::JumpList jumpsToFail) 590 590 { 591 OSRExit exit(kind, JSValueRegs(), graph().methodOfGettingAValueProfileFor(nullptr), m_speculative.get(), eventStreamIndex);591 OSRExit exit(kind, JSValueRegs(), MethodOfGettingAValueProfile(), m_speculative.get(), eventStreamIndex); 592 592 exit.m_codeOrigin = opCatchOrigin; 593 593 exit.m_exceptionHandlerCallSiteIndex = callSite; -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r208524 r208560 252 252 } else 253 253 m_jit.appendExitInfo(jumpToFail); 254 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor( node), this, m_stream->size()));254 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(m_currentNode, node), this, m_stream->size())); 255 255 } 256 256 … … 267 267 } else 268 268 m_jit.appendExitInfo(jumpsToFail); 269 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor( node), this, m_stream->size()));269 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(m_currentNode, node), this, m_stream->size())); 270 270 } 271 271 … … 276 276 unsigned index = m_jit.jitCode()->osrExit.size(); 277 277 m_jit.appendExitInfo(); 278 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor( node), this, m_stream->size()));278 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(m_currentNode, node), this, m_stream->size())); 279 279 return OSRExitJumpPlaceholder(index); 280 280 } … … 301 301 unsigned recoveryIndex = m_jit.jitCode()->appendSpeculationRecovery(recovery); 302 302 m_jit.appendExitInfo(jumpToFail); 303 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor( node), this, m_stream->size(), recoveryIndex));303 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(m_currentNode, node), this, m_stream->size(), recoveryIndex)); 304 304 } 305 305 … … 315 315 OSRExitCompilationInfo& info = m_jit.appendExitInfo(JITCompiler::JumpList()); 316 316 m_jit.jitCode()->appendOSRExit(OSRExit( 317 UncountableInvalidation, JSValueSource(), 318 m_jit.graph().methodOfGettingAValueProfileFor(node), 317 UncountableInvalidation, JSValueSource(), MethodOfGettingAValueProfile(), 319 318 this, m_stream->size())); 320 319 info.m_replacementSource = m_jit.watchpointLabel(); -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r208524 r208560 12413 12413 { 12414 12414 return &m_ftlState.jitCode->osrExitDescriptors.alloc( 12415 lowValue.format(), m_graph.methodOfGettingAValueProfileFor( highValue),12415 lowValue.format(), m_graph.methodOfGettingAValueProfileFor(m_node, highValue), 12416 12416 availabilityMap().m_locals.numberOfArguments(), 12417 12417 availabilityMap().m_locals.numberOfLocals());
Note:
See TracChangeset
for help on using the changeset viewer.