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 |