| 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 "src/base/flags.h" | 7 #include "src/base/flags.h" |
| 8 #include "src/bootstrapper.h" | 8 #include "src/bootstrapper.h" |
| 9 #include "src/compilation-dependencies.h" | 9 #include "src/compilation-dependencies.h" |
| 10 #include "src/compiler/common-operator.h" | 10 #include "src/compiler/common-operator.h" |
| 11 #include "src/compiler/graph-reducer.h" | 11 #include "src/compiler/graph-reducer.h" |
| 12 #include "src/compiler/js-operator.h" | 12 #include "src/compiler/js-operator.h" |
| 13 #include "src/compiler/node.h" | 13 #include "src/compiler/node.h" |
| 14 #include "src/compiler/node-matchers.h" | 14 #include "src/compiler/node-matchers.h" |
| 15 #include "src/compiler/node-properties.h" | 15 #include "src/compiler/node-properties.h" |
| 16 #include "src/compiler/simplified-operator.h" | 16 #include "src/compiler/simplified-operator.h" |
| 17 #include "src/objects-inl.h" | 17 #include "src/objects-inl.h" |
| 18 #include "src/type-cache.h" | 18 #include "src/type-cache.h" |
| 19 | 19 |
| 20 namespace v8 { | 20 namespace v8 { |
| 21 namespace internal { | 21 namespace internal { |
| 22 namespace compiler { | 22 namespace compiler { |
| 23 | 23 |
| 24 | |
| 25 // ------------------------------VirtualObject---------------------------------- | |
| 26 | |
| 27 | |
| 28 class VirtualObject : public ZoneObject { | 24 class VirtualObject : public ZoneObject { |
| 29 public: | 25 public: |
| 30 enum Status { kUntracked = 0, kTracked = 1 }; | 26 enum Status { kUntracked = 0, kTracked = 1 }; |
| 31 VirtualObject(NodeId id, Zone* zone) | 27 VirtualObject(NodeId id, Zone* zone) |
| 32 : id_(id), status_(kUntracked), fields_(zone), phi_(zone) {} | 28 : id_(id), |
| 29 status_(kUntracked), |
| 30 fields_(zone), |
| 31 phi_(zone), |
| 32 object_state_(nullptr) {} |
| 33 | 33 |
| 34 VirtualObject(const VirtualObject& other) | 34 VirtualObject(const VirtualObject& other) |
| 35 : id_(other.id_), | 35 : id_(other.id_), |
| 36 status_(other.status_), | 36 status_(other.status_), |
| 37 fields_(other.fields_), | 37 fields_(other.fields_), |
| 38 phi_(other.phi_) {} | 38 phi_(other.phi_), |
| 39 object_state_(other.object_state_) {} |
| 39 | 40 |
| 40 VirtualObject(NodeId id, Zone* zone, size_t field_number) | 41 VirtualObject(NodeId id, Zone* zone, size_t field_number) |
| 41 : id_(id), status_(kTracked), fields_(zone), phi_(zone) { | 42 : id_(id), |
| 43 status_(kTracked), |
| 44 fields_(zone), |
| 45 phi_(zone), |
| 46 object_state_(nullptr) { |
| 42 fields_.resize(field_number); | 47 fields_.resize(field_number); |
| 43 phi_.resize(field_number, false); | 48 phi_.resize(field_number, false); |
| 44 } | 49 } |
| 45 | 50 |
| 46 Node* GetField(size_t offset) { | 51 Node* GetField(size_t offset) { |
| 47 if (offset < fields_.size()) { | 52 if (offset < fields_.size()) { |
| 48 return fields_[offset]; | 53 return fields_[offset]; |
| 49 } | 54 } |
| 50 return nullptr; | 55 return nullptr; |
| 51 } | 56 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 85 for (size_t i = 0; i < fields_.size(); ++i) { | 90 for (size_t i = 0; i < fields_.size(); ++i) { |
| 86 if (fields_[i] != nullptr) { | 91 if (fields_[i] != nullptr) { |
| 87 fields_[i] = nullptr; | 92 fields_[i] = nullptr; |
| 88 changed = true; | 93 changed = true; |
| 89 } | 94 } |
| 90 phi_[i] = false; | 95 phi_[i] = false; |
| 91 } | 96 } |
| 92 return changed; | 97 return changed; |
| 93 } | 98 } |
| 94 bool UpdateFrom(const VirtualObject& other); | 99 bool UpdateFrom(const VirtualObject& other); |
| 100 void SetObjectState(Node* node) { object_state_ = node; } |
| 101 Node* GetObjectState() { return object_state_; } |
| 95 | 102 |
| 96 NodeId id() { return id_; } | 103 NodeId id() { return id_; } |
| 97 void id(NodeId id) { id_ = id; } | 104 void id(NodeId id) { id_ = id; } |
| 98 | 105 |
| 99 private: | 106 private: |
| 100 NodeId id_; | 107 NodeId id_; |
| 101 Status status_; | 108 Status status_; |
| 102 ZoneVector<Node*> fields_; | 109 ZoneVector<Node*> fields_; |
| 103 ZoneVector<bool> phi_; | 110 ZoneVector<bool> phi_; |
| 111 Node* object_state_; |
| 104 }; | 112 }; |
| 105 | 113 |
| 106 | 114 |
| 107 bool VirtualObject::UpdateFrom(const VirtualObject& other) { | 115 bool VirtualObject::UpdateFrom(const VirtualObject& other) { |
| 108 bool changed = status_ != other.status_; | 116 bool changed = status_ != other.status_; |
| 109 status_ = other.status_; | 117 status_ = other.status_; |
| 110 if (fields_.size() != other.fields_.size()) { | 118 if (fields_.size() != other.fields_.size()) { |
| 111 fields_ = other.fields_; | 119 fields_ = other.fields_; |
| 112 return true; | 120 return true; |
| 113 } | 121 } |
| 114 for (size_t i = 0; i < fields_.size(); ++i) { | 122 for (size_t i = 0; i < fields_.size(); ++i) { |
| 115 if (fields_[i] != other.fields_[i]) { | 123 if (fields_[i] != other.fields_[i]) { |
| 116 changed = true; | 124 changed = true; |
| 117 fields_[i] = other.fields_[i]; | 125 fields_[i] = other.fields_[i]; |
| 118 } | 126 } |
| 119 } | 127 } |
| 120 return changed; | 128 return changed; |
| 121 } | 129 } |
| 122 | 130 |
| 123 | 131 |
| 124 // ------------------------------VirtualState----------------------------------- | |
| 125 | |
| 126 | |
| 127 class VirtualState : public ZoneObject { | 132 class VirtualState : public ZoneObject { |
| 128 public: | 133 public: |
| 129 VirtualState(Zone* zone, size_t size); | 134 VirtualState(Zone* zone, size_t size); |
| 130 VirtualState(const VirtualState& states); | 135 VirtualState(const VirtualState& states); |
| 131 | 136 |
| 132 VirtualObject* GetVirtualObject(Node* node); | 137 VirtualObject* GetVirtualObject(Node* node); |
| 133 VirtualObject* GetVirtualObject(size_t id); | 138 VirtualObject* GetVirtualObject(size_t id); |
| 134 VirtualObject* GetOrCreateTrackedVirtualObject(NodeId id, Zone* zone); | 139 VirtualObject* GetOrCreateTrackedVirtualObject(NodeId id, Zone* zone); |
| 135 void SetVirtualObject(NodeId id, VirtualObject* state); | 140 void SetVirtualObject(NodeId id, VirtualObject* state); |
| 136 void LastChangedAt(Node* node) { last_changed_ = node; } | 141 void LastChangedAt(Node* node) { last_changed_ = node; } |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 } | 222 } |
| 218 if (field != rep) { | 223 if (field != rep) { |
| 219 rep = nullptr; | 224 rep = nullptr; |
| 220 } | 225 } |
| 221 } | 226 } |
| 222 return rep; | 227 return rep; |
| 223 } | 228 } |
| 224 | 229 |
| 225 | 230 |
| 226 VirtualState::VirtualState(Zone* zone, size_t size) | 231 VirtualState::VirtualState(Zone* zone, size_t size) |
| 227 : info_(zone), last_changed_(nullptr) { | 232 : info_(size, nullptr, zone), last_changed_(nullptr) {} |
| 228 info_.resize(size); | |
| 229 } | |
| 230 | 233 |
| 231 | 234 |
| 232 VirtualState::VirtualState(const VirtualState& state) | 235 VirtualState::VirtualState(const VirtualState& state) |
| 233 : info_(state.info_.get_allocator().zone()), | 236 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()), |
| 234 last_changed_(state.last_changed_) { | 237 last_changed_(state.last_changed_) { |
| 235 info_.resize(state.info_.size()); | |
| 236 for (size_t i = 0; i < state.info_.size(); ++i) { | 238 for (size_t i = 0; i < state.info_.size(); ++i) { |
| 237 if (state.info_[i] && state.info_[i]->id() == i) { | 239 if (state.info_[i] && state.info_[i]->id() == i) { |
| 238 info_[i] = new (state.info_.get_allocator().zone()) | 240 info_[i] = new (state.info_.get_allocator().zone()) |
| 239 VirtualObject(*state.info_[i]); | 241 VirtualObject(*state.info_[i]); |
| 240 } | 242 } |
| 241 } | 243 } |
| 242 for (size_t i = 0; i < state.info_.size(); ++i) { | 244 for (size_t i = 0; i < state.info_.size(); ++i) { |
| 243 if (state.info_[i] && state.info_[i]->id() != i) { | 245 if (state.info_[i] && state.info_[i]->id() != i) { |
| 244 info_[i] = info_[state.info_[i]->id()]; | 246 info_[i] = info_[state.info_[i]->id()]; |
| 245 } | 247 } |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 421 changed = true; | 423 changed = true; |
| 422 NodeProperties::ReplaceValueInput(rep, cache->fields()[n], | 424 NodeProperties::ReplaceValueInput(rep, cache->fields()[n], |
| 423 n); | 425 n); |
| 424 } | 426 } |
| 425 } else { | 427 } else { |
| 426 changed = true; | 428 changed = true; |
| 427 rep->InsertInput(graph->zone(), n, cache->fields()[n]); | 429 rep->InsertInput(graph->zone(), n, cache->fields()[n]); |
| 428 } | 430 } |
| 429 } | 431 } |
| 430 if (rep->op()->ValueInputCount() != value_input_count) { | 432 if (rep->op()->ValueInputCount() != value_input_count) { |
| 431 PrintF(" Widening Phi #%d of arity %d to %d", rep->id(), | 433 if (FLAG_trace_turbo_escape) { |
| 432 rep->op()->ValueInputCount(), value_input_count); | 434 PrintF(" Widening Phi #%d of arity %d to %d", rep->id(), |
| 435 rep->op()->ValueInputCount(), value_input_count); |
| 436 } |
| 433 NodeProperties::ChangeOp( | 437 NodeProperties::ChangeOp( |
| 434 rep, common->Phi(MachineRepresentation::kTagged, | 438 rep, common->Phi(MachineRepresentation::kTagged, |
| 435 value_input_count)); | 439 value_input_count)); |
| 436 } | 440 } |
| 437 } | 441 } |
| 438 } else { | 442 } else { |
| 439 changed = mergeObject->SetField(i, nullptr) || changed; | 443 changed = mergeObject->SetField(i, nullptr) || changed; |
| 440 } | 444 } |
| 441 } | 445 } |
| 442 } | 446 } |
| 443 | |
| 444 } else { | 447 } else { |
| 445 SetVirtualObject(id, nullptr); | 448 SetVirtualObject(id, nullptr); |
| 446 } | 449 } |
| 447 } | 450 } |
| 448 // Update linked objects. | 451 // Update linked objects. |
| 449 for (NodeId id = 0; id < cache->min_size(); ++id) { | 452 for (NodeId id = 0; id < cache->min_size(); ++id) { |
| 450 if (VirtualObject* obj = cache->states().front()->GetVirtualObject(id)) { | 453 if (VirtualObject* obj = cache->states().front()->GetVirtualObject(id)) { |
| 451 if (obj->id() != id) { | 454 if (obj->id() != id) { |
| 452 SetVirtualObject(id, GetVirtualObject(obj->id())); | 455 SetVirtualObject(id, GetVirtualObject(obj->id())); |
| 453 } | 456 } |
| 454 } | 457 } |
| 455 } | 458 } |
| 456 return changed; | 459 return changed; |
| 457 } | 460 } |
| 458 | 461 |
| 459 | 462 |
| 460 // ------------------------------EscapeStatusAnalysis--------------------------- | |
| 461 | |
| 462 | |
| 463 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, | 463 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, |
| 464 Graph* graph, Zone* zone) | 464 Graph* graph, Zone* zone) |
| 465 : object_analysis_(object_analysis), | 465 : object_analysis_(object_analysis), |
| 466 graph_(graph), | 466 graph_(graph), |
| 467 zone_(zone), | 467 zone_(zone), |
| 468 info_(graph->NodeCount(), kUnknown, zone), | 468 info_(graph->NodeCount(), kUnknown, zone), |
| 469 queue_(zone) {} | 469 queue_(zone) {} |
| 470 | 470 |
| 471 | 471 |
| 472 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} | 472 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 564 if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) { | 564 if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) { |
| 565 RevisitInputs(rep); | 565 RevisitInputs(rep); |
| 566 RevisitUses(rep); | 566 RevisitUses(rep); |
| 567 } | 567 } |
| 568 } | 568 } |
| 569 break; | 569 break; |
| 570 } | 570 } |
| 571 case IrOpcode::kPhi: | 571 case IrOpcode::kPhi: |
| 572 if (!HasEntry(node)) { | 572 if (!HasEntry(node)) { |
| 573 info_[node->id()] = kVirtual; | 573 info_[node->id()] = kVirtual; |
| 574 if (!IsAllocationPhi(node)) { |
| 575 SetEscaped(node); |
| 576 RevisitUses(node); |
| 577 } |
| 574 } | 578 } |
| 575 CheckUsesForEscape(node); | 579 CheckUsesForEscape(node); |
| 576 default: | 580 default: |
| 577 break; | 581 break; |
| 578 } | 582 } |
| 579 } | 583 } |
| 580 | 584 |
| 581 | 585 |
| 586 bool EscapeStatusAnalysis::IsAllocationPhi(Node* node) { |
| 587 for (Edge edge : node->input_edges()) { |
| 588 Node* input = edge.to(); |
| 589 if (input->opcode() == IrOpcode::kPhi && !IsEscaped(input)) continue; |
| 590 if (IsAllocation(input)) continue; |
| 591 return false; |
| 592 } |
| 593 return true; |
| 594 } |
| 595 |
| 596 |
| 582 void EscapeStatusAnalysis::ProcessStoreField(Node* node) { | 597 void EscapeStatusAnalysis::ProcessStoreField(Node* node) { |
| 583 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); | 598 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); |
| 584 Node* to = NodeProperties::GetValueInput(node, 0); | 599 Node* to = NodeProperties::GetValueInput(node, 0); |
| 585 Node* val = NodeProperties::GetValueInput(node, 1); | 600 Node* val = NodeProperties::GetValueInput(node, 1); |
| 586 if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) { | 601 if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) { |
| 587 RevisitUses(val); | 602 RevisitUses(val); |
| 588 RevisitInputs(val); | 603 RevisitInputs(val); |
| 589 if (FLAG_trace_turbo_escape) { | 604 if (FLAG_trace_turbo_escape) { |
| 590 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n", | 605 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n", |
| 591 val->id(), val->op()->mnemonic(), to->id()); | 606 val->id(), val->op()->mnemonic(), to->id()); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 611 | 626 |
| 612 void EscapeStatusAnalysis::ProcessAllocate(Node* node) { | 627 void EscapeStatusAnalysis::ProcessAllocate(Node* node) { |
| 613 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 628 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
| 614 if (!HasEntry(node)) { | 629 if (!HasEntry(node)) { |
| 615 info_[node->id()] = kVirtual; | 630 info_[node->id()] = kVirtual; |
| 616 if (FLAG_trace_turbo_escape) { | 631 if (FLAG_trace_turbo_escape) { |
| 617 PrintF("Created status entry for node #%d (%s)\n", node->id(), | 632 PrintF("Created status entry for node #%d (%s)\n", node->id(), |
| 618 node->op()->mnemonic()); | 633 node->op()->mnemonic()); |
| 619 } | 634 } |
| 620 NumberMatcher size(node->InputAt(0)); | 635 NumberMatcher size(node->InputAt(0)); |
| 636 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && |
| 637 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && |
| 638 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && |
| 639 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); |
| 621 if (!size.HasValue() && SetEscaped(node)) { | 640 if (!size.HasValue() && SetEscaped(node)) { |
| 622 RevisitUses(node); | 641 RevisitUses(node); |
| 623 if (FLAG_trace_turbo_escape) { | 642 if (FLAG_trace_turbo_escape) { |
| 624 PrintF("Setting #%d to escaped because of non-const alloc\n", | 643 PrintF("Setting #%d to escaped because of non-const alloc\n", |
| 625 node->id()); | 644 node->id()); |
| 626 } | 645 } |
| 627 // This node is known to escape, uses do not have to be checked. | 646 // This node is known to escape, uses do not have to be checked. |
| 628 return; | 647 return; |
| 629 } | 648 } |
| 630 } | 649 } |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 717 void EscapeStatusAnalysis::DebugPrint() { | 736 void EscapeStatusAnalysis::DebugPrint() { |
| 718 for (NodeId id = 0; id < info_.size(); id++) { | 737 for (NodeId id = 0; id < info_.size(); id++) { |
| 719 if (info_[id] != kUnknown) { | 738 if (info_[id] != kUnknown) { |
| 720 PrintF("Node #%d is %s\n", id, | 739 PrintF("Node #%d is %s\n", id, |
| 721 info_[id] == kEscaped ? "escaping" : "virtual"); | 740 info_[id] == kEscaped ? "escaping" : "virtual"); |
| 722 } | 741 } |
| 723 } | 742 } |
| 724 } | 743 } |
| 725 | 744 |
| 726 | 745 |
| 727 // -----------------------------EscapeAnalysis---------------------------------- | |
| 728 | |
| 729 | |
| 730 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, | 746 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, |
| 731 Zone* zone) | 747 Zone* zone) |
| 732 : graph_(graph), | 748 : graph_(graph), |
| 733 common_(common), | 749 common_(common), |
| 734 zone_(zone), | 750 zone_(zone), |
| 735 virtual_states_(zone), | 751 virtual_states_(zone), |
| 736 replacements_(zone), | 752 replacements_(zone), |
| 737 escape_status_(this, graph, zone), | 753 escape_status_(this, graph, zone), |
| 738 cache_(new (zone) MergeCache(zone)) {} | 754 cache_(new (zone) MergeCache(zone)) {} |
| 739 | 755 |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 998 | 1014 |
| 999 | 1015 |
| 1000 void EscapeAnalysis::ProcessAllocation(Node* node) { | 1016 void EscapeAnalysis::ProcessAllocation(Node* node) { |
| 1001 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 1017 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
| 1002 ForwardVirtualState(node); | 1018 ForwardVirtualState(node); |
| 1003 | 1019 |
| 1004 // Check if we have already processed this node. | 1020 // Check if we have already processed this node. |
| 1005 if (virtual_states_[node->id()]->GetVirtualObject(node)) return; | 1021 if (virtual_states_[node->id()]->GetVirtualObject(node)) return; |
| 1006 | 1022 |
| 1007 NumberMatcher size(node->InputAt(0)); | 1023 NumberMatcher size(node->InputAt(0)); |
| 1024 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && |
| 1025 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && |
| 1026 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && |
| 1027 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); |
| 1008 if (size.HasValue()) { | 1028 if (size.HasValue()) { |
| 1009 virtual_states_[node->id()]->SetVirtualObject( | 1029 virtual_states_[node->id()]->SetVirtualObject( |
| 1010 node->id(), new (zone()) VirtualObject(node->id(), zone(), | 1030 node->id(), new (zone()) VirtualObject(node->id(), zone(), |
| 1011 size.Value() / kPointerSize)); | 1031 size.Value() / kPointerSize)); |
| 1012 } else { | 1032 } else { |
| 1013 virtual_states_[node->id()]->SetVirtualObject( | 1033 virtual_states_[node->id()]->SetVirtualObject( |
| 1014 node->id(), new (zone()) VirtualObject(node->id(), zone())); | 1034 node->id(), new (zone()) VirtualObject(node->id(), zone())); |
| 1015 } | 1035 } |
| 1016 virtual_states_[node->id()]->LastChangedAt(node); | 1036 virtual_states_[node->id()]->LastChangedAt(node); |
| 1017 } | 1037 } |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1129 Node* node) { | 1149 Node* node) { |
| 1130 VirtualObject* obj = state->GetVirtualObject(ResolveReplacement(node)); | 1150 VirtualObject* obj = state->GetVirtualObject(ResolveReplacement(node)); |
| 1131 while (obj && replacement(obj->id()) && | 1151 while (obj && replacement(obj->id()) && |
| 1132 state->GetVirtualObject(replacement(obj->id()))) { | 1152 state->GetVirtualObject(replacement(obj->id()))) { |
| 1133 obj = state->GetVirtualObject(replacement(obj->id())); | 1153 obj = state->GetVirtualObject(replacement(obj->id())); |
| 1134 } | 1154 } |
| 1135 return obj; | 1155 return obj; |
| 1136 } | 1156 } |
| 1137 | 1157 |
| 1138 | 1158 |
| 1159 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { |
| 1160 DCHECK(IsVirtual(left) && IsVirtual(right)); |
| 1161 left = ResolveReplacement(left); |
| 1162 right = ResolveReplacement(right); |
| 1163 if (IsEquivalentPhi(left, right)) { |
| 1164 return true; |
| 1165 } |
| 1166 return false; |
| 1167 } |
| 1168 |
| 1169 |
| 1139 int EscapeAnalysis::OffsetFromAccess(Node* node) { | 1170 int EscapeAnalysis::OffsetFromAccess(Node* node) { |
| 1140 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); | 1171 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); |
| 1141 return OpParameter<FieldAccess>(node).offset / kPointerSize; | 1172 return OpParameter<FieldAccess>(node).offset / kPointerSize; |
| 1142 } | 1173 } |
| 1143 | 1174 |
| 1144 | 1175 |
| 1145 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, | 1176 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, |
| 1146 VirtualState* state) { | 1177 VirtualState* state) { |
| 1147 if (FLAG_trace_turbo_escape) { | 1178 if (FLAG_trace_turbo_escape) { |
| 1148 PrintF("Load #%d from phi #%d", node->id(), from->id()); | 1179 PrintF("Load #%d from phi #%d", node->id(), from->id()); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1208 } | 1239 } |
| 1209 | 1240 |
| 1210 | 1241 |
| 1211 void EscapeAnalysis::ProcessLoadElement(Node* node) { | 1242 void EscapeAnalysis::ProcessLoadElement(Node* node) { |
| 1212 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); | 1243 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); |
| 1213 ForwardVirtualState(node); | 1244 ForwardVirtualState(node); |
| 1214 Node* from = NodeProperties::GetValueInput(node, 0); | 1245 Node* from = NodeProperties::GetValueInput(node, 0); |
| 1215 VirtualState* state = virtual_states_[node->id()]; | 1246 VirtualState* state = virtual_states_[node->id()]; |
| 1216 Node* index_node = node->InputAt(1); | 1247 Node* index_node = node->InputAt(1); |
| 1217 NumberMatcher index(index_node); | 1248 NumberMatcher index(index_node); |
| 1249 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && |
| 1250 index_node->opcode() != IrOpcode::kInt64Constant && |
| 1251 index_node->opcode() != IrOpcode::kFloat32Constant && |
| 1252 index_node->opcode() != IrOpcode::kFloat64Constant); |
| 1218 ElementAccess access = OpParameter<ElementAccess>(node); | 1253 ElementAccess access = OpParameter<ElementAccess>(node); |
| 1219 if (index.HasValue()) { | 1254 if (index.HasValue()) { |
| 1220 int offset = index.Value() + access.header_size / kPointerSize; | 1255 int offset = index.Value() + access.header_size / kPointerSize; |
| 1221 if (VirtualObject* object = ResolveVirtualObject(state, from)) { | 1256 if (VirtualObject* object = ResolveVirtualObject(state, from)) { |
| 1222 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), | 1257 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), |
| 1223 kPointerSizeLog2); | 1258 kPointerSizeLog2); |
| 1224 CHECK_EQ(access.header_size % kPointerSize, 0); | 1259 CHECK_EQ(access.header_size % kPointerSize, 0); |
| 1225 | 1260 |
| 1226 if (!object->IsTracked()) return; | 1261 if (!object->IsTracked()) return; |
| 1227 Node* value = object->GetField(offset); | 1262 Node* value = object->GetField(offset); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1266 } | 1301 } |
| 1267 } | 1302 } |
| 1268 | 1303 |
| 1269 | 1304 |
| 1270 void EscapeAnalysis::ProcessStoreElement(Node* node) { | 1305 void EscapeAnalysis::ProcessStoreElement(Node* node) { |
| 1271 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); | 1306 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); |
| 1272 ForwardVirtualState(node); | 1307 ForwardVirtualState(node); |
| 1273 Node* to = NodeProperties::GetValueInput(node, 0); | 1308 Node* to = NodeProperties::GetValueInput(node, 0); |
| 1274 Node* index_node = node->InputAt(1); | 1309 Node* index_node = node->InputAt(1); |
| 1275 NumberMatcher index(index_node); | 1310 NumberMatcher index(index_node); |
| 1311 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && |
| 1312 index_node->opcode() != IrOpcode::kInt64Constant && |
| 1313 index_node->opcode() != IrOpcode::kFloat32Constant && |
| 1314 index_node->opcode() != IrOpcode::kFloat64Constant); |
| 1276 ElementAccess access = OpParameter<ElementAccess>(node); | 1315 ElementAccess access = OpParameter<ElementAccess>(node); |
| 1277 Node* val = NodeProperties::GetValueInput(node, 2); | 1316 Node* val = NodeProperties::GetValueInput(node, 2); |
| 1278 if (index.HasValue()) { | 1317 if (index.HasValue()) { |
| 1279 int offset = index.Value() + access.header_size / kPointerSize; | 1318 int offset = index.Value() + access.header_size / kPointerSize; |
| 1280 VirtualState* states = virtual_states_[node->id()]; | 1319 VirtualState* states = virtual_states_[node->id()]; |
| 1281 if (VirtualObject* obj = ResolveVirtualObject(states, to)) { | 1320 if (VirtualObject* obj = ResolveVirtualObject(states, to)) { |
| 1282 if (!obj->IsTracked()) return; | 1321 if (!obj->IsTracked()) return; |
| 1283 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), | 1322 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), |
| 1284 kPointerSizeLog2); | 1323 kPointerSizeLog2); |
| 1285 CHECK_EQ(access.header_size % kPointerSize, 0); | 1324 CHECK_EQ(access.header_size % kPointerSize, 0); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1296 "non-const " | 1335 "non-const " |
| 1297 "index #%d (%s)\n", | 1336 "index #%d (%s)\n", |
| 1298 to->id(), to->op()->mnemonic(), node->id(), index_node->id(), | 1337 to->id(), to->op()->mnemonic(), node->id(), index_node->id(), |
| 1299 index_node->op()->mnemonic()); | 1338 index_node->op()->mnemonic()); |
| 1300 } | 1339 } |
| 1301 } | 1340 } |
| 1302 } | 1341 } |
| 1303 } | 1342 } |
| 1304 | 1343 |
| 1305 | 1344 |
| 1345 Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { |
| 1346 if ((node->opcode() == IrOpcode::kFinishRegion || |
| 1347 node->opcode() == IrOpcode::kAllocate) && |
| 1348 IsVirtual(node)) { |
| 1349 if (VirtualObject* vobj = |
| 1350 ResolveVirtualObject(virtual_states_[effect->id()], node)) { |
| 1351 if (Node* object_state = vobj->GetObjectState()) { |
| 1352 return object_state; |
| 1353 } else { |
| 1354 cache_->fields().clear(); |
| 1355 for (size_t i = 0; i < vobj->field_count(); ++i) { |
| 1356 if (Node* field = vobj->GetField(i)) { |
| 1357 cache_->fields().push_back(field); |
| 1358 } |
| 1359 } |
| 1360 int input_count = static_cast<int>(cache_->fields().size()); |
| 1361 Node* new_object_state = |
| 1362 graph()->NewNode(common()->ObjectState(input_count, vobj->id()), |
| 1363 input_count, &cache_->fields().front()); |
| 1364 vobj->SetObjectState(new_object_state); |
| 1365 if (FLAG_trace_turbo_escape) { |
| 1366 PrintF( |
| 1367 "Creating object state #%d for vobj %p (from node #%d) at effect " |
| 1368 "#%d\n", |
| 1369 new_object_state->id(), static_cast<void*>(vobj), node->id(), |
| 1370 effect->id()); |
| 1371 } |
| 1372 // Now fix uses of other objects. |
| 1373 for (size_t i = 0; i < vobj->field_count(); ++i) { |
| 1374 if (Node* field = vobj->GetField(i)) { |
| 1375 if (Node* field_object_state = |
| 1376 GetOrCreateObjectState(effect, field)) { |
| 1377 NodeProperties::ReplaceValueInput( |
| 1378 new_object_state, field_object_state, static_cast<int>(i)); |
| 1379 } |
| 1380 } |
| 1381 } |
| 1382 return new_object_state; |
| 1383 } |
| 1384 } |
| 1385 } |
| 1386 return nullptr; |
| 1387 } |
| 1388 |
| 1389 |
| 1306 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, NodeId id) { | 1390 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, NodeId id) { |
| 1307 PrintF(" Object #%d with %zu fields\n", id, object->field_count()); | 1391 PrintF(" Object #%d with %zu fields\n", id, object->field_count()); |
| 1308 for (size_t i = 0; i < object->field_count(); ++i) { | 1392 for (size_t i = 0; i < object->field_count(); ++i) { |
| 1309 if (Node* f = object->GetField(i)) { | 1393 if (Node* f = object->GetField(i)) { |
| 1310 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); | 1394 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); |
| 1311 } | 1395 } |
| 1312 } | 1396 } |
| 1313 } | 1397 } |
| 1314 | 1398 |
| 1315 | 1399 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1338 } | 1422 } |
| 1339 } | 1423 } |
| 1340 for (size_t n = 0; n < object_states.size(); n++) { | 1424 for (size_t n = 0; n < object_states.size(); n++) { |
| 1341 DebugPrintState(object_states[n]); | 1425 DebugPrintState(object_states[n]); |
| 1342 } | 1426 } |
| 1343 } | 1427 } |
| 1344 | 1428 |
| 1345 } // namespace compiler | 1429 } // namespace compiler |
| 1346 } // namespace internal | 1430 } // namespace internal |
| 1347 } // namespace v8 | 1431 } // namespace v8 |
| OLD | NEW |