Changeset 181563 in webkit
- Timestamp:
- Mar 16, 2015, 10:39:07 AM (11 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 4 added
- 2 edited
-
ChangeLog (modified) (1 diff)
-
dfg/DFGPutStackSinkingPhase.cpp (modified) (4 diffs)
-
tests/stress/get-stack-identity-due-to-sinking.js (added)
-
tests/stress/get-stack-mapping-with-dead-get-stack.js (added)
-
tests/stress/get-stack-mapping.js (added)
-
tests/stress/weird-put-stack-varargs.js (added)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r181556 r181563 1 2015-03-15 Filip Pizlo <fpizlo@apple.com> 2 3 DFG::PutStackSinkingPhase should eliminate GetStacks that have an obviously known source, and emit GetStacks when the stack's value is needed and none is deferred 4 https://bugs.webkit.org/show_bug.cgi?id=141624 5 6 Reviewed by Geoffrey Garen. 7 8 Not eliminating GetStacks was an obvious omission from the original PutStackSinkingPhase. 9 Previously, we would treat GetStacks conservatively and assume that the stack slot 10 escaped. That's pretty dumb, since a GetStack is a local load of the stack. This change 11 makes GetStack a no-op from the standpoint of this phase's deferral analysis. At the end 12 we either keep the GetStack (if there was no concrete deferral) or we replace it with an 13 identity over the value that would have been stored by the deferred PutStack. Note that 14 this might be a Phi that the phase creates, so this is strictly stronger than what GCSE 15 could do. 16 17 But this change revealed the fact that this phase never correctly handled side effects in 18 case that we had done a GetStack, then a side-effect, and then found ourselves wanting the 19 value on the stack due to (for example) a Phi on a deferred PutStack and that GetStack. 20 Basically, it's only correct to use the SSA converter's incoming value mapping if we have 21 a concrete deferral - since anything but a concrete deferral may imply that the value has 22 been clobbered. 23 24 This has no performance change. I believe that the bug was previously benign because we 25 have so few operations that clobber the stack anymore, and most of those get used in a 26 very idiomatic way. The GetStack elimination will be very useful for the varargs 27 simplification that is part of bug 141174. 28 29 This includes a test for the case that Speedometer hit, plus tests for the other cases I 30 thought of once I realized the deeper issue. 31 32 * dfg/DFGPutStackSinkingPhase.cpp: 33 * tests/stress/get-stack-identity-due-to-sinking.js: Added. 34 (foo): 35 (bar): 36 * tests/stress/get-stack-mapping-with-dead-get-stack.js: Added. 37 (bar): 38 (foo): 39 * tests/stress/get-stack-mapping.js: Added. 40 (bar): 41 (foo): 42 * tests/stress/weird-put-stack-varargs.js: Added. 43 (baz): 44 (foo): 45 (fuzz): 46 (bar): 47 1 48 2015-03-16 Joseph Pecoraro <pecoraro@apple.com> 2 49 -
trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp
r181498 r181563 222 222 } 223 223 224 if (node->op() == GetStack) { 225 // A GetStack doesn't affect anything, since we know which local we are reading 226 // from. 227 continue; 228 } 229 224 230 auto escapeHandler = [&] (VirtualRegister operand) { 225 231 if (operand.isHeader()) … … 391 397 break; 392 398 } 399 400 case GetStack: { 401 StackAccessData* data = node->stackAccessData(); 402 FlushFormat format = deferred.operand(data->local); 403 if (!isConcrete(format)) { 404 // This means there is no deferral. No deferral means that the most 405 // authoritative value for this stack slot is what is stored in the stack. So, 406 // keep the GetStack. 407 mapping.operand(data->local) = node; 408 break; 409 } 410 411 // We have a concrete deferral, which means a PutStack that hasn't executed yet. It 412 // would have stored a value with a certain format. That format must match our 413 // format. But more importantly, we can simply use the value that the PutStack would 414 // have stored and get rid of the GetStack. 415 DFG_ASSERT(m_graph, node, format == data->format); 416 417 Node* incoming = mapping.operand(data->local); 418 node->child1() = incoming->defaultEdge(); 419 node->convertToIdentity(); 420 break; 421 } 393 422 394 423 default: { … … 419 448 m_graph, node, escapeHandler, escapeHandler, 420 449 [&] (VirtualRegister, Node*) { }); 421 422 // If we're a GetStack, then we also create a mapping.423 // FIXME: We should be able to just eliminate such GetLocals, when we know424 // what their incoming value will be.425 // https://bugs.webkit.org/show_bug.cgi?id=141624426 if (node->op() == GetStack) {427 StackAccessData* data = node->stackAccessData();428 VirtualRegister operand = data->local;429 mapping.operand(operand) = node;430 }431 450 break; 432 451 } } … … 445 464 DFG_ASSERT(m_graph, nullptr, isConcrete(format)); 446 465 UseKind useKind = useKindFor(format); 447 Node* incoming = mapping.operand(operand); 448 if (!incoming) { 449 // This can totally happen, see tests/stress/put-local-conservative.js. 450 // This arises because deferral and liveness are both conservative. 451 // Conservative liveness means that a load from a *different* closure 452 // variable may lead us to believe that our local is live. Conservative 453 // deferral may lead us to believe that the local doesn't have a top deferral 454 // because someone has done something that would have forced it to be 455 // materialized. The basic pattern is: 456 // 457 // GetClosureVar(loc42) // loc42's deferral is now bottom 458 // if (predicate1) 459 // PutClosureVar(loc42) // prevent GCSE of our GetClosureVar's 460 // if (predicate2) 461 // PutStack(loc42) // we now have a concrete deferral 462 // // we still have the concrete deferral because we merged with bottom 463 // GetClosureVar(loc42) // force materialization 464 // 465 // We will have a Phi with no incoming value form the basic block that 466 // bypassed the PutStack. 467 468 // Note: we sort of could have used the equivalent of LLVM's undef here. The 469 // point is that it's OK to just leave random bits in the local if we're 470 // coming down this path. But, we don't have a way of saying that in our IR 471 // right now and anyway it probably doesn't matter that much. 472 473 incoming = insertionSet.insertBottomConstantForUse( 474 upsilonInsertionPoint, upsilonOrigin, useKind).node(); 466 467 // We need to get a value for the stack slot. This phase doesn't really have a 468 // good way of determining if a stack location got clobbered. It just knows if 469 // there is a deferral. The lack of a deferral might mean that a PutStack or 470 // GetStack had never happened, or it might mean that the value was read, or 471 // that it was written. It's OK for us to make some bad decisions here, since 472 // GCSE will clean it up anyway. 473 Node* incoming; 474 if (isConcrete(deferred.operand(operand))) { 475 incoming = mapping.operand(operand); 476 DFG_ASSERT(m_graph, phiNode, incoming); 477 } else { 478 // Issue a GetStack to get the value. This might introduce some redundancy 479 // into the code, but if it's bad enough, GCSE will clean it up. 480 incoming = insertionSet.insertNode( 481 upsilonInsertionPoint, SpecNone, GetStack, upsilonOrigin, 482 OpInfo(m_graph.m_stackAccessData.add(operand, format))); 483 incoming->setResult(resultFor(format)); 475 484 } 476 485
Note:
See TracChangeset
for help on using the changeset viewer.