| 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 |