Commit e02ca14a authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[turbofan] Prepare for precomputing PropertyAccessInfo

We'll eventually map each relevant map to a PropertyAccessInfo at
serialization time.

Bug: v8:7790
Change-Id: I739075af3629359f43acfdeb609112f355f1bd38
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1565899
Commit-Queue: Georg Neis <neis@chromium.org>
Auto-Submit: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60872}
parent 81b6c6df
...@@ -154,7 +154,7 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that, ...@@ -154,7 +154,7 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
switch (this->kind_) { switch (this->kind_) {
case kInvalid: case kInvalid:
break; return that->kind_ == kInvalid;
case kDataField: case kDataField:
case kDataConstantField: { case kDataConstantField: {
...@@ -225,12 +225,9 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that, ...@@ -225,12 +225,9 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
that->receiver_maps_.end()); that->receiver_maps_.end());
return true; return true;
} }
case kModuleExport: { case kModuleExport:
return false; return false;
} }
}
UNREACHABLE();
} }
Handle<Cell> PropertyAccessInfo::export_cell() const { Handle<Cell> PropertyAccessInfo::export_cell() const {
...@@ -298,9 +295,9 @@ bool AccessInfoFactory::ComputeElementAccessInfos( ...@@ -298,9 +295,9 @@ bool AccessInfoFactory::ComputeElementAccessInfos(
return true; return true;
} }
bool AccessInfoFactory::ComputeDataFieldAccessInfo( PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
Handle<Map> receiver_map, Handle<Map> map, MaybeHandle<JSObject> holder, Handle<Map> receiver_map, Handle<Map> map, MaybeHandle<JSObject> holder,
int number, AccessMode access_mode, PropertyAccessInfo* access_info) const { int number, AccessMode access_mode) const {
DCHECK_NE(number, DescriptorArray::kNotFound); DCHECK_NE(number, DescriptorArray::kNotFound);
Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate()); Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
PropertyDetails const details = descriptors->GetDetails(number); PropertyDetails const details = descriptors->GetDetails(number);
...@@ -312,7 +309,7 @@ bool AccessInfoFactory::ComputeDataFieldAccessInfo( ...@@ -312,7 +309,7 @@ bool AccessInfoFactory::ComputeDataFieldAccessInfo(
// fields for which the representation has not yet been // fields for which the representation has not yet been
// determined by the runtime. So we need to catch this case // determined by the runtime. So we need to catch this case
// here and fall back to use the regular IC logic instead. // here and fall back to use the regular IC logic instead.
return false; return {};
} }
FieldIndex field_index = FieldIndex field_index =
FieldIndex::ForPropertyIndex(*map, index, details_representation); FieldIndex::ForPropertyIndex(*map, index, details_representation);
...@@ -341,7 +338,7 @@ bool AccessInfoFactory::ComputeDataFieldAccessInfo( ...@@ -341,7 +338,7 @@ bool AccessInfoFactory::ComputeDataFieldAccessInfo(
isolate()); isolate());
if (descriptors_field_type->IsNone()) { if (descriptors_field_type->IsNone()) {
// Store is not safe if the field type was cleared. // Store is not safe if the field type was cleared.
if (access_mode == AccessMode::kStore) return false; if (access_mode == AccessMode::kStore) return {};
// The field type was cleared by the GC, so we don't know anything // The field type was cleared by the GC, so we don't know anything
// about the contents now. // about the contents now.
...@@ -356,16 +353,14 @@ bool AccessInfoFactory::ComputeDataFieldAccessInfo( ...@@ -356,16 +353,14 @@ bool AccessInfoFactory::ComputeDataFieldAccessInfo(
field_map = MaybeHandle<Map>(map); field_map = MaybeHandle<Map>(map);
} }
} }
*access_info = PropertyAccessInfo::DataField( return PropertyAccessInfo::DataField(
details.constness(), MapHandles{receiver_map}, field_index, details.constness(), MapHandles{receiver_map}, field_index,
field_representation, field_type, field_map, holder); field_representation, field_type, field_map, holder);
return true;
} }
bool AccessInfoFactory::ComputeAccessorDescriptorAccessInfo( PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo(
Handle<Map> receiver_map, Handle<Name> name, Handle<Map> map, Handle<Map> receiver_map, Handle<Name> name, Handle<Map> map,
MaybeHandle<JSObject> holder, int number, AccessMode access_mode, MaybeHandle<JSObject> holder, int number, AccessMode access_mode) const {
PropertyAccessInfo* access_info) const {
DCHECK_NE(number, DescriptorArray::kNotFound); DCHECK_NE(number, DescriptorArray::kNotFound);
Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate()); Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
SLOW_DCHECK(number == descriptors->Search(*name, *map)); SLOW_DCHECK(number == descriptors->Search(*name, *map));
...@@ -381,69 +376,63 @@ bool AccessInfoFactory::ComputeAccessorDescriptorAccessInfo( ...@@ -381,69 +376,63 @@ bool AccessInfoFactory::ComputeAccessorDescriptorAccessInfo(
isolate()); isolate());
if (cell->value()->IsTheHole(isolate())) { if (cell->value()->IsTheHole(isolate())) {
// This module has not been fully initialized yet. // This module has not been fully initialized yet.
return false; return {};
} }
*access_info = return PropertyAccessInfo::ModuleExport(MapHandles{receiver_map}, cell);
PropertyAccessInfo::ModuleExport(MapHandles{receiver_map}, cell);
return true;
} }
if (access_mode == AccessMode::kHas) { if (access_mode == AccessMode::kHas) {
// HasProperty checks don't call getter/setters, existence is sufficient. // HasProperty checks don't call getter/setters, existence is sufficient.
*access_info = PropertyAccessInfo::AccessorConstant( return PropertyAccessInfo::AccessorConstant(MapHandles{receiver_map},
MapHandles{receiver_map}, Handle<Object>(), holder); Handle<Object>(), holder);
return true;
} }
Handle<Object> accessors(descriptors->GetStrongValue(number), isolate()); Handle<Object> accessors(descriptors->GetStrongValue(number), isolate());
if (!accessors->IsAccessorPair()) return false; if (!accessors->IsAccessorPair()) return {};
Handle<Object> accessor(access_mode == AccessMode::kLoad Handle<Object> accessor(access_mode == AccessMode::kLoad
? Handle<AccessorPair>::cast(accessors)->getter() ? Handle<AccessorPair>::cast(accessors)->getter()
: Handle<AccessorPair>::cast(accessors)->setter(), : Handle<AccessorPair>::cast(accessors)->setter(),
isolate()); isolate());
if (!accessor->IsJSFunction()) { if (!accessor->IsJSFunction()) {
CallOptimization optimization(isolate(), accessor); CallOptimization optimization(isolate(), accessor);
if (!optimization.is_simple_api_call()) return false; if (!optimization.is_simple_api_call() ||
if (optimization.IsCrossContextLazyAccessorPair( optimization.IsCrossContextLazyAccessorPair(
*broker()->native_context().object(), *map)) { *broker()->native_context().object(), *map)) {
return false; return {};
} }
CallOptimization::HolderLookup lookup; CallOptimization::HolderLookup lookup;
holder = optimization.LookupHolderOfExpectedType(receiver_map, &lookup); holder = optimization.LookupHolderOfExpectedType(receiver_map, &lookup);
if (lookup == CallOptimization::kHolderNotFound) return false; if (lookup == CallOptimization::kHolderNotFound) return {};
DCHECK_IMPLIES(lookup == CallOptimization::kHolderIsReceiver, DCHECK_IMPLIES(lookup == CallOptimization::kHolderIsReceiver,
holder.is_null()); holder.is_null());
DCHECK_IMPLIES(lookup == CallOptimization::kHolderFound, !holder.is_null()); DCHECK_IMPLIES(lookup == CallOptimization::kHolderFound, !holder.is_null());
if (V8_UNLIKELY(TracingFlags::is_runtime_stats_enabled())) return false; if (V8_UNLIKELY(TracingFlags::is_runtime_stats_enabled())) return {};
} }
if (access_mode == AccessMode::kLoad) { if (access_mode == AccessMode::kLoad) {
Handle<Name> cached_property_name; Handle<Name> cached_property_name;
if (FunctionTemplateInfo::TryGetCachedPropertyName(isolate(), accessor) if (FunctionTemplateInfo::TryGetCachedPropertyName(isolate(), accessor)
.ToHandle(&cached_property_name)) { .ToHandle(&cached_property_name)) {
if (ComputePropertyAccessInfo(map, cached_property_name, access_mode, PropertyAccessInfo access_info =
access_info)) { ComputePropertyAccessInfo(map, cached_property_name, access_mode);
return true; if (!access_info.IsInvalid()) return access_info;
}
} }
} }
*access_info = PropertyAccessInfo::AccessorConstant(MapHandles{receiver_map}, return PropertyAccessInfo::AccessorConstant(MapHandles{receiver_map},
accessor, holder); accessor, holder);
return true;
} }
bool AccessInfoFactory::ComputePropertyAccessInfo( PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
Handle<Map> map, Handle<Name> name, AccessMode access_mode, Handle<Map> map, Handle<Name> name, AccessMode access_mode) const {
PropertyAccessInfo* access_info) const {
CHECK(name->IsUniqueName()); CHECK(name->IsUniqueName());
if (access_mode == AccessMode::kHas && !map->IsJSReceiverMap()) return false; if (access_mode == AccessMode::kHas && !map->IsJSReceiverMap()) return {};
// Check if it is safe to inline property access for the {map}. // Check if it is safe to inline property access for the {map}.
if (!CanInlinePropertyAccess(map)) return false; if (!CanInlinePropertyAccess(map)) return {};
// We support fast inline cases for certain JSObject getters. // We support fast inline cases for certain JSObject getters.
if ((access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) && if (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) {
LookupSpecialFieldAccessor(map, name, access_info)) { PropertyAccessInfo access_info = LookupSpecialFieldAccessor(map, name);
return true; if (!access_info.IsInvalid()) return access_info;
} }
// Remember the receiver map. We use {map} as loop variable. // Remember the receiver map. We use {map} as loop variable.
...@@ -458,39 +447,35 @@ bool AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -458,39 +447,35 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
if (access_mode == AccessMode::kStore || if (access_mode == AccessMode::kStore ||
access_mode == AccessMode::kStoreInLiteral) { access_mode == AccessMode::kStoreInLiteral) {
// Don't bother optimizing stores to read-only properties. // Don't bother optimizing stores to read-only properties.
if (details.IsReadOnly()) { if (details.IsReadOnly()) return {};
return false;
}
if (details.kind() == kData && !holder.is_null()) { if (details.kind() == kData && !holder.is_null()) {
// This is a store to a property not found on the receiver but on a // 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 // prototype. According to ES6 section 9.1.9 [[Set]], we need to
// create a new data property on the receiver. We can still optimize // create a new data property on the receiver. We can still optimize
// if such a transition already exists. // if such a transition already exists.
return LookupTransition(receiver_map, name, holder, access_info); return LookupTransition(receiver_map, name, holder);
} }
} }
if (details.location() == kField) { if (details.location() == kField) {
if (details.kind() == kData) { if (details.kind() == kData) {
return ComputeDataFieldAccessInfo(receiver_map, map, holder, number, return ComputeDataFieldAccessInfo(receiver_map, map, holder, number,
access_mode, access_info); access_mode);
} else { } else {
DCHECK_EQ(kAccessor, details.kind()); DCHECK_EQ(kAccessor, details.kind());
// TODO(turbofan): Add support for general accessors? // TODO(turbofan): Add support for general accessors?
return false; return {};
} }
} else { } else {
DCHECK_EQ(kDescriptor, details.location()); DCHECK_EQ(kDescriptor, details.location());
if (details.kind() == kData) { if (details.kind() == kData) {
DCHECK(!FLAG_track_constant_fields); DCHECK(!FLAG_track_constant_fields);
*access_info = PropertyAccessInfo::DataConstant( return PropertyAccessInfo::DataConstant(
MapHandles{receiver_map}, MapHandles{receiver_map},
handle(descriptors->GetStrongValue(number), isolate()), holder); handle(descriptors->GetStrongValue(number), isolate()), holder);
return true;
} else { } else {
DCHECK_EQ(kAccessor, details.kind()); DCHECK_EQ(kAccessor, details.kind());
return ComputeAccessorDescriptorAccessInfo(receiver_map, name, map, return ComputeAccessorDescriptorAccessInfo(
holder, number, receiver_map, name, map, holder, number, access_mode);
access_mode, access_info);
} }
} }
UNREACHABLE(); UNREACHABLE();
...@@ -502,16 +487,16 @@ bool AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -502,16 +487,16 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
// integer indexed exotic objects (see ES6 section 9.4.5). // integer indexed exotic objects (see ES6 section 9.4.5).
if (map->IsJSTypedArrayMap() && name->IsString() && if (map->IsJSTypedArrayMap() && name->IsString() &&
IsSpecialIndex(String::cast(*name))) { IsSpecialIndex(String::cast(*name))) {
return false; return {};
} }
// Don't search on the prototype when storing in literals. // Don't search on the prototype when storing in literals.
if (access_mode == AccessMode::kStoreInLiteral) { if (access_mode == AccessMode::kStoreInLiteral) {
return LookupTransition(receiver_map, name, holder, access_info); return LookupTransition(receiver_map, name, holder);
} }
// Don't lookup private symbols on the prototype chain. // Don't lookup private symbols on the prototype chain.
if (name->IsPrivate()) return false; if (name->IsPrivate()) return {};
// Walk up the prototype chain. // Walk up the prototype chain.
if (!map->prototype()->IsJSObject()) { if (!map->prototype()->IsJSObject()) {
...@@ -527,16 +512,14 @@ bool AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -527,16 +512,14 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
// to transition to a new data property. // to transition to a new data property.
// Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver) // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
if (access_mode == AccessMode::kStore) { if (access_mode == AccessMode::kStore) {
return LookupTransition(receiver_map, name, holder, access_info); return LookupTransition(receiver_map, name, holder);
} }
// The property was not found, return undefined or throw depending // The property was not found (access returns undefined or throws
// on the language mode of the load operation. // depending on the language mode of the load operation.
// Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver) // Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver)
*access_info = return PropertyAccessInfo::NotFound(MapHandles{receiver_map}, holder);
PropertyAccessInfo::NotFound(MapHandles{receiver_map}, holder);
return true;
} else { } else {
return false; return {};
} }
} }
Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate()); Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
...@@ -548,7 +531,7 @@ bool AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -548,7 +531,7 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
map = handle(map_prototype->map(), isolate()); map = handle(map_prototype->map(), isolate());
holder = map_prototype; holder = map_prototype;
if (!CanInlinePropertyAccess(map)) return false; if (!CanInlinePropertyAccess(map)) return {};
// Successful lookup on prototype chain needs to guarantee that all // Successful lookup on prototype chain needs to guarantee that all
// the prototypes up to the holder have stable maps. Let us make sure // the prototypes up to the holder have stable maps. Let us make sure
...@@ -557,32 +540,32 @@ bool AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -557,32 +540,32 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
} }
} }
bool AccessInfoFactory::ComputePropertyAccessInfo( PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
MapHandles const& maps, Handle<Name> name, AccessMode access_mode, MapHandles const& maps, Handle<Name> name, AccessMode access_mode) const {
PropertyAccessInfo* access_info) const { ZoneVector<PropertyAccessInfo> raw_access_infos(zone());
ComputePropertyAccessInfos(maps, name, access_mode, &raw_access_infos);
ZoneVector<PropertyAccessInfo> access_infos(zone()); ZoneVector<PropertyAccessInfo> access_infos(zone());
if (ComputePropertyAccessInfos(maps, name, access_mode, &access_infos) && if (FinalizePropertyAccessInfos(raw_access_infos, access_mode,
&access_infos) &&
access_infos.size() == 1) { access_infos.size() == 1) {
*access_info = access_infos.front(); return access_infos.front();
return true;
} }
return false; return {};
} }
bool AccessInfoFactory::ComputePropertyAccessInfos( void AccessInfoFactory::ComputePropertyAccessInfos(
MapHandles const& maps, Handle<Name> name, AccessMode access_mode, MapHandles const& maps, Handle<Name> name, AccessMode access_mode,
ZoneVector<PropertyAccessInfo>* access_infos) const { ZoneVector<PropertyAccessInfo>* access_infos) const {
ZoneVector<PropertyAccessInfo> infos(zone()); DCHECK(access_infos->empty());
infos.reserve(maps.size());
for (Handle<Map> map : maps) { for (Handle<Map> map : maps) {
PropertyAccessInfo access_info; access_infos->push_back(ComputePropertyAccessInfo(map, name, access_mode));
if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) {
return false;
}
infos.push_back(access_info);
} }
}
// Merge as many as possible and push into {access_infos}. bool AccessInfoFactory::FinalizePropertyAccessInfos(
ZoneVector<PropertyAccessInfo> infos, AccessMode access_mode,
ZoneVector<PropertyAccessInfo>* result) const {
DCHECK(result->empty());
for (auto it = infos.begin(), end = infos.end(); it != end; ++it) { for (auto it = infos.begin(), end = infos.end(); it != end; ++it) {
bool merged = false; bool merged = false;
for (auto ot = it + 1; ot != end; ++ot) { for (auto ot = it + 1; ot != end; ++ot) {
...@@ -591,8 +574,10 @@ bool AccessInfoFactory::ComputePropertyAccessInfos( ...@@ -591,8 +574,10 @@ bool AccessInfoFactory::ComputePropertyAccessInfos(
break; break;
} }
} }
if (!merged) access_infos->push_back(*it); if (it->IsInvalid()) return false;
if (!merged) result->push_back(*it);
} }
CHECK(!result->empty());
return true; return true;
} }
...@@ -643,15 +628,14 @@ bool AccessInfoFactory::ConsolidateElementLoad( ...@@ -643,15 +628,14 @@ bool AccessInfoFactory::ConsolidateElementLoad(
return true; return true;
} }
bool AccessInfoFactory::LookupSpecialFieldAccessor( PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor(
Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) const { Handle<Map> map, Handle<Name> name) const {
// Check for String::length field accessor. // Check for String::length field accessor.
if (map->IsStringMap()) { if (map->IsStringMap()) {
if (Name::Equals(isolate(), name, isolate()->factory()->length_string())) { if (Name::Equals(isolate(), name, isolate()->factory()->length_string())) {
*access_info = PropertyAccessInfo::StringLength(MapHandles{map}); return PropertyAccessInfo::StringLength(MapHandles{map});
return true;
} }
return false; return {};
} }
// Check for special JSObject field accessors. // Check for special JSObject field accessors.
FieldIndex field_index; FieldIndex field_index;
...@@ -677,30 +661,28 @@ bool AccessInfoFactory::LookupSpecialFieldAccessor( ...@@ -677,30 +661,28 @@ bool AccessInfoFactory::LookupSpecialFieldAccessor(
} }
} }
// Special fields are always mutable. // Special fields are always mutable.
*access_info = PropertyAccessInfo::DataField( return PropertyAccessInfo::DataField(PropertyConstness::kMutable,
PropertyConstness::kMutable, MapHandles{map}, field_index, MapHandles{map}, field_index,
field_representation, field_type); field_representation, field_type);
return true;
} }
return false; return {};
} }
bool AccessInfoFactory::LookupTransition( PropertyAccessInfo AccessInfoFactory::LookupTransition(
Handle<Map> map, Handle<Name> name, MaybeHandle<JSObject> holder, Handle<Map> map, Handle<Name> name, MaybeHandle<JSObject> holder) const {
PropertyAccessInfo* access_info) const {
// Check if the {map} has a data transition with the given {name}. // Check if the {map} has a data transition with the given {name}.
Map transition = Map transition =
TransitionsAccessor(isolate(), map).SearchTransition(*name, kData, NONE); TransitionsAccessor(isolate(), map).SearchTransition(*name, kData, NONE);
if (transition.is_null()) return false; if (transition.is_null()) return {};
Handle<Map> transition_map(transition, isolate()); Handle<Map> transition_map(transition, isolate());
int const number = transition_map->LastAdded(); int const number = transition_map->LastAdded();
PropertyDetails const details = PropertyDetails const details =
transition_map->instance_descriptors()->GetDetails(number); transition_map->instance_descriptors()->GetDetails(number);
// Don't bother optimizing stores to read-only properties. // Don't bother optimizing stores to read-only properties.
if (details.IsReadOnly()) return false; if (details.IsReadOnly()) return {};
// TODO(bmeurer): Handle transition to data constant? // TODO(bmeurer): Handle transition to data constant?
if (details.location() != kField) return false; if (details.location() != kField) return {};
int const index = details.field_index(); int const index = details.field_index();
Representation details_representation = details.representation(); Representation details_representation = details.representation();
FieldIndex field_index = FieldIndex::ForPropertyIndex(*transition_map, index, FieldIndex field_index = FieldIndex::ForPropertyIndex(*transition_map, index,
...@@ -726,7 +708,7 @@ bool AccessInfoFactory::LookupTransition( ...@@ -726,7 +708,7 @@ bool AccessInfoFactory::LookupTransition(
isolate()); isolate());
if (descriptors_field_type->IsNone()) { if (descriptors_field_type->IsNone()) {
// Store is not safe if the field type was cleared. // Store is not safe if the field type was cleared.
return false; return {};
} }
transition_map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later. transition_map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later.
dependencies()->DependOnFieldRepresentation(transition_map_ref, number); dependencies()->DependOnFieldRepresentation(transition_map_ref, number);
...@@ -740,13 +722,11 @@ bool AccessInfoFactory::LookupTransition( ...@@ -740,13 +722,11 @@ bool AccessInfoFactory::LookupTransition(
} }
dependencies()->DependOnTransition(MapRef(broker(), transition_map)); dependencies()->DependOnTransition(MapRef(broker(), transition_map));
// Transitioning stores are never stores to constant fields. // Transitioning stores are never stores to constant fields.
*access_info = PropertyAccessInfo::DataField( return PropertyAccessInfo::DataField(
PropertyConstness::kMutable, MapHandles{map}, field_index, PropertyConstness::kMutable, MapHandles{map}, field_index,
field_representation, field_type, field_map, holder, transition_map); field_representation, field_type, field_map, holder, transition_map);
return true;
} }
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -95,6 +95,7 @@ class PropertyAccessInfo final { ...@@ -95,6 +95,7 @@ class PropertyAccessInfo final {
bool Merge(PropertyAccessInfo const* that, AccessMode access_mode, bool Merge(PropertyAccessInfo const* that, AccessMode access_mode,
Zone* zone) V8_WARN_UNUSED_RESULT; Zone* zone) V8_WARN_UNUSED_RESULT;
bool IsInvalid() const { return kind() == kInvalid; }
bool IsNotFound() const { return kind() == kNotFound; } bool IsNotFound() const { return kind() == kNotFound; }
bool IsDataConstant() const { return kind() == kDataConstant; } bool IsDataConstant() const { return kind() == kDataConstant; }
bool IsDataField() const { return kind() == kDataField; } bool IsDataField() const { return kind() == kDataField; }
...@@ -155,32 +156,37 @@ class AccessInfoFactory final { ...@@ -155,32 +156,37 @@ class AccessInfoFactory final {
FeedbackNexus nexus, MapHandles const& maps, AccessMode access_mode, FeedbackNexus nexus, MapHandles const& maps, AccessMode access_mode,
ZoneVector<ElementAccessInfo>* access_infos) const; ZoneVector<ElementAccessInfo>* access_infos) const;
bool ComputePropertyAccessInfo(Handle<Map> map, Handle<Name> name, PropertyAccessInfo ComputePropertyAccessInfo(Handle<Map> map,
AccessMode access_mode, Handle<Name> name,
PropertyAccessInfo* access_info) const; AccessMode access_mode) const;
bool ComputePropertyAccessInfo(MapHandles const& maps, Handle<Name> name, PropertyAccessInfo ComputePropertyAccessInfo(MapHandles const& maps,
AccessMode access_mode, Handle<Name> name,
PropertyAccessInfo* access_info) const; AccessMode access_mode) const;
bool ComputePropertyAccessInfos( void ComputePropertyAccessInfos(
MapHandles const& maps, Handle<Name> name, AccessMode access_mode, MapHandles const& maps, Handle<Name> name, AccessMode access_mode,
ZoneVector<PropertyAccessInfo>* access_infos) const; ZoneVector<PropertyAccessInfo>* access_infos) const;
// Merge as many of the given {infos} as possible. Return false iff
// any of them was invalid.
bool FinalizePropertyAccessInfos(
ZoneVector<PropertyAccessInfo> infos, AccessMode access_mode,
ZoneVector<PropertyAccessInfo>* result) const;
private: private:
bool ConsolidateElementLoad(ElementAccessFeedback const& processed, bool ConsolidateElementLoad(ElementAccessFeedback const& processed,
ElementAccessInfo* access_info) const; ElementAccessInfo* access_info) const;
bool LookupSpecialFieldAccessor(Handle<Map> map, Handle<Name> name, PropertyAccessInfo LookupSpecialFieldAccessor(Handle<Map> map,
PropertyAccessInfo* access_info) const; Handle<Name> name) const;
bool LookupTransition(Handle<Map> map, Handle<Name> name, PropertyAccessInfo LookupTransition(Handle<Map> map, Handle<Name> name,
MaybeHandle<JSObject> holder) const;
PropertyAccessInfo ComputeDataFieldAccessInfo(Handle<Map> receiver_map,
Handle<Map> map,
MaybeHandle<JSObject> holder, MaybeHandle<JSObject> holder,
PropertyAccessInfo* access_info) const; int number,
bool ComputeDataFieldAccessInfo(Handle<Map> receiver_map, Handle<Map> map, AccessMode access_mode) const;
MaybeHandle<JSObject> holder, int number, PropertyAccessInfo ComputeAccessorDescriptorAccessInfo(
AccessMode access_mode,
PropertyAccessInfo* access_info) const;
bool ComputeAccessorDescriptorAccessInfo(
Handle<Map> receiver_map, Handle<Name> name, Handle<Map> map, Handle<Map> receiver_map, Handle<Name> name, Handle<Map> map,
MaybeHandle<JSObject> holder, int number, AccessMode access_mode, MaybeHandle<JSObject> holder, int number, AccessMode access_mode) const;
PropertyAccessInfo* access_info) const;
CompilationDependencies* dependencies() const { return dependencies_; } CompilationDependencies* dependencies() const { return dependencies_; }
JSHeapBroker* broker() const { return broker_; } JSHeapBroker* broker() const { return broker_; }
......
...@@ -6887,14 +6887,13 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) { ...@@ -6887,14 +6887,13 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
} }
// Compute property access info for "exec" on {resolution}. // Compute property access info for "exec" on {resolution}.
PropertyAccessInfo ai_exec;
AccessInfoFactory access_info_factory(broker(), dependencies(), AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone()); graph()->zone());
if (!access_info_factory.ComputePropertyAccessInfo( PropertyAccessInfo ai_exec = access_info_factory.ComputePropertyAccessInfo(
MapHandles(regexp_maps.begin(), regexp_maps.end()), MapHandles(regexp_maps.begin(), regexp_maps.end()),
factory()->exec_string(), AccessMode::kLoad, &ai_exec)) { factory()->exec_string(), AccessMode::kLoad);
return NoChange(); if (ai_exec.IsInvalid()) return NoChange();
}
// If "exec" has been modified on {regexp}, we can't do anything. // If "exec" has been modified on {regexp}, we can't do anything.
if (ai_exec.IsDataConstant()) { if (ai_exec.IsDataConstant()) {
if (!ai_exec.constant().is_identical_to( if (!ai_exec.constant().is_identical_to(
......
...@@ -400,16 +400,12 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) { ...@@ -400,16 +400,12 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
Handle<Map> receiver_map(receiver->map(), isolate()); Handle<Map> receiver_map(receiver->map(), isolate());
// Compute property access info for @@hasInstance on the constructor. // Compute property access info for @@hasInstance on the constructor.
PropertyAccessInfo access_info;
AccessInfoFactory access_info_factory(broker(), dependencies(), AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone()); graph()->zone());
if (!access_info_factory.ComputePropertyAccessInfo( PropertyAccessInfo access_info =
receiver_map, factory()->has_instance_symbol(), AccessMode::kLoad, access_info_factory.ComputePropertyAccessInfo(
&access_info)) { receiver_map, factory()->has_instance_symbol(), AccessMode::kLoad);
return NoChange(); if (access_info.IsInvalid()) return NoChange();
}
DCHECK_EQ(access_info.receiver_maps().size(), 1);
DCHECK_EQ(access_info.receiver_maps()[0].address(), receiver_map.address());
PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies()); PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
...@@ -729,19 +725,17 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) { ...@@ -729,19 +725,17 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) {
} }
// Compute property access info for "then" on {resolution}. // Compute property access info for "then" on {resolution}.
PropertyAccessInfo access_info;
AccessInfoFactory access_info_factory(broker(), dependencies(), AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone()); graph()->zone());
if (!access_info_factory.ComputePropertyAccessInfo( PropertyAccessInfo access_info =
access_info_factory.ComputePropertyAccessInfo(
MapHandles(resolution_maps.begin(), resolution_maps.end()), MapHandles(resolution_maps.begin(), resolution_maps.end()),
factory()->then_string(), AccessMode::kLoad, &access_info)) { factory()->then_string(), AccessMode::kLoad);
return NoChange(); if (access_info.IsInvalid()) return NoChange();
}
// We can further optimize the case where {resolution} // We can further optimize the case where {resolution}
// definitely doesn't have a "then" property. // definitely doesn't have a "then" property.
if (!access_info.IsNotFound()) return NoChange(); if (!access_info.IsNotFound()) return NoChange();
PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
dependencies()->DependOnStablePrototypeChains( dependencies()->DependOnStablePrototypeChains(
access_info.receiver_maps(), access_info.receiver_maps(),
...@@ -1094,18 +1088,15 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( ...@@ -1094,18 +1088,15 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
// Compute property access infos for the receiver maps. // Compute property access infos for the receiver maps.
AccessInfoFactory access_info_factory(broker(), dependencies(), AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone()); graph()->zone());
ZoneVector<PropertyAccessInfo> raw_access_infos(zone());
access_info_factory.ComputePropertyAccessInfos(
receiver_maps, name.object(), access_mode, &raw_access_infos);
ZoneVector<PropertyAccessInfo> access_infos(zone()); ZoneVector<PropertyAccessInfo> access_infos(zone());
if (!access_info_factory.ComputePropertyAccessInfos( if (!access_info_factory.FinalizePropertyAccessInfos(
receiver_maps, name.object(), access_mode, &access_infos)) { raw_access_infos, access_mode, &access_infos)) {
return NoChange(); return NoChange();
} }
// Nothing to do if we have no non-deprecated maps.
if (access_infos.empty()) {
return ReduceSoftDeoptimize(
node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
}
// Ensure that {key} matches the specified {name} (if {key} is given). // Ensure that {key} matches the specified {name} (if {key} is given).
if (key != nullptr) { if (key != nullptr) {
effect = BuildCheckEqualsName(name, key, effect, control); effect = BuildCheckEqualsName(name, key, effect, control);
...@@ -2462,14 +2453,12 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral( ...@@ -2462,14 +2453,12 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
handle(Name::cast(nexus.GetFeedbackExtra()->GetHeapObjectAssumeStrong()), handle(Name::cast(nexus.GetFeedbackExtra()->GetHeapObjectAssumeStrong()),
isolate())); isolate()));
PropertyAccessInfo access_info;
AccessInfoFactory access_info_factory(broker(), dependencies(), AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone()); graph()->zone());
if (!access_info_factory.ComputePropertyAccessInfo( PropertyAccessInfo access_info =
receiver_map, cached_name.object(), AccessMode::kStoreInLiteral, access_info_factory.ComputePropertyAccessInfo(
&access_info)) { receiver_map, cached_name.object(), AccessMode::kStoreInLiteral);
return NoChange(); if (access_info.IsInvalid()) return NoChange();
}
Node* receiver = NodeProperties::GetValueInput(node, 0); Node* receiver = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment