Chromium Code Reviews| 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; | |
| 734 RunObjectAnalysis(); | 753 RunObjectAnalysis(); |
| 735 escape_status_.Run(); | 754 escape_status_.Run(); |
| 736 } | 755 } |
| 737 | 756 |
| 738 | 757 |
| 739 void EscapeAnalysis::AssignAliases() { | 758 void EscapeAnalysis::AssignAliases() { |
| 740 ZoneVector<Node*> stack(zone()); | 759 ZoneVector<Node*> stack(zone()); |
| 741 stack.push_back(graph()->end()); | 760 stack.push_back(graph()->end()); |
| 742 CHECK_LT(graph()->NodeCount(), kUntrackable); | 761 CHECK_LT(graph()->NodeCount(), kUntrackable); |
| 743 aliases_.resize(graph()->NodeCount(), kNotReachable); | 762 aliases_.resize(graph()->NodeCount(), kNotReachable); |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1035 mergeState->LastChangedAt(node); | 1054 mergeState->LastChangedAt(node); |
| 1036 escape_status_.Resize(); | 1055 escape_status_.Resize(); |
| 1037 } | 1056 } |
| 1038 return changed; | 1057 return changed; |
| 1039 } | 1058 } |
| 1040 | 1059 |
| 1041 | 1060 |
| 1042 void EscapeAnalysis::ProcessAllocation(Node* node) { | 1061 void EscapeAnalysis::ProcessAllocation(Node* node) { |
| 1043 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 1062 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
| 1044 ForwardVirtualState(node); | 1063 ForwardVirtualState(node); |
| 1064 VirtualState* state = virtual_states_[node->id()]; | |
| 1065 Alias alias = aliases_[node->id()]; | |
| 1045 | 1066 |
| 1046 // Check if we have already processed this node. | 1067 // Check if we have already processed this node. |
| 1047 if (virtual_states_[node->id()]->VirtualObjectFromAlias( | 1068 if (state->VirtualObjectFromAlias(alias)) { |
| 1048 aliases_[node->id()])) { | |
| 1049 return; | 1069 return; |
| 1050 } | 1070 } |
| 1051 | 1071 |
| 1052 NumberMatcher size(node->InputAt(0)); | 1072 NumberMatcher size(node->InputAt(0)); |
| 1053 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && | 1073 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && |
| 1054 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && | 1074 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && |
| 1055 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && | 1075 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && |
| 1056 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); | 1076 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); |
| 1057 if (size.HasValue()) { | 1077 if (size.HasValue()) { |
| 1058 virtual_states_[node->id()]->SetVirtualObject( | 1078 state->SetVirtualObject( |
| 1059 aliases_[node->id()], | 1079 alias, new (zone()) VirtualObject(node->id(), zone(), |
| 1060 new (zone()) | 1080 size.Value() / kPointerSize)); |
| 1061 VirtualObject(node->id(), zone(), size.Value() / kPointerSize)); | |
| 1062 } else { | 1081 } else { |
| 1063 virtual_states_[node->id()]->SetVirtualObject( | 1082 state->SetVirtualObject(alias, |
| 1064 aliases_[node->id()], new (zone()) VirtualObject(node->id(), zone())); | 1083 new (zone()) VirtualObject(node->id(), zone())); |
| 1065 } | 1084 } |
| 1066 virtual_states_[node->id()]->LastChangedAt(node); | 1085 state->LastChangedAt(node); |
| 1067 } | 1086 } |
| 1068 | 1087 |
| 1069 | 1088 |
| 1070 void EscapeAnalysis::ProcessFinishRegion(Node* node) { | 1089 void EscapeAnalysis::ProcessFinishRegion(Node* node) { |
| 1071 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); | 1090 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); |
| 1072 ForwardVirtualState(node); | 1091 ForwardVirtualState(node); |
| 1073 Node* allocation = NodeProperties::GetValueInput(node, 0); | 1092 Node* allocation = NodeProperties::GetValueInput(node, 0); |
| 1074 if (allocation->opcode() == IrOpcode::kAllocate) { | 1093 if (allocation->opcode() == IrOpcode::kAllocate) { |
| 1075 VirtualState* state = virtual_states_[node->id()]; | 1094 VirtualState* state = virtual_states_[node->id()]; |
| 1076 if (!state->VirtualObjectFromAlias(aliases_[node->id()])) { | 1095 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) { | 1190 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { |
| 1172 if (VirtualState* states = virtual_states_[at->id()]) { | 1191 if (VirtualState* states = virtual_states_[at->id()]) { |
| 1173 return states->VirtualObjectFromAlias(aliases_[id]); | 1192 return states->VirtualObjectFromAlias(aliases_[id]); |
| 1174 } | 1193 } |
| 1175 return nullptr; | 1194 return nullptr; |
| 1176 } | 1195 } |
| 1177 | 1196 |
| 1178 | 1197 |
| 1179 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, | 1198 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, |
| 1180 Node* node) { | 1199 Node* node) { |
| 1181 VirtualObject* obj = GetVirtualObject(state, ResolveReplacement(node)); | 1200 return GetVirtualObject(state, ResolveReplacement(node)); |
|
sigurds
2016/01/18 12:13:17
The loop is not necessary since we rely on aliases
| |
| 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 } | 1201 } |
| 1191 | 1202 |
| 1192 | 1203 |
| 1193 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { | 1204 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { |
| 1194 DCHECK(IsVirtual(left) && IsVirtual(right)); | 1205 DCHECK(IsVirtual(left) && IsVirtual(right)); |
| 1195 left = ResolveReplacement(left); | 1206 left = ResolveReplacement(left); |
| 1196 right = ResolveReplacement(right); | 1207 right = ResolveReplacement(right); |
| 1197 if (IsEquivalentPhi(left, right)) { | 1208 if (IsEquivalentPhi(left, right)) { |
| 1198 return true; | 1209 return true; |
| 1199 } | 1210 } |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1244 } | 1255 } |
| 1245 } else if (FLAG_trace_turbo_escape) { | 1256 } else if (FLAG_trace_turbo_escape) { |
| 1246 PrintF(" has incomplete virtual object info.\n"); | 1257 PrintF(" has incomplete virtual object info.\n"); |
| 1247 } | 1258 } |
| 1248 } | 1259 } |
| 1249 | 1260 |
| 1250 | 1261 |
| 1251 void EscapeAnalysis::ProcessLoadField(Node* node) { | 1262 void EscapeAnalysis::ProcessLoadField(Node* node) { |
| 1252 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); | 1263 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); |
| 1253 ForwardVirtualState(node); | 1264 ForwardVirtualState(node); |
| 1254 Node* from = NodeProperties::GetValueInput(node, 0); | 1265 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1255 VirtualState* state = virtual_states_[node->id()]; | 1266 VirtualState* state = virtual_states_[node->id()]; |
| 1256 if (VirtualObject* object = ResolveVirtualObject(state, from)) { | 1267 if (VirtualObject* object = GetVirtualObject(state, from)) { |
| 1257 int offset = OffsetFromAccess(node); | 1268 int offset = OffsetFromAccess(node); |
| 1258 if (!object->IsTracked()) return; | 1269 if (!object->IsTracked()) return; |
| 1259 Node* value = object->GetField(offset); | 1270 Node* value = object->GetField(offset); |
| 1260 if (value) { | 1271 if (value) { |
| 1261 value = ResolveReplacement(value); | 1272 value = ResolveReplacement(value); |
| 1262 } | 1273 } |
| 1263 // Record that the load has this alias. | 1274 // Record that the load has this alias. |
| 1264 UpdateReplacement(state, node, value); | 1275 UpdateReplacement(state, node, value); |
| 1265 } else { | 1276 } else if (from->opcode() == IrOpcode::kPhi && |
| 1266 if (from->opcode() == IrOpcode::kPhi && | 1277 OpParameter<FieldAccess>(node).offset % kPointerSize == 0) { |
| 1267 OpParameter<FieldAccess>(node).offset % kPointerSize == 0) { | |
| 1268 int offset = OffsetFromAccess(node); | 1278 int offset = OffsetFromAccess(node); |
| 1269 // Only binary phis are supported for now. | 1279 // Only binary phis are supported for now. |
| 1270 ProcessLoadFromPhi(offset, from, node, state); | 1280 ProcessLoadFromPhi(offset, from, node, state); |
| 1271 } | 1281 } else { |
| 1282 UpdateReplacement(state, node, nullptr); | |
| 1272 } | 1283 } |
| 1273 } | 1284 } |
| 1274 | 1285 |
| 1275 | 1286 |
| 1276 void EscapeAnalysis::ProcessLoadElement(Node* node) { | 1287 void EscapeAnalysis::ProcessLoadElement(Node* node) { |
| 1277 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); | 1288 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); |
| 1278 ForwardVirtualState(node); | 1289 ForwardVirtualState(node); |
| 1279 Node* from = NodeProperties::GetValueInput(node, 0); | 1290 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1280 VirtualState* state = virtual_states_[node->id()]; | 1291 VirtualState* state = virtual_states_[node->id()]; |
| 1281 Node* index_node = node->InputAt(1); | 1292 Node* index_node = node->InputAt(1); |
| 1282 NumberMatcher index(index_node); | 1293 NumberMatcher index(index_node); |
| 1283 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && | 1294 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && |
| 1284 index_node->opcode() != IrOpcode::kInt64Constant && | 1295 index_node->opcode() != IrOpcode::kInt64Constant && |
| 1285 index_node->opcode() != IrOpcode::kFloat32Constant && | 1296 index_node->opcode() != IrOpcode::kFloat32Constant && |
| 1286 index_node->opcode() != IrOpcode::kFloat64Constant); | 1297 index_node->opcode() != IrOpcode::kFloat64Constant); |
| 1287 ElementAccess access = OpParameter<ElementAccess>(node); | 1298 ElementAccess access = OpParameter<ElementAccess>(node); |
| 1288 if (index.HasValue()) { | 1299 if (index.HasValue()) { |
| 1289 int offset = index.Value() + access.header_size / kPointerSize; | 1300 int offset = index.Value() + access.header_size / kPointerSize; |
| 1290 if (VirtualObject* object = ResolveVirtualObject(state, from)) { | 1301 if (VirtualObject* object = GetVirtualObject(state, from)) { |
| 1291 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), | 1302 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), |
| 1292 kPointerSizeLog2); | 1303 kPointerSizeLog2); |
| 1293 CHECK_EQ(access.header_size % kPointerSize, 0); | 1304 CHECK_EQ(access.header_size % kPointerSize, 0); |
| 1294 | 1305 |
| 1295 if (!object->IsTracked()) return; | 1306 if (!object->IsTracked()) return; |
| 1296 Node* value = object->GetField(offset); | 1307 Node* value = object->GetField(offset); |
| 1297 if (value) { | 1308 if (value) { |
| 1298 value = ResolveReplacement(value); | 1309 value = ResolveReplacement(value); |
| 1299 } | 1310 } |
| 1300 // Record that the load has this alias. | 1311 // Record that the load has this alias. |
| 1301 UpdateReplacement(state, node, value); | 1312 UpdateReplacement(state, node, value); |
| 1302 } else if (from->opcode() == IrOpcode::kPhi) { | 1313 } else if (from->opcode() == IrOpcode::kPhi) { |
| 1303 ElementAccess access = OpParameter<ElementAccess>(node); | 1314 ElementAccess access = OpParameter<ElementAccess>(node); |
| 1304 int offset = index.Value() + access.header_size / kPointerSize; | 1315 int offset = index.Value() + access.header_size / kPointerSize; |
| 1305 ProcessLoadFromPhi(offset, from, node, state); | 1316 ProcessLoadFromPhi(offset, from, node, state); |
| 1317 } else { | |
| 1318 UpdateReplacement(state, node, nullptr); | |
|
sigurds
2016/01/18 12:13:17
This is a critical bug-fix
| |
| 1306 } | 1319 } |
| 1307 } else { | 1320 } else { |
| 1308 // We have a load from a non-const index, cannot eliminate object. | 1321 // We have a load from a non-const index, cannot eliminate object. |
| 1309 if (SetEscaped(from)) { | 1322 if (SetEscaped(from)) { |
| 1310 if (FLAG_trace_turbo_escape) { | 1323 if (FLAG_trace_turbo_escape) { |
| 1311 PrintF( | 1324 PrintF( |
| 1312 "Setting #%d (%s) to escaped because store element #%d to " | 1325 "Setting #%d (%s) to escaped because load element #%d from " |
| 1313 "non-const " | 1326 "non-const " |
| 1314 "index #%d (%s)\n", | 1327 "index #%d (%s)\n", |
| 1315 from->id(), from->op()->mnemonic(), node->id(), index_node->id(), | 1328 from->id(), from->op()->mnemonic(), node->id(), index_node->id(), |
| 1316 index_node->op()->mnemonic()); | 1329 index_node->op()->mnemonic()); |
| 1317 } | 1330 } |
| 1318 } | 1331 } |
| 1319 } | 1332 } |
| 1320 } | 1333 } |
| 1321 | 1334 |
| 1322 | 1335 |
| 1323 void EscapeAnalysis::ProcessStoreField(Node* node) { | 1336 void EscapeAnalysis::ProcessStoreField(Node* node) { |
| 1324 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); | 1337 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); |
| 1325 ForwardVirtualState(node); | 1338 ForwardVirtualState(node); |
| 1326 Node* to = NodeProperties::GetValueInput(node, 0); | 1339 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1327 Node* val = NodeProperties::GetValueInput(node, 1); | |
| 1328 VirtualState* state = virtual_states_[node->id()]; | 1340 VirtualState* state = virtual_states_[node->id()]; |
| 1329 if (VirtualObject* obj = ResolveVirtualObject(state, to)) { | 1341 VirtualObject* obj = GetVirtualObject(state, to); |
| 1330 if (!obj->IsTracked()) return; | 1342 if (obj && obj->IsTracked()) { |
| 1331 int offset = OffsetFromAccess(node); | 1343 int offset = OffsetFromAccess(node); |
| 1332 if (obj->SetField(offset, ResolveReplacement(val))) { | 1344 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1)); |
| 1345 if (obj->SetField(offset, val)) { | |
| 1333 state->LastChangedAt(node); | 1346 state->LastChangedAt(node); |
| 1334 } | 1347 } |
| 1335 } | 1348 } |
| 1336 } | 1349 } |
| 1337 | 1350 |
| 1338 | 1351 |
| 1339 void EscapeAnalysis::ProcessStoreElement(Node* node) { | 1352 void EscapeAnalysis::ProcessStoreElement(Node* node) { |
| 1340 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); | 1353 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); |
| 1341 ForwardVirtualState(node); | 1354 ForwardVirtualState(node); |
| 1342 Node* to = NodeProperties::GetValueInput(node, 0); | 1355 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1343 Node* index_node = node->InputAt(1); | 1356 Node* index_node = node->InputAt(1); |
| 1344 NumberMatcher index(index_node); | 1357 NumberMatcher index(index_node); |
| 1345 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && | 1358 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && |
| 1346 index_node->opcode() != IrOpcode::kInt64Constant && | 1359 index_node->opcode() != IrOpcode::kInt64Constant && |
| 1347 index_node->opcode() != IrOpcode::kFloat32Constant && | 1360 index_node->opcode() != IrOpcode::kFloat32Constant && |
| 1348 index_node->opcode() != IrOpcode::kFloat64Constant); | 1361 index_node->opcode() != IrOpcode::kFloat64Constant); |
| 1349 ElementAccess access = OpParameter<ElementAccess>(node); | 1362 ElementAccess access = OpParameter<ElementAccess>(node); |
| 1350 Node* val = NodeProperties::GetValueInput(node, 2); | |
| 1351 if (index.HasValue()) { | 1363 if (index.HasValue()) { |
| 1352 int offset = index.Value() + access.header_size / kPointerSize; | 1364 int offset = index.Value() + access.header_size / kPointerSize; |
| 1353 VirtualState* states = virtual_states_[node->id()]; | 1365 VirtualState* state = virtual_states_[node->id()]; |
| 1354 if (VirtualObject* obj = ResolveVirtualObject(states, to)) { | 1366 VirtualObject* obj = GetVirtualObject(state, to); |
| 1355 if (!obj->IsTracked()) return; | 1367 if (obj && obj->IsTracked()) { |
| 1356 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), | 1368 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), |
| 1357 kPointerSizeLog2); | 1369 kPointerSizeLog2); |
| 1358 CHECK_EQ(access.header_size % kPointerSize, 0); | 1370 CHECK_EQ(access.header_size % kPointerSize, 0); |
| 1359 if (obj->SetField(offset, ResolveReplacement(val))) { | 1371 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 2)); |
| 1360 states->LastChangedAt(node); | 1372 if (obj->SetField(offset, val)) { |
| 1373 state->LastChangedAt(node); | |
| 1361 } | 1374 } |
| 1362 } | 1375 } |
| 1363 } else { | 1376 } else { |
| 1364 // We have a store to a non-const index, cannot eliminate object. | 1377 // We have a store to a non-const index, cannot eliminate object. |
| 1365 if (SetEscaped(to)) { | 1378 if (SetEscaped(to)) { |
| 1366 if (FLAG_trace_turbo_escape) { | 1379 if (FLAG_trace_turbo_escape) { |
| 1367 PrintF( | 1380 PrintF( |
| 1368 "Setting #%d (%s) to escaped because store element #%d to " | 1381 "Setting #%d (%s) to escaped because store element #%d to " |
| 1369 "non-const " | 1382 "non-const " |
| 1370 "index #%d (%s)\n", | 1383 "index #%d (%s)\n", |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1459 | 1472 |
| 1460 | 1473 |
| 1461 VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state, | 1474 VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state, |
| 1462 Node* node) { | 1475 Node* node) { |
| 1463 if (node->id() >= aliases_.size()) return nullptr; | 1476 if (node->id() >= aliases_.size()) return nullptr; |
| 1464 Alias alias = aliases_[node->id()]; | 1477 Alias alias = aliases_[node->id()]; |
| 1465 if (alias >= state->size()) return nullptr; | 1478 if (alias >= state->size()) return nullptr; |
| 1466 return state->VirtualObjectFromAlias(alias); | 1479 return state->VirtualObjectFromAlias(alias); |
| 1467 } | 1480 } |
| 1468 | 1481 |
| 1482 | |
| 1483 bool EscapeAnalysis::ExistsVirtualAllocate() { | |
| 1484 for (size_t id = 0; id < aliases_.size(); ++id) { | |
| 1485 Alias alias = aliases_[id]; | |
| 1486 if (alias < kUntrackable) { | |
| 1487 if (escape_status_.IsVirtual(static_cast<int>(id))) { | |
| 1488 return true; | |
| 1489 } | |
| 1490 } | |
| 1491 } | |
| 1492 return false; | |
| 1493 } | |
| 1494 | |
| 1469 } // namespace compiler | 1495 } // namespace compiler |
| 1470 } // namespace internal | 1496 } // namespace internal |
| 1471 } // namespace v8 | 1497 } // namespace v8 |
| OLD | NEW |