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" |
(...skipping 11 matching lines...) Expand all Loading... |
22 namespace compiler { | 22 namespace compiler { |
23 | 23 |
24 | 24 |
25 // ------------------------------VirtualObject---------------------------------- | 25 // ------------------------------VirtualObject---------------------------------- |
26 | 26 |
27 | 27 |
28 class VirtualObject : public ZoneObject { | 28 class VirtualObject : public ZoneObject { |
29 public: | 29 public: |
30 enum Status { kUntracked = 0, kTracked = 1 }; | 30 enum Status { kUntracked = 0, kTracked = 1 }; |
31 VirtualObject(NodeId id, Zone* zone) | 31 VirtualObject(NodeId id, Zone* zone) |
32 : id_(id), | 32 : id_(id), status_(kUntracked), fields_(zone), phi_(zone) {} |
33 status_(kUntracked), | |
34 fields_(zone), | |
35 phi_(zone), | |
36 replacement_(nullptr) {} | |
37 | 33 |
38 VirtualObject(const VirtualObject& other) | 34 VirtualObject(const VirtualObject& other) |
39 : id_(other.id_), | 35 : id_(other.id_), |
40 status_(other.status_), | 36 status_(other.status_), |
41 fields_(other.fields_), | 37 fields_(other.fields_), |
42 phi_(other.phi_), | 38 phi_(other.phi_) {} |
43 replacement_(other.replacement_) {} | |
44 | 39 |
45 VirtualObject(NodeId id, Zone* zone, size_t field_number) | 40 VirtualObject(NodeId id, Zone* zone, size_t field_number) |
46 : id_(id), | 41 : id_(id), status_(kTracked), fields_(zone), phi_(zone) { |
47 status_(kTracked), | |
48 fields_(zone), | |
49 phi_(zone), | |
50 replacement_(nullptr) { | |
51 fields_.resize(field_number); | 42 fields_.resize(field_number); |
52 phi_.resize(field_number, false); | 43 phi_.resize(field_number, false); |
53 } | 44 } |
54 | 45 |
55 Node* GetField(size_t offset) { | 46 Node* GetField(size_t offset) { |
56 if (offset < fields_.size()) { | 47 if (offset < fields_.size()) { |
57 return fields_[offset]; | 48 return fields_[offset]; |
58 } | 49 } |
59 return nullptr; | 50 return nullptr; |
60 } | 51 } |
(...skipping 10 matching lines...) Expand all Loading... |
71 fields_[offset] = node; | 62 fields_[offset] = node; |
72 phi_[offset] = created_phi; | 63 phi_[offset] = created_phi; |
73 if (changed && FLAG_trace_turbo_escape && node) { | 64 if (changed && FLAG_trace_turbo_escape && node) { |
74 PrintF("Setting field %zu of #%d to #%d (%s)\n", offset, id(), node->id(), | 65 PrintF("Setting field %zu of #%d to #%d (%s)\n", offset, id(), node->id(), |
75 node->op()->mnemonic()); | 66 node->op()->mnemonic()); |
76 } | 67 } |
77 return changed; | 68 return changed; |
78 } | 69 } |
79 bool IsVirtual() const { return status_ == kTracked; } | 70 bool IsVirtual() const { return status_ == kTracked; } |
80 bool IsTracked() const { return status_ != kUntracked; } | 71 bool IsTracked() const { return status_ != kUntracked; } |
81 Node* GetReplacement() { return replacement_; } | |
82 bool SetReplacement(Node* node) { | |
83 bool changed = replacement_ != node; | |
84 replacement_ = node; | |
85 return changed; | |
86 } | |
87 | 72 |
88 Node** fields_array() { return &fields_.front(); } | 73 Node** fields_array() { return &fields_.front(); } |
89 size_t field_count() { return fields_.size(); } | 74 size_t field_count() { return fields_.size(); } |
90 bool ResizeFields(size_t field_count) { | 75 bool ResizeFields(size_t field_count) { |
91 if (field_count != fields_.size()) { | 76 if (field_count != fields_.size()) { |
92 fields_.resize(field_count); | 77 fields_.resize(field_count); |
93 phi_.resize(field_count); | 78 phi_.resize(field_count); |
94 return true; | 79 return true; |
95 } | 80 } |
96 return false; | 81 return false; |
(...skipping 12 matching lines...) Expand all Loading... |
109 bool UpdateFrom(const VirtualObject& other); | 94 bool UpdateFrom(const VirtualObject& other); |
110 | 95 |
111 NodeId id() { return id_; } | 96 NodeId id() { return id_; } |
112 void id(NodeId id) { id_ = id; } | 97 void id(NodeId id) { id_ = id; } |
113 | 98 |
114 private: | 99 private: |
115 NodeId id_; | 100 NodeId id_; |
116 Status status_; | 101 Status status_; |
117 ZoneVector<Node*> fields_; | 102 ZoneVector<Node*> fields_; |
118 ZoneVector<bool> phi_; | 103 ZoneVector<bool> phi_; |
119 Node* replacement_; | |
120 }; | 104 }; |
121 | 105 |
122 | 106 |
123 bool VirtualObject::UpdateFrom(const VirtualObject& other) { | 107 bool VirtualObject::UpdateFrom(const VirtualObject& other) { |
124 bool changed = status_ != other.status_; | 108 bool changed = status_ != other.status_; |
125 status_ = other.status_; | 109 status_ = other.status_; |
126 changed = replacement_ != other.replacement_ || changed; | |
127 replacement_ = other.replacement_; | |
128 if (fields_.size() != other.fields_.size()) { | 110 if (fields_.size() != other.fields_.size()) { |
129 fields_ = other.fields_; | 111 fields_ = other.fields_; |
130 return true; | 112 return true; |
131 } | 113 } |
132 for (size_t i = 0; i < fields_.size(); ++i) { | 114 for (size_t i = 0; i < fields_.size(); ++i) { |
133 if (fields_[i] != other.fields_[i]) { | 115 if (fields_[i] != other.fields_[i]) { |
134 changed = true; | 116 changed = true; |
135 fields_[i] = other.fields_[i]; | 117 fields_[i] = other.fields_[i]; |
136 } | 118 } |
137 } | 119 } |
138 return changed; | 120 return changed; |
139 } | 121 } |
140 | 122 |
141 | 123 |
142 // ------------------------------VirtualState----------------------------------- | 124 // ------------------------------VirtualState----------------------------------- |
143 | 125 |
144 | 126 |
145 class VirtualState : public ZoneObject { | 127 class VirtualState : public ZoneObject { |
146 public: | 128 public: |
147 VirtualState(Zone* zone, size_t size); | 129 VirtualState(Zone* zone, size_t size); |
148 VirtualState(const VirtualState& states); | 130 VirtualState(const VirtualState& states); |
149 | 131 |
150 VirtualObject* ResolveVirtualObject(Node* node); | |
151 VirtualObject* GetVirtualObject(Node* node); | 132 VirtualObject* GetVirtualObject(Node* node); |
152 VirtualObject* GetVirtualObject(size_t id); | 133 VirtualObject* GetVirtualObject(size_t id); |
153 VirtualObject* GetOrCreateTrackedVirtualObject(NodeId id, Zone* zone); | 134 VirtualObject* GetOrCreateTrackedVirtualObject(NodeId id, Zone* zone); |
154 void SetVirtualObject(NodeId id, VirtualObject* state); | 135 void SetVirtualObject(NodeId id, VirtualObject* state); |
155 void LastChangedAt(Node* node) { last_changed_ = node; } | 136 void LastChangedAt(Node* node) { last_changed_ = node; } |
156 Node* GetLastChanged() { return last_changed_; } | 137 Node* GetLastChanged() { return last_changed_; } |
157 bool UpdateFrom(NodeId id, VirtualObject* state, Zone* zone); | 138 bool UpdateFrom(NodeId id, VirtualObject* state, Zone* zone); |
158 Node* ResolveReplacement(Node* node); | |
159 bool UpdateReplacement(Node* node, Node* rep, Zone* zone); | |
160 bool UpdateFrom(VirtualState* state, Zone* zone); | 139 bool UpdateFrom(VirtualState* state, Zone* zone); |
161 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 140 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
162 CommonOperatorBuilder* common, Node* control); | 141 CommonOperatorBuilder* common, Node* control); |
163 | 142 |
164 size_t size() { return info_.size(); } | 143 size_t size() { return info_.size(); } |
165 | 144 |
166 private: | 145 private: |
167 ZoneVector<VirtualObject*> info_; | 146 ZoneVector<VirtualObject*> info_; |
168 Node* last_changed_; | 147 Node* last_changed_; |
169 }; | 148 }; |
(...skipping 27 matching lines...) Expand all Loading... |
197 if (id >= info_.size()) return nullptr; | 176 if (id >= info_.size()) return nullptr; |
198 return info_[id]; | 177 return info_[id]; |
199 } | 178 } |
200 | 179 |
201 | 180 |
202 VirtualObject* VirtualState::GetVirtualObject(Node* node) { | 181 VirtualObject* VirtualState::GetVirtualObject(Node* node) { |
203 return GetVirtualObject(node->id()); | 182 return GetVirtualObject(node->id()); |
204 } | 183 } |
205 | 184 |
206 | 185 |
207 VirtualObject* VirtualState::ResolveVirtualObject(Node* node) { | |
208 VirtualObject* obj = GetVirtualObject(node->id()); | |
209 while (obj && !obj->IsTracked() && obj->GetReplacement() && | |
210 GetVirtualObject(obj->GetReplacement())) { | |
211 obj = GetVirtualObject(obj->GetReplacement()); | |
212 } | |
213 return obj; | |
214 } | |
215 | |
216 | |
217 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject(NodeId id, | 186 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject(NodeId id, |
218 Zone* zone) { | 187 Zone* zone) { |
219 if (VirtualObject* obj = GetVirtualObject(id)) { | 188 if (VirtualObject* obj = GetVirtualObject(id)) { |
220 return obj; | 189 return obj; |
221 } | 190 } |
222 VirtualObject* obj = new (zone) VirtualObject(id, zone, 0); | 191 VirtualObject* obj = new (zone) VirtualObject(id, zone, 0); |
223 SetVirtualObject(id, obj); | 192 SetVirtualObject(id, obj); |
224 return obj; | 193 return obj; |
225 } | 194 } |
226 | 195 |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 Node* rep = objs.front()->GetField(pos); | 296 Node* rep = objs.front()->GetField(pos); |
328 for (VirtualObject* obj : objs) { | 297 for (VirtualObject* obj : objs) { |
329 if (obj->GetField(pos) != rep) { | 298 if (obj->GetField(pos) != rep) { |
330 return nullptr; | 299 return nullptr; |
331 } | 300 } |
332 } | 301 } |
333 return rep; | 302 return rep; |
334 } | 303 } |
335 | 304 |
336 | 305 |
337 Node* GetReplacementIfSame(ZoneVector<VirtualObject*>& objs) { | |
338 Node* rep = objs.front()->GetReplacement(); | |
339 for (VirtualObject* obj : objs) { | |
340 if (obj->GetReplacement() != rep) { | |
341 return nullptr; | |
342 } | |
343 } | |
344 return rep; | |
345 } | |
346 | |
347 | |
348 void GetFields(ZoneVector<VirtualObject*>& objs, ZoneVector<Node*>& fields, | 306 void GetFields(ZoneVector<VirtualObject*>& objs, ZoneVector<Node*>& fields, |
349 size_t pos) { | 307 size_t pos) { |
350 fields.clear(); | 308 fields.clear(); |
351 for (VirtualObject* obj : objs) { | 309 for (VirtualObject* obj : objs) { |
352 if (Node* field = obj->GetField(pos)) { | 310 if (Node* field = obj->GetField(pos)) { |
353 fields.push_back(field); | 311 fields.push_back(field); |
354 } | 312 } |
355 } | 313 } |
356 } | 314 } |
357 | 315 |
(...skipping 25 matching lines...) Expand all Loading... |
383 if (!IsEquivalentPhi(input, inputs[i])) { | 341 if (!IsEquivalentPhi(input, inputs[i])) { |
384 return false; | 342 return false; |
385 } | 343 } |
386 } | 344 } |
387 return true; | 345 return true; |
388 } | 346 } |
389 | 347 |
390 } // namespace | 348 } // namespace |
391 | 349 |
392 | 350 |
| 351 Node* EscapeAnalysis::GetReplacementIfSame(ZoneVector<VirtualObject*>& objs) { |
| 352 Node* rep = GetReplacement(objs.front()->id()); |
| 353 for (VirtualObject* obj : objs) { |
| 354 if (GetReplacement(obj->id()) != rep) { |
| 355 return nullptr; |
| 356 } |
| 357 } |
| 358 return rep; |
| 359 } |
| 360 |
| 361 |
393 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 362 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
394 CommonOperatorBuilder* common, Node* control) { | 363 CommonOperatorBuilder* common, Node* control) { |
395 DCHECK_GT(cache->states().size(), 0u); | 364 DCHECK_GT(cache->states().size(), 0u); |
396 bool changed = false; | 365 bool changed = false; |
397 for (NodeId id = 0; id < min_size(cache->states()); ++id) { | 366 for (NodeId id = 0; id < min_size(cache->states()); ++id) { |
398 GetVirtualObjects(cache->states(), cache->objects(), id); | 367 GetVirtualObjects(cache->states(), cache->objects(), id); |
399 if (cache->objects().size() == cache->states().size()) { | 368 if (cache->objects().size() == cache->states().size()) { |
400 // Don't process linked objects. | 369 // Don't process linked objects. |
401 if (cache->objects()[0]->id() != id) continue; | 370 if (cache->objects()[0]->id() != id) continue; |
402 if (FLAG_trace_turbo_escape) { | 371 if (FLAG_trace_turbo_escape) { |
403 PrintF(" Merging virtual objects of #%d\n", id); | 372 PrintF(" Merging virtual objects of #%d\n", id); |
404 } | 373 } |
405 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone); | 374 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone); |
406 mergeObject->SetReplacement(GetReplacementIfSame(cache->objects())); | |
407 size_t fields = min_field_count(cache->objects()); | 375 size_t fields = min_field_count(cache->objects()); |
408 changed = mergeObject->ResizeFields(fields) || changed; | 376 changed = mergeObject->ResizeFields(fields) || changed; |
409 for (size_t i = 0; i < fields; ++i) { | 377 for (size_t i = 0; i < fields; ++i) { |
410 if (Node* field = GetFieldIfSame(i, cache->objects())) { | 378 if (Node* field = GetFieldIfSame(i, cache->objects())) { |
411 changed = mergeObject->SetField(i, field) || changed; | 379 changed = mergeObject->SetField(i, field) || changed; |
412 if (FLAG_trace_turbo_escape) { | 380 if (FLAG_trace_turbo_escape) { |
413 PrintF(" Field %zu agree on rep #%d\n", i, field->id()); | 381 PrintF(" Field %zu agree on rep #%d\n", i, field->id()); |
414 } | 382 } |
415 } else { | 383 } else { |
416 GetFields(cache->objects(), cache->fields(), i); | 384 GetFields(cache->objects(), cache->fields(), i); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
461 if (cache->objects().size() == cache->states().size()) { | 429 if (cache->objects().size() == cache->states().size()) { |
462 if (cache->objects()[0]->id() != id) { | 430 if (cache->objects()[0]->id() != id) { |
463 SetVirtualObject(id, GetVirtualObject(cache->objects()[0]->id())); | 431 SetVirtualObject(id, GetVirtualObject(cache->objects()[0]->id())); |
464 } | 432 } |
465 } | 433 } |
466 } | 434 } |
467 return changed; | 435 return changed; |
468 } | 436 } |
469 | 437 |
470 | 438 |
471 Node* VirtualState::ResolveReplacement(Node* node) { | |
472 Node* replacement = node; | |
473 VirtualObject* obj = GetVirtualObject(node); | |
474 while (obj != nullptr && obj->GetReplacement()) { | |
475 replacement = obj->GetReplacement(); | |
476 obj = GetVirtualObject(replacement); | |
477 } | |
478 return replacement; | |
479 } | |
480 | |
481 | |
482 bool VirtualState::UpdateReplacement(Node* node, Node* rep, Zone* zone) { | |
483 if (!GetVirtualObject(node)) { | |
484 if (rep) { | |
485 SetVirtualObject(node->id(), new (zone) VirtualObject(node->id(), zone)); | |
486 } else { | |
487 return false; | |
488 } | |
489 } | |
490 if (GetVirtualObject(node)->SetReplacement(rep)) { | |
491 LastChangedAt(node); | |
492 if (FLAG_trace_turbo_escape) { | |
493 if (rep) { | |
494 PrintF("Replacement of #%d is #%d (%s)\n", node->id(), rep->id(), | |
495 rep->op()->mnemonic()); | |
496 } else { | |
497 PrintF("Replacement of #%d cleared\n", node->id()); | |
498 } | |
499 } | |
500 return true; | |
501 } | |
502 return false; | |
503 } | |
504 | |
505 | |
506 // ------------------------------EscapeStatusAnalysis--------------------------- | 439 // ------------------------------EscapeStatusAnalysis--------------------------- |
507 | 440 |
508 | 441 |
509 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, | 442 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, |
510 Graph* graph, Zone* zone) | 443 Graph* graph, Zone* zone) |
511 : object_analysis_(object_analysis), | 444 : object_analysis_(object_analysis), |
512 graph_(graph), | 445 graph_(graph), |
513 zone_(zone), | 446 zone_(zone), |
514 info_(zone), | 447 info_(zone), |
515 queue_(zone) { | 448 queue_(zone) { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
596 ProcessFinishRegion(node); | 529 ProcessFinishRegion(node); |
597 break; | 530 break; |
598 case IrOpcode::kStoreField: | 531 case IrOpcode::kStoreField: |
599 ProcessStoreField(node); | 532 ProcessStoreField(node); |
600 break; | 533 break; |
601 case IrOpcode::kStoreElement: | 534 case IrOpcode::kStoreElement: |
602 ProcessStoreElement(node); | 535 ProcessStoreElement(node); |
603 break; | 536 break; |
604 case IrOpcode::kLoadField: | 537 case IrOpcode::kLoadField: |
605 case IrOpcode::kLoadElement: { | 538 case IrOpcode::kLoadElement: { |
606 if (Node* rep = object_analysis_->GetReplacement(node, node->id())) { | 539 if (Node* rep = object_analysis_->GetReplacement(node->id())) { |
607 if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) { | 540 if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) { |
608 RevisitInputs(rep); | 541 RevisitInputs(rep); |
609 RevisitUses(rep); | 542 RevisitUses(rep); |
610 } | 543 } |
611 } | 544 } |
612 break; | 545 break; |
613 } | 546 } |
614 case IrOpcode::kPhi: | 547 case IrOpcode::kPhi: |
615 if (!HasEntry(node)) { | 548 if (!HasEntry(node)) { |
616 info_[node->id()] = kVirtual; | 549 info_[node->id()] = kVirtual; |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
769 | 702 |
770 // -----------------------------EscapeAnalysis---------------------------------- | 703 // -----------------------------EscapeAnalysis---------------------------------- |
771 | 704 |
772 | 705 |
773 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, | 706 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, |
774 Zone* zone) | 707 Zone* zone) |
775 : graph_(graph), | 708 : graph_(graph), |
776 common_(common), | 709 common_(common), |
777 zone_(zone), | 710 zone_(zone), |
778 virtual_states_(zone), | 711 virtual_states_(zone), |
| 712 replacements_(zone), |
779 escape_status_(this, graph, zone), | 713 escape_status_(this, graph, zone), |
780 cache_(zone) {} | 714 cache_(zone) {} |
781 | 715 |
782 | 716 |
783 EscapeAnalysis::~EscapeAnalysis() {} | 717 EscapeAnalysis::~EscapeAnalysis() {} |
784 | 718 |
785 | 719 |
786 void EscapeAnalysis::Run() { | 720 void EscapeAnalysis::Run() { |
| 721 replacements_.resize(graph()->NodeCount()); |
787 RunObjectAnalysis(); | 722 RunObjectAnalysis(); |
788 escape_status_.Run(); | 723 escape_status_.Run(); |
789 } | 724 } |
790 | 725 |
791 | 726 |
792 void EscapeAnalysis::RunObjectAnalysis() { | 727 void EscapeAnalysis::RunObjectAnalysis() { |
793 virtual_states_.resize(graph()->NodeCount()); | 728 virtual_states_.resize(graph()->NodeCount()); |
794 ZoneVector<Node*> stack(zone()); | 729 ZoneVector<Node*> stack(zone()); |
795 stack.push_back(graph()->start()); | 730 stack.push_back(graph()->start()); |
796 while (!stack.empty()) { | 731 while (!stack.empty()) { |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
898 case IrOpcode::kLoadField: | 833 case IrOpcode::kLoadField: |
899 case IrOpcode::kStoreElement: | 834 case IrOpcode::kStoreElement: |
900 case IrOpcode::kLoadElement: | 835 case IrOpcode::kLoadElement: |
901 case IrOpcode::kFrameState: | 836 case IrOpcode::kFrameState: |
902 case IrOpcode::kStateValues: | 837 case IrOpcode::kStateValues: |
903 case IrOpcode::kReferenceEqual: | 838 case IrOpcode::kReferenceEqual: |
904 case IrOpcode::kFinishRegion: | 839 case IrOpcode::kFinishRegion: |
905 case IrOpcode::kPhi: | 840 case IrOpcode::kPhi: |
906 break; | 841 break; |
907 default: | 842 default: |
908 VirtualState* states = virtual_states_[node->id()]; | 843 VirtualState* state = virtual_states_[node->id()]; |
909 if (VirtualObject* obj = states->ResolveVirtualObject(input)) { | 844 if (VirtualObject* obj = ResolveVirtualObject(state, input)) { |
910 if (obj->ClearAllFields()) { | 845 if (obj->ClearAllFields()) { |
911 states->LastChangedAt(node); | 846 state->LastChangedAt(node); |
912 } | 847 } |
913 } | 848 } |
914 break; | 849 break; |
915 } | 850 } |
916 } | 851 } |
917 } | 852 } |
918 | 853 |
919 | 854 |
920 bool EscapeAnalysis::IsEffectBranchPoint(Node* node) { | 855 bool EscapeAnalysis::IsEffectBranchPoint(Node* node) { |
921 int count = 0; | 856 int count = 0; |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1070 if (FLAG_trace_turbo_escape) { | 1005 if (FLAG_trace_turbo_escape) { |
1071 PrintF("Linked finish region node #%d to node #%d\n", node->id(), | 1006 PrintF("Linked finish region node #%d to node #%d\n", node->id(), |
1072 allocation->id()); | 1007 allocation->id()); |
1073 } | 1008 } |
1074 states->LastChangedAt(node); | 1009 states->LastChangedAt(node); |
1075 } | 1010 } |
1076 } | 1011 } |
1077 } | 1012 } |
1078 | 1013 |
1079 | 1014 |
1080 Node* EscapeAnalysis::GetReplacement(Node* at, NodeId id) { | 1015 Node* EscapeAnalysis::replacement(NodeId id) { |
1081 VirtualState* states = virtual_states_[at->id()]; | 1016 if (id >= replacements_.size()) return nullptr; |
1082 if (VirtualObject* obj = states->GetVirtualObject(id)) { | 1017 return replacements_[id]; |
1083 return obj->GetReplacement(); | |
1084 } | |
1085 return nullptr; | |
1086 } | 1018 } |
1087 | 1019 |
1088 | 1020 |
| 1021 Node* EscapeAnalysis::replacement(Node* node) { |
| 1022 return replacement(node->id()); |
| 1023 } |
| 1024 |
| 1025 |
| 1026 bool EscapeAnalysis::SetReplacement(Node* node, Node* rep) { |
| 1027 bool changed = replacements_[node->id()] != rep; |
| 1028 replacements_[node->id()] = rep; |
| 1029 return changed; |
| 1030 } |
| 1031 |
| 1032 |
| 1033 bool EscapeAnalysis::UpdateReplacement(VirtualState* state, Node* node, |
| 1034 Node* rep) { |
| 1035 if (SetReplacement(node, rep)) { |
| 1036 state->LastChangedAt(node); |
| 1037 if (FLAG_trace_turbo_escape) { |
| 1038 if (rep) { |
| 1039 PrintF("Replacement of #%d is #%d (%s)\n", node->id(), rep->id(), |
| 1040 rep->op()->mnemonic()); |
| 1041 } else { |
| 1042 PrintF("Replacement of #%d cleared\n", node->id()); |
| 1043 } |
| 1044 } |
| 1045 return true; |
| 1046 } |
| 1047 return false; |
| 1048 } |
| 1049 |
| 1050 |
| 1051 Node* EscapeAnalysis::ResolveReplacement(Node* node) { |
| 1052 while (replacement(node)) { |
| 1053 node = replacement(node); |
| 1054 } |
| 1055 return node; |
| 1056 } |
| 1057 |
| 1058 |
| 1059 Node* EscapeAnalysis::GetReplacement(NodeId id) { |
| 1060 Node* node = nullptr; |
| 1061 while (replacement(id)) { |
| 1062 node = replacement(id); |
| 1063 id = node->id(); |
| 1064 } |
| 1065 return node; |
| 1066 } |
| 1067 |
| 1068 |
1089 bool EscapeAnalysis::IsVirtual(Node* node) { | 1069 bool EscapeAnalysis::IsVirtual(Node* node) { |
1090 return escape_status_.IsVirtual(node); | 1070 return escape_status_.IsVirtual(node); |
1091 } | 1071 } |
1092 | 1072 |
1093 | 1073 |
1094 bool EscapeAnalysis::IsEscaped(Node* node) { | 1074 bool EscapeAnalysis::IsEscaped(Node* node) { |
1095 return escape_status_.IsEscaped(node); | 1075 return escape_status_.IsEscaped(node); |
1096 } | 1076 } |
1097 | 1077 |
1098 | 1078 |
1099 bool EscapeAnalysis::SetEscaped(Node* node) { | 1079 bool EscapeAnalysis::SetEscaped(Node* node) { |
1100 return escape_status_.SetEscaped(node); | 1080 return escape_status_.SetEscaped(node); |
1101 } | 1081 } |
1102 | 1082 |
1103 | 1083 |
1104 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { | 1084 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { |
1105 if (VirtualState* states = virtual_states_[at->id()]) { | 1085 if (VirtualState* states = virtual_states_[at->id()]) { |
1106 return states->GetVirtualObject(id); | 1086 return states->GetVirtualObject(id); |
1107 } | 1087 } |
1108 return nullptr; | 1088 return nullptr; |
1109 } | 1089 } |
1110 | 1090 |
1111 | 1091 |
| 1092 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, |
| 1093 Node* node) { |
| 1094 VirtualObject* obj = state->GetVirtualObject(ResolveReplacement(node)); |
| 1095 while (obj && replacement(obj->id()) && |
| 1096 state->GetVirtualObject(replacement(obj->id()))) { |
| 1097 obj = state->GetVirtualObject(replacement(obj->id())); |
| 1098 } |
| 1099 return obj; |
| 1100 } |
| 1101 |
| 1102 |
1112 int EscapeAnalysis::OffsetFromAccess(Node* node) { | 1103 int EscapeAnalysis::OffsetFromAccess(Node* node) { |
1113 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); | 1104 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); |
1114 return OpParameter<FieldAccess>(node).offset / kPointerSize; | 1105 return OpParameter<FieldAccess>(node).offset / kPointerSize; |
1115 } | 1106 } |
1116 | 1107 |
1117 | 1108 |
1118 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, | 1109 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, |
1119 VirtualState* state) { | 1110 VirtualState* state) { |
1120 if (FLAG_trace_turbo_escape) { | 1111 if (FLAG_trace_turbo_escape) { |
1121 PrintF("Load #%d from phi #%d", node->id(), from->id()); | 1112 PrintF("Load #%d from phi #%d", node->id(), from->id()); |
1122 } | 1113 } |
1123 | 1114 |
1124 ZoneVector<Node*> inputs(zone()); | 1115 ZoneVector<Node*> inputs(zone()); |
1125 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | 1116 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { |
1126 Node* input = NodeProperties::GetValueInput(node, i); | 1117 Node* input = NodeProperties::GetValueInput(node, i); |
1127 inputs.push_back(input); | 1118 inputs.push_back(input); |
1128 } | 1119 } |
1129 | 1120 |
1130 GetVirtualObjects(state, inputs, cache_.objects()); | 1121 GetVirtualObjects(state, inputs, cache_.objects()); |
1131 if (cache_.objects().size() == inputs.size()) { | 1122 if (cache_.objects().size() == inputs.size()) { |
1132 GetFields(cache_.objects(), cache_.fields(), offset); | 1123 GetFields(cache_.objects(), cache_.fields(), offset); |
1133 if (cache_.fields().size() == cache_.objects().size()) { | 1124 if (cache_.fields().size() == cache_.objects().size()) { |
1134 if (!state->GetVirtualObject(node)) { | 1125 Node* rep = replacement(node); |
1135 state->SetVirtualObject(node->id(), | |
1136 new (zone()) VirtualObject(node->id(), zone())); | |
1137 } | |
1138 Node* rep = state->GetVirtualObject(node)->GetReplacement(); | |
1139 if (!rep || !IsEquivalentPhi(rep, cache_.fields())) { | 1126 if (!rep || !IsEquivalentPhi(rep, cache_.fields())) { |
1140 cache_.fields().push_back(NodeProperties::GetControlInput(from)); | 1127 cache_.fields().push_back(NodeProperties::GetControlInput(from)); |
1141 Node* phi = graph()->NewNode( | 1128 Node* phi = graph()->NewNode( |
1142 common()->Phi(MachineRepresentation::kTagged, 2), | 1129 common()->Phi(MachineRepresentation::kTagged, 2), |
1143 static_cast<int>(cache_.fields().size()), &cache_.fields().front()); | 1130 static_cast<int>(cache_.fields().size()), &cache_.fields().front()); |
1144 state->GetVirtualObject(node)->SetReplacement(phi); | 1131 SetReplacement(node, phi); |
1145 state->LastChangedAt(node); | 1132 state->LastChangedAt(node); |
1146 if (FLAG_trace_turbo_escape) { | 1133 if (FLAG_trace_turbo_escape) { |
1147 PrintF(" got phi created.\n"); | 1134 PrintF(" got phi created.\n"); |
1148 } | 1135 } |
1149 } else if (FLAG_trace_turbo_escape) { | 1136 } else if (FLAG_trace_turbo_escape) { |
1150 PrintF(" has already phi #%d.\n", rep->id()); | 1137 PrintF(" has already phi #%d.\n", rep->id()); |
1151 } | 1138 } |
1152 } else if (FLAG_trace_turbo_escape) { | 1139 } else if (FLAG_trace_turbo_escape) { |
1153 PrintF(" has incomplete field info.\n"); | 1140 PrintF(" has incomplete field info.\n"); |
1154 } | 1141 } |
1155 } else if (FLAG_trace_turbo_escape) { | 1142 } else if (FLAG_trace_turbo_escape) { |
1156 PrintF(" has incomplete virtual object info.\n"); | 1143 PrintF(" has incomplete virtual object info.\n"); |
1157 } | 1144 } |
1158 } | 1145 } |
1159 | 1146 |
1160 | 1147 |
1161 void EscapeAnalysis::ProcessLoadField(Node* node) { | 1148 void EscapeAnalysis::ProcessLoadField(Node* node) { |
1162 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); | 1149 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); |
1163 ForwardVirtualState(node); | 1150 ForwardVirtualState(node); |
1164 Node* from = NodeProperties::GetValueInput(node, 0); | 1151 Node* from = NodeProperties::GetValueInput(node, 0); |
1165 VirtualState* state = virtual_states_[node->id()]; | 1152 VirtualState* state = virtual_states_[node->id()]; |
1166 if (VirtualObject* object = state->ResolveVirtualObject(from)) { | 1153 if (VirtualObject* object = ResolveVirtualObject(state, from)) { |
1167 int offset = OffsetFromAccess(node); | 1154 int offset = OffsetFromAccess(node); |
1168 if (!object->IsTracked()) return; | 1155 if (!object->IsTracked()) return; |
1169 Node* value = object->GetField(offset); | 1156 Node* value = object->GetField(offset); |
1170 if (value) { | 1157 if (value) { |
1171 value = state->ResolveReplacement(value); | 1158 value = ResolveReplacement(value); |
1172 } | 1159 } |
1173 // Record that the load has this alias. | 1160 // Record that the load has this alias. |
1174 state->UpdateReplacement(node, value, zone()); | 1161 UpdateReplacement(state, node, value); |
1175 } else { | 1162 } else { |
1176 if (from->opcode() == IrOpcode::kPhi) { | 1163 if (from->opcode() == IrOpcode::kPhi && |
| 1164 OpParameter<FieldAccess>(node).offset % kPointerSize == 0) { |
1177 int offset = OffsetFromAccess(node); | 1165 int offset = OffsetFromAccess(node); |
1178 // Only binary phis are supported for now. | 1166 // Only binary phis are supported for now. |
1179 ProcessLoadFromPhi(offset, from, node, state); | 1167 ProcessLoadFromPhi(offset, from, node, state); |
1180 } | 1168 } |
1181 } | 1169 } |
1182 } | 1170 } |
1183 | 1171 |
1184 | 1172 |
1185 void EscapeAnalysis::ProcessLoadElement(Node* node) { | 1173 void EscapeAnalysis::ProcessLoadElement(Node* node) { |
1186 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); | 1174 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); |
1187 ForwardVirtualState(node); | 1175 ForwardVirtualState(node); |
1188 Node* from = NodeProperties::GetValueInput(node, 0); | 1176 Node* from = NodeProperties::GetValueInput(node, 0); |
1189 VirtualState* state = virtual_states_[node->id()]; | 1177 VirtualState* state = virtual_states_[node->id()]; |
1190 Node* index_node = node->InputAt(1); | 1178 Node* index_node = node->InputAt(1); |
1191 NumberMatcher index(index_node); | 1179 NumberMatcher index(index_node); |
1192 ElementAccess access = OpParameter<ElementAccess>(node); | 1180 ElementAccess access = OpParameter<ElementAccess>(node); |
1193 if (index.HasValue()) { | 1181 if (index.HasValue()) { |
1194 int offset = index.Value() + access.header_size / kPointerSize; | 1182 int offset = index.Value() + access.header_size / kPointerSize; |
1195 if (VirtualObject* object = state->ResolveVirtualObject(from)) { | 1183 if (VirtualObject* object = ResolveVirtualObject(state, from)) { |
1196 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), | 1184 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), |
1197 kPointerSizeLog2); | 1185 kPointerSizeLog2); |
1198 CHECK_EQ(access.header_size % kPointerSize, 0); | 1186 CHECK_EQ(access.header_size % kPointerSize, 0); |
1199 | 1187 |
1200 if (!object->IsTracked()) return; | 1188 if (!object->IsTracked()) return; |
1201 Node* value = object->GetField(offset); | 1189 Node* value = object->GetField(offset); |
1202 if (value) { | 1190 if (value) { |
1203 value = state->ResolveReplacement(value); | 1191 value = ResolveReplacement(value); |
1204 } | 1192 } |
1205 // Record that the load has this alias. | 1193 // Record that the load has this alias. |
1206 state->UpdateReplacement(node, value, zone()); | 1194 UpdateReplacement(state, node, value); |
1207 } else if (from->opcode() == IrOpcode::kPhi) { | 1195 } else if (from->opcode() == IrOpcode::kPhi) { |
1208 ElementAccess access = OpParameter<ElementAccess>(node); | 1196 ElementAccess access = OpParameter<ElementAccess>(node); |
1209 int offset = index.Value() + access.header_size / kPointerSize; | 1197 int offset = index.Value() + access.header_size / kPointerSize; |
1210 ProcessLoadFromPhi(offset, from, node, state); | 1198 ProcessLoadFromPhi(offset, from, node, state); |
1211 } | 1199 } |
1212 } else { | 1200 } else { |
1213 // We have a load from a non-const index, cannot eliminate object. | 1201 // We have a load from a non-const index, cannot eliminate object. |
1214 if (SetEscaped(from)) { | 1202 if (SetEscaped(from)) { |
1215 if (FLAG_trace_turbo_escape) { | 1203 if (FLAG_trace_turbo_escape) { |
1216 PrintF( | 1204 PrintF( |
1217 "Setting #%d (%s) to escaped because store element #%d to " | 1205 "Setting #%d (%s) to escaped because store element #%d to " |
1218 "non-const " | 1206 "non-const " |
1219 "index #%d (%s)\n", | 1207 "index #%d (%s)\n", |
1220 from->id(), from->op()->mnemonic(), node->id(), index_node->id(), | 1208 from->id(), from->op()->mnemonic(), node->id(), index_node->id(), |
1221 index_node->op()->mnemonic()); | 1209 index_node->op()->mnemonic()); |
1222 } | 1210 } |
1223 } | 1211 } |
1224 } | 1212 } |
1225 } | 1213 } |
1226 | 1214 |
1227 | 1215 |
1228 void EscapeAnalysis::ProcessStoreField(Node* node) { | 1216 void EscapeAnalysis::ProcessStoreField(Node* node) { |
1229 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); | 1217 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); |
1230 ForwardVirtualState(node); | 1218 ForwardVirtualState(node); |
1231 Node* to = NodeProperties::GetValueInput(node, 0); | 1219 Node* to = NodeProperties::GetValueInput(node, 0); |
1232 Node* val = NodeProperties::GetValueInput(node, 1); | 1220 Node* val = NodeProperties::GetValueInput(node, 1); |
1233 int offset = OffsetFromAccess(node); | 1221 VirtualState* state = virtual_states_[node->id()]; |
1234 VirtualState* states = virtual_states_[node->id()]; | 1222 if (VirtualObject* obj = ResolveVirtualObject(state, to)) { |
1235 if (VirtualObject* obj = states->ResolveVirtualObject(to)) { | |
1236 if (!obj->IsTracked()) return; | 1223 if (!obj->IsTracked()) return; |
1237 if (obj->SetField(offset, states->ResolveReplacement(val))) { | 1224 int offset = OffsetFromAccess(node); |
1238 states->LastChangedAt(node); | 1225 if (obj->SetField(offset, ResolveReplacement(val))) { |
| 1226 state->LastChangedAt(node); |
1239 } | 1227 } |
1240 } | 1228 } |
1241 } | 1229 } |
1242 | 1230 |
1243 | 1231 |
1244 void EscapeAnalysis::ProcessStoreElement(Node* node) { | 1232 void EscapeAnalysis::ProcessStoreElement(Node* node) { |
1245 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); | 1233 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); |
1246 ForwardVirtualState(node); | 1234 ForwardVirtualState(node); |
1247 Node* to = NodeProperties::GetValueInput(node, 0); | 1235 Node* to = NodeProperties::GetValueInput(node, 0); |
1248 Node* index_node = node->InputAt(1); | 1236 Node* index_node = node->InputAt(1); |
1249 NumberMatcher index(index_node); | 1237 NumberMatcher index(index_node); |
1250 ElementAccess access = OpParameter<ElementAccess>(node); | 1238 ElementAccess access = OpParameter<ElementAccess>(node); |
1251 Node* val = NodeProperties::GetValueInput(node, 2); | 1239 Node* val = NodeProperties::GetValueInput(node, 2); |
1252 if (index.HasValue()) { | 1240 if (index.HasValue()) { |
1253 int offset = index.Value() + access.header_size / kPointerSize; | 1241 int offset = index.Value() + access.header_size / kPointerSize; |
1254 VirtualState* states = virtual_states_[node->id()]; | 1242 VirtualState* states = virtual_states_[node->id()]; |
1255 if (VirtualObject* obj = states->ResolveVirtualObject(to)) { | 1243 if (VirtualObject* obj = ResolveVirtualObject(states, to)) { |
1256 if (!obj->IsTracked()) return; | 1244 if (!obj->IsTracked()) return; |
1257 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), | 1245 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), |
1258 kPointerSizeLog2); | 1246 kPointerSizeLog2); |
1259 CHECK_EQ(access.header_size % kPointerSize, 0); | 1247 CHECK_EQ(access.header_size % kPointerSize, 0); |
1260 if (obj->SetField(offset, states->ResolveReplacement(val))) { | 1248 if (obj->SetField(offset, ResolveReplacement(val))) { |
1261 states->LastChangedAt(node); | 1249 states->LastChangedAt(node); |
1262 } | 1250 } |
1263 } | 1251 } |
1264 } else { | 1252 } else { |
1265 // We have a store to a non-const index, cannot eliminate object. | 1253 // We have a store to a non-const index, cannot eliminate object. |
1266 if (SetEscaped(to)) { | 1254 if (SetEscaped(to)) { |
1267 if (FLAG_trace_turbo_escape) { | 1255 if (FLAG_trace_turbo_escape) { |
1268 PrintF( | 1256 PrintF( |
1269 "Setting #%d (%s) to escaped because store element #%d to " | 1257 "Setting #%d (%s) to escaped because store element #%d to " |
1270 "non-const " | 1258 "non-const " |
1271 "index #%d (%s)\n", | 1259 "index #%d (%s)\n", |
1272 to->id(), to->op()->mnemonic(), node->id(), index_node->id(), | 1260 to->id(), to->op()->mnemonic(), node->id(), index_node->id(), |
1273 index_node->op()->mnemonic()); | 1261 index_node->op()->mnemonic()); |
1274 } | 1262 } |
1275 } | 1263 } |
1276 } | 1264 } |
1277 } | 1265 } |
1278 | 1266 |
1279 | 1267 |
1280 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, NodeId id) { | 1268 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, NodeId id) { |
1281 PrintF(" Object #%d with %zu fields", id, object->field_count()); | 1269 PrintF(" Object #%d with %zu fields\n", id, object->field_count()); |
1282 if (Node* rep = object->GetReplacement()) { | |
1283 PrintF(", rep = #%d (%s)", rep->id(), rep->op()->mnemonic()); | |
1284 } | |
1285 PrintF("\n"); | |
1286 for (size_t i = 0; i < object->field_count(); ++i) { | 1270 for (size_t i = 0; i < object->field_count(); ++i) { |
1287 if (Node* f = object->GetField(i)) { | 1271 if (Node* f = object->GetField(i)) { |
1288 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); | 1272 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); |
1289 } | 1273 } |
1290 } | 1274 } |
1291 } | 1275 } |
1292 | 1276 |
1293 | 1277 |
1294 void EscapeAnalysis::DebugPrintState(VirtualState* state) { | 1278 void EscapeAnalysis::DebugPrintState(VirtualState* state) { |
1295 PrintF("Dumping object state %p\n", static_cast<void*>(state)); | 1279 PrintF("Dumping object state %p\n", static_cast<void*>(state)); |
(...skipping 20 matching lines...) Expand all Loading... |
1316 } | 1300 } |
1317 } | 1301 } |
1318 for (size_t n = 0; n < object_states.size(); n++) { | 1302 for (size_t n = 0; n < object_states.size(); n++) { |
1319 DebugPrintState(object_states[n]); | 1303 DebugPrintState(object_states[n]); |
1320 } | 1304 } |
1321 } | 1305 } |
1322 | 1306 |
1323 } // namespace compiler | 1307 } // namespace compiler |
1324 } // namespace internal | 1308 } // namespace internal |
1325 } // namespace v8 | 1309 } // namespace v8 |
OLD | NEW |