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 |