diff options
author | Michaël Zasso <targos@protonmail.com> | 2019-08-01 08:38:30 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2019-08-01 12:53:56 +0200 |
commit | 2dcc3665abf57c3607cebffdeeca062f5894885d (patch) | |
tree | 4f560748132edcfb4c22d6f967a7e80d23d7ea2c /deps/v8/src/compiler/access-info.cc | |
parent | 1ee47d550c6de132f06110aa13eceb7551d643b3 (diff) | |
download | node-new-2dcc3665abf57c3607cebffdeeca062f5894885d.tar.gz |
deps: update V8 to 7.6.303.28
PR-URL: https://github.com/nodejs/node/pull/28016
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Refael Ackermann (רפאל פלחי) <refack@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Diffstat (limited to 'deps/v8/src/compiler/access-info.cc')
-rw-r--r-- | deps/v8/src/compiler/access-info.cc | 469 |
1 files changed, 276 insertions, 193 deletions
diff --git a/deps/v8/src/compiler/access-info.cc b/deps/v8/src/compiler/access-info.cc index 3fbedb6cbb..713484f734 100644 --- a/deps/v8/src/compiler/access-info.cc +++ b/deps/v8/src/compiler/access-info.cc @@ -6,16 +6,16 @@ #include "src/compiler/access-info.h" -#include "src/accessors.h" +#include "src/builtins/accessors.h" #include "src/compiler/compilation-dependencies.h" #include "src/compiler/type-cache.h" -#include "src/counters.h" -#include "src/field-index-inl.h" -#include "src/field-type.h" #include "src/ic/call-optimization.h" -#include "src/objects-inl.h" +#include "src/logging/counters.h" #include "src/objects/cell-inl.h" +#include "src/objects/field-index-inl.h" +#include "src/objects/field-type.h" #include "src/objects/module-inl.h" +#include "src/objects/objects-inl.h" #include "src/objects/struct-inl.h" #include "src/objects/templates.h" @@ -55,91 +55,112 @@ std::ostream& operator<<(std::ostream& os, AccessMode access_mode) { UNREACHABLE(); } -ElementAccessInfo::ElementAccessInfo() = default; - -ElementAccessInfo::ElementAccessInfo(MapHandles const& receiver_maps, - ElementsKind elements_kind) - : elements_kind_(elements_kind), receiver_maps_(receiver_maps) { +ElementAccessInfo::ElementAccessInfo(ZoneVector<Handle<Map>>&& receiver_maps, + ElementsKind elements_kind, Zone* zone) + : elements_kind_(elements_kind), + receiver_maps_(receiver_maps), + transition_sources_(zone) { CHECK(!receiver_maps.empty()); } // static -PropertyAccessInfo PropertyAccessInfo::NotFound(MapHandles const& receiver_maps, - MaybeHandle<JSObject> holder) { - return PropertyAccessInfo(kNotFound, holder, receiver_maps); +PropertyAccessInfo PropertyAccessInfo::Invalid(Zone* zone) { + return PropertyAccessInfo(zone); } // static -PropertyAccessInfo PropertyAccessInfo::DataConstant( - MapHandles const& receiver_maps, Handle<Object> constant, - MaybeHandle<JSObject> holder) { - return PropertyAccessInfo(kDataConstant, holder, constant, receiver_maps); +PropertyAccessInfo PropertyAccessInfo::NotFound(Zone* zone, + Handle<Map> receiver_map, + MaybeHandle<JSObject> holder) { + return PropertyAccessInfo(zone, kNotFound, holder, {{receiver_map}, zone}); } // static PropertyAccessInfo PropertyAccessInfo::DataField( - PropertyConstness constness, MapHandles const& receiver_maps, - FieldIndex field_index, MachineRepresentation field_representation, + Zone* zone, Handle<Map> receiver_map, + ZoneVector<CompilationDependencies::Dependency const*>&& dependencies, + FieldIndex field_index, Representation field_representation, Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map) { - Kind kind = - constness == PropertyConstness::kConst ? kDataConstantField : kDataField; - return PropertyAccessInfo(kind, holder, transition_map, field_index, + return PropertyAccessInfo(kDataField, holder, transition_map, field_index, field_representation, field_type, field_map, - receiver_maps); + {{receiver_map}, zone}, std::move(dependencies)); +} + +// static +PropertyAccessInfo PropertyAccessInfo::DataConstant( + Zone* zone, Handle<Map> receiver_map, + ZoneVector<CompilationDependencies::Dependency const*>&& dependencies, + FieldIndex field_index, Representation field_representation, + Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder, + MaybeHandle<Map> transition_map) { + return PropertyAccessInfo(kDataConstant, holder, transition_map, field_index, + field_representation, field_type, field_map, + {{receiver_map}, zone}, std::move(dependencies)); } // static PropertyAccessInfo PropertyAccessInfo::AccessorConstant( - MapHandles const& receiver_maps, Handle<Object> constant, + Zone* zone, Handle<Map> receiver_map, Handle<Object> constant, MaybeHandle<JSObject> holder) { - return PropertyAccessInfo(kAccessorConstant, holder, constant, receiver_maps); + return PropertyAccessInfo(zone, kAccessorConstant, holder, constant, + {{receiver_map}, zone}); } // static -PropertyAccessInfo PropertyAccessInfo::ModuleExport( - MapHandles const& receiver_maps, Handle<Cell> cell) { - return PropertyAccessInfo(kModuleExport, MaybeHandle<JSObject>(), cell, - receiver_maps); +PropertyAccessInfo PropertyAccessInfo::ModuleExport(Zone* zone, + Handle<Map> receiver_map, + Handle<Cell> cell) { + return PropertyAccessInfo(zone, kModuleExport, MaybeHandle<JSObject>(), cell, + {{receiver_map}, zone}); } // static -PropertyAccessInfo PropertyAccessInfo::StringLength( - MapHandles const& receiver_maps) { - return PropertyAccessInfo(kStringLength, MaybeHandle<JSObject>(), - receiver_maps); +PropertyAccessInfo PropertyAccessInfo::StringLength(Zone* zone, + Handle<Map> receiver_map) { + return PropertyAccessInfo(zone, kStringLength, MaybeHandle<JSObject>(), + {{receiver_map}, zone}); } -PropertyAccessInfo::PropertyAccessInfo() +PropertyAccessInfo::PropertyAccessInfo(Zone* zone) : kind_(kInvalid), - field_representation_(MachineRepresentation::kNone), + receiver_maps_(zone), + unrecorded_dependencies_(zone), + field_representation_(Representation::None()), field_type_(Type::None()) {} -PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder, - MapHandles const& receiver_maps) +PropertyAccessInfo::PropertyAccessInfo(Zone* zone, Kind kind, + MaybeHandle<JSObject> holder, + ZoneVector<Handle<Map>>&& receiver_maps) : kind_(kind), receiver_maps_(receiver_maps), + unrecorded_dependencies_(zone), holder_(holder), - field_representation_(MachineRepresentation::kNone), + field_representation_(Representation::None()), field_type_(Type::None()) {} -PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder, +PropertyAccessInfo::PropertyAccessInfo(Zone* zone, Kind kind, + MaybeHandle<JSObject> holder, Handle<Object> constant, - MapHandles const& receiver_maps) + ZoneVector<Handle<Map>>&& receiver_maps) : kind_(kind), receiver_maps_(receiver_maps), + unrecorded_dependencies_(zone), constant_(constant), holder_(holder), - field_representation_(MachineRepresentation::kNone), + field_representation_(Representation::None()), field_type_(Type::Any()) {} PropertyAccessInfo::PropertyAccessInfo( Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map, - FieldIndex field_index, MachineRepresentation field_representation, + FieldIndex field_index, Representation field_representation, Type field_type, MaybeHandle<Map> field_map, - MapHandles const& receiver_maps) + ZoneVector<Handle<Map>>&& receiver_maps, + ZoneVector<CompilationDependencies::Dependency const*>&& + unrecorded_dependencies) : kind_(kind), receiver_maps_(receiver_maps), + unrecorded_dependencies_(std::move(unrecorded_dependencies)), transition_map_(transition_map), holder_(holder), field_index_(field_index), @@ -157,7 +178,7 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that, return that->kind_ == kInvalid; case kDataField: - case kDataConstantField: { + case kDataConstant: { // Check if we actually access the same field (we use the // GetFieldAccessStubKey method here just like the ICs do // since that way we only compare the relevant bits of the @@ -167,12 +188,13 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that, switch (access_mode) { case AccessMode::kHas: case AccessMode::kLoad: { - if (this->field_representation_ != that->field_representation_) { - if (!IsAnyTagged(this->field_representation_) || - !IsAnyTagged(that->field_representation_)) { + if (!this->field_representation_.Equals( + that->field_representation_)) { + if (this->field_representation_.IsDouble() || + that->field_representation_.IsDouble()) { return false; } - this->field_representation_ = MachineRepresentation::kTagged; + this->field_representation_ = Representation::Tagged(); } if (this->field_map_.address() != that->field_map_.address()) { this->field_map_ = MaybeHandle<Map>(); @@ -186,7 +208,8 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that, // also need to make sure that in case of transitioning stores, // the transition targets match. if (this->field_map_.address() != that->field_map_.address() || - this->field_representation_ != that->field_representation_ || + !this->field_representation_.Equals( + that->field_representation_) || this->transition_map_.address() != that->transition_map_.address()) { return false; @@ -194,22 +217,25 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that, break; } } - // Merge the field type. this->field_type_ = Type::Union(this->field_type_, that->field_type_, zone); - // Merge the receiver maps. this->receiver_maps_.insert(this->receiver_maps_.end(), that->receiver_maps_.begin(), that->receiver_maps_.end()); + this->unrecorded_dependencies_.insert( + this->unrecorded_dependencies_.end(), + that->unrecorded_dependencies_.begin(), + that->unrecorded_dependencies_.end()); return true; } return false; } - case kDataConstant: case kAccessorConstant: { // Check if we actually access the same constant. if (this->constant_.address() == that->constant_.address()) { + DCHECK(this->unrecorded_dependencies_.empty()); + DCHECK(that->unrecorded_dependencies_.empty()); this->receiver_maps_.insert(this->receiver_maps_.end(), that->receiver_maps_.begin(), that->receiver_maps_.end()); @@ -220,6 +246,8 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that, case kNotFound: case kStringLength: { + DCHECK(this->unrecorded_dependencies_.empty()); + DCHECK(that->unrecorded_dependencies_.empty()); this->receiver_maps_.insert(this->receiver_maps_.end(), that->receiver_maps_.begin(), that->receiver_maps_.end()); @@ -243,65 +271,57 @@ AccessInfoFactory::AccessInfoFactory(JSHeapBroker* broker, type_cache_(TypeCache::Get()), zone_(zone) {} -bool AccessInfoFactory::ComputeElementAccessInfo( - Handle<Map> map, AccessMode access_mode, - ElementAccessInfo* access_info) const { +base::Optional<ElementAccessInfo> AccessInfoFactory::ComputeElementAccessInfo( + Handle<Map> map, AccessMode access_mode) const { // Check if it is safe to inline element access for the {map}. MapRef map_ref(broker(), map); - if (!CanInlineElementAccess(map_ref)) return false; + if (!CanInlineElementAccess(map_ref)) return base::nullopt; ElementsKind const elements_kind = map_ref.elements_kind(); - *access_info = ElementAccessInfo(MapHandles{map}, elements_kind); - return true; + return ElementAccessInfo({{map}, zone()}, elements_kind, zone()); } bool AccessInfoFactory::ComputeElementAccessInfos( - FeedbackNexus nexus, MapHandles const& maps, AccessMode access_mode, + ElementAccessFeedback const& processed, AccessMode access_mode, ZoneVector<ElementAccessInfo>* access_infos) const { - ElementAccessFeedback const* processed = - FLAG_concurrent_inlining - ? broker()->GetElementAccessFeedback(FeedbackSource(nexus)) - : broker()->ProcessFeedbackMapsForElementAccess(maps); - if (processed == nullptr) return false; - if (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) { // For polymorphic loads of similar elements kinds (i.e. all tagged or all // double), always use the "worst case" code without a transition. This is // much faster than transitioning the elements to the worst case, trading a // TransitionElementsKind for a CheckMaps, avoiding mutation of the array. - ElementAccessInfo access_info; - if (ConsolidateElementLoad(*processed, &access_info)) { - access_infos->push_back(access_info); + base::Optional<ElementAccessInfo> access_info = + ConsolidateElementLoad(processed); + if (access_info.has_value()) { + access_infos->push_back(*access_info); return true; } } - for (Handle<Map> receiver_map : processed->receiver_maps) { + for (Handle<Map> receiver_map : processed.receiver_maps) { // Compute the element access information. - ElementAccessInfo access_info; - if (!ComputeElementAccessInfo(receiver_map, access_mode, &access_info)) { - return false; - } + base::Optional<ElementAccessInfo> access_info = + ComputeElementAccessInfo(receiver_map, access_mode); + if (!access_info.has_value()) return false; // Collect the possible transitions for the {receiver_map}. - for (auto transition : processed->transitions) { + for (auto transition : processed.transitions) { if (transition.second.equals(receiver_map)) { - access_info.AddTransitionSource(transition.first); + access_info->AddTransitionSource(transition.first); } } // Schedule the access information. - access_infos->push_back(access_info); + access_infos->push_back(*access_info); } return true; } PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo( Handle<Map> receiver_map, Handle<Map> map, MaybeHandle<JSObject> holder, - int number, AccessMode access_mode) const { - DCHECK_NE(number, DescriptorArray::kNotFound); + int descriptor, AccessMode access_mode) const { + DCHECK_NE(descriptor, DescriptorArray::kNotFound); Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate()); - PropertyDetails const details = descriptors->GetDetails(number); - int index = descriptors->GetFieldIndex(number); + PropertyDetails const details = descriptors->GetDetails(descriptor); + int index = descriptors->GetFieldIndex(descriptor); Representation details_representation = details.representation(); if (details_representation.IsNone()) { // The ICs collect feedback in PREMONOMORPHIC state already, @@ -309,65 +329,77 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo( // fields for which the representation has not yet been // determined by the runtime. So we need to catch this case // here and fall back to use the regular IC logic instead. - return {}; + return PropertyAccessInfo::Invalid(zone()); } FieldIndex field_index = FieldIndex::ForPropertyIndex(*map, index, details_representation); Type field_type = Type::NonInternal(); -#ifdef V8_COMPRESS_POINTERS - MachineRepresentation field_representation = - MachineRepresentation::kCompressed; -#else - MachineRepresentation field_representation = MachineRepresentation::kTagged; -#endif MaybeHandle<Map> field_map; MapRef map_ref(broker(), map); + ZoneVector<CompilationDependencies::Dependency const*> + unrecorded_dependencies(zone()); if (details_representation.IsSmi()) { field_type = Type::SignedSmall(); -#ifdef V8_COMPRESS_POINTERS - field_representation = MachineRepresentation::kCompressedSigned; -#else - field_representation = MachineRepresentation::kTaggedSigned; -#endif - map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later. - dependencies()->DependOnFieldRepresentation(map_ref, number); + map_ref.SerializeOwnDescriptor(descriptor); + unrecorded_dependencies.push_back( + dependencies()->FieldRepresentationDependencyOffTheRecord(map_ref, + descriptor)); } else if (details_representation.IsDouble()) { field_type = type_cache_->kFloat64; - field_representation = MachineRepresentation::kFloat64; } else if (details_representation.IsHeapObject()) { // Extract the field type from the property details (make sure its // representation is TaggedPointer to reflect the heap object case). - field_representation = MachineRepresentation::kTaggedPointer; - Handle<FieldType> descriptors_field_type(descriptors->GetFieldType(number), - isolate()); + Handle<FieldType> descriptors_field_type( + descriptors->GetFieldType(descriptor), isolate()); if (descriptors_field_type->IsNone()) { // Store is not safe if the field type was cleared. - if (access_mode == AccessMode::kStore) return {}; + if (access_mode == AccessMode::kStore) { + return PropertyAccessInfo::Invalid(zone()); + } // The field type was cleared by the GC, so we don't know anything // about the contents now. } - map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later. - dependencies()->DependOnFieldRepresentation(map_ref, number); + map_ref.SerializeOwnDescriptor(descriptor); + unrecorded_dependencies.push_back( + dependencies()->FieldRepresentationDependencyOffTheRecord(map_ref, + descriptor)); if (descriptors_field_type->IsClass()) { - dependencies()->DependOnFieldType(map_ref, number); + unrecorded_dependencies.push_back( + dependencies()->FieldTypeDependencyOffTheRecord(map_ref, descriptor)); // Remember the field map, and try to infer a useful type. Handle<Map> map(descriptors_field_type->AsClass(), isolate()); field_type = Type::For(MapRef(broker(), map)); field_map = MaybeHandle<Map>(map); } } - return PropertyAccessInfo::DataField( - details.constness(), MapHandles{receiver_map}, field_index, - field_representation, field_type, field_map, holder); + PropertyConstness constness; + if (details.IsReadOnly() && !details.IsConfigurable()) { + constness = PropertyConstness::kConst; + } else { + map_ref.SerializeOwnDescriptor(descriptor); + constness = dependencies()->DependOnFieldConstness(map_ref, descriptor); + } + switch (constness) { + case PropertyConstness::kMutable: + return PropertyAccessInfo::DataField( + zone(), receiver_map, std::move(unrecorded_dependencies), field_index, + details_representation, field_type, field_map, holder); + case PropertyConstness::kConst: + return PropertyAccessInfo::DataConstant( + zone(), receiver_map, std::move(unrecorded_dependencies), field_index, + details_representation, field_type, field_map, holder); + } + UNREACHABLE(); } PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo( Handle<Map> receiver_map, Handle<Name> name, Handle<Map> map, - MaybeHandle<JSObject> holder, int number, AccessMode access_mode) const { - DCHECK_NE(number, DescriptorArray::kNotFound); + MaybeHandle<JSObject> holder, int descriptor, + AccessMode access_mode) const { + DCHECK_NE(descriptor, DescriptorArray::kNotFound); Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate()); - SLOW_DCHECK(number == descriptors->Search(*name, *map)); + SLOW_DCHECK(descriptor == descriptors->Search(*name, *map)); if (map->instance_type() == JS_MODULE_NAMESPACE_TYPE) { DCHECK(map->is_prototype_map()); Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(map->prototype_info()), @@ -375,22 +407,24 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo( Handle<JSModuleNamespace> module_namespace( JSModuleNamespace::cast(proto_info->module_namespace()), isolate()); Handle<Cell> cell( - Cell::cast(module_namespace->module()->exports()->Lookup( + Cell::cast(module_namespace->module().exports().Lookup( ReadOnlyRoots(isolate()), name, Smi::ToInt(name->GetHash()))), isolate()); - if (cell->value()->IsTheHole(isolate())) { + if (cell->value().IsTheHole(isolate())) { // This module has not been fully initialized yet. - return {}; + return PropertyAccessInfo::Invalid(zone()); } - return PropertyAccessInfo::ModuleExport(MapHandles{receiver_map}, cell); + return PropertyAccessInfo::ModuleExport(zone(), receiver_map, cell); } if (access_mode == AccessMode::kHas) { // HasProperty checks don't call getter/setters, existence is sufficient. - return PropertyAccessInfo::AccessorConstant(MapHandles{receiver_map}, + return PropertyAccessInfo::AccessorConstant(zone(), receiver_map, Handle<Object>(), holder); } - Handle<Object> accessors(descriptors->GetStrongValue(number), isolate()); - if (!accessors->IsAccessorPair()) return {}; + Handle<Object> accessors(descriptors->GetStrongValue(descriptor), isolate()); + if (!accessors->IsAccessorPair()) { + return PropertyAccessInfo::Invalid(zone()); + } Handle<Object> accessor(access_mode == AccessMode::kLoad ? Handle<AccessorPair>::cast(accessors)->getter() : Handle<AccessorPair>::cast(accessors)->setter(), @@ -400,16 +434,20 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo( if (!optimization.is_simple_api_call() || optimization.IsCrossContextLazyAccessorPair( *broker()->native_context().object(), *map)) { - return {}; + return PropertyAccessInfo::Invalid(zone()); } CallOptimization::HolderLookup lookup; holder = optimization.LookupHolderOfExpectedType(receiver_map, &lookup); - if (lookup == CallOptimization::kHolderNotFound) return {}; + if (lookup == CallOptimization::kHolderNotFound) { + return PropertyAccessInfo::Invalid(zone()); + } DCHECK_IMPLIES(lookup == CallOptimization::kHolderIsReceiver, holder.is_null()); DCHECK_IMPLIES(lookup == CallOptimization::kHolderFound, !holder.is_null()); - if (V8_UNLIKELY(TracingFlags::is_runtime_stats_enabled())) return {}; + if (V8_UNLIKELY(TracingFlags::is_runtime_stats_enabled())) { + return PropertyAccessInfo::Invalid(zone()); + } } if (access_mode == AccessMode::kLoad) { Handle<Name> cached_property_name; @@ -420,18 +458,22 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo( if (!access_info.IsInvalid()) return access_info; } } - return PropertyAccessInfo::AccessorConstant(MapHandles{receiver_map}, - accessor, holder); + return PropertyAccessInfo::AccessorConstant(zone(), receiver_map, accessor, + holder); } PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( Handle<Map> map, Handle<Name> name, AccessMode access_mode) const { CHECK(name->IsUniqueName()); - if (access_mode == AccessMode::kHas && !map->IsJSReceiverMap()) return {}; + if (access_mode == AccessMode::kHas && !map->IsJSReceiverMap()) { + return PropertyAccessInfo::Invalid(zone()); + } // Check if it is safe to inline property access for the {map}. - if (!CanInlinePropertyAccess(map)) return {}; + if (!CanInlinePropertyAccess(map)) { + return PropertyAccessInfo::Invalid(zone()); + } // We support fast inline cases for certain JSObject getters. if (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) { @@ -451,7 +493,9 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( if (access_mode == AccessMode::kStore || access_mode == AccessMode::kStoreInLiteral) { // Don't bother optimizing stores to read-only properties. - if (details.IsReadOnly()) return {}; + if (details.IsReadOnly()) { + return PropertyAccessInfo::Invalid(zone()); + } if (details.kind() == kData && !holder.is_null()) { // This is a store to a property not found on the receiver but on a // prototype. According to ES6 section 9.1.9 [[Set]], we need to @@ -467,20 +511,13 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( } else { DCHECK_EQ(kAccessor, details.kind()); // TODO(turbofan): Add support for general accessors? - return {}; + return PropertyAccessInfo::Invalid(zone()); } } else { DCHECK_EQ(kDescriptor, details.location()); - if (details.kind() == kData) { - DCHECK(!FLAG_track_constant_fields); - return PropertyAccessInfo::DataConstant( - MapHandles{receiver_map}, - handle(descriptors->GetStrongValue(number), isolate()), holder); - } else { - DCHECK_EQ(kAccessor, details.kind()); - return ComputeAccessorDescriptorAccessInfo( - receiver_map, name, map, holder, number, access_mode); - } + DCHECK_EQ(kAccessor, details.kind()); + return ComputeAccessorDescriptorAccessInfo(receiver_map, name, map, + holder, number, access_mode); } UNREACHABLE(); } @@ -491,7 +528,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( // integer indexed exotic objects (see ES6 section 9.4.5). if (map->IsJSTypedArrayMap() && name->IsString() && IsSpecialIndex(String::cast(*name))) { - return {}; + return PropertyAccessInfo::Invalid(zone()); } // Don't search on the prototype when storing in literals. @@ -500,18 +537,20 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( } // Don't lookup private symbols on the prototype chain. - if (name->IsPrivate()) return {}; + if (name->IsPrivate()) { + return PropertyAccessInfo::Invalid(zone()); + } // Walk up the prototype chain. - if (!map->prototype()->IsJSObject()) { + if (!map->prototype().IsJSObject()) { // Perform the implicit ToObject for primitives here. // Implemented according to ES6 section 7.3.2 GetV (V, P). Handle<JSFunction> constructor; if (Map::GetConstructorFunction(map, broker()->native_context().object()) .ToHandle(&constructor)) { map = handle(constructor->initial_map(), isolate()); - DCHECK(map->prototype()->IsJSObject()); - } else if (map->prototype()->IsNull(isolate())) { + DCHECK(map->prototype().IsJSObject()); + } else if (map->prototype().IsNull(isolate())) { // Store to property not found on the receiver or any prototype, we need // to transition to a new data property. // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver) @@ -521,13 +560,13 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( // The property was not found (access returns undefined or throws // depending on the language mode of the load operation. // Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver) - return PropertyAccessInfo::NotFound(MapHandles{receiver_map}, holder); + return PropertyAccessInfo::NotFound(zone(), receiver_map, holder); } else { - return {}; + return PropertyAccessInfo::Invalid(zone()); } } Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate()); - if (map_prototype->map()->is_deprecated()) { + if (map_prototype->map().is_deprecated()) { // Try to migrate the prototype object so we don't embed the deprecated // map into the optimized code. JSObject::TryMigrateInstance(map_prototype); @@ -535,26 +574,30 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( map = handle(map_prototype->map(), isolate()); holder = map_prototype; - if (!CanInlinePropertyAccess(map)) return {}; + if (!CanInlinePropertyAccess(map)) { + return PropertyAccessInfo::Invalid(zone()); + } // Successful lookup on prototype chain needs to guarantee that all // the prototypes up to the holder have stable maps. Let us make sure // the prototype maps are stable here. CHECK(map->is_stable()); } + UNREACHABLE(); } -PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( - MapHandles const& maps, Handle<Name> name, AccessMode access_mode) const { - ZoneVector<PropertyAccessInfo> raw_access_infos(zone()); - ComputePropertyAccessInfos(maps, name, access_mode, &raw_access_infos); - ZoneVector<PropertyAccessInfo> access_infos(zone()); - if (FinalizePropertyAccessInfos(raw_access_infos, access_mode, - &access_infos) && - access_infos.size() == 1) { - return access_infos.front(); - } - return {}; +PropertyAccessInfo AccessInfoFactory::FinalizePropertyAccessInfosAsOne( + ZoneVector<PropertyAccessInfo> access_infos, AccessMode access_mode) const { + ZoneVector<PropertyAccessInfo> merged_access_infos(zone()); + MergePropertyAccessInfos(access_infos, access_mode, &merged_access_infos); + if (merged_access_infos.size() == 1) { + PropertyAccessInfo& result = merged_access_infos.front(); + if (!result.IsInvalid()) { + result.RecordDependencies(dependencies()); + return result; + } + } + return PropertyAccessInfo::Invalid(zone()); } void AccessInfoFactory::ComputePropertyAccessInfos( @@ -566,7 +609,29 @@ void AccessInfoFactory::ComputePropertyAccessInfos( } } +void PropertyAccessInfo::RecordDependencies( + CompilationDependencies* dependencies) { + for (CompilationDependencies::Dependency const* d : + unrecorded_dependencies_) { + dependencies->RecordDependency(d); + } + unrecorded_dependencies_.clear(); +} + bool AccessInfoFactory::FinalizePropertyAccessInfos( + ZoneVector<PropertyAccessInfo> access_infos, AccessMode access_mode, + ZoneVector<PropertyAccessInfo>* result) const { + MergePropertyAccessInfos(access_infos, access_mode, result); + for (PropertyAccessInfo const& info : *result) { + if (info.IsInvalid()) return false; + } + for (PropertyAccessInfo& info : *result) { + info.RecordDependencies(dependencies()); + } + return true; +} + +void AccessInfoFactory::MergePropertyAccessInfos( ZoneVector<PropertyAccessInfo> infos, AccessMode access_mode, ZoneVector<PropertyAccessInfo>* result) const { DCHECK(result->empty()); @@ -578,11 +643,9 @@ bool AccessInfoFactory::FinalizePropertyAccessInfos( break; } } - if (it->IsInvalid()) return false; if (!merged) result->push_back(*it); } CHECK(!result->empty()); - return true; } namespace { @@ -608,28 +671,26 @@ Maybe<ElementsKind> GeneralizeElementsKind(ElementsKind this_kind, } // namespace -bool AccessInfoFactory::ConsolidateElementLoad( - ElementAccessFeedback const& processed, - ElementAccessInfo* access_info) const { +base::Optional<ElementAccessInfo> AccessInfoFactory::ConsolidateElementLoad( + ElementAccessFeedback const& processed) const { ElementAccessFeedback::MapIterator it = processed.all_maps(broker()); MapRef first_map = it.current(); InstanceType instance_type = first_map.instance_type(); ElementsKind elements_kind = first_map.elements_kind(); - MapHandles maps; + ZoneVector<Handle<Map>> maps(zone()); for (; !it.done(); it.advance()) { MapRef map = it.current(); if (map.instance_type() != instance_type || !CanInlineElementAccess(map)) { - return false; + return base::nullopt; } if (!GeneralizeElementsKind(elements_kind, map.elements_kind()) .To(&elements_kind)) { - return false; + return base::nullopt; } maps.push_back(map.object()); } - *access_info = ElementAccessInfo(maps, elements_kind); - return true; + return ElementAccessInfo(std::move(maps), elements_kind, zone()); } PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor( @@ -637,15 +698,15 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor( // Check for String::length field accessor. if (map->IsStringMap()) { if (Name::Equals(isolate(), name, isolate()->factory()->length_string())) { - return PropertyAccessInfo::StringLength(MapHandles{map}); + return PropertyAccessInfo::StringLength(zone(), map); } - return {}; + return PropertyAccessInfo::Invalid(zone()); } // Check for special JSObject field accessors. FieldIndex field_index; if (Accessors::IsJSObjectFieldAccessor(isolate(), map, name, &field_index)) { Type field_type = Type::NonInternal(); - MachineRepresentation field_representation = MachineRepresentation::kTagged; + Representation field_representation = Representation::Tagged(); if (map->IsJSArrayMap()) { DCHECK( Name::Equals(isolate(), isolate()->factory()->length_string(), name)); @@ -656,20 +717,19 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor( // case of other arrays. if (IsDoubleElementsKind(map->elements_kind())) { field_type = type_cache_->kFixedDoubleArrayLengthType; - field_representation = MachineRepresentation::kTaggedSigned; + field_representation = Representation::Smi(); } else if (IsFastElementsKind(map->elements_kind())) { field_type = type_cache_->kFixedArrayLengthType; - field_representation = MachineRepresentation::kTaggedSigned; + field_representation = Representation::Smi(); } else { field_type = type_cache_->kJSArrayLengthType; } } // Special fields are always mutable. - return PropertyAccessInfo::DataField(PropertyConstness::kMutable, - MapHandles{map}, field_index, + return PropertyAccessInfo::DataField(zone(), map, {{}, zone()}, field_index, field_representation, field_type); } - return {}; + return PropertyAccessInfo::Invalid(zone()); } PropertyAccessInfo AccessInfoFactory::LookupTransition( @@ -677,58 +737,81 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition( // Check if the {map} has a data transition with the given {name}. Map transition = TransitionsAccessor(isolate(), map).SearchTransition(*name, kData, NONE); - if (transition.is_null()) return {}; + if (transition.is_null()) { + return PropertyAccessInfo::Invalid(zone()); + } Handle<Map> transition_map(transition, isolate()); int const number = transition_map->LastAdded(); PropertyDetails const details = - transition_map->instance_descriptors()->GetDetails(number); + transition_map->instance_descriptors().GetDetails(number); // Don't bother optimizing stores to read-only properties. - if (details.IsReadOnly()) return {}; + if (details.IsReadOnly()) { + return PropertyAccessInfo::Invalid(zone()); + } // TODO(bmeurer): Handle transition to data constant? - if (details.location() != kField) return {}; + if (details.location() != kField) { + return PropertyAccessInfo::Invalid(zone()); + } int const index = details.field_index(); Representation details_representation = details.representation(); FieldIndex field_index = FieldIndex::ForPropertyIndex(*transition_map, index, details_representation); Type field_type = Type::NonInternal(); MaybeHandle<Map> field_map; - MachineRepresentation field_representation = MachineRepresentation::kTagged; MapRef transition_map_ref(broker(), transition_map); + ZoneVector<CompilationDependencies::Dependency const*> + unrecorded_dependencies(zone()); if (details_representation.IsSmi()) { field_type = Type::SignedSmall(); - field_representation = MachineRepresentation::kTaggedSigned; - transition_map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later. - dependencies()->DependOnFieldRepresentation(transition_map_ref, number); + transition_map_ref.SerializeOwnDescriptor(number); + unrecorded_dependencies.push_back( + dependencies()->FieldRepresentationDependencyOffTheRecord( + transition_map_ref, number)); } else if (details_representation.IsDouble()) { field_type = type_cache_->kFloat64; - field_representation = MachineRepresentation::kFloat64; } else if (details_representation.IsHeapObject()) { // Extract the field type from the property details (make sure its // representation is TaggedPointer to reflect the heap object case). - field_representation = MachineRepresentation::kTaggedPointer; Handle<FieldType> descriptors_field_type( - transition_map->instance_descriptors()->GetFieldType(number), - isolate()); + transition_map->instance_descriptors().GetFieldType(number), isolate()); if (descriptors_field_type->IsNone()) { // Store is not safe if the field type was cleared. - return {}; + return PropertyAccessInfo::Invalid(zone()); } - transition_map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later. - dependencies()->DependOnFieldRepresentation(transition_map_ref, number); + transition_map_ref.SerializeOwnDescriptor(number); + unrecorded_dependencies.push_back( + dependencies()->FieldRepresentationDependencyOffTheRecord( + transition_map_ref, number)); if (descriptors_field_type->IsClass()) { - dependencies()->DependOnFieldType(transition_map_ref, number); + unrecorded_dependencies.push_back( + dependencies()->FieldTypeDependencyOffTheRecord(transition_map_ref, + number)); // Remember the field map, and try to infer a useful type. Handle<Map> map(descriptors_field_type->AsClass(), isolate()); field_type = Type::For(MapRef(broker(), map)); field_map = MaybeHandle<Map>(map); } } - dependencies()->DependOnTransition(MapRef(broker(), transition_map)); - // Transitioning stores are never stores to constant fields. - return PropertyAccessInfo::DataField( - PropertyConstness::kMutable, MapHandles{map}, field_index, - field_representation, field_type, field_map, holder, transition_map); + unrecorded_dependencies.push_back( + dependencies()->TransitionDependencyOffTheRecord( + MapRef(broker(), transition_map))); + // Transitioning stores *may* store to const fields. The resulting + // DataConstant access infos can be distinguished from later, i.e. redundant, + // stores to the same constant field by the presence of a transition map. + switch (details.constness()) { + case PropertyConstness::kMutable: + return PropertyAccessInfo::DataField( + zone(), map, std::move(unrecorded_dependencies), field_index, + details_representation, field_type, field_map, holder, + transition_map); + case PropertyConstness::kConst: + return PropertyAccessInfo::DataConstant( + zone(), map, std::move(unrecorded_dependencies), field_index, + details_representation, field_type, field_map, holder, + transition_map); + } + UNREACHABLE(); } } // namespace compiler |