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