| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <iterator> | 5 #include <iterator> |
| 6 | 6 |
| 7 #include "src/compiler/store-store-elimination.h" | 7 #include "src/compiler/store-store-elimination.h" |
| 8 | 8 |
| 9 #include "src/compiler/all-nodes.h" | 9 #include "src/compiler/all-nodes.h" |
| 10 #include "src/compiler/js-graph.h" | 10 #include "src/compiler/js-graph.h" |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 140 const ZoneSet<Node*>& to_remove_const() { return to_remove_; } | 140 const ZoneSet<Node*>& to_remove_const() { return to_remove_; } |
| 141 | 141 |
| 142 void Visit(Node* node); | 142 void Visit(Node* node); |
| 143 | 143 |
| 144 private: | 144 private: |
| 145 static bool IsEffectful(Node* node); | 145 static bool IsEffectful(Node* node); |
| 146 void VisitEffectfulNode(Node* node); | 146 void VisitEffectfulNode(Node* node); |
| 147 UnobservablesSet RecomputeUseIntersection(Node* node); | 147 UnobservablesSet RecomputeUseIntersection(Node* node); |
| 148 UnobservablesSet RecomputeSet(Node* node, UnobservablesSet uses); | 148 UnobservablesSet RecomputeSet(Node* node, UnobservablesSet uses); |
| 149 static bool CannotObserveStoreField(Node* node); | 149 static bool CannotObserveStoreField(Node* node); |
| 150 static bool CanObserveAnything(Node* node); | |
| 151 | 150 |
| 152 void MarkForRevisit(Node* node); | 151 void MarkForRevisit(Node* node); |
| 153 bool HasBeenVisited(Node* node); | 152 bool HasBeenVisited(Node* node); |
| 154 | 153 |
| 155 JSGraph* jsgraph() const { return jsgraph_; } | 154 JSGraph* jsgraph() const { return jsgraph_; } |
| 156 Zone* temp_zone() const { return temp_zone_; } | 155 Zone* temp_zone() const { return temp_zone_; } |
| 157 ZoneVector<UnobservablesSet>& unobservable() { return unobservable_; } | 156 ZoneVector<UnobservablesSet>& unobservable() { return unobservable_; } |
| 158 UnobservablesSet& unobservable_for_id(NodeId id) { | 157 UnobservablesSet& unobservable_for_id(NodeId id) { |
| 159 DCHECK_LT(id, unobservable().size()); | 158 DCHECK_LT(id, unobservable().size()); |
| 160 return unobservable()[id]; | 159 return unobservable()[id]; |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 loaded_from->id(), offset); | 317 loaded_from->id(), offset); |
| 319 | 318 |
| 320 return uses.RemoveSameOffset(offset, temp_zone()); | 319 return uses.RemoveSameOffset(offset, temp_zone()); |
| 321 break; | 320 break; |
| 322 } | 321 } |
| 323 default: | 322 default: |
| 324 if (CannotObserveStoreField(node)) { | 323 if (CannotObserveStoreField(node)) { |
| 325 TRACE(" #%d:%s can observe nothing, set stays unchanged", node->id(), | 324 TRACE(" #%d:%s can observe nothing, set stays unchanged", node->id(), |
| 326 node->op()->mnemonic()); | 325 node->op()->mnemonic()); |
| 327 return uses; | 326 return uses; |
| 328 } else if (CanObserveAnything(node)) { | 327 } else { |
| 329 TRACE(" #%d:%s can observe everything, recording empty set", | 328 TRACE(" #%d:%s might observe anything, recording empty set", |
| 330 node->id(), node->op()->mnemonic()); | 329 node->id(), node->op()->mnemonic()); |
| 331 return unobservables_visited_empty_; | 330 return unobservables_visited_empty_; |
| 332 } else { | |
| 333 // It is safe to turn this check off in the future, but it is better | |
| 334 // to list opcodes in CannotObserveStoreField, in CanObserveAnything, | |
| 335 // or if you don't know, to add another case inside this DCHECK_EXTRA. | |
| 336 DCHECK_EXTRA(node->op()->opcode() == IrOpcode::kCall, "%s", | |
| 337 node->op()->mnemonic()); | |
| 338 TRACE( | |
| 339 " cannot determine unobservables-set for #%d:%s; " | |
| 340 "conservatively recording empty set", | |
| 341 node->id(), node->op()->mnemonic()); | |
| 342 return unobservables_visited_empty_; | |
| 343 } | 331 } |
| 344 } | 332 } |
| 345 UNREACHABLE(); | 333 UNREACHABLE(); |
| 346 return UnobservablesSet::Unvisited(); | 334 return UnobservablesSet::Unvisited(); |
| 347 } | 335 } |
| 348 | 336 |
| 349 bool RedundantStoreFinder::CannotObserveStoreField(Node* node) { | 337 bool RedundantStoreFinder::CannotObserveStoreField(Node* node) { |
| 350 Operator::Properties mask = | 338 return node->opcode() == IrOpcode::kCheckedLoad || |
| 351 Operator::kNoRead | Operator::kNoDeopt | Operator::kNoThrow; | |
| 352 | |
| 353 return (node->op()->properties() & mask) == mask || | |
| 354 node->opcode() == IrOpcode::kAllocate || | |
| 355 node->opcode() == IrOpcode::kCheckedLoad || | |
| 356 node->opcode() == IrOpcode::kLoadElement || | 339 node->opcode() == IrOpcode::kLoadElement || |
| 357 node->opcode() == IrOpcode::kLoad; | 340 node->opcode() == IrOpcode::kLoad || |
| 358 } | 341 node->opcode() == IrOpcode::kStore || |
| 359 | 342 node->opcode() == IrOpcode::kEffectPhi || |
| 360 bool RedundantStoreFinder::CanObserveAnything(Node* node) { | 343 node->opcode() == IrOpcode::kStoreElement || |
| 361 return !node->op()->HasProperty(Operator::kNoThrow) || | 344 node->opcode() == IrOpcode::kCheckedStore || |
| 362 !node->op()->HasProperty(Operator::kNoDeopt); | 345 node->opcode() == IrOpcode::kUnsafePointerAdd || |
| 346 node->opcode() == IrOpcode::kRetain; |
| 363 } | 347 } |
| 364 | 348 |
| 365 // Initialize unobservable_ with js_graph->graph->NodeCount() empty sets. | 349 // Initialize unobservable_ with js_graph->graph->NodeCount() empty sets. |
| 366 RedundantStoreFinder::RedundantStoreFinder(JSGraph* js_graph, Zone* temp_zone) | 350 RedundantStoreFinder::RedundantStoreFinder(JSGraph* js_graph, Zone* temp_zone) |
| 367 : jsgraph_(js_graph), | 351 : jsgraph_(js_graph), |
| 368 temp_zone_(temp_zone), | 352 temp_zone_(temp_zone), |
| 369 revisit_(temp_zone), | 353 revisit_(temp_zone), |
| 370 in_revisit_(js_graph->graph()->NodeCount(), temp_zone), | 354 in_revisit_(js_graph->graph()->NodeCount(), temp_zone), |
| 371 unobservable_(js_graph->graph()->NodeCount(), | 355 unobservable_(js_graph->graph()->NodeCount(), |
| 372 UnobservablesSet::Unvisited(), temp_zone), | 356 UnobservablesSet::Unvisited(), temp_zone), |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 414 if (!cur_set_changed) { | 398 if (!cur_set_changed) { |
| 415 // We will not be able to update the part of this chain above any more. | 399 // We will not be able to update the part of this chain above any more. |
| 416 // Exit. | 400 // Exit. |
| 417 TRACE("+ No change: stabilized. Not visiting effect inputs."); | 401 TRACE("+ No change: stabilized. Not visiting effect inputs."); |
| 418 } else { | 402 } else { |
| 419 unobservable_for_id(node->id()) = before_set; | 403 unobservable_for_id(node->id()) = before_set; |
| 420 | 404 |
| 421 // Mark effect inputs for visiting. | 405 // Mark effect inputs for visiting. |
| 422 for (int i = 0; i < node->op()->EffectInputCount(); i++) { | 406 for (int i = 0; i < node->op()->EffectInputCount(); i++) { |
| 423 Node* input = NodeProperties::GetEffectInput(node, i); | 407 Node* input = NodeProperties::GetEffectInput(node, i); |
| 424 if (!CanObserveAnything(input) || !HasBeenVisited(input)) { | 408 if (!HasBeenVisited(input)) { |
| 425 TRACE(" marking #%d:%s for revisit", input->id(), | 409 TRACE(" marking #%d:%s for revisit", input->id(), |
| 426 input->op()->mnemonic()); | 410 input->op()->mnemonic()); |
| 427 MarkForRevisit(input); | 411 MarkForRevisit(input); |
| 428 } | 412 } |
| 429 } | 413 } |
| 430 } | 414 } |
| 431 } | 415 } |
| 432 | 416 |
| 433 // Compute the intersection of the UnobservablesSets of all effect uses and | 417 // Compute the intersection of the UnobservablesSets of all effect uses and |
| 434 // return it. This function only works if {node} has an effect use. | 418 // return it. This function only works if {node} has an effect use. |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 577 return !(*this == other); | 561 return !(*this == other); |
| 578 } | 562 } |
| 579 | 563 |
| 580 bool UnobservableStore::operator<(const UnobservableStore other) const { | 564 bool UnobservableStore::operator<(const UnobservableStore other) const { |
| 581 return (id_ < other.id_) || (id_ == other.id_ && offset_ < other.offset_); | 565 return (id_ < other.id_) || (id_ == other.id_ && offset_ < other.offset_); |
| 582 } | 566 } |
| 583 | 567 |
| 584 } // namespace compiler | 568 } // namespace compiler |
| 585 } // namespace internal | 569 } // namespace internal |
| 586 } // namespace v8 | 570 } // namespace v8 |
| OLD | NEW |