11cb0ef41Sopenharmony_ci 21cb0ef41Sopenharmony_ci// Copyright 2015 the V8 project authors. All rights reserved. 31cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 41cb0ef41Sopenharmony_ci// found in the LICENSE file. 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ci#include "src/compiler/access-info.h" 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci#include <ostream> 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci#include "src/builtins/accessors.h" 111cb0ef41Sopenharmony_ci#include "src/compiler/compilation-dependencies.h" 121cb0ef41Sopenharmony_ci#include "src/compiler/simplified-operator.h" 131cb0ef41Sopenharmony_ci#include "src/compiler/type-cache.h" 141cb0ef41Sopenharmony_ci#include "src/ic/call-optimization.h" 151cb0ef41Sopenharmony_ci#include "src/ic/handler-configuration.h" 161cb0ef41Sopenharmony_ci#include "src/logging/counters.h" 171cb0ef41Sopenharmony_ci#include "src/objects/cell-inl.h" 181cb0ef41Sopenharmony_ci#include "src/objects/field-index-inl.h" 191cb0ef41Sopenharmony_ci#include "src/objects/field-type.h" 201cb0ef41Sopenharmony_ci#include "src/objects/module-inl.h" 211cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 221cb0ef41Sopenharmony_ci#include "src/objects/struct-inl.h" 231cb0ef41Sopenharmony_ci#include "src/objects/templates.h" 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_cinamespace v8 { 261cb0ef41Sopenharmony_cinamespace internal { 271cb0ef41Sopenharmony_cinamespace compiler { 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_cinamespace { 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_cibool CanInlinePropertyAccess(MapRef map, AccessMode access_mode) { 321cb0ef41Sopenharmony_ci // We can inline property access to prototypes of all primitives, except 331cb0ef41Sopenharmony_ci // the special Oddball ones that have no wrapper counterparts (i.e. Null, 341cb0ef41Sopenharmony_ci // Undefined and TheHole). 351cb0ef41Sopenharmony_ci // We can only inline accesses to dictionary mode holders if the access is a 361cb0ef41Sopenharmony_ci // load and the holder is a prototype. The latter ensures a 1:1 371cb0ef41Sopenharmony_ci // relationship between the map and the object (and therefore the property 381cb0ef41Sopenharmony_ci // dictionary). 391cb0ef41Sopenharmony_ci STATIC_ASSERT(ODDBALL_TYPE == LAST_PRIMITIVE_HEAP_OBJECT_TYPE); 401cb0ef41Sopenharmony_ci if (map.object()->IsBooleanMap()) return true; 411cb0ef41Sopenharmony_ci if (map.instance_type() < LAST_PRIMITIVE_HEAP_OBJECT_TYPE) return true; 421cb0ef41Sopenharmony_ci if (map.object()->IsJSObjectMap()) { 431cb0ef41Sopenharmony_ci if (map.is_dictionary_map()) { 441cb0ef41Sopenharmony_ci if (!V8_DICT_PROPERTY_CONST_TRACKING_BOOL) return false; 451cb0ef41Sopenharmony_ci return access_mode == AccessMode::kLoad && 461cb0ef41Sopenharmony_ci map.object()->is_prototype_map(); 471cb0ef41Sopenharmony_ci } 481cb0ef41Sopenharmony_ci return !map.object()->has_named_interceptor() && 491cb0ef41Sopenharmony_ci // TODO(verwaest): Allowlist contexts to which we have access. 501cb0ef41Sopenharmony_ci !map.is_access_check_needed(); 511cb0ef41Sopenharmony_ci } 521cb0ef41Sopenharmony_ci return false; 531cb0ef41Sopenharmony_ci} 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ci#ifdef DEBUG 561cb0ef41Sopenharmony_cibool HasFieldRepresentationDependenciesOnMap( 571cb0ef41Sopenharmony_ci ZoneVector<CompilationDependency const*>& dependencies, 581cb0ef41Sopenharmony_ci Handle<Map> const& field_owner_map) { 591cb0ef41Sopenharmony_ci for (auto dep : dependencies) { 601cb0ef41Sopenharmony_ci if (CompilationDependencies::IsFieldRepresentationDependencyOnMap( 611cb0ef41Sopenharmony_ci dep, field_owner_map)) { 621cb0ef41Sopenharmony_ci return true; 631cb0ef41Sopenharmony_ci } 641cb0ef41Sopenharmony_ci } 651cb0ef41Sopenharmony_ci return false; 661cb0ef41Sopenharmony_ci} 671cb0ef41Sopenharmony_ci#endif 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci} // namespace 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_cistd::ostream& operator<<(std::ostream& os, AccessMode access_mode) { 731cb0ef41Sopenharmony_ci switch (access_mode) { 741cb0ef41Sopenharmony_ci case AccessMode::kLoad: 751cb0ef41Sopenharmony_ci return os << "Load"; 761cb0ef41Sopenharmony_ci case AccessMode::kStore: 771cb0ef41Sopenharmony_ci return os << "Store"; 781cb0ef41Sopenharmony_ci case AccessMode::kStoreInLiteral: 791cb0ef41Sopenharmony_ci return os << "StoreInLiteral"; 801cb0ef41Sopenharmony_ci case AccessMode::kHas: 811cb0ef41Sopenharmony_ci return os << "Has"; 821cb0ef41Sopenharmony_ci case AccessMode::kDefine: 831cb0ef41Sopenharmony_ci return os << "Define"; 841cb0ef41Sopenharmony_ci } 851cb0ef41Sopenharmony_ci UNREACHABLE(); 861cb0ef41Sopenharmony_ci} 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ciElementAccessInfo::ElementAccessInfo( 891cb0ef41Sopenharmony_ci ZoneVector<MapRef>&& lookup_start_object_maps, ElementsKind elements_kind, 901cb0ef41Sopenharmony_ci Zone* zone) 911cb0ef41Sopenharmony_ci : elements_kind_(elements_kind), 921cb0ef41Sopenharmony_ci lookup_start_object_maps_(lookup_start_object_maps), 931cb0ef41Sopenharmony_ci transition_sources_(zone) { 941cb0ef41Sopenharmony_ci CHECK(!lookup_start_object_maps.empty()); 951cb0ef41Sopenharmony_ci} 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci// static 981cb0ef41Sopenharmony_ciPropertyAccessInfo PropertyAccessInfo::Invalid(Zone* zone) { 991cb0ef41Sopenharmony_ci return PropertyAccessInfo(zone); 1001cb0ef41Sopenharmony_ci} 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci// static 1031cb0ef41Sopenharmony_ciPropertyAccessInfo PropertyAccessInfo::NotFound( 1041cb0ef41Sopenharmony_ci Zone* zone, MapRef receiver_map, base::Optional<JSObjectRef> holder) { 1051cb0ef41Sopenharmony_ci return PropertyAccessInfo(zone, kNotFound, holder, {{receiver_map}, zone}); 1061cb0ef41Sopenharmony_ci} 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci// static 1091cb0ef41Sopenharmony_ciPropertyAccessInfo PropertyAccessInfo::DataField( 1101cb0ef41Sopenharmony_ci Zone* zone, MapRef receiver_map, 1111cb0ef41Sopenharmony_ci ZoneVector<CompilationDependency const*>&& dependencies, 1121cb0ef41Sopenharmony_ci FieldIndex field_index, Representation field_representation, 1131cb0ef41Sopenharmony_ci Type field_type, MapRef field_owner_map, base::Optional<MapRef> field_map, 1141cb0ef41Sopenharmony_ci base::Optional<JSObjectRef> holder, base::Optional<MapRef> transition_map) { 1151cb0ef41Sopenharmony_ci DCHECK(!field_representation.IsNone()); 1161cb0ef41Sopenharmony_ci DCHECK_IMPLIES( 1171cb0ef41Sopenharmony_ci field_representation.IsDouble(), 1181cb0ef41Sopenharmony_ci HasFieldRepresentationDependenciesOnMap( 1191cb0ef41Sopenharmony_ci dependencies, transition_map.has_value() 1201cb0ef41Sopenharmony_ci ? transition_map->object() 1211cb0ef41Sopenharmony_ci : holder.has_value() ? holder->map().object() 1221cb0ef41Sopenharmony_ci : receiver_map.object())); 1231cb0ef41Sopenharmony_ci return PropertyAccessInfo(kDataField, holder, transition_map, field_index, 1241cb0ef41Sopenharmony_ci field_representation, field_type, field_owner_map, 1251cb0ef41Sopenharmony_ci field_map, {{receiver_map}, zone}, 1261cb0ef41Sopenharmony_ci std::move(dependencies)); 1271cb0ef41Sopenharmony_ci} 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci// static 1301cb0ef41Sopenharmony_ciPropertyAccessInfo PropertyAccessInfo::FastDataConstant( 1311cb0ef41Sopenharmony_ci Zone* zone, MapRef receiver_map, 1321cb0ef41Sopenharmony_ci ZoneVector<CompilationDependency const*>&& dependencies, 1331cb0ef41Sopenharmony_ci FieldIndex field_index, Representation field_representation, 1341cb0ef41Sopenharmony_ci Type field_type, MapRef field_owner_map, base::Optional<MapRef> field_map, 1351cb0ef41Sopenharmony_ci base::Optional<JSObjectRef> holder, base::Optional<MapRef> transition_map) { 1361cb0ef41Sopenharmony_ci DCHECK(!field_representation.IsNone()); 1371cb0ef41Sopenharmony_ci return PropertyAccessInfo(kFastDataConstant, holder, transition_map, 1381cb0ef41Sopenharmony_ci field_index, field_representation, field_type, 1391cb0ef41Sopenharmony_ci field_owner_map, field_map, {{receiver_map}, zone}, 1401cb0ef41Sopenharmony_ci std::move(dependencies)); 1411cb0ef41Sopenharmony_ci} 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_ci// static 1441cb0ef41Sopenharmony_ciPropertyAccessInfo PropertyAccessInfo::FastAccessorConstant( 1451cb0ef41Sopenharmony_ci Zone* zone, MapRef receiver_map, base::Optional<ObjectRef> constant, 1461cb0ef41Sopenharmony_ci base::Optional<JSObjectRef> holder) { 1471cb0ef41Sopenharmony_ci return PropertyAccessInfo(zone, kFastAccessorConstant, holder, constant, {}, 1481cb0ef41Sopenharmony_ci {{receiver_map}, zone}); 1491cb0ef41Sopenharmony_ci} 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ci// static 1521cb0ef41Sopenharmony_ciPropertyAccessInfo PropertyAccessInfo::ModuleExport(Zone* zone, 1531cb0ef41Sopenharmony_ci MapRef receiver_map, 1541cb0ef41Sopenharmony_ci CellRef cell) { 1551cb0ef41Sopenharmony_ci return PropertyAccessInfo(zone, kModuleExport, {}, cell, {}, 1561cb0ef41Sopenharmony_ci {{receiver_map}, zone}); 1571cb0ef41Sopenharmony_ci} 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ci// static 1601cb0ef41Sopenharmony_ciPropertyAccessInfo PropertyAccessInfo::StringLength(Zone* zone, 1611cb0ef41Sopenharmony_ci MapRef receiver_map) { 1621cb0ef41Sopenharmony_ci return PropertyAccessInfo(zone, kStringLength, {}, {{receiver_map}, zone}); 1631cb0ef41Sopenharmony_ci} 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ci// static 1661cb0ef41Sopenharmony_ciPropertyAccessInfo PropertyAccessInfo::DictionaryProtoDataConstant( 1671cb0ef41Sopenharmony_ci Zone* zone, MapRef receiver_map, JSObjectRef holder, 1681cb0ef41Sopenharmony_ci InternalIndex dictionary_index, NameRef name) { 1691cb0ef41Sopenharmony_ci return PropertyAccessInfo(zone, kDictionaryProtoDataConstant, holder, 1701cb0ef41Sopenharmony_ci {{receiver_map}, zone}, dictionary_index, name); 1711cb0ef41Sopenharmony_ci} 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_ci// static 1741cb0ef41Sopenharmony_ciPropertyAccessInfo PropertyAccessInfo::DictionaryProtoAccessorConstant( 1751cb0ef41Sopenharmony_ci Zone* zone, MapRef receiver_map, base::Optional<JSObjectRef> holder, 1761cb0ef41Sopenharmony_ci ObjectRef constant, NameRef property_name) { 1771cb0ef41Sopenharmony_ci return PropertyAccessInfo(zone, kDictionaryProtoAccessorConstant, holder, 1781cb0ef41Sopenharmony_ci constant, property_name, {{receiver_map}, zone}); 1791cb0ef41Sopenharmony_ci} 1801cb0ef41Sopenharmony_ci 1811cb0ef41Sopenharmony_ciPropertyAccessInfo::PropertyAccessInfo(Zone* zone) 1821cb0ef41Sopenharmony_ci : kind_(kInvalid), 1831cb0ef41Sopenharmony_ci lookup_start_object_maps_(zone), 1841cb0ef41Sopenharmony_ci unrecorded_dependencies_(zone), 1851cb0ef41Sopenharmony_ci field_representation_(Representation::None()), 1861cb0ef41Sopenharmony_ci field_type_(Type::None()), 1871cb0ef41Sopenharmony_ci dictionary_index_(InternalIndex::NotFound()) {} 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_ciPropertyAccessInfo::PropertyAccessInfo( 1901cb0ef41Sopenharmony_ci Zone* zone, Kind kind, base::Optional<JSObjectRef> holder, 1911cb0ef41Sopenharmony_ci ZoneVector<MapRef>&& lookup_start_object_maps) 1921cb0ef41Sopenharmony_ci : kind_(kind), 1931cb0ef41Sopenharmony_ci lookup_start_object_maps_(lookup_start_object_maps), 1941cb0ef41Sopenharmony_ci holder_(holder), 1951cb0ef41Sopenharmony_ci unrecorded_dependencies_(zone), 1961cb0ef41Sopenharmony_ci field_representation_(Representation::None()), 1971cb0ef41Sopenharmony_ci field_type_(Type::None()), 1981cb0ef41Sopenharmony_ci dictionary_index_(InternalIndex::NotFound()) {} 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ciPropertyAccessInfo::PropertyAccessInfo( 2011cb0ef41Sopenharmony_ci Zone* zone, Kind kind, base::Optional<JSObjectRef> holder, 2021cb0ef41Sopenharmony_ci base::Optional<ObjectRef> constant, base::Optional<NameRef> name, 2031cb0ef41Sopenharmony_ci ZoneVector<MapRef>&& lookup_start_object_maps) 2041cb0ef41Sopenharmony_ci : kind_(kind), 2051cb0ef41Sopenharmony_ci lookup_start_object_maps_(lookup_start_object_maps), 2061cb0ef41Sopenharmony_ci constant_(constant), 2071cb0ef41Sopenharmony_ci holder_(holder), 2081cb0ef41Sopenharmony_ci unrecorded_dependencies_(zone), 2091cb0ef41Sopenharmony_ci field_representation_(Representation::None()), 2101cb0ef41Sopenharmony_ci field_type_(Type::Any()), 2111cb0ef41Sopenharmony_ci dictionary_index_(InternalIndex::NotFound()), 2121cb0ef41Sopenharmony_ci name_(name) { 2131cb0ef41Sopenharmony_ci DCHECK_IMPLIES(kind == kDictionaryProtoAccessorConstant, name.has_value()); 2141cb0ef41Sopenharmony_ci} 2151cb0ef41Sopenharmony_ci 2161cb0ef41Sopenharmony_ciPropertyAccessInfo::PropertyAccessInfo( 2171cb0ef41Sopenharmony_ci Kind kind, base::Optional<JSObjectRef> holder, 2181cb0ef41Sopenharmony_ci base::Optional<MapRef> transition_map, FieldIndex field_index, 2191cb0ef41Sopenharmony_ci Representation field_representation, Type field_type, 2201cb0ef41Sopenharmony_ci MapRef field_owner_map, base::Optional<MapRef> field_map, 2211cb0ef41Sopenharmony_ci ZoneVector<MapRef>&& lookup_start_object_maps, 2221cb0ef41Sopenharmony_ci ZoneVector<CompilationDependency const*>&& unrecorded_dependencies) 2231cb0ef41Sopenharmony_ci : kind_(kind), 2241cb0ef41Sopenharmony_ci lookup_start_object_maps_(lookup_start_object_maps), 2251cb0ef41Sopenharmony_ci holder_(holder), 2261cb0ef41Sopenharmony_ci unrecorded_dependencies_(std::move(unrecorded_dependencies)), 2271cb0ef41Sopenharmony_ci transition_map_(transition_map), 2281cb0ef41Sopenharmony_ci field_index_(field_index), 2291cb0ef41Sopenharmony_ci field_representation_(field_representation), 2301cb0ef41Sopenharmony_ci field_type_(field_type), 2311cb0ef41Sopenharmony_ci field_owner_map_(field_owner_map), 2321cb0ef41Sopenharmony_ci field_map_(field_map), 2331cb0ef41Sopenharmony_ci dictionary_index_(InternalIndex::NotFound()) { 2341cb0ef41Sopenharmony_ci DCHECK_IMPLIES(transition_map.has_value(), 2351cb0ef41Sopenharmony_ci field_owner_map.equals(transition_map.value())); 2361cb0ef41Sopenharmony_ci} 2371cb0ef41Sopenharmony_ci 2381cb0ef41Sopenharmony_ciPropertyAccessInfo::PropertyAccessInfo( 2391cb0ef41Sopenharmony_ci Zone* zone, Kind kind, base::Optional<JSObjectRef> holder, 2401cb0ef41Sopenharmony_ci ZoneVector<MapRef>&& lookup_start_object_maps, 2411cb0ef41Sopenharmony_ci InternalIndex dictionary_index, NameRef name) 2421cb0ef41Sopenharmony_ci : kind_(kind), 2431cb0ef41Sopenharmony_ci lookup_start_object_maps_(lookup_start_object_maps), 2441cb0ef41Sopenharmony_ci holder_(holder), 2451cb0ef41Sopenharmony_ci unrecorded_dependencies_(zone), 2461cb0ef41Sopenharmony_ci field_representation_(Representation::None()), 2471cb0ef41Sopenharmony_ci field_type_(Type::Any()), 2481cb0ef41Sopenharmony_ci dictionary_index_(dictionary_index), 2491cb0ef41Sopenharmony_ci name_{name} {} 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_cinamespace { 2521cb0ef41Sopenharmony_ci 2531cb0ef41Sopenharmony_citemplate <class RefT> 2541cb0ef41Sopenharmony_cibool OptionalRefEquals(base::Optional<RefT> lhs, base::Optional<RefT> rhs) { 2551cb0ef41Sopenharmony_ci if (!lhs.has_value()) return !rhs.has_value(); 2561cb0ef41Sopenharmony_ci if (!rhs.has_value()) return false; 2571cb0ef41Sopenharmony_ci return lhs->equals(rhs.value()); 2581cb0ef41Sopenharmony_ci} 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_citemplate <class T> 2611cb0ef41Sopenharmony_civoid AppendVector(ZoneVector<T>* dst, const ZoneVector<T>& src) { 2621cb0ef41Sopenharmony_ci dst->insert(dst->end(), src.begin(), src.end()); 2631cb0ef41Sopenharmony_ci} 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci} // namespace 2661cb0ef41Sopenharmony_ci 2671cb0ef41Sopenharmony_cibool PropertyAccessInfo::Merge(PropertyAccessInfo const* that, 2681cb0ef41Sopenharmony_ci AccessMode access_mode, Zone* zone) { 2691cb0ef41Sopenharmony_ci if (kind_ != that->kind_) return false; 2701cb0ef41Sopenharmony_ci if (!OptionalRefEquals(holder_, that->holder_)) return false; 2711cb0ef41Sopenharmony_ci 2721cb0ef41Sopenharmony_ci switch (kind_) { 2731cb0ef41Sopenharmony_ci case kInvalid: 2741cb0ef41Sopenharmony_ci DCHECK_EQ(that->kind_, kInvalid); 2751cb0ef41Sopenharmony_ci return true; 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_ci case kDataField: 2781cb0ef41Sopenharmony_ci case kFastDataConstant: { 2791cb0ef41Sopenharmony_ci // Check if we actually access the same field (we use the 2801cb0ef41Sopenharmony_ci // GetFieldAccessStubKey method here just like the ICs do 2811cb0ef41Sopenharmony_ci // since that way we only compare the relevant bits of the 2821cb0ef41Sopenharmony_ci // field indices). 2831cb0ef41Sopenharmony_ci if (field_index_.GetFieldAccessStubKey() != 2841cb0ef41Sopenharmony_ci that->field_index_.GetFieldAccessStubKey()) { 2851cb0ef41Sopenharmony_ci return false; 2861cb0ef41Sopenharmony_ci } 2871cb0ef41Sopenharmony_ci 2881cb0ef41Sopenharmony_ci switch (access_mode) { 2891cb0ef41Sopenharmony_ci case AccessMode::kHas: 2901cb0ef41Sopenharmony_ci case AccessMode::kLoad: { 2911cb0ef41Sopenharmony_ci if (!field_representation_.Equals(that->field_representation_)) { 2921cb0ef41Sopenharmony_ci if (field_representation_.IsDouble() || 2931cb0ef41Sopenharmony_ci that->field_representation_.IsDouble()) { 2941cb0ef41Sopenharmony_ci return false; 2951cb0ef41Sopenharmony_ci } 2961cb0ef41Sopenharmony_ci field_representation_ = Representation::Tagged(); 2971cb0ef41Sopenharmony_ci } 2981cb0ef41Sopenharmony_ci if (!OptionalRefEquals(field_map_, that->field_map_)) { 2991cb0ef41Sopenharmony_ci field_map_ = {}; 3001cb0ef41Sopenharmony_ci } 3011cb0ef41Sopenharmony_ci break; 3021cb0ef41Sopenharmony_ci } 3031cb0ef41Sopenharmony_ci case AccessMode::kStore: 3041cb0ef41Sopenharmony_ci case AccessMode::kStoreInLiteral: 3051cb0ef41Sopenharmony_ci case AccessMode::kDefine: { 3061cb0ef41Sopenharmony_ci // For stores, the field map and field representation information 3071cb0ef41Sopenharmony_ci // must match exactly, otherwise we cannot merge the stores. We 3081cb0ef41Sopenharmony_ci // also need to make sure that in case of transitioning stores, 3091cb0ef41Sopenharmony_ci // the transition targets match. 3101cb0ef41Sopenharmony_ci if (!OptionalRefEquals(field_map_, that->field_map_) || 3111cb0ef41Sopenharmony_ci !field_representation_.Equals(that->field_representation_) || 3121cb0ef41Sopenharmony_ci !OptionalRefEquals(transition_map_, that->transition_map_)) { 3131cb0ef41Sopenharmony_ci return false; 3141cb0ef41Sopenharmony_ci } 3151cb0ef41Sopenharmony_ci break; 3161cb0ef41Sopenharmony_ci } 3171cb0ef41Sopenharmony_ci } 3181cb0ef41Sopenharmony_ci 3191cb0ef41Sopenharmony_ci field_type_ = Type::Union(field_type_, that->field_type_, zone); 3201cb0ef41Sopenharmony_ci AppendVector(&lookup_start_object_maps_, that->lookup_start_object_maps_); 3211cb0ef41Sopenharmony_ci AppendVector(&unrecorded_dependencies_, that->unrecorded_dependencies_); 3221cb0ef41Sopenharmony_ci return true; 3231cb0ef41Sopenharmony_ci } 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_ci case kDictionaryProtoAccessorConstant: 3261cb0ef41Sopenharmony_ci case kFastAccessorConstant: { 3271cb0ef41Sopenharmony_ci // Check if we actually access the same constant. 3281cb0ef41Sopenharmony_ci if (!OptionalRefEquals(constant_, that->constant_)) return false; 3291cb0ef41Sopenharmony_ci 3301cb0ef41Sopenharmony_ci DCHECK(unrecorded_dependencies_.empty()); 3311cb0ef41Sopenharmony_ci DCHECK(that->unrecorded_dependencies_.empty()); 3321cb0ef41Sopenharmony_ci AppendVector(&lookup_start_object_maps_, that->lookup_start_object_maps_); 3331cb0ef41Sopenharmony_ci return true; 3341cb0ef41Sopenharmony_ci } 3351cb0ef41Sopenharmony_ci 3361cb0ef41Sopenharmony_ci case kDictionaryProtoDataConstant: { 3371cb0ef41Sopenharmony_ci DCHECK_EQ(AccessMode::kLoad, access_mode); 3381cb0ef41Sopenharmony_ci if (dictionary_index_ != that->dictionary_index_) return false; 3391cb0ef41Sopenharmony_ci AppendVector(&lookup_start_object_maps_, that->lookup_start_object_maps_); 3401cb0ef41Sopenharmony_ci return true; 3411cb0ef41Sopenharmony_ci } 3421cb0ef41Sopenharmony_ci 3431cb0ef41Sopenharmony_ci case kNotFound: 3441cb0ef41Sopenharmony_ci case kStringLength: { 3451cb0ef41Sopenharmony_ci DCHECK(unrecorded_dependencies_.empty()); 3461cb0ef41Sopenharmony_ci DCHECK(that->unrecorded_dependencies_.empty()); 3471cb0ef41Sopenharmony_ci AppendVector(&lookup_start_object_maps_, that->lookup_start_object_maps_); 3481cb0ef41Sopenharmony_ci return true; 3491cb0ef41Sopenharmony_ci } 3501cb0ef41Sopenharmony_ci case kModuleExport: 3511cb0ef41Sopenharmony_ci return false; 3521cb0ef41Sopenharmony_ci } 3531cb0ef41Sopenharmony_ci} 3541cb0ef41Sopenharmony_ci 3551cb0ef41Sopenharmony_ciConstFieldInfo PropertyAccessInfo::GetConstFieldInfo() const { 3561cb0ef41Sopenharmony_ci return IsFastDataConstant() ? ConstFieldInfo(field_owner_map_->object()) 3571cb0ef41Sopenharmony_ci : ConstFieldInfo::None(); 3581cb0ef41Sopenharmony_ci} 3591cb0ef41Sopenharmony_ci 3601cb0ef41Sopenharmony_ciAccessInfoFactory::AccessInfoFactory(JSHeapBroker* broker, 3611cb0ef41Sopenharmony_ci CompilationDependencies* dependencies, 3621cb0ef41Sopenharmony_ci Zone* zone) 3631cb0ef41Sopenharmony_ci : broker_(broker), 3641cb0ef41Sopenharmony_ci dependencies_(dependencies), 3651cb0ef41Sopenharmony_ci type_cache_(TypeCache::Get()), 3661cb0ef41Sopenharmony_ci zone_(zone) {} 3671cb0ef41Sopenharmony_ci 3681cb0ef41Sopenharmony_cibase::Optional<ElementAccessInfo> AccessInfoFactory::ComputeElementAccessInfo( 3691cb0ef41Sopenharmony_ci MapRef map, AccessMode access_mode) const { 3701cb0ef41Sopenharmony_ci if (!map.CanInlineElementAccess()) return {}; 3711cb0ef41Sopenharmony_ci return ElementAccessInfo({{map}, zone()}, map.elements_kind(), zone()); 3721cb0ef41Sopenharmony_ci} 3731cb0ef41Sopenharmony_ci 3741cb0ef41Sopenharmony_cibool AccessInfoFactory::ComputeElementAccessInfos( 3751cb0ef41Sopenharmony_ci ElementAccessFeedback const& feedback, 3761cb0ef41Sopenharmony_ci ZoneVector<ElementAccessInfo>* access_infos) const { 3771cb0ef41Sopenharmony_ci AccessMode access_mode = feedback.keyed_mode().access_mode(); 3781cb0ef41Sopenharmony_ci if (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) { 3791cb0ef41Sopenharmony_ci // For polymorphic loads of similar elements kinds (i.e. all tagged or all 3801cb0ef41Sopenharmony_ci // double), always use the "worst case" code without a transition. This is 3811cb0ef41Sopenharmony_ci // much faster than transitioning the elements to the worst case, trading a 3821cb0ef41Sopenharmony_ci // TransitionElementsKind for a CheckMaps, avoiding mutation of the array. 3831cb0ef41Sopenharmony_ci base::Optional<ElementAccessInfo> access_info = 3841cb0ef41Sopenharmony_ci ConsolidateElementLoad(feedback); 3851cb0ef41Sopenharmony_ci if (access_info.has_value()) { 3861cb0ef41Sopenharmony_ci access_infos->push_back(*access_info); 3871cb0ef41Sopenharmony_ci return true; 3881cb0ef41Sopenharmony_ci } 3891cb0ef41Sopenharmony_ci } 3901cb0ef41Sopenharmony_ci 3911cb0ef41Sopenharmony_ci for (auto const& group : feedback.transition_groups()) { 3921cb0ef41Sopenharmony_ci DCHECK(!group.empty()); 3931cb0ef41Sopenharmony_ci base::Optional<MapRef> target = 3941cb0ef41Sopenharmony_ci MakeRefAssumeMemoryFence(broker(), group.front()); 3951cb0ef41Sopenharmony_ci base::Optional<ElementAccessInfo> access_info = 3961cb0ef41Sopenharmony_ci ComputeElementAccessInfo(target.value(), access_mode); 3971cb0ef41Sopenharmony_ci if (!access_info.has_value()) return false; 3981cb0ef41Sopenharmony_ci 3991cb0ef41Sopenharmony_ci for (size_t i = 1; i < group.size(); ++i) { 4001cb0ef41Sopenharmony_ci base::Optional<MapRef> map_ref = 4011cb0ef41Sopenharmony_ci MakeRefAssumeMemoryFence(broker(), group[i]); 4021cb0ef41Sopenharmony_ci if (!map_ref.has_value()) continue; 4031cb0ef41Sopenharmony_ci access_info->AddTransitionSource(map_ref.value()); 4041cb0ef41Sopenharmony_ci } 4051cb0ef41Sopenharmony_ci access_infos->push_back(*access_info); 4061cb0ef41Sopenharmony_ci } 4071cb0ef41Sopenharmony_ci return true; 4081cb0ef41Sopenharmony_ci} 4091cb0ef41Sopenharmony_ci 4101cb0ef41Sopenharmony_ciPropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo( 4111cb0ef41Sopenharmony_ci MapRef receiver_map, MapRef map, NameRef name, 4121cb0ef41Sopenharmony_ci base::Optional<JSObjectRef> holder, InternalIndex descriptor, 4131cb0ef41Sopenharmony_ci AccessMode access_mode) const { 4141cb0ef41Sopenharmony_ci DCHECK(descriptor.is_found()); 4151cb0ef41Sopenharmony_ci // TODO(jgruber,v8:7790): Use DescriptorArrayRef instead. 4161cb0ef41Sopenharmony_ci Handle<DescriptorArray> descriptors = map.instance_descriptors().object(); 4171cb0ef41Sopenharmony_ci PropertyDetails const details = descriptors->GetDetails(descriptor); 4181cb0ef41Sopenharmony_ci int index = descriptors->GetFieldIndex(descriptor); 4191cb0ef41Sopenharmony_ci Representation details_representation = details.representation(); 4201cb0ef41Sopenharmony_ci if (details_representation.IsNone()) { 4211cb0ef41Sopenharmony_ci // The ICs collect feedback in PREMONOMORPHIC state already, 4221cb0ef41Sopenharmony_ci // but at this point the {receiver_map} might still contain 4231cb0ef41Sopenharmony_ci // fields for which the representation has not yet been 4241cb0ef41Sopenharmony_ci // determined by the runtime. So we need to catch this case 4251cb0ef41Sopenharmony_ci // here and fall back to use the regular IC logic instead. 4261cb0ef41Sopenharmony_ci return Invalid(); 4271cb0ef41Sopenharmony_ci } 4281cb0ef41Sopenharmony_ci FieldIndex field_index = FieldIndex::ForPropertyIndex(*map.object(), index, 4291cb0ef41Sopenharmony_ci details_representation); 4301cb0ef41Sopenharmony_ci // Private brands are used when loading private methods, which are stored in a 4311cb0ef41Sopenharmony_ci // BlockContext, an internal object. 4321cb0ef41Sopenharmony_ci Type field_type = name.object()->IsPrivateBrand() ? Type::OtherInternal() 4331cb0ef41Sopenharmony_ci : Type::NonInternal(); 4341cb0ef41Sopenharmony_ci base::Optional<MapRef> field_map; 4351cb0ef41Sopenharmony_ci 4361cb0ef41Sopenharmony_ci ZoneVector<CompilationDependency const*> unrecorded_dependencies(zone()); 4371cb0ef41Sopenharmony_ci 4381cb0ef41Sopenharmony_ci Handle<FieldType> descriptors_field_type = 4391cb0ef41Sopenharmony_ci broker()->CanonicalPersistentHandle( 4401cb0ef41Sopenharmony_ci descriptors->GetFieldType(descriptor)); 4411cb0ef41Sopenharmony_ci base::Optional<ObjectRef> descriptors_field_type_ref = 4421cb0ef41Sopenharmony_ci TryMakeRef<Object>(broker(), descriptors_field_type); 4431cb0ef41Sopenharmony_ci if (!descriptors_field_type_ref.has_value()) return Invalid(); 4441cb0ef41Sopenharmony_ci 4451cb0ef41Sopenharmony_ci if (details_representation.IsSmi()) { 4461cb0ef41Sopenharmony_ci field_type = Type::SignedSmall(); 4471cb0ef41Sopenharmony_ci unrecorded_dependencies.push_back( 4481cb0ef41Sopenharmony_ci dependencies()->FieldRepresentationDependencyOffTheRecord( 4491cb0ef41Sopenharmony_ci map, descriptor, details_representation)); 4501cb0ef41Sopenharmony_ci } else if (details_representation.IsDouble()) { 4511cb0ef41Sopenharmony_ci field_type = type_cache_->kFloat64; 4521cb0ef41Sopenharmony_ci unrecorded_dependencies.push_back( 4531cb0ef41Sopenharmony_ci dependencies()->FieldRepresentationDependencyOffTheRecord( 4541cb0ef41Sopenharmony_ci map, descriptor, details_representation)); 4551cb0ef41Sopenharmony_ci } else if (details_representation.IsHeapObject()) { 4561cb0ef41Sopenharmony_ci if (descriptors_field_type->IsNone()) { 4571cb0ef41Sopenharmony_ci switch (access_mode) { 4581cb0ef41Sopenharmony_ci case AccessMode::kStore: 4591cb0ef41Sopenharmony_ci case AccessMode::kStoreInLiteral: 4601cb0ef41Sopenharmony_ci case AccessMode::kDefine: 4611cb0ef41Sopenharmony_ci // Store is not safe if the field type was cleared. 4621cb0ef41Sopenharmony_ci return Invalid(); 4631cb0ef41Sopenharmony_ci case AccessMode::kLoad: 4641cb0ef41Sopenharmony_ci case AccessMode::kHas: 4651cb0ef41Sopenharmony_ci break; 4661cb0ef41Sopenharmony_ci } 4671cb0ef41Sopenharmony_ci 4681cb0ef41Sopenharmony_ci // The field type was cleared by the GC, so we don't know anything 4691cb0ef41Sopenharmony_ci // about the contents now. 4701cb0ef41Sopenharmony_ci } 4711cb0ef41Sopenharmony_ci unrecorded_dependencies.push_back( 4721cb0ef41Sopenharmony_ci dependencies()->FieldRepresentationDependencyOffTheRecord( 4731cb0ef41Sopenharmony_ci map, descriptor, details_representation)); 4741cb0ef41Sopenharmony_ci if (descriptors_field_type->IsClass()) { 4751cb0ef41Sopenharmony_ci // Remember the field map, and try to infer a useful type. 4761cb0ef41Sopenharmony_ci base::Optional<MapRef> maybe_field_map = 4771cb0ef41Sopenharmony_ci TryMakeRef(broker(), descriptors_field_type->AsClass()); 4781cb0ef41Sopenharmony_ci if (!maybe_field_map.has_value()) return Invalid(); 4791cb0ef41Sopenharmony_ci field_type = Type::For(maybe_field_map.value()); 4801cb0ef41Sopenharmony_ci field_map = maybe_field_map; 4811cb0ef41Sopenharmony_ci } 4821cb0ef41Sopenharmony_ci } else { 4831cb0ef41Sopenharmony_ci CHECK(details_representation.IsTagged()); 4841cb0ef41Sopenharmony_ci } 4851cb0ef41Sopenharmony_ci // TODO(turbofan): We may want to do this only depending on the use 4861cb0ef41Sopenharmony_ci // of the access info. 4871cb0ef41Sopenharmony_ci unrecorded_dependencies.push_back( 4881cb0ef41Sopenharmony_ci dependencies()->FieldTypeDependencyOffTheRecord( 4891cb0ef41Sopenharmony_ci map, descriptor, descriptors_field_type_ref.value())); 4901cb0ef41Sopenharmony_ci 4911cb0ef41Sopenharmony_ci PropertyConstness constness; 4921cb0ef41Sopenharmony_ci if (details.IsReadOnly() && !details.IsConfigurable()) { 4931cb0ef41Sopenharmony_ci constness = PropertyConstness::kConst; 4941cb0ef41Sopenharmony_ci } else { 4951cb0ef41Sopenharmony_ci constness = dependencies()->DependOnFieldConstness(map, descriptor); 4961cb0ef41Sopenharmony_ci } 4971cb0ef41Sopenharmony_ci 4981cb0ef41Sopenharmony_ci // Note: FindFieldOwner may be called multiple times throughout one 4991cb0ef41Sopenharmony_ci // compilation. This is safe since its result is fixed for a given map and 5001cb0ef41Sopenharmony_ci // descriptor. 5011cb0ef41Sopenharmony_ci MapRef field_owner_map = map.FindFieldOwner(descriptor); 5021cb0ef41Sopenharmony_ci 5031cb0ef41Sopenharmony_ci switch (constness) { 5041cb0ef41Sopenharmony_ci case PropertyConstness::kMutable: 5051cb0ef41Sopenharmony_ci return PropertyAccessInfo::DataField( 5061cb0ef41Sopenharmony_ci zone(), receiver_map, std::move(unrecorded_dependencies), field_index, 5071cb0ef41Sopenharmony_ci details_representation, field_type, field_owner_map, field_map, 5081cb0ef41Sopenharmony_ci holder, {}); 5091cb0ef41Sopenharmony_ci 5101cb0ef41Sopenharmony_ci case PropertyConstness::kConst: 5111cb0ef41Sopenharmony_ci return PropertyAccessInfo::FastDataConstant( 5121cb0ef41Sopenharmony_ci zone(), receiver_map, std::move(unrecorded_dependencies), field_index, 5131cb0ef41Sopenharmony_ci details_representation, field_type, field_owner_map, field_map, 5141cb0ef41Sopenharmony_ci holder, {}); 5151cb0ef41Sopenharmony_ci } 5161cb0ef41Sopenharmony_ci UNREACHABLE(); 5171cb0ef41Sopenharmony_ci} 5181cb0ef41Sopenharmony_ci 5191cb0ef41Sopenharmony_cinamespace { 5201cb0ef41Sopenharmony_ci 5211cb0ef41Sopenharmony_ciusing AccessorsObjectGetter = std::function<Handle<Object>()>; 5221cb0ef41Sopenharmony_ci 5231cb0ef41Sopenharmony_ciPropertyAccessInfo AccessorAccessInfoHelper( 5241cb0ef41Sopenharmony_ci Isolate* isolate, Zone* zone, JSHeapBroker* broker, 5251cb0ef41Sopenharmony_ci const AccessInfoFactory* ai_factory, MapRef receiver_map, NameRef name, 5261cb0ef41Sopenharmony_ci MapRef map, base::Optional<JSObjectRef> holder, AccessMode access_mode, 5271cb0ef41Sopenharmony_ci AccessorsObjectGetter get_accessors) { 5281cb0ef41Sopenharmony_ci if (map.instance_type() == JS_MODULE_NAMESPACE_TYPE) { 5291cb0ef41Sopenharmony_ci DCHECK(map.object()->is_prototype_map()); 5301cb0ef41Sopenharmony_ci Handle<PrototypeInfo> proto_info = broker->CanonicalPersistentHandle( 5311cb0ef41Sopenharmony_ci PrototypeInfo::cast(map.object()->prototype_info())); 5321cb0ef41Sopenharmony_ci Handle<JSModuleNamespace> module_namespace = 5331cb0ef41Sopenharmony_ci broker->CanonicalPersistentHandle( 5341cb0ef41Sopenharmony_ci JSModuleNamespace::cast(proto_info->module_namespace())); 5351cb0ef41Sopenharmony_ci Handle<Cell> cell = broker->CanonicalPersistentHandle( 5361cb0ef41Sopenharmony_ci Cell::cast(module_namespace->module().exports().Lookup( 5371cb0ef41Sopenharmony_ci isolate, name.object(), Smi::ToInt(name.object()->GetHash())))); 5381cb0ef41Sopenharmony_ci if (cell->value(kRelaxedLoad).IsTheHole(isolate)) { 5391cb0ef41Sopenharmony_ci // This module has not been fully initialized yet. 5401cb0ef41Sopenharmony_ci return PropertyAccessInfo::Invalid(zone); 5411cb0ef41Sopenharmony_ci } 5421cb0ef41Sopenharmony_ci base::Optional<CellRef> cell_ref = TryMakeRef(broker, cell); 5431cb0ef41Sopenharmony_ci if (!cell_ref.has_value()) { 5441cb0ef41Sopenharmony_ci return PropertyAccessInfo::Invalid(zone); 5451cb0ef41Sopenharmony_ci } 5461cb0ef41Sopenharmony_ci return PropertyAccessInfo::ModuleExport(zone, receiver_map, 5471cb0ef41Sopenharmony_ci cell_ref.value()); 5481cb0ef41Sopenharmony_ci } 5491cb0ef41Sopenharmony_ci if (access_mode == AccessMode::kHas) { 5501cb0ef41Sopenharmony_ci // kHas is not supported for dictionary mode objects. 5511cb0ef41Sopenharmony_ci DCHECK(!map.is_dictionary_map()); 5521cb0ef41Sopenharmony_ci 5531cb0ef41Sopenharmony_ci // HasProperty checks don't call getter/setters, existence is sufficient. 5541cb0ef41Sopenharmony_ci return PropertyAccessInfo::FastAccessorConstant(zone, receiver_map, {}, 5551cb0ef41Sopenharmony_ci holder); 5561cb0ef41Sopenharmony_ci } 5571cb0ef41Sopenharmony_ci Handle<Object> maybe_accessors = get_accessors(); 5581cb0ef41Sopenharmony_ci if (!maybe_accessors->IsAccessorPair()) { 5591cb0ef41Sopenharmony_ci return PropertyAccessInfo::Invalid(zone); 5601cb0ef41Sopenharmony_ci } 5611cb0ef41Sopenharmony_ci Handle<AccessorPair> accessors = Handle<AccessorPair>::cast(maybe_accessors); 5621cb0ef41Sopenharmony_ci Handle<Object> accessor = broker->CanonicalPersistentHandle( 5631cb0ef41Sopenharmony_ci access_mode == AccessMode::kLoad ? accessors->getter(kAcquireLoad) 5641cb0ef41Sopenharmony_ci : accessors->setter(kAcquireLoad)); 5651cb0ef41Sopenharmony_ci 5661cb0ef41Sopenharmony_ci base::Optional<ObjectRef> accessor_ref = TryMakeRef(broker, accessor); 5671cb0ef41Sopenharmony_ci if (!accessor_ref.has_value()) return PropertyAccessInfo::Invalid(zone); 5681cb0ef41Sopenharmony_ci 5691cb0ef41Sopenharmony_ci if (!accessor->IsJSFunction()) { 5701cb0ef41Sopenharmony_ci CallOptimization optimization(broker->local_isolate_or_isolate(), accessor); 5711cb0ef41Sopenharmony_ci if (!optimization.is_simple_api_call() || 5721cb0ef41Sopenharmony_ci optimization.IsCrossContextLazyAccessorPair( 5731cb0ef41Sopenharmony_ci *broker->target_native_context().object(), *map.object())) { 5741cb0ef41Sopenharmony_ci return PropertyAccessInfo::Invalid(zone); 5751cb0ef41Sopenharmony_ci } 5761cb0ef41Sopenharmony_ci 5771cb0ef41Sopenharmony_ci CallOptimization::HolderLookup lookup; 5781cb0ef41Sopenharmony_ci Handle<JSObject> holder_handle = broker->CanonicalPersistentHandle( 5791cb0ef41Sopenharmony_ci optimization.LookupHolderOfExpectedType( 5801cb0ef41Sopenharmony_ci broker->local_isolate_or_isolate(), receiver_map.object(), 5811cb0ef41Sopenharmony_ci &lookup)); 5821cb0ef41Sopenharmony_ci if (lookup == CallOptimization::kHolderNotFound) { 5831cb0ef41Sopenharmony_ci return PropertyAccessInfo::Invalid(zone); 5841cb0ef41Sopenharmony_ci } 5851cb0ef41Sopenharmony_ci DCHECK_IMPLIES(lookup == CallOptimization::kHolderIsReceiver, 5861cb0ef41Sopenharmony_ci holder_handle.is_null()); 5871cb0ef41Sopenharmony_ci DCHECK_IMPLIES(lookup == CallOptimization::kHolderFound, 5881cb0ef41Sopenharmony_ci !holder_handle.is_null()); 5891cb0ef41Sopenharmony_ci 5901cb0ef41Sopenharmony_ci if (holder_handle.is_null()) { 5911cb0ef41Sopenharmony_ci holder = {}; 5921cb0ef41Sopenharmony_ci } else { 5931cb0ef41Sopenharmony_ci holder = TryMakeRef(broker, holder_handle); 5941cb0ef41Sopenharmony_ci if (!holder.has_value()) return PropertyAccessInfo::Invalid(zone); 5951cb0ef41Sopenharmony_ci } 5961cb0ef41Sopenharmony_ci } 5971cb0ef41Sopenharmony_ci if (access_mode == AccessMode::kLoad) { 5981cb0ef41Sopenharmony_ci base::Optional<Name> cached_property_name = 5991cb0ef41Sopenharmony_ci FunctionTemplateInfo::TryGetCachedPropertyName(isolate, *accessor); 6001cb0ef41Sopenharmony_ci if (cached_property_name.has_value()) { 6011cb0ef41Sopenharmony_ci base::Optional<NameRef> cached_property_name_ref = 6021cb0ef41Sopenharmony_ci TryMakeRef(broker, cached_property_name.value()); 6031cb0ef41Sopenharmony_ci if (cached_property_name_ref.has_value()) { 6041cb0ef41Sopenharmony_ci PropertyAccessInfo access_info = ai_factory->ComputePropertyAccessInfo( 6051cb0ef41Sopenharmony_ci map, cached_property_name_ref.value(), access_mode); 6061cb0ef41Sopenharmony_ci if (!access_info.IsInvalid()) return access_info; 6071cb0ef41Sopenharmony_ci } 6081cb0ef41Sopenharmony_ci } 6091cb0ef41Sopenharmony_ci } 6101cb0ef41Sopenharmony_ci 6111cb0ef41Sopenharmony_ci if (map.is_dictionary_map()) { 6121cb0ef41Sopenharmony_ci return PropertyAccessInfo::DictionaryProtoAccessorConstant( 6131cb0ef41Sopenharmony_ci zone, receiver_map, holder, accessor_ref.value(), name); 6141cb0ef41Sopenharmony_ci } else { 6151cb0ef41Sopenharmony_ci return PropertyAccessInfo::FastAccessorConstant( 6161cb0ef41Sopenharmony_ci zone, receiver_map, accessor_ref.value(), holder); 6171cb0ef41Sopenharmony_ci } 6181cb0ef41Sopenharmony_ci} 6191cb0ef41Sopenharmony_ci 6201cb0ef41Sopenharmony_ci} // namespace 6211cb0ef41Sopenharmony_ci 6221cb0ef41Sopenharmony_ciPropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo( 6231cb0ef41Sopenharmony_ci MapRef receiver_map, NameRef name, MapRef holder_map, 6241cb0ef41Sopenharmony_ci base::Optional<JSObjectRef> holder, InternalIndex descriptor, 6251cb0ef41Sopenharmony_ci AccessMode access_mode) const { 6261cb0ef41Sopenharmony_ci DCHECK(descriptor.is_found()); 6271cb0ef41Sopenharmony_ci Handle<DescriptorArray> descriptors = broker()->CanonicalPersistentHandle( 6281cb0ef41Sopenharmony_ci holder_map.object()->instance_descriptors(kRelaxedLoad)); 6291cb0ef41Sopenharmony_ci SLOW_DCHECK(descriptor == 6301cb0ef41Sopenharmony_ci descriptors->Search(*name.object(), *holder_map.object())); 6311cb0ef41Sopenharmony_ci 6321cb0ef41Sopenharmony_ci auto get_accessors = [&]() { 6331cb0ef41Sopenharmony_ci return broker()->CanonicalPersistentHandle( 6341cb0ef41Sopenharmony_ci descriptors->GetStrongValue(descriptor)); 6351cb0ef41Sopenharmony_ci }; 6361cb0ef41Sopenharmony_ci return AccessorAccessInfoHelper(isolate(), zone(), broker(), this, 6371cb0ef41Sopenharmony_ci receiver_map, name, holder_map, holder, 6381cb0ef41Sopenharmony_ci access_mode, get_accessors); 6391cb0ef41Sopenharmony_ci} 6401cb0ef41Sopenharmony_ci 6411cb0ef41Sopenharmony_ciPropertyAccessInfo AccessInfoFactory::ComputeDictionaryProtoAccessInfo( 6421cb0ef41Sopenharmony_ci MapRef receiver_map, NameRef name, JSObjectRef holder, 6431cb0ef41Sopenharmony_ci InternalIndex dictionary_index, AccessMode access_mode, 6441cb0ef41Sopenharmony_ci PropertyDetails details) const { 6451cb0ef41Sopenharmony_ci CHECK(V8_DICT_PROPERTY_CONST_TRACKING_BOOL); 6461cb0ef41Sopenharmony_ci DCHECK(holder.map().object()->is_prototype_map()); 6471cb0ef41Sopenharmony_ci DCHECK_EQ(access_mode, AccessMode::kLoad); 6481cb0ef41Sopenharmony_ci 6491cb0ef41Sopenharmony_ci // We can only inline accesses to constant properties. 6501cb0ef41Sopenharmony_ci if (details.constness() != PropertyConstness::kConst) { 6511cb0ef41Sopenharmony_ci return Invalid(); 6521cb0ef41Sopenharmony_ci } 6531cb0ef41Sopenharmony_ci 6541cb0ef41Sopenharmony_ci if (details.kind() == PropertyKind::kData) { 6551cb0ef41Sopenharmony_ci return PropertyAccessInfo::DictionaryProtoDataConstant( 6561cb0ef41Sopenharmony_ci zone(), receiver_map, holder, dictionary_index, name); 6571cb0ef41Sopenharmony_ci } 6581cb0ef41Sopenharmony_ci 6591cb0ef41Sopenharmony_ci auto get_accessors = [&]() { 6601cb0ef41Sopenharmony_ci return JSObject::DictionaryPropertyAt(isolate(), holder.object(), 6611cb0ef41Sopenharmony_ci dictionary_index); 6621cb0ef41Sopenharmony_ci }; 6631cb0ef41Sopenharmony_ci return AccessorAccessInfoHelper(isolate(), zone(), broker(), this, 6641cb0ef41Sopenharmony_ci receiver_map, name, holder.map(), holder, 6651cb0ef41Sopenharmony_ci access_mode, get_accessors); 6661cb0ef41Sopenharmony_ci} 6671cb0ef41Sopenharmony_ci 6681cb0ef41Sopenharmony_cibool AccessInfoFactory::TryLoadPropertyDetails( 6691cb0ef41Sopenharmony_ci MapRef map, base::Optional<JSObjectRef> maybe_holder, NameRef name, 6701cb0ef41Sopenharmony_ci InternalIndex* index_out, PropertyDetails* details_out) const { 6711cb0ef41Sopenharmony_ci if (map.is_dictionary_map()) { 6721cb0ef41Sopenharmony_ci DCHECK(V8_DICT_PROPERTY_CONST_TRACKING_BOOL); 6731cb0ef41Sopenharmony_ci DCHECK(map.object()->is_prototype_map()); 6741cb0ef41Sopenharmony_ci 6751cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 6761cb0ef41Sopenharmony_ci 6771cb0ef41Sopenharmony_ci if (!maybe_holder.has_value()) { 6781cb0ef41Sopenharmony_ci // TODO(v8:11457) In this situation, we have a dictionary mode prototype 6791cb0ef41Sopenharmony_ci // as a receiver. Consider other means of obtaining the holder in this 6801cb0ef41Sopenharmony_ci // situation. 6811cb0ef41Sopenharmony_ci 6821cb0ef41Sopenharmony_ci // Without the holder, we can't get the property details. 6831cb0ef41Sopenharmony_ci return false; 6841cb0ef41Sopenharmony_ci } 6851cb0ef41Sopenharmony_ci 6861cb0ef41Sopenharmony_ci Handle<JSObject> holder = maybe_holder->object(); 6871cb0ef41Sopenharmony_ci if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) { 6881cb0ef41Sopenharmony_ci SwissNameDictionary dict = holder->property_dictionary_swiss(); 6891cb0ef41Sopenharmony_ci *index_out = dict.FindEntry(isolate(), name.object()); 6901cb0ef41Sopenharmony_ci if (index_out->is_found()) { 6911cb0ef41Sopenharmony_ci *details_out = dict.DetailsAt(*index_out); 6921cb0ef41Sopenharmony_ci } 6931cb0ef41Sopenharmony_ci } else { 6941cb0ef41Sopenharmony_ci NameDictionary dict = holder->property_dictionary(); 6951cb0ef41Sopenharmony_ci *index_out = dict.FindEntry(isolate(), name.object()); 6961cb0ef41Sopenharmony_ci if (index_out->is_found()) { 6971cb0ef41Sopenharmony_ci *details_out = dict.DetailsAt(*index_out); 6981cb0ef41Sopenharmony_ci } 6991cb0ef41Sopenharmony_ci } 7001cb0ef41Sopenharmony_ci } else { 7011cb0ef41Sopenharmony_ci DescriptorArray descriptors = *map.instance_descriptors().object(); 7021cb0ef41Sopenharmony_ci *index_out = descriptors.Search(*name.object(), *map.object(), true); 7031cb0ef41Sopenharmony_ci if (index_out->is_found()) { 7041cb0ef41Sopenharmony_ci *details_out = descriptors.GetDetails(*index_out); 7051cb0ef41Sopenharmony_ci } 7061cb0ef41Sopenharmony_ci } 7071cb0ef41Sopenharmony_ci 7081cb0ef41Sopenharmony_ci return true; 7091cb0ef41Sopenharmony_ci} 7101cb0ef41Sopenharmony_ci 7111cb0ef41Sopenharmony_ciPropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( 7121cb0ef41Sopenharmony_ci MapRef map, NameRef name, AccessMode access_mode) const { 7131cb0ef41Sopenharmony_ci CHECK(name.IsUniqueName()); 7141cb0ef41Sopenharmony_ci 7151cb0ef41Sopenharmony_ci // Dictionary property const tracking is unsupported with concurrent inlining. 7161cb0ef41Sopenharmony_ci CHECK(!V8_DICT_PROPERTY_CONST_TRACKING_BOOL); 7171cb0ef41Sopenharmony_ci 7181cb0ef41Sopenharmony_ci JSHeapBroker::MapUpdaterGuardIfNeeded mumd_scope(broker()); 7191cb0ef41Sopenharmony_ci 7201cb0ef41Sopenharmony_ci if (access_mode == AccessMode::kHas && !map.object()->IsJSReceiverMap()) { 7211cb0ef41Sopenharmony_ci return Invalid(); 7221cb0ef41Sopenharmony_ci } 7231cb0ef41Sopenharmony_ci 7241cb0ef41Sopenharmony_ci // Check if it is safe to inline property access for the {map}. 7251cb0ef41Sopenharmony_ci if (!CanInlinePropertyAccess(map, access_mode)) { 7261cb0ef41Sopenharmony_ci return Invalid(); 7271cb0ef41Sopenharmony_ci } 7281cb0ef41Sopenharmony_ci 7291cb0ef41Sopenharmony_ci // We support fast inline cases for certain JSObject getters. 7301cb0ef41Sopenharmony_ci if (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) { 7311cb0ef41Sopenharmony_ci PropertyAccessInfo access_info = LookupSpecialFieldAccessor(map, name); 7321cb0ef41Sopenharmony_ci if (!access_info.IsInvalid()) return access_info; 7331cb0ef41Sopenharmony_ci } 7341cb0ef41Sopenharmony_ci 7351cb0ef41Sopenharmony_ci // Only relevant if V8_DICT_PROPERTY_CONST_TRACKING enabled. 7361cb0ef41Sopenharmony_ci bool dictionary_prototype_on_chain = false; 7371cb0ef41Sopenharmony_ci bool fast_mode_prototype_on_chain = false; 7381cb0ef41Sopenharmony_ci 7391cb0ef41Sopenharmony_ci // Remember the receiver map. We use {map} as loop variable. 7401cb0ef41Sopenharmony_ci MapRef receiver_map = map; 7411cb0ef41Sopenharmony_ci base::Optional<JSObjectRef> holder; 7421cb0ef41Sopenharmony_ci 7431cb0ef41Sopenharmony_ci // Perform the implicit ToObject for primitives here. 7441cb0ef41Sopenharmony_ci // Implemented according to ES6 section 7.3.2 GetV (V, P). 7451cb0ef41Sopenharmony_ci // Note: Keep sync'd with 7461cb0ef41Sopenharmony_ci // CompilationDependencies::DependOnStablePrototypeChains. 7471cb0ef41Sopenharmony_ci if (receiver_map.IsPrimitiveMap()) { 7481cb0ef41Sopenharmony_ci base::Optional<JSFunctionRef> constructor = 7491cb0ef41Sopenharmony_ci broker()->target_native_context().GetConstructorFunction(receiver_map); 7501cb0ef41Sopenharmony_ci if (!constructor.has_value()) return Invalid(); 7511cb0ef41Sopenharmony_ci map = constructor->initial_map(broker()->dependencies()); 7521cb0ef41Sopenharmony_ci DCHECK(!map.IsPrimitiveMap()); 7531cb0ef41Sopenharmony_ci } 7541cb0ef41Sopenharmony_ci 7551cb0ef41Sopenharmony_ci while (true) { 7561cb0ef41Sopenharmony_ci PropertyDetails details = PropertyDetails::Empty(); 7571cb0ef41Sopenharmony_ci InternalIndex index = InternalIndex::NotFound(); 7581cb0ef41Sopenharmony_ci if (!TryLoadPropertyDetails(map, holder, name, &index, &details)) { 7591cb0ef41Sopenharmony_ci return Invalid(); 7601cb0ef41Sopenharmony_ci } 7611cb0ef41Sopenharmony_ci 7621cb0ef41Sopenharmony_ci if (index.is_found()) { 7631cb0ef41Sopenharmony_ci if (access_mode == AccessMode::kStore || 7641cb0ef41Sopenharmony_ci access_mode == AccessMode::kStoreInLiteral) { 7651cb0ef41Sopenharmony_ci DCHECK(!map.is_dictionary_map()); 7661cb0ef41Sopenharmony_ci 7671cb0ef41Sopenharmony_ci // Don't bother optimizing stores to read-only properties. 7681cb0ef41Sopenharmony_ci if (details.IsReadOnly()) return Invalid(); 7691cb0ef41Sopenharmony_ci 7701cb0ef41Sopenharmony_ci if (details.kind() == PropertyKind::kData && holder.has_value()) { 7711cb0ef41Sopenharmony_ci // This is a store to a property not found on the receiver but on a 7721cb0ef41Sopenharmony_ci // prototype. According to ES6 section 9.1.9 [[Set]], we need to 7731cb0ef41Sopenharmony_ci // create a new data property on the receiver. We can still optimize 7741cb0ef41Sopenharmony_ci // if such a transition already exists. 7751cb0ef41Sopenharmony_ci return LookupTransition(receiver_map, name, holder, NONE); 7761cb0ef41Sopenharmony_ci } 7771cb0ef41Sopenharmony_ci } 7781cb0ef41Sopenharmony_ci 7791cb0ef41Sopenharmony_ci if (map.is_dictionary_map()) { 7801cb0ef41Sopenharmony_ci DCHECK(V8_DICT_PROPERTY_CONST_TRACKING_BOOL); 7811cb0ef41Sopenharmony_ci 7821cb0ef41Sopenharmony_ci if (fast_mode_prototype_on_chain) { 7831cb0ef41Sopenharmony_ci // TODO(v8:11248) While the work on dictionary mode prototypes is in 7841cb0ef41Sopenharmony_ci // progress, we may still see fast mode objects on the chain prior to 7851cb0ef41Sopenharmony_ci // reaching a dictionary mode prototype holding the property . Due to 7861cb0ef41Sopenharmony_ci // this only being an intermediate state, we don't stupport these kind 7871cb0ef41Sopenharmony_ci // of heterogenous prototype chains. 7881cb0ef41Sopenharmony_ci return Invalid(); 7891cb0ef41Sopenharmony_ci } 7901cb0ef41Sopenharmony_ci 7911cb0ef41Sopenharmony_ci // TryLoadPropertyDetails only succeeds if we know the holder. 7921cb0ef41Sopenharmony_ci return ComputeDictionaryProtoAccessInfo( 7931cb0ef41Sopenharmony_ci receiver_map, name, holder.value(), index, access_mode, details); 7941cb0ef41Sopenharmony_ci } 7951cb0ef41Sopenharmony_ci 7961cb0ef41Sopenharmony_ci if (dictionary_prototype_on_chain) { 7971cb0ef41Sopenharmony_ci // If V8_DICT_PROPERTY_CONST_TRACKING_BOOL was disabled, then a 7981cb0ef41Sopenharmony_ci // dictionary prototype would have caused a bailout earlier. 7991cb0ef41Sopenharmony_ci DCHECK(V8_DICT_PROPERTY_CONST_TRACKING_BOOL); 8001cb0ef41Sopenharmony_ci 8011cb0ef41Sopenharmony_ci // TODO(v8:11248) We have a fast mode holder, but there was a dictionary 8021cb0ef41Sopenharmony_ci // mode prototype earlier on the chain. Note that seeing a fast mode 8031cb0ef41Sopenharmony_ci // prototype even though V8_DICT_PROPERTY_CONST_TRACKING is enabled 8041cb0ef41Sopenharmony_ci // should only be possible while the implementation of dictionary mode 8051cb0ef41Sopenharmony_ci // prototypes is work in progress. Eventually, enabling 8061cb0ef41Sopenharmony_ci // V8_DICT_PROPERTY_CONST_TRACKING will guarantee that all prototypes 8071cb0ef41Sopenharmony_ci // are always in dictionary mode, making this case unreachable. However, 8081cb0ef41Sopenharmony_ci // due to the complications of checking dictionary mode prototypes for 8091cb0ef41Sopenharmony_ci // modification, we don't attempt to support dictionary mode prototypes 8101cb0ef41Sopenharmony_ci // occuring before a fast mode holder on the chain. 8111cb0ef41Sopenharmony_ci return Invalid(); 8121cb0ef41Sopenharmony_ci } 8131cb0ef41Sopenharmony_ci if (details.location() == PropertyLocation::kField) { 8141cb0ef41Sopenharmony_ci if (details.kind() == PropertyKind::kData) { 8151cb0ef41Sopenharmony_ci return ComputeDataFieldAccessInfo(receiver_map, map, name, holder, 8161cb0ef41Sopenharmony_ci index, access_mode); 8171cb0ef41Sopenharmony_ci } else { 8181cb0ef41Sopenharmony_ci DCHECK_EQ(PropertyKind::kAccessor, details.kind()); 8191cb0ef41Sopenharmony_ci // TODO(turbofan): Add support for general accessors? 8201cb0ef41Sopenharmony_ci return Invalid(); 8211cb0ef41Sopenharmony_ci } 8221cb0ef41Sopenharmony_ci } else { 8231cb0ef41Sopenharmony_ci DCHECK_EQ(PropertyLocation::kDescriptor, details.location()); 8241cb0ef41Sopenharmony_ci DCHECK_EQ(PropertyKind::kAccessor, details.kind()); 8251cb0ef41Sopenharmony_ci return ComputeAccessorDescriptorAccessInfo(receiver_map, name, map, 8261cb0ef41Sopenharmony_ci holder, index, access_mode); 8271cb0ef41Sopenharmony_ci } 8281cb0ef41Sopenharmony_ci 8291cb0ef41Sopenharmony_ci UNREACHABLE(); 8301cb0ef41Sopenharmony_ci } 8311cb0ef41Sopenharmony_ci 8321cb0ef41Sopenharmony_ci // The property wasn't found on {map}. Look on the prototype if appropriate. 8331cb0ef41Sopenharmony_ci DCHECK(!index.is_found()); 8341cb0ef41Sopenharmony_ci 8351cb0ef41Sopenharmony_ci // Don't search on the prototype chain for special indices in case of 8361cb0ef41Sopenharmony_ci // integer indexed exotic objects (see ES6 section 9.4.5). 8371cb0ef41Sopenharmony_ci if (map.object()->IsJSTypedArrayMap() && name.IsString()) { 8381cb0ef41Sopenharmony_ci if (broker()->IsMainThread()) { 8391cb0ef41Sopenharmony_ci if (IsSpecialIndex(String::cast(*name.object()))) { 8401cb0ef41Sopenharmony_ci return Invalid(); 8411cb0ef41Sopenharmony_ci } 8421cb0ef41Sopenharmony_ci } else { 8431cb0ef41Sopenharmony_ci // TODO(jgruber): We are being conservative here since we can't access 8441cb0ef41Sopenharmony_ci // string contents from background threads. Should that become possible 8451cb0ef41Sopenharmony_ci // in the future, remove this bailout. 8461cb0ef41Sopenharmony_ci return Invalid(); 8471cb0ef41Sopenharmony_ci } 8481cb0ef41Sopenharmony_ci } 8491cb0ef41Sopenharmony_ci 8501cb0ef41Sopenharmony_ci // Don't search on the prototype when storing in literals, or performing a 8511cb0ef41Sopenharmony_ci // Define operation 8521cb0ef41Sopenharmony_ci if (access_mode == AccessMode::kStoreInLiteral || 8531cb0ef41Sopenharmony_ci access_mode == AccessMode::kDefine) { 8541cb0ef41Sopenharmony_ci PropertyAttributes attrs = NONE; 8551cb0ef41Sopenharmony_ci if (name.object()->IsPrivate()) { 8561cb0ef41Sopenharmony_ci // When PrivateNames are added to an object, they are by definition 8571cb0ef41Sopenharmony_ci // non-enumerable. 8581cb0ef41Sopenharmony_ci attrs = DONT_ENUM; 8591cb0ef41Sopenharmony_ci } 8601cb0ef41Sopenharmony_ci return LookupTransition(receiver_map, name, holder, attrs); 8611cb0ef41Sopenharmony_ci } 8621cb0ef41Sopenharmony_ci 8631cb0ef41Sopenharmony_ci // Don't lookup private symbols on the prototype chain. 8641cb0ef41Sopenharmony_ci if (name.object()->IsPrivate()) { 8651cb0ef41Sopenharmony_ci return Invalid(); 8661cb0ef41Sopenharmony_ci } 8671cb0ef41Sopenharmony_ci 8681cb0ef41Sopenharmony_ci if (V8_DICT_PROPERTY_CONST_TRACKING_BOOL && holder.has_value()) { 8691cb0ef41Sopenharmony_ci // At this point, we are past the first loop iteration. 8701cb0ef41Sopenharmony_ci DCHECK(holder->object()->map().is_prototype_map()); 8711cb0ef41Sopenharmony_ci DCHECK(!holder->map().equals(receiver_map)); 8721cb0ef41Sopenharmony_ci 8731cb0ef41Sopenharmony_ci fast_mode_prototype_on_chain = 8741cb0ef41Sopenharmony_ci fast_mode_prototype_on_chain || !map.is_dictionary_map(); 8751cb0ef41Sopenharmony_ci dictionary_prototype_on_chain = 8761cb0ef41Sopenharmony_ci dictionary_prototype_on_chain || map.is_dictionary_map(); 8771cb0ef41Sopenharmony_ci } 8781cb0ef41Sopenharmony_ci 8791cb0ef41Sopenharmony_ci // Walk up the prototype chain. 8801cb0ef41Sopenharmony_ci // Load the map's prototype's map to guarantee that every time we use it, 8811cb0ef41Sopenharmony_ci // we use the same Map. 8821cb0ef41Sopenharmony_ci HeapObjectRef prototype = map.prototype(); 8831cb0ef41Sopenharmony_ci 8841cb0ef41Sopenharmony_ci MapRef map_prototype_map = prototype.map(); 8851cb0ef41Sopenharmony_ci if (!map_prototype_map.object()->IsJSObjectMap()) { 8861cb0ef41Sopenharmony_ci // Don't allow proxies on the prototype chain. 8871cb0ef41Sopenharmony_ci if (!prototype.IsNull()) { 8881cb0ef41Sopenharmony_ci DCHECK(prototype.object()->IsJSProxy()); 8891cb0ef41Sopenharmony_ci return Invalid(); 8901cb0ef41Sopenharmony_ci } 8911cb0ef41Sopenharmony_ci 8921cb0ef41Sopenharmony_ci DCHECK(prototype.IsNull()); 8931cb0ef41Sopenharmony_ci 8941cb0ef41Sopenharmony_ci if (dictionary_prototype_on_chain) { 8951cb0ef41Sopenharmony_ci // TODO(v8:11248) See earlier comment about 8961cb0ef41Sopenharmony_ci // dictionary_prototype_on_chain. We don't support absent properties 8971cb0ef41Sopenharmony_ci // with dictionary mode prototypes on the chain, either. This is again 8981cb0ef41Sopenharmony_ci // just due to how we currently deal with dependencies for dictionary 8991cb0ef41Sopenharmony_ci // properties during finalization. 9001cb0ef41Sopenharmony_ci return Invalid(); 9011cb0ef41Sopenharmony_ci } 9021cb0ef41Sopenharmony_ci 9031cb0ef41Sopenharmony_ci // Store to property not found on the receiver or any prototype, we need 9041cb0ef41Sopenharmony_ci // to transition to a new data property. 9051cb0ef41Sopenharmony_ci // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver) 9061cb0ef41Sopenharmony_ci if (access_mode == AccessMode::kStore) { 9071cb0ef41Sopenharmony_ci return LookupTransition(receiver_map, name, holder, NONE); 9081cb0ef41Sopenharmony_ci } 9091cb0ef41Sopenharmony_ci 9101cb0ef41Sopenharmony_ci // The property was not found (access returns undefined or throws 9111cb0ef41Sopenharmony_ci // depending on the language mode of the load operation. 9121cb0ef41Sopenharmony_ci // Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver) 9131cb0ef41Sopenharmony_ci return PropertyAccessInfo::NotFound(zone(), receiver_map, holder); 9141cb0ef41Sopenharmony_ci } 9151cb0ef41Sopenharmony_ci 9161cb0ef41Sopenharmony_ci holder = prototype.AsJSObject(); 9171cb0ef41Sopenharmony_ci map = map_prototype_map; 9181cb0ef41Sopenharmony_ci 9191cb0ef41Sopenharmony_ci if (!CanInlinePropertyAccess(map, access_mode)) { 9201cb0ef41Sopenharmony_ci return Invalid(); 9211cb0ef41Sopenharmony_ci } 9221cb0ef41Sopenharmony_ci 9231cb0ef41Sopenharmony_ci // Successful lookup on prototype chain needs to guarantee that all the 9241cb0ef41Sopenharmony_ci // prototypes up to the holder have stable maps, except for dictionary-mode 9251cb0ef41Sopenharmony_ci // prototypes. We currently do this by taking a 9261cb0ef41Sopenharmony_ci // DependOnStablePrototypeChains dependency in the caller. 9271cb0ef41Sopenharmony_ci // 9281cb0ef41Sopenharmony_ci // TODO(jgruber): This is brittle and easy to miss. Consider a refactor 9291cb0ef41Sopenharmony_ci // that moves the responsibility of taking the dependency into 9301cb0ef41Sopenharmony_ci // AccessInfoFactory. 9311cb0ef41Sopenharmony_ci } 9321cb0ef41Sopenharmony_ci UNREACHABLE(); 9331cb0ef41Sopenharmony_ci} 9341cb0ef41Sopenharmony_ci 9351cb0ef41Sopenharmony_ciPropertyAccessInfo AccessInfoFactory::FinalizePropertyAccessInfosAsOne( 9361cb0ef41Sopenharmony_ci ZoneVector<PropertyAccessInfo> access_infos, AccessMode access_mode) const { 9371cb0ef41Sopenharmony_ci ZoneVector<PropertyAccessInfo> merged_access_infos(zone()); 9381cb0ef41Sopenharmony_ci MergePropertyAccessInfos(access_infos, access_mode, &merged_access_infos); 9391cb0ef41Sopenharmony_ci if (merged_access_infos.size() == 1) { 9401cb0ef41Sopenharmony_ci PropertyAccessInfo& result = merged_access_infos.front(); 9411cb0ef41Sopenharmony_ci if (!result.IsInvalid()) { 9421cb0ef41Sopenharmony_ci result.RecordDependencies(dependencies()); 9431cb0ef41Sopenharmony_ci return result; 9441cb0ef41Sopenharmony_ci } 9451cb0ef41Sopenharmony_ci } 9461cb0ef41Sopenharmony_ci return Invalid(); 9471cb0ef41Sopenharmony_ci} 9481cb0ef41Sopenharmony_ci 9491cb0ef41Sopenharmony_civoid PropertyAccessInfo::RecordDependencies( 9501cb0ef41Sopenharmony_ci CompilationDependencies* dependencies) { 9511cb0ef41Sopenharmony_ci for (CompilationDependency const* d : unrecorded_dependencies_) { 9521cb0ef41Sopenharmony_ci dependencies->RecordDependency(d); 9531cb0ef41Sopenharmony_ci } 9541cb0ef41Sopenharmony_ci unrecorded_dependencies_.clear(); 9551cb0ef41Sopenharmony_ci} 9561cb0ef41Sopenharmony_ci 9571cb0ef41Sopenharmony_cibool AccessInfoFactory::FinalizePropertyAccessInfos( 9581cb0ef41Sopenharmony_ci ZoneVector<PropertyAccessInfo> access_infos, AccessMode access_mode, 9591cb0ef41Sopenharmony_ci ZoneVector<PropertyAccessInfo>* result) const { 9601cb0ef41Sopenharmony_ci if (access_infos.empty()) return false; 9611cb0ef41Sopenharmony_ci MergePropertyAccessInfos(access_infos, access_mode, result); 9621cb0ef41Sopenharmony_ci for (PropertyAccessInfo const& info : *result) { 9631cb0ef41Sopenharmony_ci if (info.IsInvalid()) return false; 9641cb0ef41Sopenharmony_ci } 9651cb0ef41Sopenharmony_ci for (PropertyAccessInfo& info : *result) { 9661cb0ef41Sopenharmony_ci info.RecordDependencies(dependencies()); 9671cb0ef41Sopenharmony_ci } 9681cb0ef41Sopenharmony_ci return true; 9691cb0ef41Sopenharmony_ci} 9701cb0ef41Sopenharmony_ci 9711cb0ef41Sopenharmony_civoid AccessInfoFactory::MergePropertyAccessInfos( 9721cb0ef41Sopenharmony_ci ZoneVector<PropertyAccessInfo> infos, AccessMode access_mode, 9731cb0ef41Sopenharmony_ci ZoneVector<PropertyAccessInfo>* result) const { 9741cb0ef41Sopenharmony_ci DCHECK(result->empty()); 9751cb0ef41Sopenharmony_ci for (auto it = infos.begin(), end = infos.end(); it != end; ++it) { 9761cb0ef41Sopenharmony_ci bool merged = false; 9771cb0ef41Sopenharmony_ci for (auto ot = it + 1; ot != end; ++ot) { 9781cb0ef41Sopenharmony_ci if (ot->Merge(&(*it), access_mode, zone())) { 9791cb0ef41Sopenharmony_ci merged = true; 9801cb0ef41Sopenharmony_ci break; 9811cb0ef41Sopenharmony_ci } 9821cb0ef41Sopenharmony_ci } 9831cb0ef41Sopenharmony_ci if (!merged) result->push_back(*it); 9841cb0ef41Sopenharmony_ci } 9851cb0ef41Sopenharmony_ci CHECK(!result->empty()); 9861cb0ef41Sopenharmony_ci} 9871cb0ef41Sopenharmony_ci 9881cb0ef41Sopenharmony_ciIsolate* AccessInfoFactory::isolate() const { return broker()->isolate(); } 9891cb0ef41Sopenharmony_ci 9901cb0ef41Sopenharmony_cinamespace { 9911cb0ef41Sopenharmony_ci 9921cb0ef41Sopenharmony_ciMaybe<ElementsKind> GeneralizeElementsKind(ElementsKind this_kind, 9931cb0ef41Sopenharmony_ci ElementsKind that_kind) { 9941cb0ef41Sopenharmony_ci if (IsHoleyElementsKind(this_kind)) { 9951cb0ef41Sopenharmony_ci that_kind = GetHoleyElementsKind(that_kind); 9961cb0ef41Sopenharmony_ci } else if (IsHoleyElementsKind(that_kind)) { 9971cb0ef41Sopenharmony_ci this_kind = GetHoleyElementsKind(this_kind); 9981cb0ef41Sopenharmony_ci } 9991cb0ef41Sopenharmony_ci if (this_kind == that_kind) return Just(this_kind); 10001cb0ef41Sopenharmony_ci if (IsDoubleElementsKind(that_kind) == IsDoubleElementsKind(this_kind)) { 10011cb0ef41Sopenharmony_ci if (IsMoreGeneralElementsKindTransition(that_kind, this_kind)) { 10021cb0ef41Sopenharmony_ci return Just(this_kind); 10031cb0ef41Sopenharmony_ci } 10041cb0ef41Sopenharmony_ci if (IsMoreGeneralElementsKindTransition(this_kind, that_kind)) { 10051cb0ef41Sopenharmony_ci return Just(that_kind); 10061cb0ef41Sopenharmony_ci } 10071cb0ef41Sopenharmony_ci } 10081cb0ef41Sopenharmony_ci return Nothing<ElementsKind>(); 10091cb0ef41Sopenharmony_ci} 10101cb0ef41Sopenharmony_ci 10111cb0ef41Sopenharmony_ci} // namespace 10121cb0ef41Sopenharmony_ci 10131cb0ef41Sopenharmony_cibase::Optional<ElementAccessInfo> AccessInfoFactory::ConsolidateElementLoad( 10141cb0ef41Sopenharmony_ci ElementAccessFeedback const& feedback) const { 10151cb0ef41Sopenharmony_ci if (feedback.transition_groups().empty()) return {}; 10161cb0ef41Sopenharmony_ci 10171cb0ef41Sopenharmony_ci DCHECK(!feedback.transition_groups().front().empty()); 10181cb0ef41Sopenharmony_ci Handle<Map> first_map = feedback.transition_groups().front().front(); 10191cb0ef41Sopenharmony_ci base::Optional<MapRef> first_map_ref = TryMakeRef(broker(), first_map); 10201cb0ef41Sopenharmony_ci if (!first_map_ref.has_value()) return {}; 10211cb0ef41Sopenharmony_ci InstanceType instance_type = first_map_ref->instance_type(); 10221cb0ef41Sopenharmony_ci ElementsKind elements_kind = first_map_ref->elements_kind(); 10231cb0ef41Sopenharmony_ci 10241cb0ef41Sopenharmony_ci ZoneVector<MapRef> maps(zone()); 10251cb0ef41Sopenharmony_ci for (auto const& group : feedback.transition_groups()) { 10261cb0ef41Sopenharmony_ci for (Handle<Map> map_handle : group) { 10271cb0ef41Sopenharmony_ci base::Optional<MapRef> map = TryMakeRef(broker(), map_handle); 10281cb0ef41Sopenharmony_ci if (!map.has_value()) return {}; 10291cb0ef41Sopenharmony_ci if (map->instance_type() != instance_type || 10301cb0ef41Sopenharmony_ci !map->CanInlineElementAccess()) { 10311cb0ef41Sopenharmony_ci return {}; 10321cb0ef41Sopenharmony_ci } 10331cb0ef41Sopenharmony_ci if (!GeneralizeElementsKind(elements_kind, map->elements_kind()) 10341cb0ef41Sopenharmony_ci .To(&elements_kind)) { 10351cb0ef41Sopenharmony_ci return {}; 10361cb0ef41Sopenharmony_ci } 10371cb0ef41Sopenharmony_ci maps.push_back(map.value()); 10381cb0ef41Sopenharmony_ci } 10391cb0ef41Sopenharmony_ci } 10401cb0ef41Sopenharmony_ci 10411cb0ef41Sopenharmony_ci return ElementAccessInfo(std::move(maps), elements_kind, zone()); 10421cb0ef41Sopenharmony_ci} 10431cb0ef41Sopenharmony_ci 10441cb0ef41Sopenharmony_ciPropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor( 10451cb0ef41Sopenharmony_ci MapRef map, NameRef name) const { 10461cb0ef41Sopenharmony_ci // Check for String::length field accessor. 10471cb0ef41Sopenharmony_ci if (map.object()->IsStringMap()) { 10481cb0ef41Sopenharmony_ci if (Name::Equals(isolate(), name.object(), 10491cb0ef41Sopenharmony_ci isolate()->factory()->length_string())) { 10501cb0ef41Sopenharmony_ci return PropertyAccessInfo::StringLength(zone(), map); 10511cb0ef41Sopenharmony_ci } 10521cb0ef41Sopenharmony_ci return Invalid(); 10531cb0ef41Sopenharmony_ci } 10541cb0ef41Sopenharmony_ci // Check for special JSObject field accessors. 10551cb0ef41Sopenharmony_ci FieldIndex field_index; 10561cb0ef41Sopenharmony_ci if (Accessors::IsJSObjectFieldAccessor(isolate(), map.object(), name.object(), 10571cb0ef41Sopenharmony_ci &field_index)) { 10581cb0ef41Sopenharmony_ci Type field_type = Type::NonInternal(); 10591cb0ef41Sopenharmony_ci Representation field_representation = Representation::Tagged(); 10601cb0ef41Sopenharmony_ci if (map.object()->IsJSArrayMap()) { 10611cb0ef41Sopenharmony_ci DCHECK(Name::Equals(isolate(), isolate()->factory()->length_string(), 10621cb0ef41Sopenharmony_ci name.object())); 10631cb0ef41Sopenharmony_ci // The JSArray::length property is a smi in the range 10641cb0ef41Sopenharmony_ci // [0, FixedDoubleArray::kMaxLength] in case of fast double 10651cb0ef41Sopenharmony_ci // elements, a smi in the range [0, FixedArray::kMaxLength] 10661cb0ef41Sopenharmony_ci // in case of other fast elements, and [0, kMaxUInt32] in 10671cb0ef41Sopenharmony_ci // case of other arrays. 10681cb0ef41Sopenharmony_ci if (IsDoubleElementsKind(map.elements_kind())) { 10691cb0ef41Sopenharmony_ci field_type = type_cache_->kFixedDoubleArrayLengthType; 10701cb0ef41Sopenharmony_ci field_representation = Representation::Smi(); 10711cb0ef41Sopenharmony_ci } else if (IsFastElementsKind(map.elements_kind())) { 10721cb0ef41Sopenharmony_ci field_type = type_cache_->kFixedArrayLengthType; 10731cb0ef41Sopenharmony_ci field_representation = Representation::Smi(); 10741cb0ef41Sopenharmony_ci } else { 10751cb0ef41Sopenharmony_ci field_type = type_cache_->kJSArrayLengthType; 10761cb0ef41Sopenharmony_ci } 10771cb0ef41Sopenharmony_ci } 10781cb0ef41Sopenharmony_ci // Special fields are always mutable. 10791cb0ef41Sopenharmony_ci return PropertyAccessInfo::DataField(zone(), map, {{}, zone()}, field_index, 10801cb0ef41Sopenharmony_ci field_representation, field_type, map, 10811cb0ef41Sopenharmony_ci {}, {}, {}); 10821cb0ef41Sopenharmony_ci } 10831cb0ef41Sopenharmony_ci return Invalid(); 10841cb0ef41Sopenharmony_ci} 10851cb0ef41Sopenharmony_ci 10861cb0ef41Sopenharmony_ciPropertyAccessInfo AccessInfoFactory::LookupTransition( 10871cb0ef41Sopenharmony_ci MapRef map, NameRef name, base::Optional<JSObjectRef> holder, 10881cb0ef41Sopenharmony_ci PropertyAttributes attrs) const { 10891cb0ef41Sopenharmony_ci // Check if the {map} has a data transition with the given {name}. 10901cb0ef41Sopenharmony_ci Map transition = 10911cb0ef41Sopenharmony_ci TransitionsAccessor(isolate(), *map.object(), true) 10921cb0ef41Sopenharmony_ci .SearchTransition(*name.object(), PropertyKind::kData, attrs); 10931cb0ef41Sopenharmony_ci if (transition.is_null()) return Invalid(); 10941cb0ef41Sopenharmony_ci base::Optional<MapRef> maybe_transition_map = 10951cb0ef41Sopenharmony_ci TryMakeRef(broker(), transition); 10961cb0ef41Sopenharmony_ci if (!maybe_transition_map.has_value()) return Invalid(); 10971cb0ef41Sopenharmony_ci MapRef transition_map = maybe_transition_map.value(); 10981cb0ef41Sopenharmony_ci 10991cb0ef41Sopenharmony_ci InternalIndex const number = transition_map.object()->LastAdded(); 11001cb0ef41Sopenharmony_ci Handle<DescriptorArray> descriptors = 11011cb0ef41Sopenharmony_ci transition_map.instance_descriptors().object(); 11021cb0ef41Sopenharmony_ci PropertyDetails const details = descriptors->GetDetails(number); 11031cb0ef41Sopenharmony_ci 11041cb0ef41Sopenharmony_ci // Don't bother optimizing stores to read-only properties. 11051cb0ef41Sopenharmony_ci if (details.IsReadOnly()) return Invalid(); 11061cb0ef41Sopenharmony_ci 11071cb0ef41Sopenharmony_ci // TODO(bmeurer): Handle transition to data constant? 11081cb0ef41Sopenharmony_ci if (details.location() != PropertyLocation::kField) return Invalid(); 11091cb0ef41Sopenharmony_ci 11101cb0ef41Sopenharmony_ci int const index = details.field_index(); 11111cb0ef41Sopenharmony_ci Representation details_representation = details.representation(); 11121cb0ef41Sopenharmony_ci if (details_representation.IsNone()) return Invalid(); 11131cb0ef41Sopenharmony_ci 11141cb0ef41Sopenharmony_ci FieldIndex field_index = FieldIndex::ForPropertyIndex( 11151cb0ef41Sopenharmony_ci *transition_map.object(), index, details_representation); 11161cb0ef41Sopenharmony_ci Type field_type = Type::NonInternal(); 11171cb0ef41Sopenharmony_ci base::Optional<MapRef> field_map; 11181cb0ef41Sopenharmony_ci 11191cb0ef41Sopenharmony_ci ZoneVector<CompilationDependency const*> unrecorded_dependencies(zone()); 11201cb0ef41Sopenharmony_ci if (details_representation.IsSmi()) { 11211cb0ef41Sopenharmony_ci field_type = Type::SignedSmall(); 11221cb0ef41Sopenharmony_ci unrecorded_dependencies.push_back( 11231cb0ef41Sopenharmony_ci dependencies()->FieldRepresentationDependencyOffTheRecord( 11241cb0ef41Sopenharmony_ci transition_map, number, details_representation)); 11251cb0ef41Sopenharmony_ci } else if (details_representation.IsDouble()) { 11261cb0ef41Sopenharmony_ci field_type = type_cache_->kFloat64; 11271cb0ef41Sopenharmony_ci unrecorded_dependencies.push_back( 11281cb0ef41Sopenharmony_ci dependencies()->FieldRepresentationDependencyOffTheRecord( 11291cb0ef41Sopenharmony_ci transition_map, number, details_representation)); 11301cb0ef41Sopenharmony_ci } else if (details_representation.IsHeapObject()) { 11311cb0ef41Sopenharmony_ci // Extract the field type from the property details (make sure its 11321cb0ef41Sopenharmony_ci // representation is TaggedPointer to reflect the heap object case). 11331cb0ef41Sopenharmony_ci // TODO(jgruber,v8:7790): Use DescriptorArrayRef instead. 11341cb0ef41Sopenharmony_ci Handle<FieldType> descriptors_field_type = 11351cb0ef41Sopenharmony_ci broker()->CanonicalPersistentHandle(descriptors->GetFieldType(number)); 11361cb0ef41Sopenharmony_ci base::Optional<ObjectRef> descriptors_field_type_ref = 11371cb0ef41Sopenharmony_ci TryMakeRef<Object>(broker(), descriptors_field_type); 11381cb0ef41Sopenharmony_ci if (!descriptors_field_type_ref.has_value()) return Invalid(); 11391cb0ef41Sopenharmony_ci 11401cb0ef41Sopenharmony_ci if (descriptors_field_type->IsNone()) { 11411cb0ef41Sopenharmony_ci // Store is not safe if the field type was cleared. 11421cb0ef41Sopenharmony_ci return Invalid(); 11431cb0ef41Sopenharmony_ci } 11441cb0ef41Sopenharmony_ci unrecorded_dependencies.push_back( 11451cb0ef41Sopenharmony_ci dependencies()->FieldRepresentationDependencyOffTheRecord( 11461cb0ef41Sopenharmony_ci transition_map, number, details_representation)); 11471cb0ef41Sopenharmony_ci if (descriptors_field_type->IsClass()) { 11481cb0ef41Sopenharmony_ci unrecorded_dependencies.push_back( 11491cb0ef41Sopenharmony_ci dependencies()->FieldTypeDependencyOffTheRecord( 11501cb0ef41Sopenharmony_ci transition_map, number, *descriptors_field_type_ref)); 11511cb0ef41Sopenharmony_ci // Remember the field map, and try to infer a useful type. 11521cb0ef41Sopenharmony_ci base::Optional<MapRef> maybe_field_map = 11531cb0ef41Sopenharmony_ci TryMakeRef(broker(), descriptors_field_type->AsClass()); 11541cb0ef41Sopenharmony_ci if (!maybe_field_map.has_value()) return Invalid(); 11551cb0ef41Sopenharmony_ci field_type = Type::For(maybe_field_map.value()); 11561cb0ef41Sopenharmony_ci field_map = maybe_field_map; 11571cb0ef41Sopenharmony_ci } 11581cb0ef41Sopenharmony_ci } 11591cb0ef41Sopenharmony_ci 11601cb0ef41Sopenharmony_ci unrecorded_dependencies.push_back( 11611cb0ef41Sopenharmony_ci dependencies()->TransitionDependencyOffTheRecord(transition_map)); 11621cb0ef41Sopenharmony_ci // Transitioning stores *may* store to const fields. The resulting 11631cb0ef41Sopenharmony_ci // DataConstant access infos can be distinguished from later, i.e. redundant, 11641cb0ef41Sopenharmony_ci // stores to the same constant field by the presence of a transition map. 11651cb0ef41Sopenharmony_ci switch (dependencies()->DependOnFieldConstness(transition_map, number)) { 11661cb0ef41Sopenharmony_ci case PropertyConstness::kMutable: 11671cb0ef41Sopenharmony_ci return PropertyAccessInfo::DataField( 11681cb0ef41Sopenharmony_ci zone(), map, std::move(unrecorded_dependencies), field_index, 11691cb0ef41Sopenharmony_ci details_representation, field_type, transition_map, field_map, holder, 11701cb0ef41Sopenharmony_ci transition_map); 11711cb0ef41Sopenharmony_ci case PropertyConstness::kConst: 11721cb0ef41Sopenharmony_ci return PropertyAccessInfo::FastDataConstant( 11731cb0ef41Sopenharmony_ci zone(), map, std::move(unrecorded_dependencies), field_index, 11741cb0ef41Sopenharmony_ci details_representation, field_type, transition_map, field_map, holder, 11751cb0ef41Sopenharmony_ci transition_map); 11761cb0ef41Sopenharmony_ci } 11771cb0ef41Sopenharmony_ci UNREACHABLE(); 11781cb0ef41Sopenharmony_ci} 11791cb0ef41Sopenharmony_ci 11801cb0ef41Sopenharmony_ci} // namespace compiler 11811cb0ef41Sopenharmony_ci} // namespace internal 11821cb0ef41Sopenharmony_ci} // namespace v8 1183