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 |