OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/escape-analysis.h" | 5 #include "src/compiler/escape-analysis.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 | 8 |
9 #include "src/base/flags.h" | 9 #include "src/base/flags.h" |
10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 Status status_; | 117 Status status_; |
118 ZoneVector<Node*> fields_; | 118 ZoneVector<Node*> fields_; |
119 ZoneVector<bool> phi_; | 119 ZoneVector<bool> phi_; |
120 Node* object_state_; | 120 Node* object_state_; |
121 }; | 121 }; |
122 | 122 |
123 | 123 |
124 bool VirtualObject::UpdateFrom(const VirtualObject& other) { | 124 bool VirtualObject::UpdateFrom(const VirtualObject& other) { |
125 bool changed = status_ != other.status_; | 125 bool changed = status_ != other.status_; |
126 status_ = other.status_; | 126 status_ = other.status_; |
| 127 phi_ = other.phi_; |
127 if (fields_.size() != other.fields_.size()) { | 128 if (fields_.size() != other.fields_.size()) { |
128 fields_ = other.fields_; | 129 fields_ = other.fields_; |
129 return true; | 130 return true; |
130 } | 131 } |
131 for (size_t i = 0; i < fields_.size(); ++i) { | 132 for (size_t i = 0; i < fields_.size(); ++i) { |
132 if (fields_[i] != other.fields_[i]) { | 133 if (fields_[i] != other.fields_[i]) { |
133 changed = true; | 134 changed = true; |
134 fields_[i] = other.fields_[i]; | 135 fields_[i] = other.fields_[i]; |
135 } | 136 } |
136 } | 137 } |
137 return changed; | 138 return changed; |
138 } | 139 } |
139 | 140 |
140 | 141 |
141 class VirtualState : public ZoneObject { | 142 class VirtualState : public ZoneObject { |
142 public: | 143 public: |
143 VirtualState(Zone* zone, size_t size); | 144 VirtualState(Zone* zone, size_t size); |
144 VirtualState(const VirtualState& states); | 145 VirtualState(const VirtualState& states); |
145 | 146 |
146 VirtualObject* VirtualObjectFromAlias(size_t alias); | 147 VirtualObject* VirtualObjectFromAlias(size_t alias); |
147 VirtualObject* GetOrCreateTrackedVirtualObject(EscapeAnalysis::Alias alias, | 148 VirtualObject* GetOrCreateTrackedVirtualObject(EscapeAnalysis::Alias alias, |
148 NodeId id, Zone* zone); | 149 NodeId id, size_t fields, |
| 150 Zone* zone); |
149 void SetVirtualObject(EscapeAnalysis::Alias alias, VirtualObject* state); | 151 void SetVirtualObject(EscapeAnalysis::Alias alias, VirtualObject* state); |
150 void LastChangedAt(Node* node) { last_changed_ = node; } | 152 void LastChangedAt(Node* node) { last_changed_ = node; } |
151 Node* GetLastChanged() { return last_changed_; } | 153 Node* GetLastChanged() { return last_changed_; } |
152 bool UpdateFrom(VirtualState* state, Zone* zone); | 154 bool UpdateFrom(VirtualState* state, Zone* zone); |
153 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 155 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
154 CommonOperatorBuilder* common, Node* control); | 156 CommonOperatorBuilder* common, Node* control); |
155 size_t size() const { return info_.size(); } | 157 size_t size() const { return info_.size(); } |
156 | 158 |
157 private: | 159 private: |
158 ZoneVector<VirtualObject*> info_; | 160 ZoneVector<VirtualObject*> info_; |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 } | 250 } |
249 } | 251 } |
250 | 252 |
251 | 253 |
252 VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) { | 254 VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) { |
253 return info_[alias]; | 255 return info_[alias]; |
254 } | 256 } |
255 | 257 |
256 | 258 |
257 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject( | 259 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject( |
258 EscapeAnalysis::Alias alias, NodeId id, Zone* zone) { | 260 EscapeAnalysis::Alias alias, NodeId id, size_t field_number, Zone* zone) { |
259 if (VirtualObject* obj = VirtualObjectFromAlias(alias)) { | 261 if (VirtualObject* obj = VirtualObjectFromAlias(alias)) { |
260 return obj; | 262 return obj; |
261 } | 263 } |
262 VirtualObject* obj = new (zone) VirtualObject(id, zone, 0); | 264 VirtualObject* obj = new (zone) VirtualObject(id, zone, 0); |
263 SetVirtualObject(alias, obj); | 265 SetVirtualObject(alias, obj); |
264 return obj; | 266 return obj; |
265 } | 267 } |
266 | 268 |
267 | 269 |
268 void VirtualState::SetVirtualObject(EscapeAnalysis::Alias alias, | 270 void VirtualState::SetVirtualObject(EscapeAnalysis::Alias alias, |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 CommonOperatorBuilder* common, Node* control) { | 351 CommonOperatorBuilder* common, Node* control) { |
350 DCHECK_GT(cache->states().size(), 0u); | 352 DCHECK_GT(cache->states().size(), 0u); |
351 bool changed = false; | 353 bool changed = false; |
352 for (EscapeAnalysis::Alias alias = 0; alias < size(); ++alias) { | 354 for (EscapeAnalysis::Alias alias = 0; alias < size(); ++alias) { |
353 size_t fields = cache->LoadVirtualObjectsFromStatesFor(alias); | 355 size_t fields = cache->LoadVirtualObjectsFromStatesFor(alias); |
354 if (cache->objects().size() == cache->states().size()) { | 356 if (cache->objects().size() == cache->states().size()) { |
355 if (FLAG_trace_turbo_escape) { | 357 if (FLAG_trace_turbo_escape) { |
356 PrintF(" Merging virtual objects of @%d\n", alias); | 358 PrintF(" Merging virtual objects of @%d\n", alias); |
357 } | 359 } |
358 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject( | 360 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject( |
359 alias, cache->objects().front()->id(), zone); | 361 alias, cache->objects().front()->id(), fields, zone); |
360 changed = mergeObject->ResizeFields(fields) || changed; | 362 changed = mergeObject->ResizeFields(fields) || changed; |
361 for (size_t i = 0; i < fields; ++i) { | 363 for (size_t i = 0; i < fields; ++i) { |
362 if (Node* field = cache->GetFields(i)) { | 364 if (Node* field = cache->GetFields(i)) { |
363 changed = mergeObject->SetField(i, field) || changed; | 365 changed = mergeObject->SetField(i, field) || changed; |
364 if (FLAG_trace_turbo_escape) { | 366 if (FLAG_trace_turbo_escape) { |
365 PrintF(" Field %zu agree on rep #%d\n", i, field->id()); | 367 PrintF(" Field %zu agree on rep #%d\n", i, field->id()); |
366 } | 368 } |
367 } else { | 369 } else { |
368 int value_input_count = static_cast<int>(cache->fields().size()); | 370 int value_input_count = static_cast<int>(cache->fields().size()); |
369 if (cache->fields().size() == cache->objects().size()) { | 371 if (cache->fields().size() == cache->objects().size()) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
403 if (FLAG_trace_turbo_escape) { | 405 if (FLAG_trace_turbo_escape) { |
404 PrintF(" Widening Phi #%d of arity %d to %d", rep->id(), | 406 PrintF(" Widening Phi #%d of arity %d to %d", rep->id(), |
405 rep->op()->ValueInputCount(), value_input_count); | 407 rep->op()->ValueInputCount(), value_input_count); |
406 } | 408 } |
407 NodeProperties::ChangeOp( | 409 NodeProperties::ChangeOp( |
408 rep, common->Phi(MachineRepresentation::kTagged, | 410 rep, common->Phi(MachineRepresentation::kTagged, |
409 value_input_count)); | 411 value_input_count)); |
410 } | 412 } |
411 } | 413 } |
412 } else { | 414 } else { |
| 415 if (FLAG_trace_turbo_escape) { |
| 416 PrintF(" Field %zu cleared\n", i); |
| 417 } |
413 changed = mergeObject->SetField(i, nullptr) || changed; | 418 changed = mergeObject->SetField(i, nullptr) || changed; |
414 } | 419 } |
415 } | 420 } |
416 } | 421 } |
417 } else { | 422 } else { |
418 SetVirtualObject(alias, nullptr); | 423 SetVirtualObject(alias, nullptr); |
419 } | 424 } |
420 } | 425 } |
421 return changed; | 426 return changed; |
422 } | 427 } |
(...skipping 10 matching lines...) Expand all Loading... |
433 | 438 |
434 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} | 439 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} |
435 | 440 |
436 | 441 |
437 bool EscapeStatusAnalysis::HasEntry(Node* node) { | 442 bool EscapeStatusAnalysis::HasEntry(Node* node) { |
438 return status_[node->id()] & (kTracked | kEscaped); | 443 return status_[node->id()] & (kTracked | kEscaped); |
439 } | 444 } |
440 | 445 |
441 | 446 |
442 bool EscapeStatusAnalysis::IsVirtual(Node* node) { | 447 bool EscapeStatusAnalysis::IsVirtual(Node* node) { |
443 return (status_[node->id()] & kTracked) && !(status_[node->id()] & kEscaped); | 448 return IsVirtual(node->id()); |
444 } | 449 } |
445 | 450 |
446 | 451 |
| 452 bool EscapeStatusAnalysis::IsVirtual(NodeId id) { |
| 453 return (status_[id] & kTracked) && !(status_[id] & kEscaped); |
| 454 } |
| 455 |
| 456 |
447 bool EscapeStatusAnalysis::IsEscaped(Node* node) { | 457 bool EscapeStatusAnalysis::IsEscaped(Node* node) { |
448 return status_[node->id()] & kEscaped; | 458 return status_[node->id()] & kEscaped; |
449 } | 459 } |
450 | 460 |
451 | 461 |
452 bool EscapeStatusAnalysis::IsAllocation(Node* node) { | 462 bool EscapeStatusAnalysis::IsAllocation(Node* node) { |
453 return node->opcode() == IrOpcode::kAllocate || | 463 return node->opcode() == IrOpcode::kAllocate || |
454 node->opcode() == IrOpcode::kFinishRegion; | 464 node->opcode() == IrOpcode::kFinishRegion; |
455 } | 465 } |
456 | 466 |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
662 } | 672 } |
663 break; | 673 break; |
664 case IrOpcode::kObjectIsSmi: | 674 case IrOpcode::kObjectIsSmi: |
665 if (!IsAllocation(rep) && SetEscaped(rep)) { | 675 if (!IsAllocation(rep) && SetEscaped(rep)) { |
666 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", | 676 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", |
667 rep->id(), rep->op()->mnemonic(), use->id(), | 677 rep->id(), rep->op()->mnemonic(), use->id(), |
668 use->op()->mnemonic()); | 678 use->op()->mnemonic()); |
669 return true; | 679 return true; |
670 } | 680 } |
671 break; | 681 break; |
| 682 case IrOpcode::kSelect: |
| 683 if (SetEscaped(rep)) { |
| 684 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", |
| 685 rep->id(), rep->op()->mnemonic(), use->id(), |
| 686 use->op()->mnemonic()); |
| 687 return true; |
| 688 } |
| 689 break; |
672 default: | 690 default: |
673 if (use->op()->EffectInputCount() == 0 && | 691 if (use->op()->EffectInputCount() == 0 && |
674 uses->op()->EffectInputCount() > 0) { | 692 uses->op()->EffectInputCount() > 0) { |
675 PrintF("Encountered unaccounted use by #%d (%s)\n", use->id(), | 693 PrintF("Encountered unaccounted use by #%d (%s)\n", use->id(), |
676 use->op()->mnemonic()); | 694 use->op()->mnemonic()); |
677 UNREACHABLE(); | 695 UNREACHABLE(); |
678 } | 696 } |
679 if (SetEscaped(rep)) { | 697 if (SetEscaped(rep)) { |
680 if (FLAG_trace_turbo_escape) { | 698 if (FLAG_trace_turbo_escape) { |
681 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", | 699 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
724 aliases_(zone), | 742 aliases_(zone), |
725 next_free_alias_(0) {} | 743 next_free_alias_(0) {} |
726 | 744 |
727 | 745 |
728 EscapeAnalysis::~EscapeAnalysis() {} | 746 EscapeAnalysis::~EscapeAnalysis() {} |
729 | 747 |
730 | 748 |
731 void EscapeAnalysis::Run() { | 749 void EscapeAnalysis::Run() { |
732 replacements_.resize(graph()->NodeCount()); | 750 replacements_.resize(graph()->NodeCount()); |
733 AssignAliases(); | 751 AssignAliases(); |
| 752 if (AliasCount() == 0) return; |
| 753 escape_status_.Resize(); |
734 RunObjectAnalysis(); | 754 RunObjectAnalysis(); |
735 escape_status_.Run(); | 755 escape_status_.Run(); |
736 } | 756 } |
737 | 757 |
738 | 758 |
739 void EscapeAnalysis::AssignAliases() { | 759 void EscapeAnalysis::AssignAliases() { |
740 ZoneVector<Node*> stack(zone()); | 760 ZoneVector<Node*> stack(zone()); |
741 stack.push_back(graph()->end()); | 761 stack.push_back(graph()->end()); |
742 CHECK_LT(graph()->NodeCount(), kUntrackable); | 762 CHECK_LT(graph()->NodeCount(), kUntrackable); |
743 aliases_.resize(graph()->NodeCount(), kNotReachable); | 763 aliases_.resize(graph()->NodeCount(), kNotReachable); |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1035 mergeState->LastChangedAt(node); | 1055 mergeState->LastChangedAt(node); |
1036 escape_status_.Resize(); | 1056 escape_status_.Resize(); |
1037 } | 1057 } |
1038 return changed; | 1058 return changed; |
1039 } | 1059 } |
1040 | 1060 |
1041 | 1061 |
1042 void EscapeAnalysis::ProcessAllocation(Node* node) { | 1062 void EscapeAnalysis::ProcessAllocation(Node* node) { |
1043 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 1063 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
1044 ForwardVirtualState(node); | 1064 ForwardVirtualState(node); |
| 1065 VirtualState* state = virtual_states_[node->id()]; |
| 1066 Alias alias = aliases_[node->id()]; |
1045 | 1067 |
1046 // Check if we have already processed this node. | 1068 // Check if we have already processed this node. |
1047 if (virtual_states_[node->id()]->VirtualObjectFromAlias( | 1069 if (state->VirtualObjectFromAlias(alias)) { |
1048 aliases_[node->id()])) { | |
1049 return; | 1070 return; |
1050 } | 1071 } |
1051 | 1072 |
1052 NumberMatcher size(node->InputAt(0)); | 1073 NumberMatcher size(node->InputAt(0)); |
1053 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && | 1074 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && |
1054 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && | 1075 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && |
1055 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && | 1076 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && |
1056 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); | 1077 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); |
1057 if (size.HasValue()) { | 1078 if (size.HasValue()) { |
1058 virtual_states_[node->id()]->SetVirtualObject( | 1079 state->SetVirtualObject( |
1059 aliases_[node->id()], | 1080 alias, new (zone()) VirtualObject(node->id(), zone(), |
1060 new (zone()) | 1081 size.Value() / kPointerSize)); |
1061 VirtualObject(node->id(), zone(), size.Value() / kPointerSize)); | |
1062 } else { | 1082 } else { |
1063 virtual_states_[node->id()]->SetVirtualObject( | 1083 state->SetVirtualObject(alias, |
1064 aliases_[node->id()], new (zone()) VirtualObject(node->id(), zone())); | 1084 new (zone()) VirtualObject(node->id(), zone())); |
1065 } | 1085 } |
1066 virtual_states_[node->id()]->LastChangedAt(node); | 1086 state->LastChangedAt(node); |
1067 } | 1087 } |
1068 | 1088 |
1069 | 1089 |
1070 void EscapeAnalysis::ProcessFinishRegion(Node* node) { | 1090 void EscapeAnalysis::ProcessFinishRegion(Node* node) { |
1071 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); | 1091 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); |
1072 ForwardVirtualState(node); | 1092 ForwardVirtualState(node); |
1073 Node* allocation = NodeProperties::GetValueInput(node, 0); | 1093 Node* allocation = NodeProperties::GetValueInput(node, 0); |
1074 if (allocation->opcode() == IrOpcode::kAllocate) { | 1094 if (allocation->opcode() == IrOpcode::kAllocate) { |
1075 VirtualState* state = virtual_states_[node->id()]; | 1095 VirtualState* state = virtual_states_[node->id()]; |
1076 if (!state->VirtualObjectFromAlias(aliases_[node->id()])) { | 1096 if (!state->VirtualObjectFromAlias(aliases_[node->id()])) { |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1171 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { | 1191 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { |
1172 if (VirtualState* states = virtual_states_[at->id()]) { | 1192 if (VirtualState* states = virtual_states_[at->id()]) { |
1173 return states->VirtualObjectFromAlias(aliases_[id]); | 1193 return states->VirtualObjectFromAlias(aliases_[id]); |
1174 } | 1194 } |
1175 return nullptr; | 1195 return nullptr; |
1176 } | 1196 } |
1177 | 1197 |
1178 | 1198 |
1179 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, | 1199 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, |
1180 Node* node) { | 1200 Node* node) { |
1181 VirtualObject* obj = GetVirtualObject(state, ResolveReplacement(node)); | 1201 return GetVirtualObject(state, ResolveReplacement(node)); |
1182 while (obj && replacement(obj->id())) { | |
1183 if (VirtualObject* next = GetVirtualObject(state, replacement(obj->id()))) { | |
1184 obj = next; | |
1185 } else { | |
1186 break; | |
1187 } | |
1188 } | |
1189 return obj; | |
1190 } | 1202 } |
1191 | 1203 |
1192 | 1204 |
1193 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { | 1205 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { |
1194 DCHECK(IsVirtual(left) && IsVirtual(right)); | 1206 DCHECK(IsVirtual(left) && IsVirtual(right)); |
1195 left = ResolveReplacement(left); | 1207 left = ResolveReplacement(left); |
1196 right = ResolveReplacement(right); | 1208 right = ResolveReplacement(right); |
1197 if (IsEquivalentPhi(left, right)) { | 1209 if (IsEquivalentPhi(left, right)) { |
1198 return true; | 1210 return true; |
1199 } | 1211 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1244 } | 1256 } |
1245 } else if (FLAG_trace_turbo_escape) { | 1257 } else if (FLAG_trace_turbo_escape) { |
1246 PrintF(" has incomplete virtual object info.\n"); | 1258 PrintF(" has incomplete virtual object info.\n"); |
1247 } | 1259 } |
1248 } | 1260 } |
1249 | 1261 |
1250 | 1262 |
1251 void EscapeAnalysis::ProcessLoadField(Node* node) { | 1263 void EscapeAnalysis::ProcessLoadField(Node* node) { |
1252 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); | 1264 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); |
1253 ForwardVirtualState(node); | 1265 ForwardVirtualState(node); |
1254 Node* from = NodeProperties::GetValueInput(node, 0); | 1266 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
1255 VirtualState* state = virtual_states_[node->id()]; | 1267 VirtualState* state = virtual_states_[node->id()]; |
1256 if (VirtualObject* object = ResolveVirtualObject(state, from)) { | 1268 if (VirtualObject* object = GetVirtualObject(state, from)) { |
1257 int offset = OffsetFromAccess(node); | 1269 int offset = OffsetFromAccess(node); |
1258 if (!object->IsTracked()) return; | 1270 if (!object->IsTracked()) return; |
1259 Node* value = object->GetField(offset); | 1271 Node* value = object->GetField(offset); |
1260 if (value) { | 1272 if (value) { |
1261 value = ResolveReplacement(value); | 1273 value = ResolveReplacement(value); |
1262 } | 1274 } |
1263 // Record that the load has this alias. | 1275 // Record that the load has this alias. |
1264 UpdateReplacement(state, node, value); | 1276 UpdateReplacement(state, node, value); |
1265 } else { | 1277 } else if (from->opcode() == IrOpcode::kPhi && |
1266 if (from->opcode() == IrOpcode::kPhi && | 1278 OpParameter<FieldAccess>(node).offset % kPointerSize == 0) { |
1267 OpParameter<FieldAccess>(node).offset % kPointerSize == 0) { | |
1268 int offset = OffsetFromAccess(node); | 1279 int offset = OffsetFromAccess(node); |
1269 // Only binary phis are supported for now. | 1280 // Only binary phis are supported for now. |
1270 ProcessLoadFromPhi(offset, from, node, state); | 1281 ProcessLoadFromPhi(offset, from, node, state); |
1271 } | 1282 } else { |
| 1283 UpdateReplacement(state, node, nullptr); |
1272 } | 1284 } |
1273 } | 1285 } |
1274 | 1286 |
1275 | 1287 |
1276 void EscapeAnalysis::ProcessLoadElement(Node* node) { | 1288 void EscapeAnalysis::ProcessLoadElement(Node* node) { |
1277 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); | 1289 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); |
1278 ForwardVirtualState(node); | 1290 ForwardVirtualState(node); |
1279 Node* from = NodeProperties::GetValueInput(node, 0); | 1291 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
1280 VirtualState* state = virtual_states_[node->id()]; | 1292 VirtualState* state = virtual_states_[node->id()]; |
1281 Node* index_node = node->InputAt(1); | 1293 Node* index_node = node->InputAt(1); |
1282 NumberMatcher index(index_node); | 1294 NumberMatcher index(index_node); |
1283 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && | 1295 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && |
1284 index_node->opcode() != IrOpcode::kInt64Constant && | 1296 index_node->opcode() != IrOpcode::kInt64Constant && |
1285 index_node->opcode() != IrOpcode::kFloat32Constant && | 1297 index_node->opcode() != IrOpcode::kFloat32Constant && |
1286 index_node->opcode() != IrOpcode::kFloat64Constant); | 1298 index_node->opcode() != IrOpcode::kFloat64Constant); |
1287 ElementAccess access = OpParameter<ElementAccess>(node); | 1299 ElementAccess access = OpParameter<ElementAccess>(node); |
1288 if (index.HasValue()) { | 1300 if (index.HasValue()) { |
1289 int offset = index.Value() + access.header_size / kPointerSize; | 1301 int offset = index.Value() + access.header_size / kPointerSize; |
1290 if (VirtualObject* object = ResolveVirtualObject(state, from)) { | 1302 if (VirtualObject* object = GetVirtualObject(state, from)) { |
1291 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), | 1303 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), |
1292 kPointerSizeLog2); | 1304 kPointerSizeLog2); |
1293 CHECK_EQ(access.header_size % kPointerSize, 0); | 1305 CHECK_EQ(access.header_size % kPointerSize, 0); |
1294 | 1306 |
1295 if (!object->IsTracked()) return; | 1307 if (!object->IsTracked()) return; |
1296 Node* value = object->GetField(offset); | 1308 Node* value = object->GetField(offset); |
1297 if (value) { | 1309 if (value) { |
1298 value = ResolveReplacement(value); | 1310 value = ResolveReplacement(value); |
1299 } | 1311 } |
1300 // Record that the load has this alias. | 1312 // Record that the load has this alias. |
1301 UpdateReplacement(state, node, value); | 1313 UpdateReplacement(state, node, value); |
1302 } else if (from->opcode() == IrOpcode::kPhi) { | 1314 } else if (from->opcode() == IrOpcode::kPhi) { |
1303 ElementAccess access = OpParameter<ElementAccess>(node); | 1315 ElementAccess access = OpParameter<ElementAccess>(node); |
1304 int offset = index.Value() + access.header_size / kPointerSize; | 1316 int offset = index.Value() + access.header_size / kPointerSize; |
1305 ProcessLoadFromPhi(offset, from, node, state); | 1317 ProcessLoadFromPhi(offset, from, node, state); |
| 1318 } else { |
| 1319 UpdateReplacement(state, node, nullptr); |
1306 } | 1320 } |
1307 } else { | 1321 } else { |
1308 // We have a load from a non-const index, cannot eliminate object. | 1322 // We have a load from a non-const index, cannot eliminate object. |
1309 if (SetEscaped(from)) { | 1323 if (SetEscaped(from)) { |
1310 if (FLAG_trace_turbo_escape) { | 1324 if (FLAG_trace_turbo_escape) { |
1311 PrintF( | 1325 PrintF( |
1312 "Setting #%d (%s) to escaped because store element #%d to " | 1326 "Setting #%d (%s) to escaped because load element #%d from " |
1313 "non-const " | 1327 "non-const " |
1314 "index #%d (%s)\n", | 1328 "index #%d (%s)\n", |
1315 from->id(), from->op()->mnemonic(), node->id(), index_node->id(), | 1329 from->id(), from->op()->mnemonic(), node->id(), index_node->id(), |
1316 index_node->op()->mnemonic()); | 1330 index_node->op()->mnemonic()); |
1317 } | 1331 } |
1318 } | 1332 } |
1319 } | 1333 } |
1320 } | 1334 } |
1321 | 1335 |
1322 | 1336 |
1323 void EscapeAnalysis::ProcessStoreField(Node* node) { | 1337 void EscapeAnalysis::ProcessStoreField(Node* node) { |
1324 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); | 1338 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); |
1325 ForwardVirtualState(node); | 1339 ForwardVirtualState(node); |
1326 Node* to = NodeProperties::GetValueInput(node, 0); | 1340 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
1327 Node* val = NodeProperties::GetValueInput(node, 1); | |
1328 VirtualState* state = virtual_states_[node->id()]; | 1341 VirtualState* state = virtual_states_[node->id()]; |
1329 if (VirtualObject* obj = ResolveVirtualObject(state, to)) { | 1342 VirtualObject* obj = GetVirtualObject(state, to); |
1330 if (!obj->IsTracked()) return; | 1343 if (obj && obj->IsTracked()) { |
1331 int offset = OffsetFromAccess(node); | 1344 int offset = OffsetFromAccess(node); |
1332 if (obj->SetField(offset, ResolveReplacement(val))) { | 1345 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1)); |
| 1346 if (obj->SetField(offset, val)) { |
1333 state->LastChangedAt(node); | 1347 state->LastChangedAt(node); |
1334 } | 1348 } |
1335 } | 1349 } |
1336 } | 1350 } |
1337 | 1351 |
1338 | 1352 |
1339 void EscapeAnalysis::ProcessStoreElement(Node* node) { | 1353 void EscapeAnalysis::ProcessStoreElement(Node* node) { |
1340 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); | 1354 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); |
1341 ForwardVirtualState(node); | 1355 ForwardVirtualState(node); |
1342 Node* to = NodeProperties::GetValueInput(node, 0); | 1356 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
1343 Node* index_node = node->InputAt(1); | 1357 Node* index_node = node->InputAt(1); |
1344 NumberMatcher index(index_node); | 1358 NumberMatcher index(index_node); |
1345 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && | 1359 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && |
1346 index_node->opcode() != IrOpcode::kInt64Constant && | 1360 index_node->opcode() != IrOpcode::kInt64Constant && |
1347 index_node->opcode() != IrOpcode::kFloat32Constant && | 1361 index_node->opcode() != IrOpcode::kFloat32Constant && |
1348 index_node->opcode() != IrOpcode::kFloat64Constant); | 1362 index_node->opcode() != IrOpcode::kFloat64Constant); |
1349 ElementAccess access = OpParameter<ElementAccess>(node); | 1363 ElementAccess access = OpParameter<ElementAccess>(node); |
1350 Node* val = NodeProperties::GetValueInput(node, 2); | 1364 VirtualState* state = virtual_states_[node->id()]; |
| 1365 VirtualObject* obj = GetVirtualObject(state, to); |
1351 if (index.HasValue()) { | 1366 if (index.HasValue()) { |
1352 int offset = index.Value() + access.header_size / kPointerSize; | 1367 int offset = index.Value() + access.header_size / kPointerSize; |
1353 VirtualState* states = virtual_states_[node->id()]; | 1368 if (obj && obj->IsTracked()) { |
1354 if (VirtualObject* obj = ResolveVirtualObject(states, to)) { | |
1355 if (!obj->IsTracked()) return; | |
1356 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), | 1369 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), |
1357 kPointerSizeLog2); | 1370 kPointerSizeLog2); |
1358 CHECK_EQ(access.header_size % kPointerSize, 0); | 1371 CHECK_EQ(access.header_size % kPointerSize, 0); |
1359 if (obj->SetField(offset, ResolveReplacement(val))) { | 1372 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 2)); |
1360 states->LastChangedAt(node); | 1373 if (obj->SetField(offset, val)) { |
| 1374 state->LastChangedAt(node); |
1361 } | 1375 } |
1362 } | 1376 } |
1363 } else { | 1377 } else { |
1364 // We have a store to a non-const index, cannot eliminate object. | 1378 // We have a store to a non-const index, cannot eliminate object. |
1365 if (SetEscaped(to)) { | 1379 if (SetEscaped(to)) { |
1366 if (FLAG_trace_turbo_escape) { | 1380 if (FLAG_trace_turbo_escape) { |
1367 PrintF( | 1381 PrintF( |
1368 "Setting #%d (%s) to escaped because store element #%d to " | 1382 "Setting #%d (%s) to escaped because store element #%d to " |
1369 "non-const " | 1383 "non-const " |
1370 "index #%d (%s)\n", | 1384 "index #%d (%s)\n", |
1371 to->id(), to->op()->mnemonic(), node->id(), index_node->id(), | 1385 to->id(), to->op()->mnemonic(), node->id(), index_node->id(), |
1372 index_node->op()->mnemonic()); | 1386 index_node->op()->mnemonic()); |
1373 } | 1387 } |
1374 } | 1388 } |
| 1389 if (obj && obj->IsTracked() && obj->ClearAllFields()) { |
| 1390 state->LastChangedAt(node); |
| 1391 } |
1375 } | 1392 } |
1376 } | 1393 } |
1377 | 1394 |
1378 | 1395 |
1379 Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { | 1396 Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { |
1380 if ((node->opcode() == IrOpcode::kFinishRegion || | 1397 if ((node->opcode() == IrOpcode::kFinishRegion || |
1381 node->opcode() == IrOpcode::kAllocate) && | 1398 node->opcode() == IrOpcode::kAllocate) && |
1382 IsVirtual(node)) { | 1399 IsVirtual(node)) { |
1383 if (VirtualObject* vobj = | 1400 if (VirtualObject* vobj = |
1384 ResolveVirtualObject(virtual_states_[effect->id()], node)) { | 1401 ResolveVirtualObject(virtual_states_[effect->id()], node)) { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1459 | 1476 |
1460 | 1477 |
1461 VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state, | 1478 VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state, |
1462 Node* node) { | 1479 Node* node) { |
1463 if (node->id() >= aliases_.size()) return nullptr; | 1480 if (node->id() >= aliases_.size()) return nullptr; |
1464 Alias alias = aliases_[node->id()]; | 1481 Alias alias = aliases_[node->id()]; |
1465 if (alias >= state->size()) return nullptr; | 1482 if (alias >= state->size()) return nullptr; |
1466 return state->VirtualObjectFromAlias(alias); | 1483 return state->VirtualObjectFromAlias(alias); |
1467 } | 1484 } |
1468 | 1485 |
| 1486 |
| 1487 bool EscapeAnalysis::ExistsVirtualAllocate() { |
| 1488 for (size_t id = 0; id < aliases_.size(); ++id) { |
| 1489 Alias alias = aliases_[id]; |
| 1490 if (alias < kUntrackable) { |
| 1491 if (escape_status_.IsVirtual(static_cast<int>(id))) { |
| 1492 return true; |
| 1493 } |
| 1494 } |
| 1495 } |
| 1496 return false; |
| 1497 } |
| 1498 |
1469 } // namespace compiler | 1499 } // namespace compiler |
1470 } // namespace internal | 1500 } // namespace internal |
1471 } // namespace v8 | 1501 } // namespace v8 |
OLD | NEW |