LCOV - code coverage report
Current view: top level - src/compiler - load-elimination.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 475 536 88.6 %
Date: 2019-02-19 Functions: 48 65 73.8 %

          Line data    Source code
       1             : // Copyright 2016 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/compiler/load-elimination.h"
       6             : 
       7             : #include "src/compiler/access-builder.h"
       8             : #include "src/compiler/common-operator.h"
       9             : #include "src/compiler/js-graph.h"
      10             : #include "src/compiler/node-properties.h"
      11             : #include "src/compiler/simplified-operator.h"
      12             : #include "src/heap/factory.h"
      13             : #include "src/objects-inl.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : namespace compiler {
      18             : 
      19             : namespace {
      20             : 
      21   341107977 : bool IsRename(Node* node) {
      22   341107977 :   switch (node->opcode()) {
      23             :     case IrOpcode::kCheckHeapObject:
      24             :     case IrOpcode::kFinishRegion:
      25             :     case IrOpcode::kTypeGuard:
      26      840627 :       return !node->IsDead();
      27             :     default:
      28             :       return false;
      29             :   }
      30             : }
      31             : 
      32   338957497 : Node* ResolveRenames(Node* node) {
      33   678376211 :   while (IsRename(node)) {
      34             :     node = node->InputAt(0);
      35             :   }
      36   338957497 :   return node;
      37             : }
      38             : 
      39     2779629 : bool MayAlias(Node* a, Node* b) {
      40     1825575 :   if (a != b) {
      41     1164503 :     if (!NodeProperties::GetType(a).Maybe(NodeProperties::GetType(b))) {
      42             :       return false;
      43      856437 :     } else if (IsRename(b)) {
      44       23611 :       return MayAlias(a, b->InputAt(0));
      45      832826 :     } else if (IsRename(a)) {
      46      355799 :       return MayAlias(a->InputAt(0), b);
      47      477027 :     } else if (b->opcode() == IrOpcode::kAllocate) {
      48       65194 :       switch (a->opcode()) {
      49             :         case IrOpcode::kAllocate:
      50             :         case IrOpcode::kHeapConstant:
      51             :         case IrOpcode::kParameter:
      52             :           return false;
      53             :         default:
      54             :           break;
      55             :       }
      56             :     } else if (a->opcode() == IrOpcode::kAllocate) {
      57      134889 :       switch (b->opcode()) {
      58             :         case IrOpcode::kHeapConstant:
      59             :         case IrOpcode::kParameter:
      60             :           return false;
      61             :         default:
      62             :           break;
      63             :       }
      64             :     }
      65             :   }
      66             :   return true;
      67             : }
      68             : 
      69             : bool MustAlias(Node* a, Node* b) {
      70   169310955 :   return ResolveRenames(a) == ResolveRenames(b);
      71             : }
      72             : 
      73             : }  // namespace
      74             : 
      75    75651332 : Reduction LoadElimination::Reduce(Node* node) {
      76    37825666 :   if (FLAG_trace_turbo_load_elimination) {
      77           0 :     if (node->op()->EffectInputCount() > 0) {
      78           0 :       PrintF(" visit #%d:%s", node->id(), node->op()->mnemonic());
      79           0 :       if (node->op()->ValueInputCount() > 0) {
      80           0 :         PrintF("(");
      81           0 :         for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
      82           0 :           if (i > 0) PrintF(", ");
      83           0 :           Node* const value = NodeProperties::GetValueInput(node, i);
      84           0 :           PrintF("#%d:%s", value->id(), value->op()->mnemonic());
      85             :         }
      86           0 :         PrintF(")");
      87             :       }
      88           0 :       PrintF("\n");
      89           0 :       for (int i = 0; i < node->op()->EffectInputCount(); ++i) {
      90           0 :         Node* const effect = NodeProperties::GetEffectInput(node, i);
      91           0 :         if (AbstractState const* const state = node_states_.Get(effect)) {
      92             :           PrintF("  state[%i]: #%d:%s\n", i, effect->id(),
      93           0 :                  effect->op()->mnemonic());
      94           0 :           state->Print();
      95             :         } else {
      96             :           PrintF("  no state[%i]: #%d:%s\n", i, effect->id(),
      97           0 :                  effect->op()->mnemonic());
      98             :         }
      99             :       }
     100             :     }
     101             :   }
     102    37825666 :   switch (node->opcode()) {
     103             :     case IrOpcode::kMapGuard:
     104        8426 :       return ReduceMapGuard(node);
     105             :     case IrOpcode::kCheckMaps:
     106      187559 :       return ReduceCheckMaps(node);
     107             :     case IrOpcode::kCompareMaps:
     108        9006 :       return ReduceCompareMaps(node);
     109             :     case IrOpcode::kEnsureWritableFastElements:
     110        9443 :       return ReduceEnsureWritableFastElements(node);
     111             :     case IrOpcode::kMaybeGrowFastElements:
     112       12923 :       return ReduceMaybeGrowFastElements(node);
     113             :     case IrOpcode::kTransitionElementsKind:
     114         958 :       return ReduceTransitionElementsKind(node);
     115             :     case IrOpcode::kLoadField:
     116     1576079 :       return ReduceLoadField(node, FieldAccessOf(node->op()));
     117             :     case IrOpcode::kStoreField:
     118     2406582 :       return ReduceStoreField(node, FieldAccessOf(node->op()));
     119             :     case IrOpcode::kStoreMessage:
     120       57506 :       return ReduceStoreField(node, AccessBuilder::ForExternalIntPtr());
     121             :     case IrOpcode::kLoadMessage:
     122       51733 :       return ReduceLoadField(node, AccessBuilder::ForExternalIntPtr());
     123             :     case IrOpcode::kLoadElement:
     124       35142 :       return ReduceLoadElement(node);
     125             :     case IrOpcode::kStoreElement:
     126       59234 :       return ReduceStoreElement(node);
     127             :     case IrOpcode::kTransitionAndStoreElement:
     128         565 :       return ReduceTransitionAndStoreElement(node);
     129             :     case IrOpcode::kStoreTypedElement:
     130        5789 :       return ReduceStoreTypedElement(node);
     131             :     case IrOpcode::kEffectPhi:
     132      618888 :       return ReduceEffectPhi(node);
     133             :     case IrOpcode::kDead:
     134             :       break;
     135             :     case IrOpcode::kStart:
     136             :       return ReduceStart(node);
     137             :     default:
     138    32317213 :       return ReduceOtherNode(node);
     139             :   }
     140             :   return NoChange();
     141             : }
     142             : 
     143             : namespace {
     144             : 
     145        1603 : bool IsCompatible(MachineRepresentation r1, MachineRepresentation r2) {
     146        1603 :   if (r1 == r2) return true;
     147         232 :   return IsAnyTagged(r1) && IsAnyTagged(r2);
     148             : }
     149             : 
     150             : }  // namespace
     151             : 
     152       37522 : Node* LoadElimination::AbstractElements::Lookup(
     153             :     Node* object, Node* index, MachineRepresentation representation) const {
     154      327374 :   for (Element const element : elements_) {
     155      291448 :     if (element.object == nullptr) continue;
     156             :     DCHECK_NOT_NULL(element.index);
     157             :     DCHECK_NOT_NULL(element.value);
     158      238167 :     if (MustAlias(object, element.object) && MustAlias(index, element.index) &&
     159        1603 :         IsCompatible(representation, element.representation)) {
     160             :       return element.value;
     161             :     }
     162             :   }
     163             :   return nullptr;
     164             : }
     165             : 
     166             : LoadElimination::AbstractElements const*
     167       33774 : LoadElimination::AbstractElements::Kill(Node* object, Node* index,
     168             :                                         Zone* zone) const {
     169       64424 :   for (Element const element : this->elements_) {
     170       61129 :     if (element.object == nullptr) continue;
     171       38707 :     if (MayAlias(object, element.object)) {
     172       30479 :       AbstractElements* that = new (zone) AbstractElements(zone);
     173      274311 :       for (Element const element : this->elements_) {
     174      243832 :         if (element.object == nullptr) continue;
     175             :         DCHECK_NOT_NULL(element.index);
     176             :         DCHECK_NOT_NULL(element.value);
     177      336738 :         if (!MayAlias(object, element.object) ||
     178             :             !NodeProperties::GetType(index).Maybe(
     179      322018 :                 NodeProperties::GetType(element.index))) {
     180      103560 :           that->elements_[that->next_index_++] = element;
     181             :         }
     182             :       }
     183       30479 :       that->next_index_ %= arraysize(elements_);
     184             :       return that;
     185             :     }
     186             :   }
     187        3295 :   return this;
     188             : }
     189             : 
     190       13789 : bool LoadElimination::AbstractElements::Equals(
     191             :     AbstractElements const* that) const {
     192       13789 :   if (this == that) return true;
     193       34406 :   for (size_t i = 0; i < arraysize(elements_); ++i) {
     194       35645 :     Element this_element = this->elements_[i];
     195       35645 :     if (this_element.object == nullptr) continue;
     196       16060 :     for (size_t j = 0;; ++j) {
     197       22631 :       if (j == arraysize(elements_)) return false;
     198       21392 :       Element that_element = that->elements_[j];
     199       21392 :       if (this_element.object == that_element.object &&
     200        5339 :           this_element.index == that_element.index &&
     201             :           this_element.value == that_element.value) {
     202             :         break;
     203             :       }
     204       16060 :     }
     205             :   }
     206       27982 :   for (size_t i = 0; i < arraysize(elements_); ++i) {
     207       28809 :     Element that_element = that->elements_[i];
     208       28809 :     if (that_element.object == nullptr) continue;
     209        9673 :     for (size_t j = 0;; ++j) {
     210       14788 :       if (j == arraysize(elements_)) return false;
     211       13961 :       Element this_element = this->elements_[j];
     212       13961 :       if (that_element.object == this_element.object &&
     213        4288 :           that_element.index == this_element.index &&
     214             :           that_element.value == this_element.value) {
     215             :         break;
     216             :       }
     217        9673 :     }
     218             :   }
     219             :   return true;
     220             : }
     221             : 
     222             : LoadElimination::AbstractElements const*
     223        7221 : LoadElimination::AbstractElements::Merge(AbstractElements const* that,
     224             :                                          Zone* zone) const {
     225        7221 :   if (this->Equals(that)) return this;
     226        1543 :   AbstractElements* copy = new (zone) AbstractElements(zone);
     227       13887 :   for (Element const this_element : this->elements_) {
     228       12344 :     if (this_element.object == nullptr) continue;
     229       15195 :     for (Element const that_element : that->elements_) {
     230       13756 :       if (this_element.object == that_element.object &&
     231         946 :           this_element.index == that_element.index &&
     232             :           this_element.value == that_element.value) {
     233         939 :         copy->elements_[copy->next_index_++] = this_element;
     234         939 :         break;
     235             :       }
     236             :     }
     237             :   }
     238        1543 :   copy->next_index_ %= arraysize(elements_);
     239        1543 :   return copy;
     240             : }
     241             : 
     242           0 : void LoadElimination::AbstractElements::Print() const {
     243           0 :   for (Element const& element : elements_) {
     244           0 :     if (element.object) {
     245             :       PrintF("    #%d:%s @ #%d:%s -> #%d:%s\n", element.object->id(),
     246             :              element.object->op()->mnemonic(), element.index->id(),
     247             :              element.index->op()->mnemonic(), element.value->id(),
     248           0 :              element.value->op()->mnemonic());
     249             :     }
     250             :   }
     251           0 : }
     252             : 
     253      766280 : Node* LoadElimination::AbstractField::Lookup(Node* object) const {
     254   170365206 :   for (auto pair : info_for_node_) {
     255   169074391 :     if (pair.first->IsDead()) continue;
     256   169074391 :     if (MustAlias(object, pair.first)) return pair.second.value;
     257             :   }
     258             :   return nullptr;
     259             : }
     260             : 
     261             : namespace {
     262             : 
     263             : bool MayAlias(MaybeHandle<Name> x, MaybeHandle<Name> y) {
     264      510711 :   if (!x.address()) return true;
     265      296305 :   if (!y.address()) return true;
     266      226639 :   if (x.address() != y.address()) return false;
     267             :   return true;
     268             : }
     269             : 
     270             : }  // namespace
     271             : 
     272             : class LoadElimination::AliasStateInfo {
     273             :  public:
     274             :   AliasStateInfo(const AbstractState* state, Node* object, Handle<Map> map)
     275        1332 :       : state_(state), object_(object), map_(map) {}
     276             :   AliasStateInfo(const AbstractState* state, Node* object)
     277     2322148 :       : state_(state), object_(object) {}
     278             : 
     279             :   bool MayAlias(Node* other) const;
     280             : 
     281             :  private:
     282             :   const AbstractState* state_;
     283             :   Node* object_;
     284             :   MaybeHandle<Map> map_;
     285             : };
     286             : 
     287    26336468 : LoadElimination::AbstractField const* LoadElimination::AbstractField::Kill(
     288             :     const AliasStateInfo& alias_info, MaybeHandle<Name> name,
     289             :     Zone* zone) const {
     290   265223563 :   for (auto pair : this->info_for_node_) {
     291   213055368 :     if (pair.first->IsDead()) continue;
     292   213055368 :     if (alias_info.MayAlias(pair.first)) {
     293             :       AbstractField* that = new (zone) AbstractField(zone);
     294     1775060 :       for (auto pair : this->info_for_node_) {
     295     1276289 :         if (!alias_info.MayAlias(pair.first) ||
     296             :             !MayAlias(name, pair.second.name)) {
     297             :           that->info_for_node_.insert(pair);
     298             :         }
     299             :       }
     300             :       return that;
     301             :     }
     302             :   }
     303             :   return this;
     304             : }
     305             : 
     306           0 : void LoadElimination::AbstractField::Print() const {
     307           0 :   for (auto pair : info_for_node_) {
     308             :     PrintF("    #%d:%s -> #%d:%s\n", pair.first->id(),
     309             :            pair.first->op()->mnemonic(), pair.second.value->id(),
     310           0 :            pair.second.value->op()->mnemonic());
     311             :   }
     312           0 : }
     313             : 
     314           0 : LoadElimination::AbstractMaps::AbstractMaps(Zone* zone)
     315           0 :     : info_for_node_(zone) {}
     316             : 
     317      115874 : LoadElimination::AbstractMaps::AbstractMaps(Node* object,
     318             :                                             ZoneHandleSet<Map> maps, Zone* zone)
     319             :     : info_for_node_(zone) {
     320      115874 :   object = ResolveRenames(object);
     321      231750 :   info_for_node_.insert(std::make_pair(object, maps));
     322      115875 : }
     323             : 
     324       96733 : bool LoadElimination::AbstractMaps::Lookup(
     325             :     Node* object, ZoneHandleSet<Map>* object_maps) const {
     326      193466 :   auto it = info_for_node_.find(ResolveRenames(object));
     327       96733 :   if (it == info_for_node_.end()) return false;
     328       47950 :   *object_maps = it->second;
     329       47950 :   return true;
     330             : }
     331             : 
     332       95663 : LoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Kill(
     333             :     const AliasStateInfo& alias_info, Zone* zone) const {
     334    28334889 :   for (auto pair : this->info_for_node_) {
     335    28166273 :     if (alias_info.MayAlias(pair.first)) {
     336             :       AbstractMaps* that = new (zone) AbstractMaps(zone);
     337       78670 :       for (auto pair : this->info_for_node_) {
     338       33250 :         if (!alias_info.MayAlias(pair.first)) that->info_for_node_.insert(pair);
     339             :       }
     340             :       return that;
     341             :     }
     342             :   }
     343             :   return this;
     344             : }
     345             : 
     346       33193 : LoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Merge(
     347             :     AbstractMaps const* that, Zone* zone) const {
     348       33193 :   if (this->Equals(that)) return this;
     349             :   AbstractMaps* copy = new (zone) AbstractMaps(zone);
     350       36315 :   for (auto this_it : this->info_for_node_) {
     351       16239 :     Node* this_object = this_it.first;
     352       16239 :     ZoneHandleSet<Map> this_maps = this_it.second;
     353             :     auto that_it = that->info_for_node_.find(this_object);
     354       16239 :     if (that_it != that->info_for_node_.end() && that_it->second == this_maps) {
     355             :       copy->info_for_node_.insert(this_it);
     356             :     }
     357             :   }
     358       10038 :   return copy;
     359             : }
     360             : 
     361      122980 : LoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Extend(
     362             :     Node* object, ZoneHandleSet<Map> maps, Zone* zone) const {
     363             :   AbstractMaps* that = new (zone) AbstractMaps(zone);
     364             :   that->info_for_node_ = this->info_for_node_;
     365      122980 :   object = ResolveRenames(object);
     366      122980 :   that->info_for_node_[object] = maps;
     367      122980 :   return that;
     368             : }
     369             : 
     370           0 : void LoadElimination::AbstractMaps::Print() const {
     371             :   AllowHandleDereference allow_handle_dereference;
     372           0 :   StdoutStream os;
     373           0 :   for (auto pair : info_for_node_) {
     374           0 :     os << "    #" << pair.first->id() << ":" << pair.first->op()->mnemonic()
     375             :        << std::endl;
     376             :     ZoneHandleSet<Map> const& maps = pair.second;
     377           0 :     for (size_t i = 0; i < maps.size(); ++i) {
     378           0 :       os << "     - " << Brief(*maps[i]) << std::endl;
     379             :     }
     380           0 :   }
     381           0 : }
     382             : 
     383       54965 : bool LoadElimination::AbstractState::Equals(AbstractState const* that) const {
     384       54965 :   if (this->elements_) {
     385        6582 :     if (!that->elements_ || !that->elements_->Equals(this->elements_)) {
     386             :       return false;
     387             :     }
     388       48383 :   } else if (that->elements_) {
     389             :     return false;
     390             :   }
     391     1705650 :   for (size_t i = 0u; i < arraysize(fields_); ++i) {
     392     1706823 :     AbstractField const* this_field = this->fields_[i];
     393     1706823 :     AbstractField const* that_field = that->fields_[i];
     394     1706823 :     if (this_field) {
     395      126804 :       if (!that_field || !that_field->Equals(this_field)) return false;
     396     1643420 :     } else if (that_field) {
     397             :       return false;
     398             :     }
     399             :   }
     400       53255 :   if (this->maps_) {
     401       35260 :     if (!that->maps_ || !that->maps_->Equals(this->maps_)) {
     402             :       return false;
     403             :     }
     404       35625 :   } else if (that->maps_) {
     405             :     return false;
     406             :   }
     407             :   return true;
     408             : }
     409             : 
     410      666689 : void LoadElimination::AbstractState::Merge(AbstractState const* that,
     411             :                                            Zone* zone) {
     412             :   // Merge the information we have about the elements.
     413      666689 :   if (this->elements_) {
     414             :     this->elements_ = that->elements_
     415             :                           ? that->elements_->Merge(this->elements_, zone)
     416       12244 :                           : nullptr;
     417             :   }
     418             : 
     419             :   // Merge the information we have about the fields.
     420    21333872 :   for (size_t i = 0; i < arraysize(fields_); ++i) {
     421    21333869 :     if (this->fields_[i]) {
     422      338828 :       if (that->fields_[i]) {
     423      267595 :         this->fields_[i] = this->fields_[i]->Merge(that->fields_[i], zone);
     424             :       } else {
     425       71233 :         this->fields_[i] = nullptr;
     426             :       }
     427             :     }
     428             :   }
     429             : 
     430             :   // Merge the information we have about the maps.
     431      666692 :   if (this->maps_) {
     432       42285 :     this->maps_ = that->maps_ ? that->maps_->Merge(this->maps_, zone) : nullptr;
     433             :   }
     434      666692 : }
     435             : 
     436           0 : bool LoadElimination::AbstractState::LookupMaps(
     437             :     Node* object, ZoneHandleSet<Map>* object_map) const {
     438      360417 :   return this->maps_ && this->maps_->Lookup(object, object_map);
     439             : }
     440             : 
     441      238854 : LoadElimination::AbstractState const* LoadElimination::AbstractState::SetMaps(
     442             :     Node* object, ZoneHandleSet<Map> maps, Zone* zone) const {
     443      238854 :   AbstractState* that = new (zone) AbstractState(*this);
     444      238854 :   if (that->maps_) {
     445      122980 :     that->maps_ = that->maps_->Extend(object, maps, zone);
     446             :   } else {
     447      231748 :     that->maps_ = new (zone) AbstractMaps(object, maps, zone);
     448             :   }
     449      238855 :   return that;
     450             : }
     451             : 
     452      170423 : LoadElimination::AbstractState const* LoadElimination::AbstractState::KillMaps(
     453             :     const AliasStateInfo& alias_info, Zone* zone) const {
     454      170423 :   if (this->maps_) {
     455       95663 :     AbstractMaps const* that_maps = this->maps_->Kill(alias_info, zone);
     456       95663 :     if (this->maps_ != that_maps) {
     457       22710 :       AbstractState* that = new (zone) AbstractState(*this);
     458       22710 :       that->maps_ = that_maps;
     459       22710 :       return that;
     460             :     }
     461             :   }
     462      147713 :   return this;
     463             : }
     464             : 
     465           0 : LoadElimination::AbstractState const* LoadElimination::AbstractState::KillMaps(
     466             :     Node* object, Zone* zone) const {
     467             :   AliasStateInfo alias_info(this, object);
     468      169655 :   return KillMaps(alias_info, zone);
     469             : }
     470             : 
     471           0 : Node* LoadElimination::AbstractState::LookupElement(
     472             :     Node* object, Node* index, MachineRepresentation representation) const {
     473       60325 :   if (this->elements_) {
     474       37522 :     return this->elements_->Lookup(object, index, representation);
     475             :   }
     476             :   return nullptr;
     477             : }
     478             : 
     479             : LoadElimination::AbstractState const*
     480       59090 : LoadElimination::AbstractState::AddElement(Node* object, Node* index,
     481             :                                            Node* value,
     482             :                                            MachineRepresentation representation,
     483             :                                            Zone* zone) const {
     484       59090 :   AbstractState* that = new (zone) AbstractState(*this);
     485       59090 :   if (that->elements_) {
     486             :     that->elements_ =
     487       36287 :         that->elements_->Extend(object, index, value, representation, zone);
     488             :   } else {
     489             :     that->elements_ =
     490       22803 :         new (zone) AbstractElements(object, index, value, representation, zone);
     491             :   }
     492       59090 :   return that;
     493             : }
     494             : 
     495             : LoadElimination::AbstractState const*
     496       44957 : LoadElimination::AbstractState::KillElement(Node* object, Node* index,
     497             :                                             Zone* zone) const {
     498       44957 :   if (this->elements_) {
     499             :     AbstractElements const* that_elements =
     500       33774 :         this->elements_->Kill(object, index, zone);
     501       33774 :     if (this->elements_ != that_elements) {
     502       30479 :       AbstractState* that = new (zone) AbstractState(*this);
     503       30479 :       that->elements_ = that_elements;
     504       30479 :       return that;
     505             :     }
     506             :   }
     507       14478 :   return this;
     508             : }
     509             : 
     510     1641264 : LoadElimination::AbstractState const* LoadElimination::AbstractState::AddField(
     511             :     Node* object, size_t index, Node* value, MaybeHandle<Name> name,
     512             :     Zone* zone) const {
     513     1641263 :   AbstractState* that = new (zone) AbstractState(*this);
     514     1641263 :   if (that->fields_[index]) {
     515             :     that->fields_[index] =
     516      653558 :         that->fields_[index]->Extend(object, value, name, zone);
     517             :   } else {
     518     1975410 :     that->fields_[index] = new (zone) AbstractField(object, value, name, zone);
     519             :   }
     520     1641265 :   return that;
     521             : }
     522             : 
     523           0 : LoadElimination::AbstractState const* LoadElimination::AbstractState::KillField(
     524             :     Node* object, size_t index, MaybeHandle<Name> name, Zone* zone) const {
     525             :   AliasStateInfo alias_info(this, object);
     526     1184353 :   return KillField(alias_info, index, name, zone);
     527             : }
     528             : 
     529     1184916 : LoadElimination::AbstractState const* LoadElimination::AbstractState::KillField(
     530             :     const AliasStateInfo& alias_info, size_t index, MaybeHandle<Name> name,
     531             :     Zone* zone) const {
     532     1184916 :   if (AbstractField const* this_field = this->fields_[index]) {
     533      543388 :     this_field = this_field->Kill(alias_info, name, zone);
     534      543388 :     if (this->fields_[index] != this_field) {
     535      157401 :       AbstractState* that = new (zone) AbstractState(*this);
     536      157401 :       that->fields_[index] = this_field;
     537      157401 :       return that;
     538             :     }
     539             :   }
     540     1027515 :   return this;
     541             : }
     542             : 
     543             : LoadElimination::AbstractState const*
     544      968140 : LoadElimination::AbstractState::KillFields(Node* object, MaybeHandle<Name> name,
     545             :                                            Zone* zone) const {
     546             :   AliasStateInfo alias_info(this, object);
     547    30598054 :   for (size_t i = 0;; ++i) {
     548    31566194 :     if (i == arraysize(fields_)) return this;
     549    30610486 :     if (AbstractField const* this_field = this->fields_[i]) {
     550             :       AbstractField const* that_field =
     551    25450011 :           this_field->Kill(alias_info, name, zone);
     552    25450011 :       if (that_field != this_field) {
     553       12432 :         AbstractState* that = new (zone) AbstractState(*this);
     554       12432 :         that->fields_[i] = that_field;
     555      394858 :         while (++i < arraysize(fields_)) {
     556      369994 :           if (this->fields_[i] != nullptr) {
     557      343069 :             that->fields_[i] = this->fields_[i]->Kill(alias_info, name, zone);
     558             :           }
     559             :         }
     560             :         return that;
     561             :       }
     562             :     }
     563    30598054 :   }
     564             : }
     565             : 
     566           0 : Node* LoadElimination::AbstractState::LookupField(Node* object,
     567             :                                                   size_t index) const {
     568     1753987 :   if (AbstractField const* this_field = this->fields_[index]) {
     569      766280 :     return this_field->Lookup(object);
     570             :   }
     571             :   return nullptr;
     572             : }
     573             : 
     574   242020469 : bool LoadElimination::AliasStateInfo::MayAlias(Node* other) const {
     575             :   // If {object} is being initialized right here (indicated by {object} being
     576             :   // an Allocate node instead of a FinishRegion node), we know that {other}
     577             :   // can only alias with {object} if they refer to exactly the same node.
     578   484040938 :   if (object_->opcode() == IrOpcode::kAllocate) {
     579   240725257 :     return object_ == other;
     580             :   }
     581             :   // Decide aliasing based on the node kinds.
     582     1295212 :   if (!compiler::MayAlias(object_, other)) {
     583             :     return false;
     584             :   }
     585             :   // Decide aliasing based on maps (if available).
     586             :   Handle<Map> map;
     587      938538 :   if (map_.ToHandle(&map)) {
     588             :     ZoneHandleSet<Map> other_maps;
     589        2734 :     if (state_->LookupMaps(other, &other_maps) && other_maps.size() == 1) {
     590        1722 :       if (map.address() != other_maps.at(0).address()) {
     591         546 :         return false;
     592             :       }
     593             :     }
     594             :   }
     595             :   return true;
     596             : }
     597             : 
     598           0 : void LoadElimination::AbstractState::Print() const {
     599           0 :   if (maps_) {
     600           0 :     PrintF("   maps:\n");
     601           0 :     maps_->Print();
     602             :   }
     603           0 :   if (elements_) {
     604           0 :     PrintF("   elements:\n");
     605           0 :     elements_->Print();
     606             :   }
     607           0 :   for (size_t i = 0; i < arraysize(fields_); ++i) {
     608           0 :     if (AbstractField const* const field = fields_[i]) {
     609           0 :       PrintF("   field %zu:\n", i);
     610           0 :       field->Print();
     611             :     }
     612             :   }
     613           0 : }
     614             : 
     615             : LoadElimination::AbstractState const*
     616    30340017 : LoadElimination::AbstractStateForEffectNodes::Get(Node* node) const {
     617    30340017 :   size_t const id = node->id();
     618    83876361 :   if (id < info_for_node_.size()) return info_for_node_[id];
     619             :   return nullptr;
     620             : }
     621             : 
     622    12504617 : void LoadElimination::AbstractStateForEffectNodes::Set(
     623    12504617 :     Node* node, AbstractState const* state) {
     624    12504617 :   size_t const id = node->id();
     625    25009234 :   if (id >= info_for_node_.size()) info_for_node_.resize(id + 1, nullptr);
     626    12504618 :   info_for_node_[id] = state;
     627    12504618 : }
     628             : 
     629        8426 : Reduction LoadElimination::ReduceMapGuard(Node* node) {
     630        8426 :   ZoneHandleSet<Map> const maps = MapGuardMapsOf(node->op()).maps();
     631        8426 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     632        8426 :   Node* const effect = NodeProperties::GetEffectInput(node);
     633             :   AbstractState const* state = node_states_.Get(effect);
     634        8426 :   if (state == nullptr) return NoChange();
     635             :   ZoneHandleSet<Map> object_maps;
     636        7443 :   if (state->LookupMaps(object, &object_maps)) {
     637         224 :     if (maps.contains(object_maps)) return Replace(effect);
     638             :     // TODO(turbofan): Compute the intersection.
     639             :   }
     640        7355 :   state = state->SetMaps(object, maps, zone());
     641        7355 :   return UpdateState(node, state);
     642             : }
     643             : 
     644      187559 : Reduction LoadElimination::ReduceCheckMaps(Node* node) {
     645      187559 :   ZoneHandleSet<Map> const maps = CheckMapsParametersOf(node->op()).maps();
     646      187559 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     647      187559 :   Node* const effect = NodeProperties::GetEffectInput(node);
     648             :   AbstractState const* state = node_states_.Get(effect);
     649      187559 :   if (state == nullptr) return NoChange();
     650             :   ZoneHandleSet<Map> object_maps;
     651      104865 :   if (state->LookupMaps(object, &object_maps)) {
     652       44747 :     if (maps.contains(object_maps)) return Replace(effect);
     653             :     // TODO(turbofan): Compute the intersection.
     654             :   }
     655       60392 :   state = state->SetMaps(object, maps, zone());
     656       60392 :   return UpdateState(node, state);
     657             : }
     658             : 
     659        9051 : Reduction LoadElimination::ReduceCompareMaps(Node* node) {
     660        9006 :   ZoneHandleSet<Map> const maps = CompareMapsParametersOf(node->op()).maps();
     661        9006 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     662        9006 :   Node* const effect = NodeProperties::GetEffectInput(node);
     663             :   AbstractState const* state = node_states_.Get(effect);
     664        9006 :   if (state == nullptr) return NoChange();
     665             :   ZoneHandleSet<Map> object_maps;
     666        7823 :   if (state->LookupMaps(object, &object_maps)) {
     667         180 :     if (maps.contains(object_maps)) {
     668          45 :       Node* value = jsgraph()->TrueConstant();
     669          45 :       ReplaceWithValue(node, value, effect);
     670             :       return Replace(value);
     671             :     }
     672             :     // TODO(turbofan): Compute the intersection.
     673             :   }
     674        7778 :   return UpdateState(node, state);
     675             : }
     676             : 
     677        9443 : Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) {
     678        9443 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     679        9443 :   Node* const elements = NodeProperties::GetValueInput(node, 1);
     680        9443 :   Node* const effect = NodeProperties::GetEffectInput(node);
     681             :   AbstractState const* state = node_states_.Get(effect);
     682        9443 :   if (state == nullptr) return NoChange();
     683             :   // Check if the {elements} already have the fixed array map.
     684             :   ZoneHandleSet<Map> elements_maps;
     685             :   ZoneHandleSet<Map> fixed_array_maps(factory()->fixed_array_map());
     686        2939 :   if (state->LookupMaps(elements, &elements_maps) &&
     687        1200 :       fixed_array_maps.contains(elements_maps)) {
     688          11 :     ReplaceWithValue(node, elements, effect);
     689             :     return Replace(elements);
     690             :   }
     691             :   // We know that the resulting elements have the fixed array map.
     692        1728 :   state = state->SetMaps(node, fixed_array_maps, zone());
     693             :   // Kill the previous elements on {object}.
     694             :   state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset),
     695             :                            MaybeHandle<Name>(), zone());
     696             :   // Add the new elements on {object}.
     697             :   state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node,
     698        1728 :                           MaybeHandle<Name>(), zone());
     699        1728 :   return UpdateState(node, state);
     700             : }
     701             : 
     702       12923 : Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) {
     703       12923 :   GrowFastElementsParameters params = GrowFastElementsParametersOf(node->op());
     704       12923 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     705       12923 :   Node* const effect = NodeProperties::GetEffectInput(node);
     706             :   AbstractState const* state = node_states_.Get(effect);
     707       12923 :   if (state == nullptr) return NoChange();
     708        3778 :   if (params.mode() == GrowFastElementsMode::kDoubleElements) {
     709             :     // We know that the resulting elements have the fixed double array map.
     710             :     state = state->SetMaps(
     711         451 :         node, ZoneHandleSet<Map>(factory()->fixed_double_array_map()), zone());
     712             :   } else {
     713             :     // We know that the resulting elements have the fixed array map or the COW
     714             :     // version thereof (if we didn't grow and it was already COW before).
     715             :     ZoneHandleSet<Map> fixed_array_maps(factory()->fixed_array_map());
     716        3327 :     fixed_array_maps.insert(factory()->fixed_cow_array_map(), zone());
     717        3327 :     state = state->SetMaps(node, fixed_array_maps, zone());
     718             :   }
     719             :   // Kill the previous elements on {object}.
     720             :   state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset),
     721             :                            MaybeHandle<Name>(), zone());
     722             :   // Add the new elements on {object}.
     723             :   state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node,
     724        3778 :                           MaybeHandle<Name>(), zone());
     725        3778 :   return UpdateState(node, state);
     726             : }
     727             : 
     728         958 : Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) {
     729         958 :   ElementsTransition transition = ElementsTransitionOf(node->op());
     730         958 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     731             :   Handle<Map> source_map(transition.source());
     732             :   Handle<Map> target_map(transition.target());
     733         958 :   Node* const effect = NodeProperties::GetEffectInput(node);
     734             :   AbstractState const* state = node_states_.Get(effect);
     735         958 :   if (state == nullptr) return NoChange();
     736         725 :   switch (transition.mode()) {
     737             :     case ElementsTransition::kFastTransition:
     738             :       break;
     739             :     case ElementsTransition::kSlowTransition:
     740             :       // Kill the elements as well.
     741             :       AliasStateInfo alias_info(state, object, source_map);
     742             :       state =
     743             :           state->KillField(alias_info, FieldIndexOf(JSObject::kElementsOffset),
     744         463 :                            MaybeHandle<Name>(), zone());
     745         463 :       break;
     746             :   }
     747             :   ZoneHandleSet<Map> object_maps;
     748         725 :   if (state->LookupMaps(object, &object_maps)) {
     749         192 :     if (ZoneHandleSet<Map>(target_map).contains(object_maps)) {
     750             :       // The {object} already has the {target_map}, so this TransitionElements
     751             :       // {node} is fully redundant (independent of what {source_map} is).
     752             :       return Replace(effect);
     753             :     }
     754         102 :     if (object_maps.contains(ZoneHandleSet<Map>(source_map))) {
     755         102 :       object_maps.remove(source_map, zone());
     756         102 :       object_maps.insert(target_map, zone());
     757             :       AliasStateInfo alias_info(state, object, source_map);
     758         102 :       state = state->KillMaps(alias_info, zone());
     759         102 :       state = state->SetMaps(object, object_maps, zone());
     760             :     }
     761             :   } else {
     762             :     AliasStateInfo alias_info(state, object, source_map);
     763         533 :     state = state->KillMaps(alias_info, zone());
     764             :   }
     765         635 :   return UpdateState(node, state);
     766             : }
     767             : 
     768        1695 : Reduction LoadElimination::ReduceTransitionAndStoreElement(Node* node) {
     769         565 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     770         565 :   Handle<Map> double_map(DoubleMapParameterOf(node->op()));
     771         565 :   Handle<Map> fast_map(FastMapParameterOf(node->op()));
     772         565 :   Node* const effect = NodeProperties::GetEffectInput(node);
     773             :   AbstractState const* state = node_states_.Get(effect);
     774         565 :   if (state == nullptr) return NoChange();
     775             : 
     776             :   // We need to add the double and fast maps to the set of possible maps for
     777             :   // this object, because we don't know which of those we'll transition to.
     778             :   // Additionally, we should kill all alias information.
     779             :   ZoneHandleSet<Map> object_maps;
     780         257 :   if (state->LookupMaps(object, &object_maps)) {
     781           0 :     object_maps.insert(double_map, zone());
     782           0 :     object_maps.insert(fast_map, zone());
     783             :     state = state->KillMaps(object, zone());
     784           0 :     state = state->SetMaps(object, object_maps, zone());
     785             :   }
     786             :   // Kill the elements as well.
     787             :   state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset),
     788             :                            MaybeHandle<Name>(), zone());
     789         257 :   return UpdateState(node, state);
     790             : }
     791             : 
     792     1627812 : Reduction LoadElimination::ReduceLoadField(Node* node,
     793          14 :                                            FieldAccess const& access) {
     794     1627812 :   Node* object = NodeProperties::GetValueInput(node, 0);
     795     1627812 :   Node* effect = NodeProperties::GetEffectInput(node);
     796     1627812 :   Node* control = NodeProperties::GetControlInput(node);
     797             :   AbstractState const* state = node_states_.Get(effect);
     798     1627812 :   if (state == nullptr) return NoChange();
     799     1404346 :   if (access.offset == HeapObject::kMapOffset &&
     800             :       access.base_is_tagged == kTaggedBase) {
     801             :     DCHECK(IsAnyTagged(access.machine_type.representation()));
     802             :     ZoneHandleSet<Map> object_maps;
     803        4062 :     if (state->LookupMaps(object, &object_maps) && object_maps.size() == 1) {
     804          14 :       Node* value = jsgraph()->HeapConstant(object_maps[0]);
     805             :       NodeProperties::SetType(value, Type::OtherInternal());
     806      116132 :       ReplaceWithValue(node, value, effect);
     807          14 :       return Replace(value);
     808             :     }
     809             :   } else {
     810     1400298 :     int field_index = FieldIndexOf(access);
     811     1400298 :     if (field_index >= 0) {
     812     1209614 :       if (Node* replacement = state->LookupField(object, field_index)) {
     813             :         // Make sure we don't resurrect dead {replacement} nodes.
     814      116118 :         if (!replacement->IsDead()) {
     815             :           // Introduce a TypeGuard if the type of the {replacement} node is not
     816             :           // a subtype of the original {node}'s type.
     817      116118 :           if (!NodeProperties::GetType(replacement)
     818      232236 :                    .Is(NodeProperties::GetType(node))) {
     819             :             Type replacement_type = Type::Intersect(
     820             :                 NodeProperties::GetType(node),
     821        1058 :                 NodeProperties::GetType(replacement), graph()->zone());
     822             :             replacement = effect =
     823             :                 graph()->NewNode(common()->TypeGuard(replacement_type),
     824        1058 :                                  replacement, effect, control);
     825             :             NodeProperties::SetType(replacement, replacement_type);
     826             :           }
     827             :           ReplaceWithValue(node, replacement, effect);
     828             :           return Replace(replacement);
     829             :         }
     830             :       }
     831      488689 :       state = state->AddField(object, field_index, node, access.name, zone());
     832             :     }
     833             :   }
     834             :   Handle<Map> field_map;
     835     1288214 :   if (access.map.ToHandle(&field_map)) {
     836        2431 :     state = state->SetMaps(node, ZoneHandleSet<Map>(field_map), zone());
     837             :   }
     838     1288214 :   return UpdateState(node, state);
     839             : }
     840             : 
     841     2464088 : Reduction LoadElimination::ReduceStoreField(Node* node,
     842             :                                             FieldAccess const& access) {
     843     2464088 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     844     2464089 :   Node* const new_value = NodeProperties::GetValueInput(node, 1);
     845     2464089 :   Node* const effect = NodeProperties::GetEffectInput(node);
     846             :   AbstractState const* state = node_states_.Get(effect);
     847     2464087 :   if (state == nullptr) return NoChange();
     848     2280341 :   if (access.offset == HeapObject::kMapOffset &&
     849             :       access.base_is_tagged == kTaggedBase) {
     850             :     DCHECK(IsAnyTagged(access.machine_type.representation()));
     851             :     // Kill all potential knowledge about the {object}s map.
     852             :     state = state->KillMaps(object, zone());
     853      163028 :     Type const new_value_type = NodeProperties::GetType(new_value);
     854      163028 :     if (new_value_type.IsHeapConstant()) {
     855             :       // Record the new {object} map information.
     856             :       AllowHandleDereference handle_dereference;
     857             :       ZoneHandleSet<Map> object_maps(
     858      163027 :           Handle<Map>::cast(new_value_type.AsHeapConstant()->Value()));
     859      163027 :       state = state->SetMaps(object, object_maps, zone());
     860             :     }
     861             :   } else {
     862     2117313 :     int field_index = FieldIndexOf(access);
     863     2117314 :     if (field_index >= 0) {
     864     1149180 :       Node* const old_value = state->LookupField(object, field_index);
     865     1149180 :       if (old_value == new_value) {
     866             :         // This store is fully redundant.
     867             :         return Replace(effect);
     868             :       }
     869             :       // Kill all potentially aliasing fields and record the new value.
     870             :       state = state->KillField(object, field_index, access.name, zone());
     871             :       state =
     872     1147069 :           state->AddField(object, field_index, new_value, access.name, zone());
     873             :     } else {
     874             :       // Unsupported StoreField operator.
     875      968134 :       state = state->KillFields(object, access.name, zone());
     876             :     }
     877             :   }
     878     2278234 :   return UpdateState(node, state);
     879             : }
     880             : 
     881       55728 : Reduction LoadElimination::ReduceLoadElement(Node* node) {
     882       35142 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     883       35142 :   Node* const index = NodeProperties::GetValueInput(node, 1);
     884       35142 :   Node* const effect = NodeProperties::GetEffectInput(node);
     885             :   AbstractState const* state = node_states_.Get(effect);
     886       35142 :   if (state == nullptr) return NoChange();
     887             : 
     888             :   // Only handle loads that do not require truncations.
     889       20586 :   ElementAccess const& access = ElementAccessOf(node->op());
     890       39958 :   switch (access.machine_type.representation()) {
     891             :     case MachineRepresentation::kNone:
     892             :     case MachineRepresentation::kBit:
     893           0 :       UNREACHABLE();
     894             :       break;
     895             :     case MachineRepresentation::kWord8:
     896             :     case MachineRepresentation::kWord16:
     897             :     case MachineRepresentation::kWord32:
     898             :     case MachineRepresentation::kWord64:
     899             :     case MachineRepresentation::kFloat32:
     900             :       // TODO(turbofan): Add support for doing the truncations.
     901             :       break;
     902             :     case MachineRepresentation::kFloat64:
     903             :     case MachineRepresentation::kSimd128:
     904             :     case MachineRepresentation::kTaggedSigned:
     905             :     case MachineRepresentation::kTaggedPointer:
     906             :     case MachineRepresentation::kTagged:
     907       20586 :       if (Node* replacement = state->LookupElement(
     908             :               object, index, access.machine_type.representation())) {
     909             :         // Make sure we don't resurrect dead {replacement} nodes.
     910             :         // Skip lowering if the type of the {replacement} node is not a subtype
     911             :         // of the original {node}'s type.
     912             :         // TODO(tebbi): We should insert a {TypeGuard} for the intersection of
     913             :         // these two types here once we properly handle {Type::None} everywhere.
     914        3687 :         if (!replacement->IsDead() && NodeProperties::GetType(replacement)
     915        3687 :                                           .Is(NodeProperties::GetType(node))) {
     916        1214 :           ReplaceWithValue(node, replacement, effect);
     917             :           return Replace(replacement);
     918             :         }
     919             :       }
     920             :       state = state->AddElement(object, index, node,
     921       19372 :                                 access.machine_type.representation(), zone());
     922       19372 :       return UpdateState(node, state);
     923             :   }
     924             :   return NoChange();
     925             : }
     926             : 
     927       59234 : Reduction LoadElimination::ReduceStoreElement(Node* node) {
     928       59234 :   ElementAccess const& access = ElementAccessOf(node->op());
     929       59234 :   Node* const object = NodeProperties::GetValueInput(node, 0);
     930       59234 :   Node* const index = NodeProperties::GetValueInput(node, 1);
     931       59234 :   Node* const new_value = NodeProperties::GetValueInput(node, 2);
     932       59234 :   Node* const effect = NodeProperties::GetEffectInput(node);
     933             :   AbstractState const* state = node_states_.Get(effect);
     934       59234 :   if (state == nullptr) return NoChange();
     935             :   Node* const old_value =
     936       79457 :       state->LookupElement(object, index, access.machine_type.representation());
     937       39739 :   if (old_value == new_value) {
     938             :     // This store is fully redundant.
     939             :     return Replace(effect);
     940             :   }
     941             :   // Kill all potentially aliasing elements.
     942       39718 :   state = state->KillElement(object, index, zone());
     943             :   // Only record the new value if the store doesn't have an implicit truncation.
     944             :   switch (access.machine_type.representation()) {
     945             :     case MachineRepresentation::kNone:
     946             :     case MachineRepresentation::kBit:
     947           0 :       UNREACHABLE();
     948             :       break;
     949             :     case MachineRepresentation::kWord8:
     950             :     case MachineRepresentation::kWord16:
     951             :     case MachineRepresentation::kWord32:
     952             :     case MachineRepresentation::kWord64:
     953             :     case MachineRepresentation::kFloat32:
     954             :       // TODO(turbofan): Add support for doing the truncations.
     955             :       break;
     956             :     case MachineRepresentation::kFloat64:
     957             :     case MachineRepresentation::kSimd128:
     958             :     case MachineRepresentation::kTaggedSigned:
     959             :     case MachineRepresentation::kTaggedPointer:
     960             :     case MachineRepresentation::kTagged:
     961             :       state = state->AddElement(object, index, new_value,
     962       39718 :                                 access.machine_type.representation(), zone());
     963       39718 :       break;
     964             :   }
     965       39718 :   return UpdateState(node, state);
     966             : }
     967             : 
     968        5789 : Reduction LoadElimination::ReduceStoreTypedElement(Node* node) {
     969        5789 :   Node* const effect = NodeProperties::GetEffectInput(node);
     970             :   AbstractState const* state = node_states_.Get(effect);
     971        5789 :   if (state == nullptr) return NoChange();
     972        4463 :   return UpdateState(node, state);
     973             : }
     974             : 
     975      232020 : LoadElimination::AbstractState const* LoadElimination::UpdateStateForPhi(
     976             :     AbstractState const* state, Node* effect_phi, Node* phi) {
     977      232020 :   int predecessor_count = phi->InputCount() - 1;
     978             :   // TODO(jarin) Consider doing a union here. At the moment, we just keep this
     979             :   // consistent with AbstractState::Merge.
     980             : 
     981             :   // Check if all the inputs have the same maps.
     982             :   AbstractState const* input_state =
     983      232020 :       node_states_.Get(NodeProperties::GetEffectInput(effect_phi, 0));
     984             :   ZoneHandleSet<Map> object_maps;
     985      232018 :   if (!input_state->LookupMaps(phi->InputAt(0), &object_maps)) return state;
     986         443 :   for (int i = 1; i < predecessor_count; i++) {
     987             :     input_state =
     988         357 :         node_states_.Get(NodeProperties::GetEffectInput(effect_phi, i));
     989             :     ZoneHandleSet<Map> input_maps;
     990         669 :     if (!input_state->LookupMaps(phi->InputAt(i), &input_maps)) return state;
     991          45 :     if (input_maps != object_maps) return state;
     992             :   }
     993          41 :   return state->SetMaps(phi, object_maps, zone());
     994             : }
     995             : 
     996     1000460 : Reduction LoadElimination::ReduceEffectPhi(Node* node) {
     997      618886 :   Node* const effect0 = NodeProperties::GetEffectInput(node, 0);
     998     1087625 :   Node* const control = NodeProperties::GetControlInput(node);
     999             :   AbstractState const* state0 = node_states_.Get(effect0);
    1000      618892 :   if (state0 == nullptr) return NoChange();
    1001      468733 :   if (control->opcode() == IrOpcode::kLoop) {
    1002             :     // Here we rely on having only reducible loops:
    1003             :     // The loop entry edge always dominates the header, so we can just take
    1004             :     // the state from the first input, and compute the loop state based on it.
    1005       87159 :     AbstractState const* state = ComputeLoopState(node, state0);
    1006       87159 :     return UpdateState(node, state);
    1007             :   }
    1008             :   DCHECK_EQ(IrOpcode::kMerge, control->opcode());
    1009             : 
    1010             :   // Shortcut for the case when we do not know anything about some input.
    1011      381574 :   int const input_count = node->op()->EffectInputCount();
    1012     2065070 :   for (int i = 1; i < input_count; ++i) {
    1013     1768055 :     Node* const effect = NodeProperties::GetEffectInput(node, i);
    1014     1768055 :     if (node_states_.Get(effect) == nullptr) return NoChange();
    1015             :   }
    1016             : 
    1017             :   // Make a copy of the first input's state and merge with the state
    1018             :   // from other inputs.
    1019      297016 :   AbstractState* state = new (zone()) AbstractState(*state0);
    1020      963707 :   for (int i = 1; i < input_count; ++i) {
    1021      666686 :     Node* const input = NodeProperties::GetEffectInput(node, i);
    1022      666686 :     state->Merge(node_states_.Get(input), zone());
    1023             :   }
    1024             : 
    1025             :   // For each phi, try to compute the new state for the phi from
    1026             :   // the inputs.
    1027             :   AbstractState const* state_with_phis = state;
    1028     3252960 :   for (Node* use : control->uses()) {
    1029     1329462 :     if (use->opcode() == IrOpcode::kPhi) {
    1030      232023 :       state_with_phis = UpdateStateForPhi(state_with_phis, node, use);
    1031             :     }
    1032             :   }
    1033             : 
    1034      297015 :   return UpdateState(node, state_with_phis);
    1035             : }
    1036             : 
    1037           0 : Reduction LoadElimination::ReduceStart(Node* node) {
    1038      456693 :   return UpdateState(node, empty_state());
    1039             : }
    1040             : 
    1041    40547997 : Reduction LoadElimination::ReduceOtherNode(Node* node) {
    1042    32318145 :   if (node->op()->EffectInputCount() == 1) {
    1043    10714636 :     if (node->op()->EffectOutputCount() == 1) {
    1044     9850340 :       Node* const effect = NodeProperties::GetEffectInput(node);
    1045             :       AbstractState const* state = node_states_.Get(effect);
    1046             :       // If we do not know anything about the predecessor, do not propagate
    1047             :       // just yet because we will have to recompute anyway once we compute
    1048             :       // the predecessor.
    1049     9850448 :       if (state == nullptr) return NoChange();
    1050             :       // Check if this {node} has some uncontrolled side effects.
    1051     8229852 :       if (!node->op()->HasProperty(Operator::kNoWrite)) {
    1052     2796963 :         state = empty_state();
    1053             :       }
    1054     8229852 :       return UpdateState(node, state);
    1055             :     } else {
    1056             :       // Effect terminators should be handled specially.
    1057             :       return NoChange();
    1058             :     }
    1059             :   }
    1060             :   DCHECK_EQ(0, node->op()->EffectInputCount());
    1061             :   DCHECK_EQ(0, node->op()->EffectOutputCount());
    1062             :   return NoChange();
    1063             : }
    1064             : 
    1065    12782617 : Reduction LoadElimination::UpdateState(Node* node, AbstractState const* state) {
    1066             :   AbstractState const* original = node_states_.Get(node);
    1067             :   // Only signal that the {node} has Changed, if the information about {state}
    1068             :   // has changed wrt. the {original}.
    1069    12782617 :   if (state != original) {
    1070    12557872 :     if (original == nullptr || !state->Equals(original)) {
    1071    12504620 :       node_states_.Set(node, state);
    1072             :       return Changed(node);
    1073             :     }
    1074             :   }
    1075             :   return NoChange();
    1076             : }
    1077             : 
    1078             : LoadElimination::AbstractState const*
    1079       34676 : LoadElimination::ComputeLoopStateForStoreField(
    1080             :     Node* current, LoadElimination::AbstractState const* state,
    1081             :     FieldAccess const& access) const {
    1082       34676 :   Node* const object = NodeProperties::GetValueInput(current, 0);
    1083       34676 :   if (access.offset == HeapObject::kMapOffset) {
    1084             :     // Invalidate what we know about the {object}s map.
    1085             :     state = state->KillMaps(object, zone());
    1086             :   } else {
    1087       28481 :     int field_index = FieldIndexOf(access);
    1088       28481 :     if (field_index < 0) {
    1089           6 :       state = state->KillFields(object, access.name, zone());
    1090             :     } else {
    1091       28475 :       state = state->KillField(object, field_index, access.name, zone());
    1092             :     }
    1093             :   }
    1094       34676 :   return state;
    1095             : }
    1096             : 
    1097       87159 : LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
    1098             :     Node* node, AbstractState const* state) const {
    1099       87159 :   Node* const control = NodeProperties::GetControlInput(node);
    1100             :   struct TransitionElementsKindInfo {
    1101             :     ElementsTransition transition;
    1102             :     Node* object;
    1103             :   };
    1104             :   ZoneVector<TransitionElementsKindInfo> element_transitions_(zone());
    1105       87159 :   ZoneQueue<Node*> queue(zone());
    1106             :   ZoneSet<Node*> visited(zone());
    1107             :   visited.insert(node);
    1108      348632 :   for (int i = 1; i < control->InputCount(); ++i) {
    1109      261474 :     queue.push(node->InputAt(i));
    1110             :   }
    1111      892575 :   while (!queue.empty()) {
    1112      869238 :     Node* const current = queue.front();
    1113             :     queue.pop();
    1114      869244 :     if (visited.find(current) == visited.end()) {
    1115             :       visited.insert(current);
    1116     3161571 :       if (!current->op()->HasProperty(Operator::kNoWrite)) {
    1117      109257 :         switch (current->opcode()) {
    1118             :           case IrOpcode::kEnsureWritableFastElements: {
    1119         759 :             Node* const object = NodeProperties::GetValueInput(current, 0);
    1120             :             state = state->KillField(object,
    1121             :                                      FieldIndexOf(JSObject::kElementsOffset),
    1122             :                                      MaybeHandle<Name>(), zone());
    1123         759 :             break;
    1124             :           }
    1125             :           case IrOpcode::kMaybeGrowFastElements: {
    1126        1854 :             Node* const object = NodeProperties::GetValueInput(current, 0);
    1127             :             state = state->KillField(object,
    1128             :                                      FieldIndexOf(JSObject::kElementsOffset),
    1129             :                                      MaybeHandle<Name>(), zone());
    1130        1854 :             break;
    1131             :           }
    1132             :           case IrOpcode::kTransitionElementsKind: {
    1133         226 :             ElementsTransition transition = ElementsTransitionOf(current->op());
    1134         226 :             Node* const object = NodeProperties::GetValueInput(current, 0);
    1135             :             ZoneHandleSet<Map> object_maps;
    1136         678 :             if (!state->LookupMaps(object, &object_maps) ||
    1137             :                 !ZoneHandleSet<Map>(transition.target())
    1138         412 :                      .contains(object_maps)) {
    1139         266 :               element_transitions_.push_back({transition, object});
    1140             :             }
    1141             :             break;
    1142             :           }
    1143             :           case IrOpcode::kTransitionAndStoreElement: {
    1144         432 :             Node* const object = NodeProperties::GetValueInput(current, 0);
    1145             :             // Invalidate what we know about the {object}s map.
    1146             :             state = state->KillMaps(object, zone());
    1147             :             // Kill the elements as well.
    1148             :             state = state->KillField(object,
    1149             :                                      FieldIndexOf(JSObject::kElementsOffset),
    1150             :                                      MaybeHandle<Name>(), zone());
    1151         432 :             break;
    1152             :           }
    1153             :           case IrOpcode::kStoreField:
    1154             :             state = ComputeLoopStateForStoreField(current, state,
    1155       31832 :                                                   FieldAccessOf(current->op()));
    1156       31832 :             break;
    1157             :           case IrOpcode::kStoreMessage:
    1158             :             state = ComputeLoopStateForStoreField(
    1159        2844 :                 current, state, AccessBuilder::ForExternalIntPtr());
    1160        2844 :             break;
    1161             :           case IrOpcode::kStoreElement: {
    1162        5239 :             Node* const object = NodeProperties::GetValueInput(current, 0);
    1163        5239 :             Node* const index = NodeProperties::GetValueInput(current, 1);
    1164        5239 :             state = state->KillElement(object, index, zone());
    1165        5239 :             break;
    1166             :           }
    1167             :           case IrOpcode::kStoreTypedElement: {
    1168             :             // Doesn't affect anything we track with the state currently.
    1169             :             break;
    1170             :           }
    1171             :           default:
    1172       63822 :             return empty_state();
    1173             :         }
    1174             :       }
    1175     4658127 :       for (int i = 0; i < current->op()->EffectInputCount(); ++i) {
    1176     1624313 :         queue.push(NodeProperties::GetEffectInput(current, i));
    1177             :       }
    1178             :     }
    1179             :   }
    1180             : 
    1181             :   // Finally, we apply the element transitions. For each transition, we will try
    1182             :   // to only invalidate information about nodes that can have the transition's
    1183             :   // source map. The trouble is that an object can be transitioned by some other
    1184             :   // transition to the source map. In that case, the other transition will
    1185             :   // invalidate the information, so we are mostly fine.
    1186             :   //
    1187             :   // The only bad case is
    1188             :   //
    1189             :   //    mapA   ---fast--->   mapB   ---slow--->   mapC
    1190             :   //
    1191             :   // If we process the slow transition first on an object that has mapA, we will
    1192             :   // ignore the transition because the object does not have its source map
    1193             :   // (mapB). When we later process the fast transition, we invalidate the
    1194             :   // object's map, but we keep the information about the object's elements. This
    1195             :   // is wrong because the elements will be overwritten by the slow transition.
    1196             :   //
    1197             :   // Note that the slow-slow case is fine because either of the slow transition
    1198             :   // will invalidate the elements field, so the processing order does not
    1199             :   // matter.
    1200             :   //
    1201             :   // To handle the bad case properly, we first kill the maps using all
    1202             :   // transitions. We kill the the fields later when all the transitions are
    1203             :   // already reflected in the map information.
    1204             : 
    1205       46807 :   for (const TransitionElementsKindInfo& t : element_transitions_) {
    1206         133 :     AliasStateInfo alias_info(state, t.object, t.transition.source());
    1207         133 :     state = state->KillMaps(alias_info, zone());
    1208             :   }
    1209       46807 :   for (const TransitionElementsKindInfo& t : element_transitions_) {
    1210         133 :     switch (t.transition.mode()) {
    1211             :       case ElementsTransition::kFastTransition:
    1212             :         break;
    1213             :       case ElementsTransition::kSlowTransition: {
    1214         101 :         AliasStateInfo alias_info(state, t.object, t.transition.source());
    1215             :         state = state->KillField(alias_info,
    1216             :                                  FieldIndexOf(JSObject::kElementsOffset),
    1217         101 :                                  MaybeHandle<Name>(), zone());
    1218             :         break;
    1219             :       }
    1220             :     }
    1221             :   }
    1222             :   return state;
    1223             : }
    1224             : 
    1225             : // static
    1226           0 : int LoadElimination::FieldIndexOf(int offset) {
    1227             :   DCHECK(IsAligned(offset, kTaggedSize));
    1228     3477505 :   int field_index = offset / kTaggedSize;
    1229     3477505 :   if (field_index >= static_cast<int>(kMaxTrackedFields)) return -1;
    1230             :   DCHECK_LT(0, field_index);
    1231     1782461 :   return field_index - 1;
    1232             : }
    1233             : 
    1234             : // static
    1235     3546088 : int LoadElimination::FieldIndexOf(FieldAccess const& access) {
    1236     3546088 :   MachineRepresentation rep = access.machine_type.representation();
    1237             :   switch (rep) {
    1238             :     case MachineRepresentation::kNone:
    1239             :     case MachineRepresentation::kBit:
    1240             :     case MachineRepresentation::kSimd128:
    1241           0 :       UNREACHABLE();
    1242             :       break;
    1243             :     case MachineRepresentation::kWord32:
    1244             :       if (kInt32Size != kTaggedSize) {
    1245             :         return -1;  // We currently only track tagged pointer size fields.
    1246             :       }
    1247             :       break;
    1248             :     case MachineRepresentation::kWord64:
    1249             :       if (kInt64Size != kTaggedSize) {
    1250             :         return -1;  // We currently only track tagged pointer size fields.
    1251             :       }
    1252             :       break;
    1253             :     case MachineRepresentation::kWord8:
    1254             :     case MachineRepresentation::kWord16:
    1255             :     case MachineRepresentation::kFloat32:
    1256             :       return -1;  // Currently untracked.
    1257             :     case MachineRepresentation::kFloat64:
    1258             :       if (kDoubleSize != kTaggedSize) {
    1259             :         return -1;  // We currently only track tagged pointer size fields.
    1260             :       }
    1261             :       break;
    1262             :     case MachineRepresentation::kTaggedSigned:
    1263             :     case MachineRepresentation::kTaggedPointer:
    1264             :     case MachineRepresentation::kTagged:
    1265             :       // TODO(bmeurer): Check that we never do overlapping load/stores of
    1266             :       // individual parts of Float64 values.
    1267             :       break;
    1268             :   }
    1269     3542842 :   if (access.base_is_tagged != kTaggedBase) {
    1270             :     return -1;  // We currently only track tagged objects.
    1271             :   }
    1272     6955010 :   return FieldIndexOf(access.offset);
    1273             : }
    1274             : 
    1275        1058 : CommonOperatorBuilder* LoadElimination::common() const {
    1276        1058 :   return jsgraph()->common();
    1277             : }
    1278             : 
    1279        2116 : Graph* LoadElimination::graph() const { return jsgraph()->graph(); }
    1280             : 
    1281           0 : Isolate* LoadElimination::isolate() const { return jsgraph()->isolate(); }
    1282             : 
    1283        5517 : Factory* LoadElimination::factory() const { return jsgraph()->factory(); }
    1284             : 
    1285             : }  // namespace compiler
    1286             : }  // namespace internal
    1287      178779 : }  // namespace v8

Generated by: LCOV version 1.10