| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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 "src/compiler/escape-analysis.h" | 5 #include "src/compiler/escape-analysis.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "src/base/flags.h" | 9 #include "src/base/flags.h" |
| 10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 } | 193 } |
| 194 bool AllFieldsClear() { | 194 bool AllFieldsClear() { |
| 195 for (size_t i = 0; i < fields_.size(); ++i) { | 195 for (size_t i = 0; i < fields_.size(); ++i) { |
| 196 if (fields_[i] != nullptr) { | 196 if (fields_[i] != nullptr) { |
| 197 return false; | 197 return false; |
| 198 } | 198 } |
| 199 } | 199 } |
| 200 return true; | 200 return true; |
| 201 } | 201 } |
| 202 bool UpdateFrom(const VirtualObject& other); | 202 bool UpdateFrom(const VirtualObject& other); |
| 203 bool MergeFrom(MergeCache* cache, Node* at, Graph* graph, | 203 bool MergeFrom(MergeCache* cache, Zone* zone, Node* at, Graph* graph, |
| 204 CommonOperatorBuilder* common); | 204 CommonOperatorBuilder* common); |
| 205 void SetObjectState(Node* node) { object_state_ = node; } | 205 void SetObjectState(Node* node) { object_state_ = node; } |
| 206 Node* GetObjectState() const { return object_state_; } | 206 Node* GetObjectState() const { return object_state_; } |
| 207 bool IsCopyRequired() const { return status_ & kCopyRequired; } | 207 bool IsCopyRequired() const { return status_ & kCopyRequired; } |
| 208 void SetCopyRequired() { status_ |= kCopyRequired; } | 208 void SetCopyRequired() { status_ |= kCopyRequired; } |
| 209 bool NeedCopyForModification() { | 209 bool NeedCopyForModification() { |
| 210 if (!IsCopyRequired() || !IsInitialized()) { | 210 if (!IsCopyRequired() || !IsInitialized()) { |
| 211 return false; | 211 return false; |
| 212 } | 212 } |
| 213 return true; | 213 return true; |
| 214 } | 214 } |
| 215 | 215 |
| 216 NodeId id() const { return id_; } | 216 NodeId id() const { return id_; } |
| 217 void id(NodeId id) { id_ = id; } | 217 void id(NodeId id) { id_ = id; } |
| 218 | 218 |
| 219 private: | 219 private: |
| 220 bool MergeFields(size_t i, Node* at, MergeCache* cache, Graph* graph, | 220 bool MergeFields(size_t i, Zone* zone, Node* at, MergeCache* cache, |
| 221 CommonOperatorBuilder* common); | 221 Graph* graph, CommonOperatorBuilder* common); |
| 222 | 222 |
| 223 NodeId id_; | 223 NodeId id_; |
| 224 StatusFlags status_; | 224 StatusFlags status_; |
| 225 ZoneVector<Node*> fields_; | 225 ZoneVector<Node*> fields_; |
| 226 ZoneVector<bool> phi_; | 226 ZoneVector<bool> phi_; |
| 227 Node* object_state_; | 227 Node* object_state_; |
| 228 VirtualState* owner_; | 228 VirtualState* owner_; |
| 229 | 229 |
| 230 DISALLOW_COPY_AND_ASSIGN(VirtualObject); | 230 DISALLOW_COPY_AND_ASSIGN(VirtualObject); |
| 231 }; | 231 }; |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 } | 425 } |
| 426 for (size_t i = 0; i < inputs.size(); ++i) { | 426 for (size_t i = 0; i < inputs.size(); ++i) { |
| 427 Node* input = NodeProperties::GetValueInput(phi, static_cast<int>(i)); | 427 Node* input = NodeProperties::GetValueInput(phi, static_cast<int>(i)); |
| 428 if (!IsEquivalentPhi(input, inputs[i])) { | 428 if (!IsEquivalentPhi(input, inputs[i])) { |
| 429 return false; | 429 return false; |
| 430 } | 430 } |
| 431 } | 431 } |
| 432 return true; | 432 return true; |
| 433 } | 433 } |
| 434 | 434 |
| 435 Type* GetTypeForPhi(Node* phi, Zone* zone) { |
| 436 int arity = phi->op()->ValueInputCount(); |
| 437 Type* type = Type::None(); |
| 438 for (int i = 1; i < arity; ++i) { |
| 439 Node* inner_node = NodeProperties::GetValueInput(phi, i); |
| 440 Type* inner_type = NodeProperties::IsTyped(inner_node) |
| 441 ? NodeProperties::GetType(inner_node) |
| 442 : Type::None(); |
| 443 type = Type::Union(type, inner_type, zone); |
| 444 } |
| 445 return type; |
| 446 } |
| 435 } // namespace | 447 } // namespace |
| 436 | 448 |
| 437 bool VirtualObject::MergeFields(size_t i, Node* at, MergeCache* cache, | 449 bool VirtualObject::MergeFields(size_t i, Zone* zone, Node* at, |
| 438 Graph* graph, CommonOperatorBuilder* common) { | 450 MergeCache* cache, Graph* graph, |
| 451 CommonOperatorBuilder* common) { |
| 439 bool changed = false; | 452 bool changed = false; |
| 440 int value_input_count = static_cast<int>(cache->fields().size()); | 453 int value_input_count = static_cast<int>(cache->fields().size()); |
| 441 Node* rep = GetField(i); | 454 Node* rep = GetField(i); |
| 442 if (!rep || !IsCreatedPhi(i)) { | 455 if (!rep || !IsCreatedPhi(i)) { |
| 443 Node* control = NodeProperties::GetControlInput(at); | 456 Node* control = NodeProperties::GetControlInput(at); |
| 444 cache->fields().push_back(control); | 457 cache->fields().push_back(control); |
| 445 Node* phi = graph->NewNode( | 458 Node* phi = graph->NewNode( |
| 446 common->Phi(MachineRepresentation::kTagged, value_input_count), | 459 common->Phi(MachineRepresentation::kTagged, value_input_count), |
| 447 value_input_count + 1, &cache->fields().front()); | 460 value_input_count + 1, &cache->fields().front()); |
| 448 SetField(i, phi, true); | 461 SetField(i, phi, true); |
| 462 NodeProperties::SetType(phi, GetTypeForPhi(phi, zone)); |
| 463 |
| 449 #ifdef DEBUG | 464 #ifdef DEBUG |
| 450 if (FLAG_trace_turbo_escape) { | 465 if (FLAG_trace_turbo_escape) { |
| 451 PrintF(" Creating Phi #%d as merge of", phi->id()); | 466 PrintF(" Creating Phi #%d as merge of", phi->id()); |
| 452 for (int i = 0; i < value_input_count; i++) { | 467 for (int i = 0; i < value_input_count; i++) { |
| 453 PrintF(" #%d (%s)", cache->fields()[i]->id(), | 468 PrintF(" #%d (%s)", cache->fields()[i]->id(), |
| 454 cache->fields()[i]->op()->mnemonic()); | 469 cache->fields()[i]->op()->mnemonic()); |
| 455 } | 470 } |
| 456 PrintF("\n"); | 471 PrintF("\n"); |
| 457 } | 472 } |
| 458 #endif | 473 #endif |
| 459 changed = true; | 474 changed = true; |
| 460 } else { | 475 } else { |
| 461 DCHECK(rep->opcode() == IrOpcode::kPhi); | 476 DCHECK(rep->opcode() == IrOpcode::kPhi); |
| 462 for (int n = 0; n < value_input_count; ++n) { | 477 for (int n = 0; n < value_input_count; ++n) { |
| 463 Node* old = NodeProperties::GetValueInput(rep, n); | 478 Node* old = NodeProperties::GetValueInput(rep, n); |
| 464 if (old != cache->fields()[n]) { | 479 if (old != cache->fields()[n]) { |
| 465 changed = true; | 480 changed = true; |
| 466 NodeProperties::ReplaceValueInput(rep, cache->fields()[n], n); | 481 NodeProperties::ReplaceValueInput(rep, cache->fields()[n], n); |
| 467 } | 482 } |
| 468 } | 483 } |
| 469 } | 484 } |
| 470 return changed; | 485 return changed; |
| 471 } | 486 } |
| 472 | 487 |
| 473 bool VirtualObject::MergeFrom(MergeCache* cache, Node* at, Graph* graph, | 488 bool VirtualObject::MergeFrom(MergeCache* cache, Zone* zone, Node* at, |
| 474 CommonOperatorBuilder* common) { | 489 Graph* graph, CommonOperatorBuilder* common) { |
| 475 DCHECK(at->opcode() == IrOpcode::kEffectPhi || | 490 DCHECK(at->opcode() == IrOpcode::kEffectPhi || |
| 476 at->opcode() == IrOpcode::kPhi); | 491 at->opcode() == IrOpcode::kPhi); |
| 477 bool changed = false; | 492 bool changed = false; |
| 478 for (size_t i = 0; i < field_count(); ++i) { | 493 for (size_t i = 0; i < field_count(); ++i) { |
| 479 Node* field = cache->GetFields(i); | 494 Node* field = cache->GetFields(i); |
| 480 if (field && !IsCreatedPhi(i)) { | 495 if (field && !IsCreatedPhi(i)) { |
| 481 changed = changed || GetField(i) != field; | 496 changed = changed || GetField(i) != field; |
| 482 SetField(i, field); | 497 SetField(i, field); |
| 483 TRACE(" Field %zu agree on rep #%d\n", i, field->id()); | 498 TRACE(" Field %zu agree on rep #%d\n", i, field->id()); |
| 484 } else { | 499 } else { |
| 485 size_t arity = at->opcode() == IrOpcode::kEffectPhi | 500 size_t arity = at->opcode() == IrOpcode::kEffectPhi |
| 486 ? at->op()->EffectInputCount() | 501 ? at->op()->EffectInputCount() |
| 487 : at->op()->ValueInputCount(); | 502 : at->op()->ValueInputCount(); |
| 488 if (cache->fields().size() == arity && | 503 if (cache->fields().size() == arity && |
| 489 (GetField(i) || !IsCreatedPhi(i))) { | 504 (GetField(i) || !IsCreatedPhi(i))) { |
| 490 changed = MergeFields(i, at, cache, graph, common) || changed; | 505 changed = MergeFields(i, zone, at, cache, graph, common) || changed; |
| 491 } else { | 506 } else { |
| 492 if (GetField(i) != nullptr) { | 507 if (GetField(i) != nullptr) { |
| 493 TRACE(" Field %zu cleared\n", i); | 508 TRACE(" Field %zu cleared\n", i); |
| 494 changed = true; | 509 changed = true; |
| 495 } | 510 } |
| 496 SetField(i, nullptr); | 511 SetField(i, nullptr); |
| 497 } | 512 } |
| 498 } | 513 } |
| 499 } | 514 } |
| 500 return changed; | 515 return changed; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 537 #ifdef DEBUG | 552 #ifdef DEBUG |
| 538 if (FLAG_trace_turbo_escape) { | 553 if (FLAG_trace_turbo_escape) { |
| 539 PrintF(" Alias @%d, merging into %p virtual objects", alias, | 554 PrintF(" Alias @%d, merging into %p virtual objects", alias, |
| 540 static_cast<void*>(mergeObject)); | 555 static_cast<void*>(mergeObject)); |
| 541 for (size_t i = 0; i < cache->objects().size(); i++) { | 556 for (size_t i = 0; i < cache->objects().size(); i++) { |
| 542 PrintF(" %p", static_cast<void*>(cache->objects()[i])); | 557 PrintF(" %p", static_cast<void*>(cache->objects()[i])); |
| 543 } | 558 } |
| 544 PrintF("\n"); | 559 PrintF("\n"); |
| 545 } | 560 } |
| 546 #endif // DEBUG | 561 #endif // DEBUG |
| 547 changed = mergeObject->MergeFrom(cache, at, graph, common) || changed; | 562 changed = |
| 563 mergeObject->MergeFrom(cache, zone, at, graph, common) || changed; |
| 548 } else { | 564 } else { |
| 549 if (mergeObject) { | 565 if (mergeObject) { |
| 550 TRACE(" Alias %d, virtual object removed\n", alias); | 566 TRACE(" Alias %d, virtual object removed\n", alias); |
| 551 changed = true; | 567 changed = true; |
| 552 } | 568 } |
| 553 SetVirtualObject(alias, nullptr); | 569 SetVirtualObject(alias, nullptr); |
| 554 } | 570 } |
| 555 } | 571 } |
| 556 return changed; | 572 return changed; |
| 557 } | 573 } |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 859 | 875 |
| 860 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, | 876 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, |
| 861 Zone* zone) | 877 Zone* zone) |
| 862 : zone_(zone), | 878 : zone_(zone), |
| 863 slot_not_analyzed_(graph->NewNode(common->NumberConstant(0x1c0debad))), | 879 slot_not_analyzed_(graph->NewNode(common->NumberConstant(0x1c0debad))), |
| 864 common_(common), | 880 common_(common), |
| 865 status_analysis_(new (zone) EscapeStatusAnalysis(this, graph, zone)), | 881 status_analysis_(new (zone) EscapeStatusAnalysis(this, graph, zone)), |
| 866 virtual_states_(zone), | 882 virtual_states_(zone), |
| 867 replacements_(zone), | 883 replacements_(zone), |
| 868 cycle_detection_(zone), | 884 cycle_detection_(zone), |
| 869 cache_(nullptr) {} | 885 cache_(nullptr) { |
| 886 // Type slot_not_analyzed_ manually. |
| 887 double v = OpParameter<double>(slot_not_analyzed_); |
| 888 NodeProperties::SetType(slot_not_analyzed_, Type::Range(v, v, zone)); |
| 889 } |
| 870 | 890 |
| 871 EscapeAnalysis::~EscapeAnalysis() {} | 891 EscapeAnalysis::~EscapeAnalysis() {} |
| 872 | 892 |
| 873 void EscapeAnalysis::Run() { | 893 void EscapeAnalysis::Run() { |
| 874 replacements_.resize(graph()->NodeCount()); | 894 replacements_.resize(graph()->NodeCount()); |
| 875 status_analysis_->AssignAliases(); | 895 status_analysis_->AssignAliases(); |
| 876 if (status_analysis_->AliasCount() > 0) { | 896 if (status_analysis_->AliasCount() > 0) { |
| 877 cache_ = new (zone()) MergeCache(zone()); | 897 cache_ = new (zone()) MergeCache(zone()); |
| 878 replacements_.resize(graph()->NodeCount()); | 898 replacements_.resize(graph()->NodeCount()); |
| 879 status_analysis_->ResizeStatusVector(); | 899 status_analysis_->ResizeStatusVector(); |
| (...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1396 if (cache_->objects().size() == cache_->fields().size()) { | 1416 if (cache_->objects().size() == cache_->fields().size()) { |
| 1397 cache_->GetFields(offset); | 1417 cache_->GetFields(offset); |
| 1398 if (cache_->fields().size() == cache_->objects().size()) { | 1418 if (cache_->fields().size() == cache_->objects().size()) { |
| 1399 Node* rep = replacement(load); | 1419 Node* rep = replacement(load); |
| 1400 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { | 1420 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { |
| 1401 int value_input_count = static_cast<int>(cache_->fields().size()); | 1421 int value_input_count = static_cast<int>(cache_->fields().size()); |
| 1402 cache_->fields().push_back(NodeProperties::GetControlInput(from)); | 1422 cache_->fields().push_back(NodeProperties::GetControlInput(from)); |
| 1403 Node* phi = graph()->NewNode( | 1423 Node* phi = graph()->NewNode( |
| 1404 common()->Phi(MachineRepresentation::kTagged, value_input_count), | 1424 common()->Phi(MachineRepresentation::kTagged, value_input_count), |
| 1405 value_input_count + 1, &cache_->fields().front()); | 1425 value_input_count + 1, &cache_->fields().front()); |
| 1426 NodeProperties::SetType(phi, GetTypeForPhi(phi, zone())); |
| 1406 status_analysis_->ResizeStatusVector(); | 1427 status_analysis_->ResizeStatusVector(); |
| 1407 SetReplacement(load, phi); | 1428 SetReplacement(load, phi); |
| 1408 TRACE(" got phi created.\n"); | 1429 TRACE(" got phi created.\n"); |
| 1409 } else { | 1430 } else { |
| 1410 TRACE(" has already phi #%d.\n", rep->id()); | 1431 TRACE(" has already phi #%d.\n", rep->id()); |
| 1411 } | 1432 } |
| 1412 } else { | 1433 } else { |
| 1413 TRACE(" has incomplete field info.\n"); | 1434 TRACE(" has incomplete field info.\n"); |
| 1414 } | 1435 } |
| 1415 } else { | 1436 } else { |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1589 cache_->fields().clear(); | 1610 cache_->fields().clear(); |
| 1590 for (size_t i = 0; i < vobj->field_count(); ++i) { | 1611 for (size_t i = 0; i < vobj->field_count(); ++i) { |
| 1591 if (Node* field = vobj->GetField(i)) { | 1612 if (Node* field = vobj->GetField(i)) { |
| 1592 cache_->fields().push_back(ResolveReplacement(field)); | 1613 cache_->fields().push_back(ResolveReplacement(field)); |
| 1593 } | 1614 } |
| 1594 } | 1615 } |
| 1595 int input_count = static_cast<int>(cache_->fields().size()); | 1616 int input_count = static_cast<int>(cache_->fields().size()); |
| 1596 Node* new_object_state = | 1617 Node* new_object_state = |
| 1597 graph()->NewNode(common()->ObjectState(input_count), input_count, | 1618 graph()->NewNode(common()->ObjectState(input_count), input_count, |
| 1598 &cache_->fields().front()); | 1619 &cache_->fields().front()); |
| 1620 NodeProperties::SetType(new_object_state, Type::Internal()); |
| 1599 vobj->SetObjectState(new_object_state); | 1621 vobj->SetObjectState(new_object_state); |
| 1600 TRACE( | 1622 TRACE( |
| 1601 "Creating object state #%d for vobj %p (from node #%d) at effect " | 1623 "Creating object state #%d for vobj %p (from node #%d) at effect " |
| 1602 "#%d\n", | 1624 "#%d\n", |
| 1603 new_object_state->id(), static_cast<void*>(vobj), node->id(), | 1625 new_object_state->id(), static_cast<void*>(vobj), node->id(), |
| 1604 effect->id()); | 1626 effect->id()); |
| 1605 // Now fix uses of other objects. | 1627 // Now fix uses of other objects. |
| 1606 for (size_t i = 0; i < vobj->field_count(); ++i) { | 1628 for (size_t i = 0; i < vobj->field_count(); ++i) { |
| 1607 if (Node* field = vobj->GetField(i)) { | 1629 if (Node* field = vobj->GetField(i)) { |
| 1608 if (Node* field_object_state = | 1630 if (Node* field_object_state = |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1688 } | 1710 } |
| 1689 } | 1711 } |
| 1690 return false; | 1712 return false; |
| 1691 } | 1713 } |
| 1692 | 1714 |
| 1693 Graph* EscapeAnalysis::graph() const { return status_analysis_->graph(); } | 1715 Graph* EscapeAnalysis::graph() const { return status_analysis_->graph(); } |
| 1694 | 1716 |
| 1695 } // namespace compiler | 1717 } // namespace compiler |
| 1696 } // namespace internal | 1718 } // namespace internal |
| 1697 } // namespace v8 | 1719 } // namespace v8 |
| OLD | NEW |