11cb0ef41Sopenharmony_ci// Copyright 2016 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/compiler/load-elimination.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "src/compiler/access-builder.h" 81cb0ef41Sopenharmony_ci#include "src/compiler/common-operator.h" 91cb0ef41Sopenharmony_ci#include "src/compiler/js-graph.h" 101cb0ef41Sopenharmony_ci#include "src/compiler/node-properties.h" 111cb0ef41Sopenharmony_ci#include "src/heap/factory.h" 121cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_cinamespace v8 { 151cb0ef41Sopenharmony_cinamespace internal { 161cb0ef41Sopenharmony_cinamespace compiler { 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_cinamespace { 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_cibool IsRename(Node* node) { 211cb0ef41Sopenharmony_ci switch (node->opcode()) { 221cb0ef41Sopenharmony_ci case IrOpcode::kCheckHeapObject: 231cb0ef41Sopenharmony_ci case IrOpcode::kFinishRegion: 241cb0ef41Sopenharmony_ci case IrOpcode::kTypeGuard: 251cb0ef41Sopenharmony_ci return !node->IsDead(); 261cb0ef41Sopenharmony_ci default: 271cb0ef41Sopenharmony_ci return false; 281cb0ef41Sopenharmony_ci } 291cb0ef41Sopenharmony_ci} 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ciNode* ResolveRenames(Node* node) { 321cb0ef41Sopenharmony_ci while (IsRename(node)) { 331cb0ef41Sopenharmony_ci node = node->InputAt(0); 341cb0ef41Sopenharmony_ci } 351cb0ef41Sopenharmony_ci return node; 361cb0ef41Sopenharmony_ci} 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_cibool MayAlias(Node* a, Node* b) { 391cb0ef41Sopenharmony_ci if (a != b) { 401cb0ef41Sopenharmony_ci if (!NodeProperties::GetType(a).Maybe(NodeProperties::GetType(b))) { 411cb0ef41Sopenharmony_ci return false; 421cb0ef41Sopenharmony_ci } else if (IsRename(b)) { 431cb0ef41Sopenharmony_ci return MayAlias(a, b->InputAt(0)); 441cb0ef41Sopenharmony_ci } else if (IsRename(a)) { 451cb0ef41Sopenharmony_ci return MayAlias(a->InputAt(0), b); 461cb0ef41Sopenharmony_ci } else if (b->opcode() == IrOpcode::kAllocate) { 471cb0ef41Sopenharmony_ci switch (a->opcode()) { 481cb0ef41Sopenharmony_ci case IrOpcode::kAllocate: 491cb0ef41Sopenharmony_ci case IrOpcode::kHeapConstant: 501cb0ef41Sopenharmony_ci case IrOpcode::kParameter: 511cb0ef41Sopenharmony_ci return false; 521cb0ef41Sopenharmony_ci default: 531cb0ef41Sopenharmony_ci break; 541cb0ef41Sopenharmony_ci } 551cb0ef41Sopenharmony_ci } else if (a->opcode() == IrOpcode::kAllocate) { 561cb0ef41Sopenharmony_ci switch (b->opcode()) { 571cb0ef41Sopenharmony_ci case IrOpcode::kHeapConstant: 581cb0ef41Sopenharmony_ci case IrOpcode::kParameter: 591cb0ef41Sopenharmony_ci return false; 601cb0ef41Sopenharmony_ci default: 611cb0ef41Sopenharmony_ci break; 621cb0ef41Sopenharmony_ci } 631cb0ef41Sopenharmony_ci } 641cb0ef41Sopenharmony_ci } 651cb0ef41Sopenharmony_ci return true; 661cb0ef41Sopenharmony_ci} 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_cibool MustAlias(Node* a, Node* b) { 691cb0ef41Sopenharmony_ci return ResolveRenames(a) == ResolveRenames(b); 701cb0ef41Sopenharmony_ci} 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci} // namespace 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ciReduction LoadElimination::Reduce(Node* node) { 751cb0ef41Sopenharmony_ci if (FLAG_trace_turbo_load_elimination) { 761cb0ef41Sopenharmony_ci if (node->op()->EffectInputCount() > 0) { 771cb0ef41Sopenharmony_ci PrintF(" visit #%d:%s", node->id(), node->op()->mnemonic()); 781cb0ef41Sopenharmony_ci if (node->op()->ValueInputCount() > 0) { 791cb0ef41Sopenharmony_ci PrintF("("); 801cb0ef41Sopenharmony_ci for (int i = 0; i < node->op()->ValueInputCount(); ++i) { 811cb0ef41Sopenharmony_ci if (i > 0) PrintF(", "); 821cb0ef41Sopenharmony_ci Node* const value = NodeProperties::GetValueInput(node, i); 831cb0ef41Sopenharmony_ci PrintF("#%d:%s", value->id(), value->op()->mnemonic()); 841cb0ef41Sopenharmony_ci } 851cb0ef41Sopenharmony_ci PrintF(")"); 861cb0ef41Sopenharmony_ci } 871cb0ef41Sopenharmony_ci PrintF("\n"); 881cb0ef41Sopenharmony_ci for (int i = 0; i < node->op()->EffectInputCount(); ++i) { 891cb0ef41Sopenharmony_ci Node* const effect = NodeProperties::GetEffectInput(node, i); 901cb0ef41Sopenharmony_ci if (AbstractState const* const state = node_states_.Get(effect)) { 911cb0ef41Sopenharmony_ci PrintF(" state[%i]: #%d:%s\n", i, effect->id(), 921cb0ef41Sopenharmony_ci effect->op()->mnemonic()); 931cb0ef41Sopenharmony_ci state->Print(); 941cb0ef41Sopenharmony_ci } else { 951cb0ef41Sopenharmony_ci PrintF(" no state[%i]: #%d:%s\n", i, effect->id(), 961cb0ef41Sopenharmony_ci effect->op()->mnemonic()); 971cb0ef41Sopenharmony_ci } 981cb0ef41Sopenharmony_ci } 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci } 1011cb0ef41Sopenharmony_ci switch (node->opcode()) { 1021cb0ef41Sopenharmony_ci case IrOpcode::kMapGuard: 1031cb0ef41Sopenharmony_ci return ReduceMapGuard(node); 1041cb0ef41Sopenharmony_ci case IrOpcode::kCheckMaps: 1051cb0ef41Sopenharmony_ci return ReduceCheckMaps(node); 1061cb0ef41Sopenharmony_ci case IrOpcode::kCompareMaps: 1071cb0ef41Sopenharmony_ci return ReduceCompareMaps(node); 1081cb0ef41Sopenharmony_ci case IrOpcode::kEnsureWritableFastElements: 1091cb0ef41Sopenharmony_ci return ReduceEnsureWritableFastElements(node); 1101cb0ef41Sopenharmony_ci case IrOpcode::kMaybeGrowFastElements: 1111cb0ef41Sopenharmony_ci return ReduceMaybeGrowFastElements(node); 1121cb0ef41Sopenharmony_ci case IrOpcode::kTransitionElementsKind: 1131cb0ef41Sopenharmony_ci return ReduceTransitionElementsKind(node); 1141cb0ef41Sopenharmony_ci case IrOpcode::kLoadField: 1151cb0ef41Sopenharmony_ci return ReduceLoadField(node, FieldAccessOf(node->op())); 1161cb0ef41Sopenharmony_ci case IrOpcode::kStoreField: 1171cb0ef41Sopenharmony_ci return ReduceStoreField(node, FieldAccessOf(node->op())); 1181cb0ef41Sopenharmony_ci case IrOpcode::kLoadElement: 1191cb0ef41Sopenharmony_ci return ReduceLoadElement(node); 1201cb0ef41Sopenharmony_ci case IrOpcode::kStoreElement: 1211cb0ef41Sopenharmony_ci return ReduceStoreElement(node); 1221cb0ef41Sopenharmony_ci case IrOpcode::kTransitionAndStoreElement: 1231cb0ef41Sopenharmony_ci return ReduceTransitionAndStoreElement(node); 1241cb0ef41Sopenharmony_ci case IrOpcode::kStoreTypedElement: 1251cb0ef41Sopenharmony_ci return ReduceStoreTypedElement(node); 1261cb0ef41Sopenharmony_ci case IrOpcode::kEffectPhi: 1271cb0ef41Sopenharmony_ci return ReduceEffectPhi(node); 1281cb0ef41Sopenharmony_ci case IrOpcode::kDead: 1291cb0ef41Sopenharmony_ci break; 1301cb0ef41Sopenharmony_ci case IrOpcode::kStart: 1311cb0ef41Sopenharmony_ci return ReduceStart(node); 1321cb0ef41Sopenharmony_ci default: 1331cb0ef41Sopenharmony_ci return ReduceOtherNode(node); 1341cb0ef41Sopenharmony_ci } 1351cb0ef41Sopenharmony_ci return NoChange(); 1361cb0ef41Sopenharmony_ci} 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_cinamespace { 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_cibool IsCompatible(MachineRepresentation r1, MachineRepresentation r2) { 1411cb0ef41Sopenharmony_ci if (r1 == r2) return true; 1421cb0ef41Sopenharmony_ci return IsAnyTagged(r1) && IsAnyTagged(r2); 1431cb0ef41Sopenharmony_ci} 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci} // namespace 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ciLoadElimination::AbstractState const 1481cb0ef41Sopenharmony_ci LoadElimination::AbstractState::empty_state_; 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ciNode* LoadElimination::AbstractElements::Lookup( 1511cb0ef41Sopenharmony_ci Node* object, Node* index, MachineRepresentation representation) const { 1521cb0ef41Sopenharmony_ci for (Element const element : elements_) { 1531cb0ef41Sopenharmony_ci if (element.object == nullptr) continue; 1541cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(element.index); 1551cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(element.value); 1561cb0ef41Sopenharmony_ci if (MustAlias(object, element.object) && MustAlias(index, element.index) && 1571cb0ef41Sopenharmony_ci IsCompatible(representation, element.representation)) { 1581cb0ef41Sopenharmony_ci return element.value; 1591cb0ef41Sopenharmony_ci } 1601cb0ef41Sopenharmony_ci } 1611cb0ef41Sopenharmony_ci return nullptr; 1621cb0ef41Sopenharmony_ci} 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_ciLoadElimination::AbstractElements const* 1651cb0ef41Sopenharmony_ciLoadElimination::AbstractElements::Kill(Node* object, Node* index, 1661cb0ef41Sopenharmony_ci Zone* zone) const { 1671cb0ef41Sopenharmony_ci for (Element const element : this->elements_) { 1681cb0ef41Sopenharmony_ci if (element.object == nullptr) continue; 1691cb0ef41Sopenharmony_ci if (MayAlias(object, element.object)) { 1701cb0ef41Sopenharmony_ci AbstractElements* that = zone->New<AbstractElements>(zone); 1711cb0ef41Sopenharmony_ci for (Element const element2 : this->elements_) { 1721cb0ef41Sopenharmony_ci if (element2.object == nullptr) continue; 1731cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(element2.index); 1741cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(element2.value); 1751cb0ef41Sopenharmony_ci if (!MayAlias(object, element2.object) || 1761cb0ef41Sopenharmony_ci !NodeProperties::GetType(index).Maybe( 1771cb0ef41Sopenharmony_ci NodeProperties::GetType(element2.index))) { 1781cb0ef41Sopenharmony_ci that->elements_[that->next_index_++] = element2; 1791cb0ef41Sopenharmony_ci } 1801cb0ef41Sopenharmony_ci } 1811cb0ef41Sopenharmony_ci that->next_index_ %= arraysize(elements_); 1821cb0ef41Sopenharmony_ci return that; 1831cb0ef41Sopenharmony_ci } 1841cb0ef41Sopenharmony_ci } 1851cb0ef41Sopenharmony_ci return this; 1861cb0ef41Sopenharmony_ci} 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_cibool LoadElimination::AbstractElements::Equals( 1891cb0ef41Sopenharmony_ci AbstractElements const* that) const { 1901cb0ef41Sopenharmony_ci if (this == that) return true; 1911cb0ef41Sopenharmony_ci for (size_t i = 0; i < arraysize(elements_); ++i) { 1921cb0ef41Sopenharmony_ci Element this_element = this->elements_[i]; 1931cb0ef41Sopenharmony_ci if (this_element.object == nullptr) continue; 1941cb0ef41Sopenharmony_ci for (size_t j = 0;; ++j) { 1951cb0ef41Sopenharmony_ci if (j == arraysize(elements_)) return false; 1961cb0ef41Sopenharmony_ci Element that_element = that->elements_[j]; 1971cb0ef41Sopenharmony_ci if (this_element.object == that_element.object && 1981cb0ef41Sopenharmony_ci this_element.index == that_element.index && 1991cb0ef41Sopenharmony_ci this_element.value == that_element.value) { 2001cb0ef41Sopenharmony_ci break; 2011cb0ef41Sopenharmony_ci } 2021cb0ef41Sopenharmony_ci } 2031cb0ef41Sopenharmony_ci } 2041cb0ef41Sopenharmony_ci for (size_t i = 0; i < arraysize(elements_); ++i) { 2051cb0ef41Sopenharmony_ci Element that_element = that->elements_[i]; 2061cb0ef41Sopenharmony_ci if (that_element.object == nullptr) continue; 2071cb0ef41Sopenharmony_ci for (size_t j = 0;; ++j) { 2081cb0ef41Sopenharmony_ci if (j == arraysize(elements_)) return false; 2091cb0ef41Sopenharmony_ci Element this_element = this->elements_[j]; 2101cb0ef41Sopenharmony_ci if (that_element.object == this_element.object && 2111cb0ef41Sopenharmony_ci that_element.index == this_element.index && 2121cb0ef41Sopenharmony_ci that_element.value == this_element.value) { 2131cb0ef41Sopenharmony_ci break; 2141cb0ef41Sopenharmony_ci } 2151cb0ef41Sopenharmony_ci } 2161cb0ef41Sopenharmony_ci } 2171cb0ef41Sopenharmony_ci return true; 2181cb0ef41Sopenharmony_ci} 2191cb0ef41Sopenharmony_ci 2201cb0ef41Sopenharmony_ciLoadElimination::AbstractElements const* 2211cb0ef41Sopenharmony_ciLoadElimination::AbstractElements::Merge(AbstractElements const* that, 2221cb0ef41Sopenharmony_ci Zone* zone) const { 2231cb0ef41Sopenharmony_ci if (this->Equals(that)) return this; 2241cb0ef41Sopenharmony_ci AbstractElements* copy = zone->New<AbstractElements>(zone); 2251cb0ef41Sopenharmony_ci for (Element const this_element : this->elements_) { 2261cb0ef41Sopenharmony_ci if (this_element.object == nullptr) continue; 2271cb0ef41Sopenharmony_ci for (Element const that_element : that->elements_) { 2281cb0ef41Sopenharmony_ci if (this_element.object == that_element.object && 2291cb0ef41Sopenharmony_ci this_element.index == that_element.index && 2301cb0ef41Sopenharmony_ci this_element.value == that_element.value) { 2311cb0ef41Sopenharmony_ci copy->elements_[copy->next_index_++] = this_element; 2321cb0ef41Sopenharmony_ci break; 2331cb0ef41Sopenharmony_ci } 2341cb0ef41Sopenharmony_ci } 2351cb0ef41Sopenharmony_ci } 2361cb0ef41Sopenharmony_ci copy->next_index_ %= arraysize(elements_); 2371cb0ef41Sopenharmony_ci return copy; 2381cb0ef41Sopenharmony_ci} 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_civoid LoadElimination::AbstractElements::Print() const { 2411cb0ef41Sopenharmony_ci for (Element const& element : elements_) { 2421cb0ef41Sopenharmony_ci if (element.object) { 2431cb0ef41Sopenharmony_ci PrintF(" #%d:%s @ #%d:%s -> #%d:%s\n", element.object->id(), 2441cb0ef41Sopenharmony_ci element.object->op()->mnemonic(), element.index->id(), 2451cb0ef41Sopenharmony_ci element.index->op()->mnemonic(), element.value->id(), 2461cb0ef41Sopenharmony_ci element.value->op()->mnemonic()); 2471cb0ef41Sopenharmony_ci } 2481cb0ef41Sopenharmony_ci } 2491cb0ef41Sopenharmony_ci} 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_ciLoadElimination::FieldInfo const* LoadElimination::AbstractField::Lookup( 2521cb0ef41Sopenharmony_ci Node* object) const { 2531cb0ef41Sopenharmony_ci for (auto& pair : info_for_node_) { 2541cb0ef41Sopenharmony_ci if (pair.first->IsDead()) continue; 2551cb0ef41Sopenharmony_ci if (MustAlias(object, pair.first)) return &pair.second; 2561cb0ef41Sopenharmony_ci } 2571cb0ef41Sopenharmony_ci return nullptr; 2581cb0ef41Sopenharmony_ci} 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_cinamespace { 2611cb0ef41Sopenharmony_ci 2621cb0ef41Sopenharmony_cibool MayAlias(MaybeHandle<Name> x, MaybeHandle<Name> y) { 2631cb0ef41Sopenharmony_ci if (!x.address()) return true; 2641cb0ef41Sopenharmony_ci if (!y.address()) return true; 2651cb0ef41Sopenharmony_ci if (x.address() != y.address()) return false; 2661cb0ef41Sopenharmony_ci return true; 2671cb0ef41Sopenharmony_ci} 2681cb0ef41Sopenharmony_ci 2691cb0ef41Sopenharmony_ci} // namespace 2701cb0ef41Sopenharmony_ci 2711cb0ef41Sopenharmony_ciclass LoadElimination::AliasStateInfo { 2721cb0ef41Sopenharmony_ci public: 2731cb0ef41Sopenharmony_ci AliasStateInfo(const AbstractState* state, Node* object, Handle<Map> map) 2741cb0ef41Sopenharmony_ci : state_(state), object_(object), map_(map) {} 2751cb0ef41Sopenharmony_ci AliasStateInfo(const AbstractState* state, Node* object) 2761cb0ef41Sopenharmony_ci : state_(state), object_(object) {} 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_ci bool MayAlias(Node* other) const; 2791cb0ef41Sopenharmony_ci 2801cb0ef41Sopenharmony_ci private: 2811cb0ef41Sopenharmony_ci const AbstractState* state_; 2821cb0ef41Sopenharmony_ci Node* object_; 2831cb0ef41Sopenharmony_ci MaybeHandle<Map> map_; 2841cb0ef41Sopenharmony_ci}; 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ciLoadElimination::AbstractField const* LoadElimination::AbstractField::KillConst( 2871cb0ef41Sopenharmony_ci Node* object, Zone* zone) const { 2881cb0ef41Sopenharmony_ci for (auto info1 : this->info_for_node_) { 2891cb0ef41Sopenharmony_ci if (info1.first->IsDead()) continue; 2901cb0ef41Sopenharmony_ci // If we previously recorded information about a const store on the given 2911cb0ef41Sopenharmony_ci // 'object', we might not have done it on the same node; e.g. we might now 2921cb0ef41Sopenharmony_ci // identify the object by a FinishRegion node, whereas the initial const 2931cb0ef41Sopenharmony_ci // store was performed on the Allocate node. We therefore remove information 2941cb0ef41Sopenharmony_ci // on all nodes that must alias with 'object'. 2951cb0ef41Sopenharmony_ci if (MustAlias(object, info1.first)) { 2961cb0ef41Sopenharmony_ci AbstractField* that = zone->New<AbstractField>(zone); 2971cb0ef41Sopenharmony_ci for (auto info2 : this->info_for_node_) { 2981cb0ef41Sopenharmony_ci if (!MustAlias(object, info2.first)) { 2991cb0ef41Sopenharmony_ci that->info_for_node_.insert(info2); 3001cb0ef41Sopenharmony_ci } 3011cb0ef41Sopenharmony_ci } 3021cb0ef41Sopenharmony_ci return that; 3031cb0ef41Sopenharmony_ci } 3041cb0ef41Sopenharmony_ci } 3051cb0ef41Sopenharmony_ci return this; 3061cb0ef41Sopenharmony_ci} 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_ciLoadElimination::AbstractField const* LoadElimination::AbstractField::Kill( 3091cb0ef41Sopenharmony_ci const AliasStateInfo& alias_info, MaybeHandle<Name> name, 3101cb0ef41Sopenharmony_ci Zone* zone) const { 3111cb0ef41Sopenharmony_ci for (auto info1 : this->info_for_node_) { 3121cb0ef41Sopenharmony_ci if (info1.first->IsDead()) continue; 3131cb0ef41Sopenharmony_ci if (alias_info.MayAlias(info1.first)) { 3141cb0ef41Sopenharmony_ci AbstractField* that = zone->New<AbstractField>(zone); 3151cb0ef41Sopenharmony_ci for (auto info2 : this->info_for_node_) { 3161cb0ef41Sopenharmony_ci if (!alias_info.MayAlias(info2.first) || 3171cb0ef41Sopenharmony_ci !MayAlias(name, info2.second.name)) { 3181cb0ef41Sopenharmony_ci that->info_for_node_.insert(info2); 3191cb0ef41Sopenharmony_ci } 3201cb0ef41Sopenharmony_ci } 3211cb0ef41Sopenharmony_ci return that; 3221cb0ef41Sopenharmony_ci } 3231cb0ef41Sopenharmony_ci } 3241cb0ef41Sopenharmony_ci return this; 3251cb0ef41Sopenharmony_ci} 3261cb0ef41Sopenharmony_ci 3271cb0ef41Sopenharmony_civoid LoadElimination::AbstractField::Print() const { 3281cb0ef41Sopenharmony_ci for (auto pair : info_for_node_) { 3291cb0ef41Sopenharmony_ci PrintF(" #%d:%s -> #%d:%s [repr=%s]\n", pair.first->id(), 3301cb0ef41Sopenharmony_ci pair.first->op()->mnemonic(), pair.second.value->id(), 3311cb0ef41Sopenharmony_ci pair.second.value->op()->mnemonic(), 3321cb0ef41Sopenharmony_ci MachineReprToString(pair.second.representation)); 3331cb0ef41Sopenharmony_ci } 3341cb0ef41Sopenharmony_ci} 3351cb0ef41Sopenharmony_ci 3361cb0ef41Sopenharmony_ciLoadElimination::AbstractMaps::AbstractMaps(Zone* zone) 3371cb0ef41Sopenharmony_ci : info_for_node_(zone) {} 3381cb0ef41Sopenharmony_ci 3391cb0ef41Sopenharmony_ciLoadElimination::AbstractMaps::AbstractMaps(Node* object, 3401cb0ef41Sopenharmony_ci ZoneHandleSet<Map> maps, Zone* zone) 3411cb0ef41Sopenharmony_ci : info_for_node_(zone) { 3421cb0ef41Sopenharmony_ci object = ResolveRenames(object); 3431cb0ef41Sopenharmony_ci info_for_node_.insert(std::make_pair(object, maps)); 3441cb0ef41Sopenharmony_ci} 3451cb0ef41Sopenharmony_ci 3461cb0ef41Sopenharmony_cibool LoadElimination::AbstractMaps::Lookup( 3471cb0ef41Sopenharmony_ci Node* object, ZoneHandleSet<Map>* object_maps) const { 3481cb0ef41Sopenharmony_ci auto it = info_for_node_.find(ResolveRenames(object)); 3491cb0ef41Sopenharmony_ci if (it == info_for_node_.end()) return false; 3501cb0ef41Sopenharmony_ci *object_maps = it->second; 3511cb0ef41Sopenharmony_ci return true; 3521cb0ef41Sopenharmony_ci} 3531cb0ef41Sopenharmony_ci 3541cb0ef41Sopenharmony_ciLoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Kill( 3551cb0ef41Sopenharmony_ci const AliasStateInfo& alias_info, Zone* zone) const { 3561cb0ef41Sopenharmony_ci for (auto info1 : this->info_for_node_) { 3571cb0ef41Sopenharmony_ci if (alias_info.MayAlias(info1.first)) { 3581cb0ef41Sopenharmony_ci AbstractMaps* that = zone->New<AbstractMaps>(zone); 3591cb0ef41Sopenharmony_ci for (auto info2 : this->info_for_node_) { 3601cb0ef41Sopenharmony_ci if (!alias_info.MayAlias(info2.first)) 3611cb0ef41Sopenharmony_ci that->info_for_node_.insert(info2); 3621cb0ef41Sopenharmony_ci } 3631cb0ef41Sopenharmony_ci return that; 3641cb0ef41Sopenharmony_ci } 3651cb0ef41Sopenharmony_ci } 3661cb0ef41Sopenharmony_ci return this; 3671cb0ef41Sopenharmony_ci} 3681cb0ef41Sopenharmony_ci 3691cb0ef41Sopenharmony_ciLoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Merge( 3701cb0ef41Sopenharmony_ci AbstractMaps const* that, Zone* zone) const { 3711cb0ef41Sopenharmony_ci if (this->Equals(that)) return this; 3721cb0ef41Sopenharmony_ci AbstractMaps* copy = zone->New<AbstractMaps>(zone); 3731cb0ef41Sopenharmony_ci for (auto this_it : this->info_for_node_) { 3741cb0ef41Sopenharmony_ci Node* this_object = this_it.first; 3751cb0ef41Sopenharmony_ci ZoneHandleSet<Map> this_maps = this_it.second; 3761cb0ef41Sopenharmony_ci auto that_it = that->info_for_node_.find(this_object); 3771cb0ef41Sopenharmony_ci if (that_it != that->info_for_node_.end() && that_it->second == this_maps) { 3781cb0ef41Sopenharmony_ci copy->info_for_node_.insert(this_it); 3791cb0ef41Sopenharmony_ci } 3801cb0ef41Sopenharmony_ci } 3811cb0ef41Sopenharmony_ci return copy; 3821cb0ef41Sopenharmony_ci} 3831cb0ef41Sopenharmony_ci 3841cb0ef41Sopenharmony_ciLoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Extend( 3851cb0ef41Sopenharmony_ci Node* object, ZoneHandleSet<Map> maps, Zone* zone) const { 3861cb0ef41Sopenharmony_ci AbstractMaps* that = zone->New<AbstractMaps>(zone); 3871cb0ef41Sopenharmony_ci that->info_for_node_ = this->info_for_node_; 3881cb0ef41Sopenharmony_ci object = ResolveRenames(object); 3891cb0ef41Sopenharmony_ci that->info_for_node_[object] = maps; 3901cb0ef41Sopenharmony_ci return that; 3911cb0ef41Sopenharmony_ci} 3921cb0ef41Sopenharmony_ci 3931cb0ef41Sopenharmony_civoid LoadElimination::AbstractMaps::Print() const { 3941cb0ef41Sopenharmony_ci AllowHandleDereference allow_handle_dereference; 3951cb0ef41Sopenharmony_ci StdoutStream os; 3961cb0ef41Sopenharmony_ci for (auto pair : info_for_node_) { 3971cb0ef41Sopenharmony_ci os << " #" << pair.first->id() << ":" << pair.first->op()->mnemonic() 3981cb0ef41Sopenharmony_ci << std::endl; 3991cb0ef41Sopenharmony_ci ZoneHandleSet<Map> const& maps = pair.second; 4001cb0ef41Sopenharmony_ci for (size_t i = 0; i < maps.size(); ++i) { 4011cb0ef41Sopenharmony_ci os << " - " << Brief(*maps[i]) << std::endl; 4021cb0ef41Sopenharmony_ci } 4031cb0ef41Sopenharmony_ci } 4041cb0ef41Sopenharmony_ci} 4051cb0ef41Sopenharmony_ci 4061cb0ef41Sopenharmony_cibool LoadElimination::AbstractState::FieldsEquals( 4071cb0ef41Sopenharmony_ci AbstractFields const& this_fields, 4081cb0ef41Sopenharmony_ci AbstractFields const& that_fields) const { 4091cb0ef41Sopenharmony_ci for (size_t i = 0u; i < this_fields.size(); ++i) { 4101cb0ef41Sopenharmony_ci AbstractField const* this_field = this_fields[i]; 4111cb0ef41Sopenharmony_ci AbstractField const* that_field = that_fields[i]; 4121cb0ef41Sopenharmony_ci if (this_field) { 4131cb0ef41Sopenharmony_ci if (!that_field || !that_field->Equals(this_field)) return false; 4141cb0ef41Sopenharmony_ci } else if (that_field) { 4151cb0ef41Sopenharmony_ci return false; 4161cb0ef41Sopenharmony_ci } 4171cb0ef41Sopenharmony_ci } 4181cb0ef41Sopenharmony_ci return true; 4191cb0ef41Sopenharmony_ci} 4201cb0ef41Sopenharmony_ci 4211cb0ef41Sopenharmony_cibool LoadElimination::AbstractState::Equals(AbstractState const* that) const { 4221cb0ef41Sopenharmony_ci if (this->elements_) { 4231cb0ef41Sopenharmony_ci if (!that->elements_ || !that->elements_->Equals(this->elements_)) { 4241cb0ef41Sopenharmony_ci return false; 4251cb0ef41Sopenharmony_ci } 4261cb0ef41Sopenharmony_ci } else if (that->elements_) { 4271cb0ef41Sopenharmony_ci return false; 4281cb0ef41Sopenharmony_ci } 4291cb0ef41Sopenharmony_ci if (!FieldsEquals(this->fields_, that->fields_) || 4301cb0ef41Sopenharmony_ci !FieldsEquals(this->const_fields_, that->const_fields_)) { 4311cb0ef41Sopenharmony_ci return false; 4321cb0ef41Sopenharmony_ci } 4331cb0ef41Sopenharmony_ci if (this->maps_) { 4341cb0ef41Sopenharmony_ci if (!that->maps_ || !that->maps_->Equals(this->maps_)) { 4351cb0ef41Sopenharmony_ci return false; 4361cb0ef41Sopenharmony_ci } 4371cb0ef41Sopenharmony_ci } else if (that->maps_) { 4381cb0ef41Sopenharmony_ci return false; 4391cb0ef41Sopenharmony_ci } 4401cb0ef41Sopenharmony_ci return true; 4411cb0ef41Sopenharmony_ci} 4421cb0ef41Sopenharmony_ci 4431cb0ef41Sopenharmony_civoid LoadElimination::AbstractState::FieldsMerge( 4441cb0ef41Sopenharmony_ci AbstractFields* this_fields, AbstractFields const& that_fields, 4451cb0ef41Sopenharmony_ci Zone* zone) { 4461cb0ef41Sopenharmony_ci for (size_t i = 0; i < this_fields->size(); ++i) { 4471cb0ef41Sopenharmony_ci AbstractField const*& this_field = (*this_fields)[i]; 4481cb0ef41Sopenharmony_ci if (this_field) { 4491cb0ef41Sopenharmony_ci if (that_fields[i]) { 4501cb0ef41Sopenharmony_ci this_field = this_field->Merge(that_fields[i], zone); 4511cb0ef41Sopenharmony_ci } else { 4521cb0ef41Sopenharmony_ci this_field = nullptr; 4531cb0ef41Sopenharmony_ci } 4541cb0ef41Sopenharmony_ci } 4551cb0ef41Sopenharmony_ci } 4561cb0ef41Sopenharmony_ci} 4571cb0ef41Sopenharmony_ci 4581cb0ef41Sopenharmony_civoid LoadElimination::AbstractState::Merge(AbstractState const* that, 4591cb0ef41Sopenharmony_ci Zone* zone) { 4601cb0ef41Sopenharmony_ci // Merge the information we have about the elements. 4611cb0ef41Sopenharmony_ci if (this->elements_) { 4621cb0ef41Sopenharmony_ci this->elements_ = that->elements_ 4631cb0ef41Sopenharmony_ci ? that->elements_->Merge(this->elements_, zone) 4641cb0ef41Sopenharmony_ci : nullptr; 4651cb0ef41Sopenharmony_ci } 4661cb0ef41Sopenharmony_ci 4671cb0ef41Sopenharmony_ci // Merge the information we have about the fields. 4681cb0ef41Sopenharmony_ci FieldsMerge(&this->fields_, that->fields_, zone); 4691cb0ef41Sopenharmony_ci FieldsMerge(&this->const_fields_, that->const_fields_, zone); 4701cb0ef41Sopenharmony_ci 4711cb0ef41Sopenharmony_ci // Merge the information we have about the maps. 4721cb0ef41Sopenharmony_ci if (this->maps_) { 4731cb0ef41Sopenharmony_ci this->maps_ = that->maps_ ? that->maps_->Merge(this->maps_, zone) : nullptr; 4741cb0ef41Sopenharmony_ci } 4751cb0ef41Sopenharmony_ci} 4761cb0ef41Sopenharmony_ci 4771cb0ef41Sopenharmony_cibool LoadElimination::AbstractState::LookupMaps( 4781cb0ef41Sopenharmony_ci Node* object, ZoneHandleSet<Map>* object_map) const { 4791cb0ef41Sopenharmony_ci return this->maps_ && this->maps_->Lookup(object, object_map); 4801cb0ef41Sopenharmony_ci} 4811cb0ef41Sopenharmony_ci 4821cb0ef41Sopenharmony_ciLoadElimination::AbstractState const* LoadElimination::AbstractState::SetMaps( 4831cb0ef41Sopenharmony_ci Node* object, ZoneHandleSet<Map> maps, Zone* zone) const { 4841cb0ef41Sopenharmony_ci AbstractState* that = zone->New<AbstractState>(*this); 4851cb0ef41Sopenharmony_ci if (that->maps_) { 4861cb0ef41Sopenharmony_ci that->maps_ = that->maps_->Extend(object, maps, zone); 4871cb0ef41Sopenharmony_ci } else { 4881cb0ef41Sopenharmony_ci that->maps_ = zone->New<AbstractMaps>(object, maps, zone); 4891cb0ef41Sopenharmony_ci } 4901cb0ef41Sopenharmony_ci return that; 4911cb0ef41Sopenharmony_ci} 4921cb0ef41Sopenharmony_ci 4931cb0ef41Sopenharmony_ciLoadElimination::AbstractState const* LoadElimination::AbstractState::KillMaps( 4941cb0ef41Sopenharmony_ci const AliasStateInfo& alias_info, Zone* zone) const { 4951cb0ef41Sopenharmony_ci if (this->maps_) { 4961cb0ef41Sopenharmony_ci AbstractMaps const* that_maps = this->maps_->Kill(alias_info, zone); 4971cb0ef41Sopenharmony_ci if (this->maps_ != that_maps) { 4981cb0ef41Sopenharmony_ci AbstractState* that = zone->New<AbstractState>(*this); 4991cb0ef41Sopenharmony_ci that->maps_ = that_maps; 5001cb0ef41Sopenharmony_ci return that; 5011cb0ef41Sopenharmony_ci } 5021cb0ef41Sopenharmony_ci } 5031cb0ef41Sopenharmony_ci return this; 5041cb0ef41Sopenharmony_ci} 5051cb0ef41Sopenharmony_ci 5061cb0ef41Sopenharmony_ciLoadElimination::AbstractState const* LoadElimination::AbstractState::KillMaps( 5071cb0ef41Sopenharmony_ci Node* object, Zone* zone) const { 5081cb0ef41Sopenharmony_ci AliasStateInfo alias_info(this, object); 5091cb0ef41Sopenharmony_ci return KillMaps(alias_info, zone); 5101cb0ef41Sopenharmony_ci} 5111cb0ef41Sopenharmony_ci 5121cb0ef41Sopenharmony_ciNode* LoadElimination::AbstractState::LookupElement( 5131cb0ef41Sopenharmony_ci Node* object, Node* index, MachineRepresentation representation) const { 5141cb0ef41Sopenharmony_ci if (this->elements_) { 5151cb0ef41Sopenharmony_ci return this->elements_->Lookup(object, index, representation); 5161cb0ef41Sopenharmony_ci } 5171cb0ef41Sopenharmony_ci return nullptr; 5181cb0ef41Sopenharmony_ci} 5191cb0ef41Sopenharmony_ci 5201cb0ef41Sopenharmony_ciLoadElimination::AbstractState const* 5211cb0ef41Sopenharmony_ciLoadElimination::AbstractState::AddElement(Node* object, Node* index, 5221cb0ef41Sopenharmony_ci Node* value, 5231cb0ef41Sopenharmony_ci MachineRepresentation representation, 5241cb0ef41Sopenharmony_ci Zone* zone) const { 5251cb0ef41Sopenharmony_ci AbstractState* that = zone->New<AbstractState>(*this); 5261cb0ef41Sopenharmony_ci if (that->elements_) { 5271cb0ef41Sopenharmony_ci that->elements_ = 5281cb0ef41Sopenharmony_ci that->elements_->Extend(object, index, value, representation, zone); 5291cb0ef41Sopenharmony_ci } else { 5301cb0ef41Sopenharmony_ci that->elements_ = 5311cb0ef41Sopenharmony_ci zone->New<AbstractElements>(object, index, value, representation, zone); 5321cb0ef41Sopenharmony_ci } 5331cb0ef41Sopenharmony_ci return that; 5341cb0ef41Sopenharmony_ci} 5351cb0ef41Sopenharmony_ci 5361cb0ef41Sopenharmony_ciLoadElimination::AbstractState const* 5371cb0ef41Sopenharmony_ciLoadElimination::AbstractState::KillElement(Node* object, Node* index, 5381cb0ef41Sopenharmony_ci Zone* zone) const { 5391cb0ef41Sopenharmony_ci if (this->elements_) { 5401cb0ef41Sopenharmony_ci AbstractElements const* that_elements = 5411cb0ef41Sopenharmony_ci this->elements_->Kill(object, index, zone); 5421cb0ef41Sopenharmony_ci if (this->elements_ != that_elements) { 5431cb0ef41Sopenharmony_ci AbstractState* that = zone->New<AbstractState>(*this); 5441cb0ef41Sopenharmony_ci that->elements_ = that_elements; 5451cb0ef41Sopenharmony_ci return that; 5461cb0ef41Sopenharmony_ci } 5471cb0ef41Sopenharmony_ci } 5481cb0ef41Sopenharmony_ci return this; 5491cb0ef41Sopenharmony_ci} 5501cb0ef41Sopenharmony_ci 5511cb0ef41Sopenharmony_ciLoadElimination::AbstractState const* LoadElimination::AbstractState::AddField( 5521cb0ef41Sopenharmony_ci Node* object, IndexRange index_range, LoadElimination::FieldInfo info, 5531cb0ef41Sopenharmony_ci Zone* zone) const { 5541cb0ef41Sopenharmony_ci AbstractState* that = zone->New<AbstractState>(*this); 5551cb0ef41Sopenharmony_ci AbstractFields& fields = 5561cb0ef41Sopenharmony_ci info.const_field_info.IsConst() ? that->const_fields_ : that->fields_; 5571cb0ef41Sopenharmony_ci for (int index : index_range) { 5581cb0ef41Sopenharmony_ci if (fields[index]) { 5591cb0ef41Sopenharmony_ci fields[index] = fields[index]->Extend(object, info, zone); 5601cb0ef41Sopenharmony_ci } else { 5611cb0ef41Sopenharmony_ci fields[index] = zone->New<AbstractField>(object, info, zone); 5621cb0ef41Sopenharmony_ci } 5631cb0ef41Sopenharmony_ci } 5641cb0ef41Sopenharmony_ci return that; 5651cb0ef41Sopenharmony_ci} 5661cb0ef41Sopenharmony_ci 5671cb0ef41Sopenharmony_ciLoadElimination::AbstractState const* 5681cb0ef41Sopenharmony_ciLoadElimination::AbstractState::KillConstField(Node* object, 5691cb0ef41Sopenharmony_ci IndexRange index_range, 5701cb0ef41Sopenharmony_ci Zone* zone) const { 5711cb0ef41Sopenharmony_ci AliasStateInfo alias_info(this, object); 5721cb0ef41Sopenharmony_ci AbstractState* that = nullptr; 5731cb0ef41Sopenharmony_ci for (int index : index_range) { 5741cb0ef41Sopenharmony_ci if (AbstractField const* this_field = this->const_fields_[index]) { 5751cb0ef41Sopenharmony_ci this_field = this_field->KillConst(object, zone); 5761cb0ef41Sopenharmony_ci if (this->const_fields_[index] != this_field) { 5771cb0ef41Sopenharmony_ci if (!that) that = zone->New<AbstractState>(*this); 5781cb0ef41Sopenharmony_ci that->const_fields_[index] = this_field; 5791cb0ef41Sopenharmony_ci } 5801cb0ef41Sopenharmony_ci } 5811cb0ef41Sopenharmony_ci } 5821cb0ef41Sopenharmony_ci return that ? that : this; 5831cb0ef41Sopenharmony_ci} 5841cb0ef41Sopenharmony_ci 5851cb0ef41Sopenharmony_ciLoadElimination::AbstractState const* LoadElimination::AbstractState::KillField( 5861cb0ef41Sopenharmony_ci Node* object, IndexRange index_range, MaybeHandle<Name> name, 5871cb0ef41Sopenharmony_ci Zone* zone) const { 5881cb0ef41Sopenharmony_ci AliasStateInfo alias_info(this, object); 5891cb0ef41Sopenharmony_ci return KillField(alias_info, index_range, name, zone); 5901cb0ef41Sopenharmony_ci} 5911cb0ef41Sopenharmony_ci 5921cb0ef41Sopenharmony_ciLoadElimination::AbstractState const* LoadElimination::AbstractState::KillField( 5931cb0ef41Sopenharmony_ci const AliasStateInfo& alias_info, IndexRange index_range, 5941cb0ef41Sopenharmony_ci MaybeHandle<Name> name, Zone* zone) const { 5951cb0ef41Sopenharmony_ci AbstractState* that = nullptr; 5961cb0ef41Sopenharmony_ci for (int index : index_range) { 5971cb0ef41Sopenharmony_ci if (AbstractField const* this_field = this->fields_[index]) { 5981cb0ef41Sopenharmony_ci this_field = this_field->Kill(alias_info, name, zone); 5991cb0ef41Sopenharmony_ci if (this->fields_[index] != this_field) { 6001cb0ef41Sopenharmony_ci if (!that) that = zone->New<AbstractState>(*this); 6011cb0ef41Sopenharmony_ci that->fields_[index] = this_field; 6021cb0ef41Sopenharmony_ci } 6031cb0ef41Sopenharmony_ci } 6041cb0ef41Sopenharmony_ci } 6051cb0ef41Sopenharmony_ci return that ? that : this; 6061cb0ef41Sopenharmony_ci} 6071cb0ef41Sopenharmony_ci 6081cb0ef41Sopenharmony_ciLoadElimination::AbstractState const* 6091cb0ef41Sopenharmony_ciLoadElimination::AbstractState::KillFields(Node* object, MaybeHandle<Name> name, 6101cb0ef41Sopenharmony_ci Zone* zone) const { 6111cb0ef41Sopenharmony_ci AliasStateInfo alias_info(this, object); 6121cb0ef41Sopenharmony_ci for (size_t i = 0;; ++i) { 6131cb0ef41Sopenharmony_ci if (i == fields_.size()) return this; 6141cb0ef41Sopenharmony_ci if (AbstractField const* this_field = this->fields_[i]) { 6151cb0ef41Sopenharmony_ci AbstractField const* that_field = 6161cb0ef41Sopenharmony_ci this_field->Kill(alias_info, name, zone); 6171cb0ef41Sopenharmony_ci if (that_field != this_field) { 6181cb0ef41Sopenharmony_ci AbstractState* that = zone->New<AbstractState>(*this); 6191cb0ef41Sopenharmony_ci that->fields_[i] = that_field; 6201cb0ef41Sopenharmony_ci while (++i < fields_.size()) { 6211cb0ef41Sopenharmony_ci if (this->fields_[i] != nullptr) { 6221cb0ef41Sopenharmony_ci that->fields_[i] = this->fields_[i]->Kill(alias_info, name, zone); 6231cb0ef41Sopenharmony_ci } 6241cb0ef41Sopenharmony_ci } 6251cb0ef41Sopenharmony_ci return that; 6261cb0ef41Sopenharmony_ci } 6271cb0ef41Sopenharmony_ci } 6281cb0ef41Sopenharmony_ci } 6291cb0ef41Sopenharmony_ci} 6301cb0ef41Sopenharmony_ci 6311cb0ef41Sopenharmony_ciLoadElimination::AbstractState const* LoadElimination::AbstractState::KillAll( 6321cb0ef41Sopenharmony_ci Zone* zone) const { 6331cb0ef41Sopenharmony_ci // Kill everything except for const fields 6341cb0ef41Sopenharmony_ci for (size_t i = 0; i < const_fields_.size(); ++i) { 6351cb0ef41Sopenharmony_ci if (const_fields_[i]) { 6361cb0ef41Sopenharmony_ci AbstractState* that = zone->New<AbstractState>(); 6371cb0ef41Sopenharmony_ci that->const_fields_ = const_fields_; 6381cb0ef41Sopenharmony_ci return that; 6391cb0ef41Sopenharmony_ci } 6401cb0ef41Sopenharmony_ci } 6411cb0ef41Sopenharmony_ci return LoadElimination::empty_state(); 6421cb0ef41Sopenharmony_ci} 6431cb0ef41Sopenharmony_ci 6441cb0ef41Sopenharmony_ciLoadElimination::FieldInfo const* LoadElimination::AbstractState::LookupField( 6451cb0ef41Sopenharmony_ci Node* object, IndexRange index_range, 6461cb0ef41Sopenharmony_ci ConstFieldInfo const_field_info) const { 6471cb0ef41Sopenharmony_ci // Check if all the indices in {index_range} contain identical information. 6481cb0ef41Sopenharmony_ci // If not, a partially overlapping access has invalidated part of the value. 6491cb0ef41Sopenharmony_ci base::Optional<LoadElimination::FieldInfo const*> result; 6501cb0ef41Sopenharmony_ci for (int index : index_range) { 6511cb0ef41Sopenharmony_ci LoadElimination::FieldInfo const* info = nullptr; 6521cb0ef41Sopenharmony_ci if (const_field_info.IsConst()) { 6531cb0ef41Sopenharmony_ci if (AbstractField const* this_field = const_fields_[index]) { 6541cb0ef41Sopenharmony_ci info = this_field->Lookup(object); 6551cb0ef41Sopenharmony_ci } 6561cb0ef41Sopenharmony_ci if (!(info && info->const_field_info == const_field_info)) return nullptr; 6571cb0ef41Sopenharmony_ci } else { 6581cb0ef41Sopenharmony_ci if (AbstractField const* this_field = fields_[index]) { 6591cb0ef41Sopenharmony_ci info = this_field->Lookup(object); 6601cb0ef41Sopenharmony_ci } 6611cb0ef41Sopenharmony_ci if (!info) return nullptr; 6621cb0ef41Sopenharmony_ci } 6631cb0ef41Sopenharmony_ci if (!result.has_value()) { 6641cb0ef41Sopenharmony_ci result = info; 6651cb0ef41Sopenharmony_ci } else if (**result != *info) { 6661cb0ef41Sopenharmony_ci // We detected inconsistent information for a field here. 6671cb0ef41Sopenharmony_ci // This can happen when incomplete alias information makes an unrelated 6681cb0ef41Sopenharmony_ci // write invalidate part of a field and then we re-combine this partial 6691cb0ef41Sopenharmony_ci // information. 6701cb0ef41Sopenharmony_ci // This is probably OK, but since it's rare, we better bail out here. 6711cb0ef41Sopenharmony_ci return nullptr; 6721cb0ef41Sopenharmony_ci } 6731cb0ef41Sopenharmony_ci } 6741cb0ef41Sopenharmony_ci return *result; 6751cb0ef41Sopenharmony_ci} 6761cb0ef41Sopenharmony_ci 6771cb0ef41Sopenharmony_cibool LoadElimination::AliasStateInfo::MayAlias(Node* other) const { 6781cb0ef41Sopenharmony_ci // If {object} is being initialized right here (indicated by {object} being 6791cb0ef41Sopenharmony_ci // an Allocate node instead of a FinishRegion node), we know that {other} 6801cb0ef41Sopenharmony_ci // can only alias with {object} if they refer to exactly the same node. 6811cb0ef41Sopenharmony_ci if (object_->opcode() == IrOpcode::kAllocate) { 6821cb0ef41Sopenharmony_ci return object_ == other; 6831cb0ef41Sopenharmony_ci } 6841cb0ef41Sopenharmony_ci // Decide aliasing based on the node kinds. 6851cb0ef41Sopenharmony_ci if (!compiler::MayAlias(object_, other)) { 6861cb0ef41Sopenharmony_ci return false; 6871cb0ef41Sopenharmony_ci } 6881cb0ef41Sopenharmony_ci // Decide aliasing based on maps (if available). 6891cb0ef41Sopenharmony_ci Handle<Map> map; 6901cb0ef41Sopenharmony_ci if (map_.ToHandle(&map)) { 6911cb0ef41Sopenharmony_ci ZoneHandleSet<Map> other_maps; 6921cb0ef41Sopenharmony_ci if (state_->LookupMaps(other, &other_maps) && other_maps.size() == 1) { 6931cb0ef41Sopenharmony_ci if (map.address() != other_maps.at(0).address()) { 6941cb0ef41Sopenharmony_ci return false; 6951cb0ef41Sopenharmony_ci } 6961cb0ef41Sopenharmony_ci } 6971cb0ef41Sopenharmony_ci } 6981cb0ef41Sopenharmony_ci return true; 6991cb0ef41Sopenharmony_ci} 7001cb0ef41Sopenharmony_ci 7011cb0ef41Sopenharmony_civoid LoadElimination::AbstractState::Print() const { 7021cb0ef41Sopenharmony_ci if (maps_) { 7031cb0ef41Sopenharmony_ci PrintF(" maps:\n"); 7041cb0ef41Sopenharmony_ci maps_->Print(); 7051cb0ef41Sopenharmony_ci } 7061cb0ef41Sopenharmony_ci if (elements_) { 7071cb0ef41Sopenharmony_ci PrintF(" elements:\n"); 7081cb0ef41Sopenharmony_ci elements_->Print(); 7091cb0ef41Sopenharmony_ci } 7101cb0ef41Sopenharmony_ci for (size_t i = 0; i < fields_.size(); ++i) { 7111cb0ef41Sopenharmony_ci if (AbstractField const* const field = fields_[i]) { 7121cb0ef41Sopenharmony_ci PrintF(" field %zu:\n", i); 7131cb0ef41Sopenharmony_ci field->Print(); 7141cb0ef41Sopenharmony_ci } 7151cb0ef41Sopenharmony_ci } 7161cb0ef41Sopenharmony_ci for (size_t i = 0; i < const_fields_.size(); ++i) { 7171cb0ef41Sopenharmony_ci if (AbstractField const* const const_field = const_fields_[i]) { 7181cb0ef41Sopenharmony_ci PrintF(" const field %zu:\n", i); 7191cb0ef41Sopenharmony_ci const_field->Print(); 7201cb0ef41Sopenharmony_ci } 7211cb0ef41Sopenharmony_ci } 7221cb0ef41Sopenharmony_ci} 7231cb0ef41Sopenharmony_ci 7241cb0ef41Sopenharmony_ciLoadElimination::AbstractState const* 7251cb0ef41Sopenharmony_ciLoadElimination::AbstractStateForEffectNodes::Get(Node* node) const { 7261cb0ef41Sopenharmony_ci size_t const id = node->id(); 7271cb0ef41Sopenharmony_ci if (id < info_for_node_.size()) return info_for_node_[id]; 7281cb0ef41Sopenharmony_ci return nullptr; 7291cb0ef41Sopenharmony_ci} 7301cb0ef41Sopenharmony_ci 7311cb0ef41Sopenharmony_civoid LoadElimination::AbstractStateForEffectNodes::Set( 7321cb0ef41Sopenharmony_ci Node* node, AbstractState const* state) { 7331cb0ef41Sopenharmony_ci size_t const id = node->id(); 7341cb0ef41Sopenharmony_ci if (id >= info_for_node_.size()) info_for_node_.resize(id + 1, nullptr); 7351cb0ef41Sopenharmony_ci info_for_node_[id] = state; 7361cb0ef41Sopenharmony_ci} 7371cb0ef41Sopenharmony_ci 7381cb0ef41Sopenharmony_ciReduction LoadElimination::ReduceMapGuard(Node* node) { 7391cb0ef41Sopenharmony_ci ZoneHandleSet<Map> const& maps = MapGuardMapsOf(node->op()); 7401cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(node, 0); 7411cb0ef41Sopenharmony_ci Node* const effect = NodeProperties::GetEffectInput(node); 7421cb0ef41Sopenharmony_ci AbstractState const* state = node_states_.Get(effect); 7431cb0ef41Sopenharmony_ci if (state == nullptr) return NoChange(); 7441cb0ef41Sopenharmony_ci ZoneHandleSet<Map> object_maps; 7451cb0ef41Sopenharmony_ci if (state->LookupMaps(object, &object_maps)) { 7461cb0ef41Sopenharmony_ci if (maps.contains(object_maps)) return Replace(effect); 7471cb0ef41Sopenharmony_ci // TODO(turbofan): Compute the intersection. 7481cb0ef41Sopenharmony_ci } 7491cb0ef41Sopenharmony_ci state = state->SetMaps(object, maps, zone()); 7501cb0ef41Sopenharmony_ci return UpdateState(node, state); 7511cb0ef41Sopenharmony_ci} 7521cb0ef41Sopenharmony_ci 7531cb0ef41Sopenharmony_ciReduction LoadElimination::ReduceCheckMaps(Node* node) { 7541cb0ef41Sopenharmony_ci ZoneHandleSet<Map> const& maps = CheckMapsParametersOf(node->op()).maps(); 7551cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(node, 0); 7561cb0ef41Sopenharmony_ci Node* const effect = NodeProperties::GetEffectInput(node); 7571cb0ef41Sopenharmony_ci AbstractState const* state = node_states_.Get(effect); 7581cb0ef41Sopenharmony_ci if (state == nullptr) return NoChange(); 7591cb0ef41Sopenharmony_ci ZoneHandleSet<Map> object_maps; 7601cb0ef41Sopenharmony_ci if (state->LookupMaps(object, &object_maps)) { 7611cb0ef41Sopenharmony_ci if (maps.contains(object_maps)) return Replace(effect); 7621cb0ef41Sopenharmony_ci // TODO(turbofan): Compute the intersection. 7631cb0ef41Sopenharmony_ci } 7641cb0ef41Sopenharmony_ci state = state->SetMaps(object, maps, zone()); 7651cb0ef41Sopenharmony_ci return UpdateState(node, state); 7661cb0ef41Sopenharmony_ci} 7671cb0ef41Sopenharmony_ci 7681cb0ef41Sopenharmony_ciReduction LoadElimination::ReduceCompareMaps(Node* node) { 7691cb0ef41Sopenharmony_ci ZoneHandleSet<Map> const& maps = CompareMapsParametersOf(node->op()); 7701cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(node, 0); 7711cb0ef41Sopenharmony_ci Node* const effect = NodeProperties::GetEffectInput(node); 7721cb0ef41Sopenharmony_ci AbstractState const* state = node_states_.Get(effect); 7731cb0ef41Sopenharmony_ci if (state == nullptr) return NoChange(); 7741cb0ef41Sopenharmony_ci ZoneHandleSet<Map> object_maps; 7751cb0ef41Sopenharmony_ci if (state->LookupMaps(object, &object_maps)) { 7761cb0ef41Sopenharmony_ci if (maps.contains(object_maps)) { 7771cb0ef41Sopenharmony_ci Node* value = jsgraph()->TrueConstant(); 7781cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect); 7791cb0ef41Sopenharmony_ci return Replace(value); 7801cb0ef41Sopenharmony_ci } 7811cb0ef41Sopenharmony_ci // TODO(turbofan): Compute the intersection. 7821cb0ef41Sopenharmony_ci } 7831cb0ef41Sopenharmony_ci return UpdateState(node, state); 7841cb0ef41Sopenharmony_ci} 7851cb0ef41Sopenharmony_ci 7861cb0ef41Sopenharmony_ciReduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) { 7871cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(node, 0); 7881cb0ef41Sopenharmony_ci Node* const elements = NodeProperties::GetValueInput(node, 1); 7891cb0ef41Sopenharmony_ci Node* const effect = NodeProperties::GetEffectInput(node); 7901cb0ef41Sopenharmony_ci AbstractState const* state = node_states_.Get(effect); 7911cb0ef41Sopenharmony_ci if (state == nullptr) return NoChange(); 7921cb0ef41Sopenharmony_ci // Check if the {elements} already have the fixed array map. 7931cb0ef41Sopenharmony_ci ZoneHandleSet<Map> elements_maps; 7941cb0ef41Sopenharmony_ci ZoneHandleSet<Map> fixed_array_maps(factory()->fixed_array_map()); 7951cb0ef41Sopenharmony_ci if (state->LookupMaps(elements, &elements_maps) && 7961cb0ef41Sopenharmony_ci fixed_array_maps.contains(elements_maps)) { 7971cb0ef41Sopenharmony_ci ReplaceWithValue(node, elements, effect); 7981cb0ef41Sopenharmony_ci return Replace(elements); 7991cb0ef41Sopenharmony_ci } 8001cb0ef41Sopenharmony_ci // We know that the resulting elements have the fixed array map. 8011cb0ef41Sopenharmony_ci state = state->SetMaps(node, fixed_array_maps, zone()); 8021cb0ef41Sopenharmony_ci // Kill the previous elements on {object}. 8031cb0ef41Sopenharmony_ci state = state->KillField(object, 8041cb0ef41Sopenharmony_ci FieldIndexOf(JSObject::kElementsOffset, kTaggedSize), 8051cb0ef41Sopenharmony_ci MaybeHandle<Name>(), zone()); 8061cb0ef41Sopenharmony_ci // Add the new elements on {object}. 8071cb0ef41Sopenharmony_ci state = state->AddField( 8081cb0ef41Sopenharmony_ci object, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize), 8091cb0ef41Sopenharmony_ci {node, MachineRepresentation::kTaggedPointer}, zone()); 8101cb0ef41Sopenharmony_ci return UpdateState(node, state); 8111cb0ef41Sopenharmony_ci} 8121cb0ef41Sopenharmony_ci 8131cb0ef41Sopenharmony_ciReduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) { 8141cb0ef41Sopenharmony_ci GrowFastElementsParameters params = GrowFastElementsParametersOf(node->op()); 8151cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(node, 0); 8161cb0ef41Sopenharmony_ci Node* const effect = NodeProperties::GetEffectInput(node); 8171cb0ef41Sopenharmony_ci AbstractState const* state = node_states_.Get(effect); 8181cb0ef41Sopenharmony_ci if (state == nullptr) return NoChange(); 8191cb0ef41Sopenharmony_ci if (params.mode() == GrowFastElementsMode::kDoubleElements) { 8201cb0ef41Sopenharmony_ci // We know that the resulting elements have the fixed double array map. 8211cb0ef41Sopenharmony_ci state = state->SetMaps( 8221cb0ef41Sopenharmony_ci node, ZoneHandleSet<Map>(factory()->fixed_double_array_map()), zone()); 8231cb0ef41Sopenharmony_ci } else { 8241cb0ef41Sopenharmony_ci // We know that the resulting elements have the fixed array map or the COW 8251cb0ef41Sopenharmony_ci // version thereof (if we didn't grow and it was already COW before). 8261cb0ef41Sopenharmony_ci ZoneHandleSet<Map> fixed_array_maps(factory()->fixed_array_map()); 8271cb0ef41Sopenharmony_ci fixed_array_maps.insert(factory()->fixed_cow_array_map(), zone()); 8281cb0ef41Sopenharmony_ci state = state->SetMaps(node, fixed_array_maps, zone()); 8291cb0ef41Sopenharmony_ci } 8301cb0ef41Sopenharmony_ci // Kill the previous elements on {object}. 8311cb0ef41Sopenharmony_ci state = state->KillField(object, 8321cb0ef41Sopenharmony_ci FieldIndexOf(JSObject::kElementsOffset, kTaggedSize), 8331cb0ef41Sopenharmony_ci MaybeHandle<Name>(), zone()); 8341cb0ef41Sopenharmony_ci // Add the new elements on {object}. 8351cb0ef41Sopenharmony_ci state = state->AddField( 8361cb0ef41Sopenharmony_ci object, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize), 8371cb0ef41Sopenharmony_ci {node, MachineRepresentation::kTaggedPointer}, zone()); 8381cb0ef41Sopenharmony_ci return UpdateState(node, state); 8391cb0ef41Sopenharmony_ci} 8401cb0ef41Sopenharmony_ci 8411cb0ef41Sopenharmony_ciReduction LoadElimination::ReduceTransitionElementsKind(Node* node) { 8421cb0ef41Sopenharmony_ci ElementsTransition transition = ElementsTransitionOf(node->op()); 8431cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(node, 0); 8441cb0ef41Sopenharmony_ci Handle<Map> source_map(transition.source()); 8451cb0ef41Sopenharmony_ci Handle<Map> target_map(transition.target()); 8461cb0ef41Sopenharmony_ci Node* const effect = NodeProperties::GetEffectInput(node); 8471cb0ef41Sopenharmony_ci AbstractState const* state = node_states_.Get(effect); 8481cb0ef41Sopenharmony_ci if (state == nullptr) return NoChange(); 8491cb0ef41Sopenharmony_ci switch (transition.mode()) { 8501cb0ef41Sopenharmony_ci case ElementsTransition::kFastTransition: 8511cb0ef41Sopenharmony_ci break; 8521cb0ef41Sopenharmony_ci case ElementsTransition::kSlowTransition: 8531cb0ef41Sopenharmony_ci // Kill the elements as well. 8541cb0ef41Sopenharmony_ci AliasStateInfo alias_info(state, object, source_map); 8551cb0ef41Sopenharmony_ci state = state->KillField( 8561cb0ef41Sopenharmony_ci alias_info, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize), 8571cb0ef41Sopenharmony_ci MaybeHandle<Name>(), zone()); 8581cb0ef41Sopenharmony_ci break; 8591cb0ef41Sopenharmony_ci } 8601cb0ef41Sopenharmony_ci ZoneHandleSet<Map> object_maps; 8611cb0ef41Sopenharmony_ci if (state->LookupMaps(object, &object_maps)) { 8621cb0ef41Sopenharmony_ci if (ZoneHandleSet<Map>(target_map).contains(object_maps)) { 8631cb0ef41Sopenharmony_ci // The {object} already has the {target_map}, so this TransitionElements 8641cb0ef41Sopenharmony_ci // {node} is fully redundant (independent of what {source_map} is). 8651cb0ef41Sopenharmony_ci return Replace(effect); 8661cb0ef41Sopenharmony_ci } 8671cb0ef41Sopenharmony_ci if (object_maps.contains(ZoneHandleSet<Map>(source_map))) { 8681cb0ef41Sopenharmony_ci object_maps.remove(source_map, zone()); 8691cb0ef41Sopenharmony_ci object_maps.insert(target_map, zone()); 8701cb0ef41Sopenharmony_ci AliasStateInfo alias_info(state, object, source_map); 8711cb0ef41Sopenharmony_ci state = state->KillMaps(alias_info, zone()); 8721cb0ef41Sopenharmony_ci state = state->SetMaps(object, object_maps, zone()); 8731cb0ef41Sopenharmony_ci } 8741cb0ef41Sopenharmony_ci } else { 8751cb0ef41Sopenharmony_ci AliasStateInfo alias_info(state, object, source_map); 8761cb0ef41Sopenharmony_ci state = state->KillMaps(alias_info, zone()); 8771cb0ef41Sopenharmony_ci } 8781cb0ef41Sopenharmony_ci return UpdateState(node, state); 8791cb0ef41Sopenharmony_ci} 8801cb0ef41Sopenharmony_ci 8811cb0ef41Sopenharmony_ciReduction LoadElimination::ReduceTransitionAndStoreElement(Node* node) { 8821cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(node, 0); 8831cb0ef41Sopenharmony_ci Handle<Map> double_map(DoubleMapParameterOf(node->op())); 8841cb0ef41Sopenharmony_ci Handle<Map> fast_map(FastMapParameterOf(node->op())); 8851cb0ef41Sopenharmony_ci Node* const effect = NodeProperties::GetEffectInput(node); 8861cb0ef41Sopenharmony_ci AbstractState const* state = node_states_.Get(effect); 8871cb0ef41Sopenharmony_ci if (state == nullptr) return NoChange(); 8881cb0ef41Sopenharmony_ci 8891cb0ef41Sopenharmony_ci // We need to add the double and fast maps to the set of possible maps for 8901cb0ef41Sopenharmony_ci // this object, because we don't know which of those we'll transition to. 8911cb0ef41Sopenharmony_ci // Additionally, we should kill all alias information. 8921cb0ef41Sopenharmony_ci ZoneHandleSet<Map> object_maps; 8931cb0ef41Sopenharmony_ci if (state->LookupMaps(object, &object_maps)) { 8941cb0ef41Sopenharmony_ci object_maps.insert(double_map, zone()); 8951cb0ef41Sopenharmony_ci object_maps.insert(fast_map, zone()); 8961cb0ef41Sopenharmony_ci state = state->KillMaps(object, zone()); 8971cb0ef41Sopenharmony_ci state = state->SetMaps(object, object_maps, zone()); 8981cb0ef41Sopenharmony_ci } 8991cb0ef41Sopenharmony_ci // Kill the elements as well. 9001cb0ef41Sopenharmony_ci state = state->KillField(object, 9011cb0ef41Sopenharmony_ci FieldIndexOf(JSObject::kElementsOffset, kTaggedSize), 9021cb0ef41Sopenharmony_ci MaybeHandle<Name>(), zone()); 9031cb0ef41Sopenharmony_ci return UpdateState(node, state); 9041cb0ef41Sopenharmony_ci} 9051cb0ef41Sopenharmony_ci 9061cb0ef41Sopenharmony_ciReduction LoadElimination::ReduceLoadField(Node* node, 9071cb0ef41Sopenharmony_ci FieldAccess const& access) { 9081cb0ef41Sopenharmony_ci Node* object = NodeProperties::GetValueInput(node, 0); 9091cb0ef41Sopenharmony_ci Node* effect = NodeProperties::GetEffectInput(node); 9101cb0ef41Sopenharmony_ci Node* control = NodeProperties::GetControlInput(node); 9111cb0ef41Sopenharmony_ci AbstractState const* state = node_states_.Get(effect); 9121cb0ef41Sopenharmony_ci if (state == nullptr) return NoChange(); 9131cb0ef41Sopenharmony_ci if (access.offset == HeapObject::kMapOffset && 9141cb0ef41Sopenharmony_ci access.base_is_tagged == kTaggedBase) { 9151cb0ef41Sopenharmony_ci DCHECK(IsAnyTagged(access.machine_type.representation())); 9161cb0ef41Sopenharmony_ci ZoneHandleSet<Map> object_maps; 9171cb0ef41Sopenharmony_ci if (state->LookupMaps(object, &object_maps) && object_maps.size() == 1) { 9181cb0ef41Sopenharmony_ci Node* value = jsgraph()->HeapConstant(object_maps[0]); 9191cb0ef41Sopenharmony_ci NodeProperties::SetType(value, Type::OtherInternal()); 9201cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect); 9211cb0ef41Sopenharmony_ci return Replace(value); 9221cb0ef41Sopenharmony_ci } 9231cb0ef41Sopenharmony_ci } else { 9241cb0ef41Sopenharmony_ci IndexRange field_index = FieldIndexOf(access); 9251cb0ef41Sopenharmony_ci if (field_index != IndexRange::Invalid()) { 9261cb0ef41Sopenharmony_ci MachineRepresentation representation = 9271cb0ef41Sopenharmony_ci access.machine_type.representation(); 9281cb0ef41Sopenharmony_ci FieldInfo const* lookup_result = 9291cb0ef41Sopenharmony_ci state->LookupField(object, field_index, access.const_field_info); 9301cb0ef41Sopenharmony_ci if (!lookup_result && access.const_field_info.IsConst()) { 9311cb0ef41Sopenharmony_ci // If the access is const and we didn't find anything, also try to look 9321cb0ef41Sopenharmony_ci // up information from mutable stores 9331cb0ef41Sopenharmony_ci lookup_result = 9341cb0ef41Sopenharmony_ci state->LookupField(object, field_index, ConstFieldInfo::None()); 9351cb0ef41Sopenharmony_ci } 9361cb0ef41Sopenharmony_ci if (lookup_result) { 9371cb0ef41Sopenharmony_ci // Make sure we don't reuse values that were recorded with a different 9381cb0ef41Sopenharmony_ci // representation or resurrect dead {replacement} nodes. 9391cb0ef41Sopenharmony_ci Node* replacement = lookup_result->value; 9401cb0ef41Sopenharmony_ci if (IsCompatible(representation, lookup_result->representation) && 9411cb0ef41Sopenharmony_ci !replacement->IsDead()) { 9421cb0ef41Sopenharmony_ci // Introduce a TypeGuard if the type of the {replacement} node is not 9431cb0ef41Sopenharmony_ci // a subtype of the original {node}'s type. 9441cb0ef41Sopenharmony_ci if (!NodeProperties::GetType(replacement) 9451cb0ef41Sopenharmony_ci .Is(NodeProperties::GetType(node))) { 9461cb0ef41Sopenharmony_ci Type replacement_type = Type::Intersect( 9471cb0ef41Sopenharmony_ci NodeProperties::GetType(node), 9481cb0ef41Sopenharmony_ci NodeProperties::GetType(replacement), graph()->zone()); 9491cb0ef41Sopenharmony_ci replacement = effect = 9501cb0ef41Sopenharmony_ci graph()->NewNode(common()->TypeGuard(replacement_type), 9511cb0ef41Sopenharmony_ci replacement, effect, control); 9521cb0ef41Sopenharmony_ci NodeProperties::SetType(replacement, replacement_type); 9531cb0ef41Sopenharmony_ci } 9541cb0ef41Sopenharmony_ci ReplaceWithValue(node, replacement, effect); 9551cb0ef41Sopenharmony_ci return Replace(replacement); 9561cb0ef41Sopenharmony_ci } 9571cb0ef41Sopenharmony_ci } 9581cb0ef41Sopenharmony_ci FieldInfo info(node, representation, access.name, 9591cb0ef41Sopenharmony_ci access.const_field_info); 9601cb0ef41Sopenharmony_ci state = state->AddField(object, field_index, info, zone()); 9611cb0ef41Sopenharmony_ci } 9621cb0ef41Sopenharmony_ci } 9631cb0ef41Sopenharmony_ci Handle<Map> field_map; 9641cb0ef41Sopenharmony_ci if (access.map.ToHandle(&field_map)) { 9651cb0ef41Sopenharmony_ci state = state->SetMaps(node, ZoneHandleSet<Map>(field_map), zone()); 9661cb0ef41Sopenharmony_ci } 9671cb0ef41Sopenharmony_ci return UpdateState(node, state); 9681cb0ef41Sopenharmony_ci} 9691cb0ef41Sopenharmony_ci 9701cb0ef41Sopenharmony_ciReduction LoadElimination::ReduceStoreField(Node* node, 9711cb0ef41Sopenharmony_ci FieldAccess const& access) { 9721cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(node, 0); 9731cb0ef41Sopenharmony_ci Node* const new_value = NodeProperties::GetValueInput(node, 1); 9741cb0ef41Sopenharmony_ci Node* const effect = NodeProperties::GetEffectInput(node); 9751cb0ef41Sopenharmony_ci AbstractState const* state = node_states_.Get(effect); 9761cb0ef41Sopenharmony_ci if (state == nullptr) return NoChange(); 9771cb0ef41Sopenharmony_ci if (access.offset == HeapObject::kMapOffset && 9781cb0ef41Sopenharmony_ci access.base_is_tagged == kTaggedBase) { 9791cb0ef41Sopenharmony_ci DCHECK(IsAnyTagged(access.machine_type.representation())); 9801cb0ef41Sopenharmony_ci // Kill all potential knowledge about the {object}s map. 9811cb0ef41Sopenharmony_ci state = state->KillMaps(object, zone()); 9821cb0ef41Sopenharmony_ci Type const new_value_type = NodeProperties::GetType(new_value); 9831cb0ef41Sopenharmony_ci if (new_value_type.IsHeapConstant()) { 9841cb0ef41Sopenharmony_ci // Record the new {object} map information. 9851cb0ef41Sopenharmony_ci ZoneHandleSet<Map> object_maps( 9861cb0ef41Sopenharmony_ci new_value_type.AsHeapConstant()->Ref().AsMap().object()); 9871cb0ef41Sopenharmony_ci state = state->SetMaps(object, object_maps, zone()); 9881cb0ef41Sopenharmony_ci } 9891cb0ef41Sopenharmony_ci } else { 9901cb0ef41Sopenharmony_ci IndexRange field_index = FieldIndexOf(access); 9911cb0ef41Sopenharmony_ci if (field_index != IndexRange::Invalid()) { 9921cb0ef41Sopenharmony_ci bool is_const_store = access.const_field_info.IsConst(); 9931cb0ef41Sopenharmony_ci MachineRepresentation representation = 9941cb0ef41Sopenharmony_ci access.machine_type.representation(); 9951cb0ef41Sopenharmony_ci FieldInfo const* lookup_result = 9961cb0ef41Sopenharmony_ci state->LookupField(object, field_index, access.const_field_info); 9971cb0ef41Sopenharmony_ci 9981cb0ef41Sopenharmony_ci if (lookup_result && 9991cb0ef41Sopenharmony_ci (!is_const_store || V8_ENABLE_DOUBLE_CONST_STORE_CHECK_BOOL)) { 10001cb0ef41Sopenharmony_ci // At runtime, we should never encounter 10011cb0ef41Sopenharmony_ci // - any store replacing existing info with a different, incompatible 10021cb0ef41Sopenharmony_ci // representation, nor 10031cb0ef41Sopenharmony_ci // - two consecutive const stores, unless the latter is a store into 10041cb0ef41Sopenharmony_ci // a literal. 10051cb0ef41Sopenharmony_ci // However, we may see such code statically, so we guard against 10061cb0ef41Sopenharmony_ci // executing it by emitting Unreachable. 10071cb0ef41Sopenharmony_ci // TODO(gsps): Re-enable the double const store check even for 10081cb0ef41Sopenharmony_ci // non-debug builds once we have identified other FieldAccesses 10091cb0ef41Sopenharmony_ci // that should be marked mutable instead of const 10101cb0ef41Sopenharmony_ci // (cf. JSCreateLowering::AllocateFastLiteral). 10111cb0ef41Sopenharmony_ci bool incompatible_representation = 10121cb0ef41Sopenharmony_ci !lookup_result->name.is_null() && 10131cb0ef41Sopenharmony_ci !IsCompatible(representation, lookup_result->representation); 10141cb0ef41Sopenharmony_ci bool illegal_double_const_store = 10151cb0ef41Sopenharmony_ci is_const_store && !access.is_store_in_literal; 10161cb0ef41Sopenharmony_ci if (incompatible_representation || illegal_double_const_store) { 10171cb0ef41Sopenharmony_ci Node* control = NodeProperties::GetControlInput(node); 10181cb0ef41Sopenharmony_ci Node* unreachable = 10191cb0ef41Sopenharmony_ci graph()->NewNode(common()->Unreachable(), effect, control); 10201cb0ef41Sopenharmony_ci return Replace(unreachable); 10211cb0ef41Sopenharmony_ci } 10221cb0ef41Sopenharmony_ci if (lookup_result->value == new_value) { 10231cb0ef41Sopenharmony_ci // This store is fully redundant. 10241cb0ef41Sopenharmony_ci return Replace(effect); 10251cb0ef41Sopenharmony_ci } 10261cb0ef41Sopenharmony_ci } 10271cb0ef41Sopenharmony_ci 10281cb0ef41Sopenharmony_ci // Kill all potentially aliasing fields and record the new value. 10291cb0ef41Sopenharmony_ci FieldInfo new_info(new_value, representation, access.name, 10301cb0ef41Sopenharmony_ci access.const_field_info); 10311cb0ef41Sopenharmony_ci if (is_const_store && access.is_store_in_literal) { 10321cb0ef41Sopenharmony_ci // We only kill const information when there is a chance that we 10331cb0ef41Sopenharmony_ci // previously stored information about the given const field (namely, 10341cb0ef41Sopenharmony_ci // when we observe const stores to literals). 10351cb0ef41Sopenharmony_ci state = state->KillConstField(object, field_index, zone()); 10361cb0ef41Sopenharmony_ci } 10371cb0ef41Sopenharmony_ci state = state->KillField(object, field_index, access.name, zone()); 10381cb0ef41Sopenharmony_ci state = state->AddField(object, field_index, new_info, zone()); 10391cb0ef41Sopenharmony_ci if (is_const_store) { 10401cb0ef41Sopenharmony_ci // For const stores, we track information in both the const and the 10411cb0ef41Sopenharmony_ci // mutable world to guard against field accesses that should have 10421cb0ef41Sopenharmony_ci // been marked const, but were not. 10431cb0ef41Sopenharmony_ci new_info.const_field_info = ConstFieldInfo::None(); 10441cb0ef41Sopenharmony_ci state = state->AddField(object, field_index, new_info, zone()); 10451cb0ef41Sopenharmony_ci } 10461cb0ef41Sopenharmony_ci } else { 10471cb0ef41Sopenharmony_ci // Unsupported StoreField operator. 10481cb0ef41Sopenharmony_ci state = state->KillFields(object, access.name, zone()); 10491cb0ef41Sopenharmony_ci } 10501cb0ef41Sopenharmony_ci } 10511cb0ef41Sopenharmony_ci return UpdateState(node, state); 10521cb0ef41Sopenharmony_ci} 10531cb0ef41Sopenharmony_ci 10541cb0ef41Sopenharmony_ciReduction LoadElimination::ReduceLoadElement(Node* node) { 10551cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(node, 0); 10561cb0ef41Sopenharmony_ci Node* const index = NodeProperties::GetValueInput(node, 1); 10571cb0ef41Sopenharmony_ci Node* const effect = NodeProperties::GetEffectInput(node); 10581cb0ef41Sopenharmony_ci AbstractState const* state = node_states_.Get(effect); 10591cb0ef41Sopenharmony_ci if (state == nullptr) return NoChange(); 10601cb0ef41Sopenharmony_ci 10611cb0ef41Sopenharmony_ci // Only handle loads that do not require truncations. 10621cb0ef41Sopenharmony_ci ElementAccess const& access = ElementAccessOf(node->op()); 10631cb0ef41Sopenharmony_ci switch (access.machine_type.representation()) { 10641cb0ef41Sopenharmony_ci case MachineRepresentation::kNone: 10651cb0ef41Sopenharmony_ci case MachineRepresentation::kBit: 10661cb0ef41Sopenharmony_ci case MachineRepresentation::kWord8: 10671cb0ef41Sopenharmony_ci case MachineRepresentation::kWord16: 10681cb0ef41Sopenharmony_ci case MachineRepresentation::kWord32: 10691cb0ef41Sopenharmony_ci case MachineRepresentation::kWord64: 10701cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat32: 10711cb0ef41Sopenharmony_ci case MachineRepresentation::kCompressedPointer: 10721cb0ef41Sopenharmony_ci case MachineRepresentation::kCompressed: 10731cb0ef41Sopenharmony_ci case MachineRepresentation::kSandboxedPointer: 10741cb0ef41Sopenharmony_ci // TODO(turbofan): Add support for doing the truncations. 10751cb0ef41Sopenharmony_ci break; 10761cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat64: 10771cb0ef41Sopenharmony_ci case MachineRepresentation::kSimd128: 10781cb0ef41Sopenharmony_ci case MachineRepresentation::kTaggedSigned: 10791cb0ef41Sopenharmony_ci case MachineRepresentation::kTaggedPointer: 10801cb0ef41Sopenharmony_ci case MachineRepresentation::kTagged: 10811cb0ef41Sopenharmony_ci case MachineRepresentation::kMapWord: 10821cb0ef41Sopenharmony_ci if (Node* replacement = state->LookupElement( 10831cb0ef41Sopenharmony_ci object, index, access.machine_type.representation())) { 10841cb0ef41Sopenharmony_ci // Make sure we don't resurrect dead {replacement} nodes. 10851cb0ef41Sopenharmony_ci // Skip lowering if the type of the {replacement} node is not a subtype 10861cb0ef41Sopenharmony_ci // of the original {node}'s type. 10871cb0ef41Sopenharmony_ci // TODO(turbofan): We should insert a {TypeGuard} for the intersection 10881cb0ef41Sopenharmony_ci // of these two types here once we properly handle {Type::None} 10891cb0ef41Sopenharmony_ci // everywhere. 10901cb0ef41Sopenharmony_ci if (!replacement->IsDead() && NodeProperties::GetType(replacement) 10911cb0ef41Sopenharmony_ci .Is(NodeProperties::GetType(node))) { 10921cb0ef41Sopenharmony_ci ReplaceWithValue(node, replacement, effect); 10931cb0ef41Sopenharmony_ci return Replace(replacement); 10941cb0ef41Sopenharmony_ci } 10951cb0ef41Sopenharmony_ci } 10961cb0ef41Sopenharmony_ci state = state->AddElement(object, index, node, 10971cb0ef41Sopenharmony_ci access.machine_type.representation(), zone()); 10981cb0ef41Sopenharmony_ci return UpdateState(node, state); 10991cb0ef41Sopenharmony_ci } 11001cb0ef41Sopenharmony_ci return NoChange(); 11011cb0ef41Sopenharmony_ci} 11021cb0ef41Sopenharmony_ci 11031cb0ef41Sopenharmony_ciReduction LoadElimination::ReduceStoreElement(Node* node) { 11041cb0ef41Sopenharmony_ci ElementAccess const& access = ElementAccessOf(node->op()); 11051cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(node, 0); 11061cb0ef41Sopenharmony_ci Node* const index = NodeProperties::GetValueInput(node, 1); 11071cb0ef41Sopenharmony_ci Node* const new_value = NodeProperties::GetValueInput(node, 2); 11081cb0ef41Sopenharmony_ci Node* const effect = NodeProperties::GetEffectInput(node); 11091cb0ef41Sopenharmony_ci AbstractState const* state = node_states_.Get(effect); 11101cb0ef41Sopenharmony_ci if (state == nullptr) return NoChange(); 11111cb0ef41Sopenharmony_ci Node* const old_value = 11121cb0ef41Sopenharmony_ci state->LookupElement(object, index, access.machine_type.representation()); 11131cb0ef41Sopenharmony_ci if (old_value == new_value) { 11141cb0ef41Sopenharmony_ci // This store is fully redundant. 11151cb0ef41Sopenharmony_ci return Replace(effect); 11161cb0ef41Sopenharmony_ci } 11171cb0ef41Sopenharmony_ci // Kill all potentially aliasing elements. 11181cb0ef41Sopenharmony_ci state = state->KillElement(object, index, zone()); 11191cb0ef41Sopenharmony_ci // Only record the new value if the store doesn't have an implicit truncation. 11201cb0ef41Sopenharmony_ci switch (access.machine_type.representation()) { 11211cb0ef41Sopenharmony_ci case MachineRepresentation::kNone: 11221cb0ef41Sopenharmony_ci case MachineRepresentation::kBit: 11231cb0ef41Sopenharmony_ci case MachineRepresentation::kWord8: 11241cb0ef41Sopenharmony_ci case MachineRepresentation::kWord16: 11251cb0ef41Sopenharmony_ci case MachineRepresentation::kWord32: 11261cb0ef41Sopenharmony_ci case MachineRepresentation::kWord64: 11271cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat32: 11281cb0ef41Sopenharmony_ci case MachineRepresentation::kCompressedPointer: 11291cb0ef41Sopenharmony_ci case MachineRepresentation::kCompressed: 11301cb0ef41Sopenharmony_ci case MachineRepresentation::kSandboxedPointer: 11311cb0ef41Sopenharmony_ci // TODO(turbofan): Add support for doing the truncations. 11321cb0ef41Sopenharmony_ci break; 11331cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat64: 11341cb0ef41Sopenharmony_ci case MachineRepresentation::kSimd128: 11351cb0ef41Sopenharmony_ci case MachineRepresentation::kTaggedSigned: 11361cb0ef41Sopenharmony_ci case MachineRepresentation::kTaggedPointer: 11371cb0ef41Sopenharmony_ci case MachineRepresentation::kTagged: 11381cb0ef41Sopenharmony_ci case MachineRepresentation::kMapWord: 11391cb0ef41Sopenharmony_ci state = state->AddElement(object, index, new_value, 11401cb0ef41Sopenharmony_ci access.machine_type.representation(), zone()); 11411cb0ef41Sopenharmony_ci break; 11421cb0ef41Sopenharmony_ci } 11431cb0ef41Sopenharmony_ci return UpdateState(node, state); 11441cb0ef41Sopenharmony_ci} 11451cb0ef41Sopenharmony_ci 11461cb0ef41Sopenharmony_ciReduction LoadElimination::ReduceStoreTypedElement(Node* node) { 11471cb0ef41Sopenharmony_ci Node* const effect = NodeProperties::GetEffectInput(node); 11481cb0ef41Sopenharmony_ci AbstractState const* state = node_states_.Get(effect); 11491cb0ef41Sopenharmony_ci if (state == nullptr) return NoChange(); 11501cb0ef41Sopenharmony_ci return UpdateState(node, state); 11511cb0ef41Sopenharmony_ci} 11521cb0ef41Sopenharmony_ci 11531cb0ef41Sopenharmony_ciLoadElimination::AbstractState const* LoadElimination::UpdateStateForPhi( 11541cb0ef41Sopenharmony_ci AbstractState const* state, Node* effect_phi, Node* phi) { 11551cb0ef41Sopenharmony_ci int predecessor_count = phi->InputCount() - 1; 11561cb0ef41Sopenharmony_ci // TODO(jarin) Consider doing a union here. At the moment, we just keep this 11571cb0ef41Sopenharmony_ci // consistent with AbstractState::Merge. 11581cb0ef41Sopenharmony_ci 11591cb0ef41Sopenharmony_ci // Check if all the inputs have the same maps. 11601cb0ef41Sopenharmony_ci AbstractState const* input_state = 11611cb0ef41Sopenharmony_ci node_states_.Get(NodeProperties::GetEffectInput(effect_phi, 0)); 11621cb0ef41Sopenharmony_ci ZoneHandleSet<Map> object_maps; 11631cb0ef41Sopenharmony_ci if (!input_state->LookupMaps(phi->InputAt(0), &object_maps)) return state; 11641cb0ef41Sopenharmony_ci for (int i = 1; i < predecessor_count; i++) { 11651cb0ef41Sopenharmony_ci input_state = 11661cb0ef41Sopenharmony_ci node_states_.Get(NodeProperties::GetEffectInput(effect_phi, i)); 11671cb0ef41Sopenharmony_ci ZoneHandleSet<Map> input_maps; 11681cb0ef41Sopenharmony_ci if (!input_state->LookupMaps(phi->InputAt(i), &input_maps)) return state; 11691cb0ef41Sopenharmony_ci if (input_maps != object_maps) return state; 11701cb0ef41Sopenharmony_ci } 11711cb0ef41Sopenharmony_ci return state->SetMaps(phi, object_maps, zone()); 11721cb0ef41Sopenharmony_ci} 11731cb0ef41Sopenharmony_ci 11741cb0ef41Sopenharmony_ciReduction LoadElimination::ReduceEffectPhi(Node* node) { 11751cb0ef41Sopenharmony_ci Node* const effect0 = NodeProperties::GetEffectInput(node, 0); 11761cb0ef41Sopenharmony_ci Node* const control = NodeProperties::GetControlInput(node); 11771cb0ef41Sopenharmony_ci AbstractState const* state0 = node_states_.Get(effect0); 11781cb0ef41Sopenharmony_ci if (state0 == nullptr) return NoChange(); 11791cb0ef41Sopenharmony_ci if (control->opcode() == IrOpcode::kLoop) { 11801cb0ef41Sopenharmony_ci // Here we rely on having only reducible loops: 11811cb0ef41Sopenharmony_ci // The loop entry edge always dominates the header, so we can just take 11821cb0ef41Sopenharmony_ci // the state from the first input, and compute the loop state based on it. 11831cb0ef41Sopenharmony_ci AbstractState const* state = ComputeLoopState(node, state0); 11841cb0ef41Sopenharmony_ci return UpdateState(node, state); 11851cb0ef41Sopenharmony_ci } 11861cb0ef41Sopenharmony_ci DCHECK_EQ(IrOpcode::kMerge, control->opcode()); 11871cb0ef41Sopenharmony_ci 11881cb0ef41Sopenharmony_ci // Shortcut for the case when we do not know anything about some input. 11891cb0ef41Sopenharmony_ci int const input_count = node->op()->EffectInputCount(); 11901cb0ef41Sopenharmony_ci for (int i = 1; i < input_count; ++i) { 11911cb0ef41Sopenharmony_ci Node* const effect = NodeProperties::GetEffectInput(node, i); 11921cb0ef41Sopenharmony_ci if (node_states_.Get(effect) == nullptr) return NoChange(); 11931cb0ef41Sopenharmony_ci } 11941cb0ef41Sopenharmony_ci 11951cb0ef41Sopenharmony_ci // Make a copy of the first input's state and merge with the state 11961cb0ef41Sopenharmony_ci // from other inputs. 11971cb0ef41Sopenharmony_ci AbstractState* state = zone()->New<AbstractState>(*state0); 11981cb0ef41Sopenharmony_ci for (int i = 1; i < input_count; ++i) { 11991cb0ef41Sopenharmony_ci Node* const input = NodeProperties::GetEffectInput(node, i); 12001cb0ef41Sopenharmony_ci state->Merge(node_states_.Get(input), zone()); 12011cb0ef41Sopenharmony_ci } 12021cb0ef41Sopenharmony_ci 12031cb0ef41Sopenharmony_ci // For each phi, try to compute the new state for the phi from 12041cb0ef41Sopenharmony_ci // the inputs. 12051cb0ef41Sopenharmony_ci AbstractState const* state_with_phis = state; 12061cb0ef41Sopenharmony_ci for (Node* use : control->uses()) { 12071cb0ef41Sopenharmony_ci if (use->opcode() == IrOpcode::kPhi) { 12081cb0ef41Sopenharmony_ci state_with_phis = UpdateStateForPhi(state_with_phis, node, use); 12091cb0ef41Sopenharmony_ci } 12101cb0ef41Sopenharmony_ci } 12111cb0ef41Sopenharmony_ci 12121cb0ef41Sopenharmony_ci return UpdateState(node, state_with_phis); 12131cb0ef41Sopenharmony_ci} 12141cb0ef41Sopenharmony_ci 12151cb0ef41Sopenharmony_ciReduction LoadElimination::ReduceStart(Node* node) { 12161cb0ef41Sopenharmony_ci return UpdateState(node, empty_state()); 12171cb0ef41Sopenharmony_ci} 12181cb0ef41Sopenharmony_ci 12191cb0ef41Sopenharmony_ciReduction LoadElimination::ReduceOtherNode(Node* node) { 12201cb0ef41Sopenharmony_ci if (node->op()->EffectInputCount() == 1) { 12211cb0ef41Sopenharmony_ci if (node->op()->EffectOutputCount() == 1) { 12221cb0ef41Sopenharmony_ci Node* const effect = NodeProperties::GetEffectInput(node); 12231cb0ef41Sopenharmony_ci AbstractState const* state = node_states_.Get(effect); 12241cb0ef41Sopenharmony_ci // If we do not know anything about the predecessor, do not propagate 12251cb0ef41Sopenharmony_ci // just yet because we will have to recompute anyway once we compute 12261cb0ef41Sopenharmony_ci // the predecessor. 12271cb0ef41Sopenharmony_ci if (state == nullptr) return NoChange(); 12281cb0ef41Sopenharmony_ci // Check if this {node} has some uncontrolled side effects. 12291cb0ef41Sopenharmony_ci if (!node->op()->HasProperty(Operator::kNoWrite)) { 12301cb0ef41Sopenharmony_ci state = state->KillAll(zone()); 12311cb0ef41Sopenharmony_ci } 12321cb0ef41Sopenharmony_ci return UpdateState(node, state); 12331cb0ef41Sopenharmony_ci } else { 12341cb0ef41Sopenharmony_ci // Effect terminators should be handled specially. 12351cb0ef41Sopenharmony_ci return NoChange(); 12361cb0ef41Sopenharmony_ci } 12371cb0ef41Sopenharmony_ci } 12381cb0ef41Sopenharmony_ci DCHECK_EQ(0, node->op()->EffectInputCount()); 12391cb0ef41Sopenharmony_ci DCHECK_EQ(0, node->op()->EffectOutputCount()); 12401cb0ef41Sopenharmony_ci return NoChange(); 12411cb0ef41Sopenharmony_ci} 12421cb0ef41Sopenharmony_ci 12431cb0ef41Sopenharmony_ciReduction LoadElimination::UpdateState(Node* node, AbstractState const* state) { 12441cb0ef41Sopenharmony_ci AbstractState const* original = node_states_.Get(node); 12451cb0ef41Sopenharmony_ci // Only signal that the {node} has Changed, if the information about {state} 12461cb0ef41Sopenharmony_ci // has changed wrt. the {original}. 12471cb0ef41Sopenharmony_ci if (state != original) { 12481cb0ef41Sopenharmony_ci if (original == nullptr || !state->Equals(original)) { 12491cb0ef41Sopenharmony_ci node_states_.Set(node, state); 12501cb0ef41Sopenharmony_ci return Changed(node); 12511cb0ef41Sopenharmony_ci } 12521cb0ef41Sopenharmony_ci } 12531cb0ef41Sopenharmony_ci return NoChange(); 12541cb0ef41Sopenharmony_ci} 12551cb0ef41Sopenharmony_ci 12561cb0ef41Sopenharmony_ciLoadElimination::AbstractState const* 12571cb0ef41Sopenharmony_ciLoadElimination::ComputeLoopStateForStoreField( 12581cb0ef41Sopenharmony_ci Node* current, LoadElimination::AbstractState const* state, 12591cb0ef41Sopenharmony_ci FieldAccess const& access) const { 12601cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(current, 0); 12611cb0ef41Sopenharmony_ci if (access.offset == HeapObject::kMapOffset) { 12621cb0ef41Sopenharmony_ci // Invalidate what we know about the {object}s map. 12631cb0ef41Sopenharmony_ci state = state->KillMaps(object, zone()); 12641cb0ef41Sopenharmony_ci } else { 12651cb0ef41Sopenharmony_ci IndexRange field_index = FieldIndexOf(access); 12661cb0ef41Sopenharmony_ci if (field_index == IndexRange::Invalid()) { 12671cb0ef41Sopenharmony_ci state = state->KillFields(object, access.name, zone()); 12681cb0ef41Sopenharmony_ci } else { 12691cb0ef41Sopenharmony_ci state = state->KillField(object, field_index, access.name, zone()); 12701cb0ef41Sopenharmony_ci } 12711cb0ef41Sopenharmony_ci } 12721cb0ef41Sopenharmony_ci return state; 12731cb0ef41Sopenharmony_ci} 12741cb0ef41Sopenharmony_ci 12751cb0ef41Sopenharmony_ciLoadElimination::AbstractState const* LoadElimination::ComputeLoopState( 12761cb0ef41Sopenharmony_ci Node* node, AbstractState const* state) const { 12771cb0ef41Sopenharmony_ci Node* const control = NodeProperties::GetControlInput(node); 12781cb0ef41Sopenharmony_ci struct TransitionElementsKindInfo { 12791cb0ef41Sopenharmony_ci ElementsTransition transition; 12801cb0ef41Sopenharmony_ci Node* object; 12811cb0ef41Sopenharmony_ci }; 12821cb0ef41Sopenharmony_ci // Allocate zone data structures in a temporary zone with a lifetime limited 12831cb0ef41Sopenharmony_ci // to this function to avoid blowing up the size of the stage-global zone. 12841cb0ef41Sopenharmony_ci Zone temp_zone(zone()->allocator(), "Temporary scoped zone"); 12851cb0ef41Sopenharmony_ci ZoneVector<TransitionElementsKindInfo> element_transitions_(&temp_zone); 12861cb0ef41Sopenharmony_ci ZoneQueue<Node*> queue(&temp_zone); 12871cb0ef41Sopenharmony_ci ZoneSet<Node*> visited(&temp_zone); 12881cb0ef41Sopenharmony_ci visited.insert(node); 12891cb0ef41Sopenharmony_ci for (int i = 1; i < control->InputCount(); ++i) { 12901cb0ef41Sopenharmony_ci queue.push(node->InputAt(i)); 12911cb0ef41Sopenharmony_ci } 12921cb0ef41Sopenharmony_ci while (!queue.empty()) { 12931cb0ef41Sopenharmony_ci Node* const current = queue.front(); 12941cb0ef41Sopenharmony_ci queue.pop(); 12951cb0ef41Sopenharmony_ci if (visited.find(current) == visited.end()) { 12961cb0ef41Sopenharmony_ci visited.insert(current); 12971cb0ef41Sopenharmony_ci if (!current->op()->HasProperty(Operator::kNoWrite)) { 12981cb0ef41Sopenharmony_ci switch (current->opcode()) { 12991cb0ef41Sopenharmony_ci case IrOpcode::kEnsureWritableFastElements: { 13001cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(current, 0); 13011cb0ef41Sopenharmony_ci state = state->KillField( 13021cb0ef41Sopenharmony_ci object, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize), 13031cb0ef41Sopenharmony_ci MaybeHandle<Name>(), zone()); 13041cb0ef41Sopenharmony_ci break; 13051cb0ef41Sopenharmony_ci } 13061cb0ef41Sopenharmony_ci case IrOpcode::kMaybeGrowFastElements: { 13071cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(current, 0); 13081cb0ef41Sopenharmony_ci state = state->KillField( 13091cb0ef41Sopenharmony_ci object, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize), 13101cb0ef41Sopenharmony_ci MaybeHandle<Name>(), zone()); 13111cb0ef41Sopenharmony_ci break; 13121cb0ef41Sopenharmony_ci } 13131cb0ef41Sopenharmony_ci case IrOpcode::kTransitionElementsKind: { 13141cb0ef41Sopenharmony_ci ElementsTransition transition = ElementsTransitionOf(current->op()); 13151cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(current, 0); 13161cb0ef41Sopenharmony_ci ZoneHandleSet<Map> object_maps; 13171cb0ef41Sopenharmony_ci if (!state->LookupMaps(object, &object_maps) || 13181cb0ef41Sopenharmony_ci !ZoneHandleSet<Map>(transition.target()) 13191cb0ef41Sopenharmony_ci .contains(object_maps)) { 13201cb0ef41Sopenharmony_ci element_transitions_.push_back({transition, object}); 13211cb0ef41Sopenharmony_ci } 13221cb0ef41Sopenharmony_ci break; 13231cb0ef41Sopenharmony_ci } 13241cb0ef41Sopenharmony_ci case IrOpcode::kTransitionAndStoreElement: { 13251cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(current, 0); 13261cb0ef41Sopenharmony_ci // Invalidate what we know about the {object}s map. 13271cb0ef41Sopenharmony_ci state = state->KillMaps(object, zone()); 13281cb0ef41Sopenharmony_ci // Kill the elements as well. 13291cb0ef41Sopenharmony_ci state = state->KillField( 13301cb0ef41Sopenharmony_ci object, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize), 13311cb0ef41Sopenharmony_ci MaybeHandle<Name>(), zone()); 13321cb0ef41Sopenharmony_ci break; 13331cb0ef41Sopenharmony_ci } 13341cb0ef41Sopenharmony_ci case IrOpcode::kStoreField: { 13351cb0ef41Sopenharmony_ci FieldAccess access = FieldAccessOf(current->op()); 13361cb0ef41Sopenharmony_ci state = ComputeLoopStateForStoreField(current, state, access); 13371cb0ef41Sopenharmony_ci break; 13381cb0ef41Sopenharmony_ci } 13391cb0ef41Sopenharmony_ci case IrOpcode::kStoreElement: { 13401cb0ef41Sopenharmony_ci Node* const object = NodeProperties::GetValueInput(current, 0); 13411cb0ef41Sopenharmony_ci Node* const index = NodeProperties::GetValueInput(current, 1); 13421cb0ef41Sopenharmony_ci state = state->KillElement(object, index, zone()); 13431cb0ef41Sopenharmony_ci break; 13441cb0ef41Sopenharmony_ci } 13451cb0ef41Sopenharmony_ci case IrOpcode::kStoreTypedElement: { 13461cb0ef41Sopenharmony_ci // Doesn't affect anything we track with the state currently. 13471cb0ef41Sopenharmony_ci break; 13481cb0ef41Sopenharmony_ci } 13491cb0ef41Sopenharmony_ci default: 13501cb0ef41Sopenharmony_ci return state->KillAll(zone()); 13511cb0ef41Sopenharmony_ci } 13521cb0ef41Sopenharmony_ci } 13531cb0ef41Sopenharmony_ci for (int i = 0; i < current->op()->EffectInputCount(); ++i) { 13541cb0ef41Sopenharmony_ci queue.push(NodeProperties::GetEffectInput(current, i)); 13551cb0ef41Sopenharmony_ci } 13561cb0ef41Sopenharmony_ci } 13571cb0ef41Sopenharmony_ci } 13581cb0ef41Sopenharmony_ci 13591cb0ef41Sopenharmony_ci // Finally, we apply the element transitions. For each transition, we will try 13601cb0ef41Sopenharmony_ci // to only invalidate information about nodes that can have the transition's 13611cb0ef41Sopenharmony_ci // source map. The trouble is that an object can be transitioned by some other 13621cb0ef41Sopenharmony_ci // transition to the source map. In that case, the other transition will 13631cb0ef41Sopenharmony_ci // invalidate the information, so we are mostly fine. 13641cb0ef41Sopenharmony_ci // 13651cb0ef41Sopenharmony_ci // The only bad case is 13661cb0ef41Sopenharmony_ci // 13671cb0ef41Sopenharmony_ci // mapA ---fast---> mapB ---slow---> mapC 13681cb0ef41Sopenharmony_ci // 13691cb0ef41Sopenharmony_ci // If we process the slow transition first on an object that has mapA, we will 13701cb0ef41Sopenharmony_ci // ignore the transition because the object does not have its source map 13711cb0ef41Sopenharmony_ci // (mapB). When we later process the fast transition, we invalidate the 13721cb0ef41Sopenharmony_ci // object's map, but we keep the information about the object's elements. This 13731cb0ef41Sopenharmony_ci // is wrong because the elements will be overwritten by the slow transition. 13741cb0ef41Sopenharmony_ci // 13751cb0ef41Sopenharmony_ci // Note that the slow-slow case is fine because either of the slow transition 13761cb0ef41Sopenharmony_ci // will invalidate the elements field, so the processing order does not 13771cb0ef41Sopenharmony_ci // matter. 13781cb0ef41Sopenharmony_ci // 13791cb0ef41Sopenharmony_ci // To handle the bad case properly, we first kill the maps using all 13801cb0ef41Sopenharmony_ci // transitions. We kill the the fields later when all the transitions are 13811cb0ef41Sopenharmony_ci // already reflected in the map information. 13821cb0ef41Sopenharmony_ci 13831cb0ef41Sopenharmony_ci for (const TransitionElementsKindInfo& t : element_transitions_) { 13841cb0ef41Sopenharmony_ci AliasStateInfo alias_info(state, t.object, t.transition.source()); 13851cb0ef41Sopenharmony_ci state = state->KillMaps(alias_info, zone()); 13861cb0ef41Sopenharmony_ci } 13871cb0ef41Sopenharmony_ci for (const TransitionElementsKindInfo& t : element_transitions_) { 13881cb0ef41Sopenharmony_ci switch (t.transition.mode()) { 13891cb0ef41Sopenharmony_ci case ElementsTransition::kFastTransition: 13901cb0ef41Sopenharmony_ci break; 13911cb0ef41Sopenharmony_ci case ElementsTransition::kSlowTransition: { 13921cb0ef41Sopenharmony_ci AliasStateInfo alias_info(state, t.object, t.transition.source()); 13931cb0ef41Sopenharmony_ci state = state->KillField( 13941cb0ef41Sopenharmony_ci alias_info, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize), 13951cb0ef41Sopenharmony_ci MaybeHandle<Name>(), zone()); 13961cb0ef41Sopenharmony_ci break; 13971cb0ef41Sopenharmony_ci } 13981cb0ef41Sopenharmony_ci } 13991cb0ef41Sopenharmony_ci } 14001cb0ef41Sopenharmony_ci return state; 14011cb0ef41Sopenharmony_ci} 14021cb0ef41Sopenharmony_ci 14031cb0ef41Sopenharmony_ci// static 14041cb0ef41Sopenharmony_ciLoadElimination::IndexRange LoadElimination::FieldIndexOf( 14051cb0ef41Sopenharmony_ci int offset, int representation_size) { 14061cb0ef41Sopenharmony_ci DCHECK(IsAligned(offset, kTaggedSize)); 14071cb0ef41Sopenharmony_ci int field_index = offset / kTaggedSize - 1; 14081cb0ef41Sopenharmony_ci DCHECK_EQ(0, representation_size % kTaggedSize); 14091cb0ef41Sopenharmony_ci return IndexRange(field_index, representation_size / kTaggedSize); 14101cb0ef41Sopenharmony_ci} 14111cb0ef41Sopenharmony_ci 14121cb0ef41Sopenharmony_ci// static 14131cb0ef41Sopenharmony_ciLoadElimination::IndexRange LoadElimination::FieldIndexOf( 14141cb0ef41Sopenharmony_ci FieldAccess const& access) { 14151cb0ef41Sopenharmony_ci MachineRepresentation rep = access.machine_type.representation(); 14161cb0ef41Sopenharmony_ci switch (rep) { 14171cb0ef41Sopenharmony_ci case MachineRepresentation::kNone: 14181cb0ef41Sopenharmony_ci case MachineRepresentation::kBit: 14191cb0ef41Sopenharmony_ci case MachineRepresentation::kSimd128: 14201cb0ef41Sopenharmony_ci UNREACHABLE(); 14211cb0ef41Sopenharmony_ci case MachineRepresentation::kWord8: 14221cb0ef41Sopenharmony_ci case MachineRepresentation::kWord16: 14231cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat32: 14241cb0ef41Sopenharmony_ci // Currently untracked. 14251cb0ef41Sopenharmony_ci return IndexRange::Invalid(); 14261cb0ef41Sopenharmony_ci case MachineRepresentation::kFloat64: 14271cb0ef41Sopenharmony_ci case MachineRepresentation::kWord32: 14281cb0ef41Sopenharmony_ci case MachineRepresentation::kWord64: 14291cb0ef41Sopenharmony_ci case MachineRepresentation::kTaggedSigned: 14301cb0ef41Sopenharmony_ci case MachineRepresentation::kTaggedPointer: 14311cb0ef41Sopenharmony_ci case MachineRepresentation::kTagged: 14321cb0ef41Sopenharmony_ci case MachineRepresentation::kMapWord: 14331cb0ef41Sopenharmony_ci case MachineRepresentation::kCompressedPointer: 14341cb0ef41Sopenharmony_ci case MachineRepresentation::kCompressed: 14351cb0ef41Sopenharmony_ci case MachineRepresentation::kSandboxedPointer: 14361cb0ef41Sopenharmony_ci break; 14371cb0ef41Sopenharmony_ci } 14381cb0ef41Sopenharmony_ci int representation_size = ElementSizeInBytes(rep); 14391cb0ef41Sopenharmony_ci // We currently only track fields that are at least tagged pointer sized. 14401cb0ef41Sopenharmony_ci if (representation_size < kTaggedSize) return IndexRange::Invalid(); 14411cb0ef41Sopenharmony_ci DCHECK_EQ(0, representation_size % kTaggedSize); 14421cb0ef41Sopenharmony_ci 14431cb0ef41Sopenharmony_ci if (access.base_is_tagged != kTaggedBase) { 14441cb0ef41Sopenharmony_ci // We currently only track tagged objects. 14451cb0ef41Sopenharmony_ci return IndexRange::Invalid(); 14461cb0ef41Sopenharmony_ci } 14471cb0ef41Sopenharmony_ci return FieldIndexOf(access.offset, representation_size); 14481cb0ef41Sopenharmony_ci} 14491cb0ef41Sopenharmony_ci 14501cb0ef41Sopenharmony_ciCommonOperatorBuilder* LoadElimination::common() const { 14511cb0ef41Sopenharmony_ci return jsgraph()->common(); 14521cb0ef41Sopenharmony_ci} 14531cb0ef41Sopenharmony_ci 14541cb0ef41Sopenharmony_ciGraph* LoadElimination::graph() const { return jsgraph()->graph(); } 14551cb0ef41Sopenharmony_ci 14561cb0ef41Sopenharmony_ciIsolate* LoadElimination::isolate() const { return jsgraph()->isolate(); } 14571cb0ef41Sopenharmony_ci 14581cb0ef41Sopenharmony_ciFactory* LoadElimination::factory() const { return jsgraph()->factory(); } 14591cb0ef41Sopenharmony_ci 14601cb0ef41Sopenharmony_ci} // namespace compiler 14611cb0ef41Sopenharmony_ci} // namespace internal 14621cb0ef41Sopenharmony_ci} // namespace v8 1463