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

[turbofan] Introduce NamedAccessFeedback

Brokerize parts of named property access.

Bug: v8:7790
Change-Id: I465bced5f266969040d1e966946a162b0a850c5b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1596734Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61414}
parent e5a5f5ae
...@@ -55,82 +55,97 @@ std::ostream& operator<<(std::ostream& os, AccessMode access_mode) { ...@@ -55,82 +55,97 @@ std::ostream& operator<<(std::ostream& os, AccessMode access_mode) {
UNREACHABLE(); UNREACHABLE();
} }
ElementAccessInfo::ElementAccessInfo() = default; ElementAccessInfo::ElementAccessInfo(ZoneVector<Handle<Map>>&& receiver_maps,
ElementsKind elements_kind, Zone* zone)
ElementAccessInfo::ElementAccessInfo(MapHandles const& receiver_maps, : elements_kind_(elements_kind),
ElementsKind elements_kind) receiver_maps_(receiver_maps),
: elements_kind_(elements_kind), receiver_maps_(receiver_maps) { transition_sources_(zone) {
CHECK(!receiver_maps.empty()); CHECK(!receiver_maps.empty());
} }
// static // static
PropertyAccessInfo PropertyAccessInfo::NotFound(MapHandles const& receiver_maps, PropertyAccessInfo PropertyAccessInfo::Invalid(Zone* zone) {
return PropertyAccessInfo(zone);
}
// static
PropertyAccessInfo PropertyAccessInfo::NotFound(Zone* zone,
Handle<Map> receiver_map,
MaybeHandle<JSObject> holder) { MaybeHandle<JSObject> holder) {
return PropertyAccessInfo(kNotFound, holder, receiver_maps); return PropertyAccessInfo(zone, kNotFound, holder, {{receiver_map}, zone});
} }
// static // static
PropertyAccessInfo PropertyAccessInfo::DataField( PropertyAccessInfo PropertyAccessInfo::DataField(
MapHandles const& receiver_maps, Zone* zone, Handle<Map> receiver_map,
std::vector<CompilationDependencies::Dependency const*>&& dependencies, ZoneVector<CompilationDependencies::Dependency const*>&& dependencies,
FieldIndex field_index, MachineRepresentation field_representation, FieldIndex field_index, MachineRepresentation field_representation,
Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder, Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder,
MaybeHandle<Map> transition_map) { MaybeHandle<Map> transition_map) {
return PropertyAccessInfo(kDataField, holder, transition_map, field_index, return PropertyAccessInfo(kDataField, holder, transition_map, field_index,
field_representation, field_type, field_map, field_representation, field_type, field_map,
receiver_maps, std::move(dependencies)); {{receiver_map}, zone}, std::move(dependencies));
} }
// static // static
PropertyAccessInfo PropertyAccessInfo::DataConstant( PropertyAccessInfo PropertyAccessInfo::DataConstant(
MapHandles const& receiver_maps, Zone* zone, Handle<Map> receiver_map,
std::vector<CompilationDependencies::Dependency const*>&& dependencies, ZoneVector<CompilationDependencies::Dependency const*>&& dependencies,
FieldIndex field_index, MachineRepresentation field_representation, FieldIndex field_index, MachineRepresentation field_representation,
Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder) { Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder) {
return PropertyAccessInfo(kDataConstant, holder, MaybeHandle<Map>(), return PropertyAccessInfo(kDataConstant, holder, MaybeHandle<Map>(),
field_index, field_representation, field_type, field_index, field_representation, field_type,
field_map, receiver_maps, std::move(dependencies)); field_map, {{receiver_map}, zone},
std::move(dependencies));
} }
// static // static
PropertyAccessInfo PropertyAccessInfo::AccessorConstant( PropertyAccessInfo PropertyAccessInfo::AccessorConstant(
MapHandles const& receiver_maps, Handle<Object> constant, Zone* zone, Handle<Map> receiver_map, Handle<Object> constant,
MaybeHandle<JSObject> holder) { MaybeHandle<JSObject> holder) {
return PropertyAccessInfo(kAccessorConstant, holder, constant, receiver_maps); return PropertyAccessInfo(zone, kAccessorConstant, holder, constant,
{{receiver_map}, zone});
} }
// static // static
PropertyAccessInfo PropertyAccessInfo::ModuleExport( PropertyAccessInfo PropertyAccessInfo::ModuleExport(Zone* zone,
MapHandles const& receiver_maps, Handle<Cell> cell) { Handle<Map> receiver_map,
return PropertyAccessInfo(kModuleExport, MaybeHandle<JSObject>(), cell, Handle<Cell> cell) {
receiver_maps); return PropertyAccessInfo(zone, kModuleExport, MaybeHandle<JSObject>(), cell,
{{receiver_map}, zone});
} }
// static // static
PropertyAccessInfo PropertyAccessInfo::StringLength( PropertyAccessInfo PropertyAccessInfo::StringLength(Zone* zone,
MapHandles const& receiver_maps) { Handle<Map> receiver_map) {
return PropertyAccessInfo(kStringLength, MaybeHandle<JSObject>(), return PropertyAccessInfo(zone, kStringLength, MaybeHandle<JSObject>(),
receiver_maps); {{receiver_map}, zone});
} }
PropertyAccessInfo::PropertyAccessInfo() PropertyAccessInfo::PropertyAccessInfo(Zone* zone)
: kind_(kInvalid), : kind_(kInvalid),
receiver_maps_(zone),
unrecorded_dependencies_(zone),
field_representation_(MachineRepresentation::kNone), field_representation_(MachineRepresentation::kNone),
field_type_(Type::None()) {} field_type_(Type::None()) {}
PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder, PropertyAccessInfo::PropertyAccessInfo(Zone* zone, Kind kind,
MapHandles const& receiver_maps) MaybeHandle<JSObject> holder,
ZoneVector<Handle<Map>>&& receiver_maps)
: kind_(kind), : kind_(kind),
receiver_maps_(receiver_maps), receiver_maps_(receiver_maps),
unrecorded_dependencies_(zone),
holder_(holder), holder_(holder),
field_representation_(MachineRepresentation::kNone), field_representation_(MachineRepresentation::kNone),
field_type_(Type::None()) {} field_type_(Type::None()) {}
PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder, PropertyAccessInfo::PropertyAccessInfo(Zone* zone, Kind kind,
MaybeHandle<JSObject> holder,
Handle<Object> constant, Handle<Object> constant,
MapHandles const& receiver_maps) ZoneVector<Handle<Map>>&& receiver_maps)
: kind_(kind), : kind_(kind),
receiver_maps_(receiver_maps), receiver_maps_(receiver_maps),
unrecorded_dependencies_(zone),
constant_(constant), constant_(constant),
holder_(holder), holder_(holder),
field_representation_(MachineRepresentation::kNone), field_representation_(MachineRepresentation::kNone),
...@@ -140,8 +155,8 @@ PropertyAccessInfo::PropertyAccessInfo( ...@@ -140,8 +155,8 @@ PropertyAccessInfo::PropertyAccessInfo(
Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map, Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map,
FieldIndex field_index, MachineRepresentation field_representation, FieldIndex field_index, MachineRepresentation field_representation,
Type field_type, MaybeHandle<Map> field_map, Type field_type, MaybeHandle<Map> field_map,
MapHandles const& receiver_maps, ZoneVector<Handle<Map>>&& receiver_maps,
std::vector<CompilationDependencies::Dependency const*>&& ZoneVector<CompilationDependencies::Dependency const*>&&
unrecorded_dependencies) unrecorded_dependencies)
: kind_(kind), : kind_(kind),
receiver_maps_(receiver_maps), receiver_maps_(receiver_maps),
...@@ -254,15 +269,13 @@ AccessInfoFactory::AccessInfoFactory(JSHeapBroker* broker, ...@@ -254,15 +269,13 @@ AccessInfoFactory::AccessInfoFactory(JSHeapBroker* broker,
type_cache_(TypeCache::Get()), type_cache_(TypeCache::Get()),
zone_(zone) {} zone_(zone) {}
bool AccessInfoFactory::ComputeElementAccessInfo( base::Optional<ElementAccessInfo> AccessInfoFactory::ComputeElementAccessInfo(
Handle<Map> map, AccessMode access_mode, Handle<Map> map, AccessMode access_mode) const {
ElementAccessInfo* access_info) const {
// Check if it is safe to inline element access for the {map}. // Check if it is safe to inline element access for the {map}.
MapRef map_ref(broker(), 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(); ElementsKind const elements_kind = map_ref.elements_kind();
*access_info = ElementAccessInfo(MapHandles{map}, elements_kind); return ElementAccessInfo({{map}, zone()}, elements_kind, zone());
return true;
} }
bool AccessInfoFactory::ComputeElementAccessInfos( bool AccessInfoFactory::ComputeElementAccessInfos(
...@@ -279,29 +292,29 @@ bool AccessInfoFactory::ComputeElementAccessInfos( ...@@ -279,29 +292,29 @@ bool AccessInfoFactory::ComputeElementAccessInfos(
// double), always use the "worst case" code without a transition. This is // double), always use the "worst case" code without a transition. This is
// much faster than transitioning the elements to the worst case, trading a // much faster than transitioning the elements to the worst case, trading a
// TransitionElementsKind for a CheckMaps, avoiding mutation of the array. // TransitionElementsKind for a CheckMaps, avoiding mutation of the array.
ElementAccessInfo access_info; base::Optional<ElementAccessInfo> access_info =
if (ConsolidateElementLoad(*processed, &access_info)) { ConsolidateElementLoad(*processed);
access_infos->push_back(access_info); if (access_info.has_value()) {
access_infos->push_back(*access_info);
return true; return true;
} }
} }
for (Handle<Map> receiver_map : processed->receiver_maps) { for (Handle<Map> receiver_map : processed->receiver_maps) {
// Compute the element access information. // Compute the element access information.
ElementAccessInfo access_info; base::Optional<ElementAccessInfo> access_info =
if (!ComputeElementAccessInfo(receiver_map, access_mode, &access_info)) { ComputeElementAccessInfo(receiver_map, access_mode);
return false; if (!access_info.has_value()) return false;
}
// Collect the possible transitions for the {receiver_map}. // Collect the possible transitions for the {receiver_map}.
for (auto transition : processed->transitions) { for (auto transition : processed->transitions) {
if (transition.second.equals(receiver_map)) { if (transition.second.equals(receiver_map)) {
access_info.AddTransitionSource(transition.first); access_info->AddTransitionSource(transition.first);
} }
} }
// Schedule the access information. // Schedule the access information.
access_infos->push_back(access_info); access_infos->push_back(*access_info);
} }
return true; return true;
} }
...@@ -320,7 +333,7 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo( ...@@ -320,7 +333,7 @@ PropertyAccessInfo 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 {}; return PropertyAccessInfo::Invalid(zone());
} }
FieldIndex field_index = FieldIndex field_index =
FieldIndex::ForPropertyIndex(*map, index, details_representation); FieldIndex::ForPropertyIndex(*map, index, details_representation);
...@@ -329,8 +342,8 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo( ...@@ -329,8 +342,8 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
MachineType::RepCompressedTagged(); MachineType::RepCompressedTagged();
MaybeHandle<Map> field_map; MaybeHandle<Map> field_map;
MapRef map_ref(broker(), map); MapRef map_ref(broker(), map);
std::vector<CompilationDependencies::Dependency const*> ZoneVector<CompilationDependencies::Dependency const*>
unrecorded_dependencies; unrecorded_dependencies(zone());
if (details_representation.IsSmi()) { if (details_representation.IsSmi()) {
field_type = Type::SignedSmall(); field_type = Type::SignedSmall();
field_representation = MachineType::RepCompressedTaggedSigned(); field_representation = MachineType::RepCompressedTaggedSigned();
...@@ -349,7 +362,9 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo( ...@@ -349,7 +362,9 @@ PropertyAccessInfo 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 {}; if (access_mode == AccessMode::kStore) {
return PropertyAccessInfo::Invalid(zone());
}
// 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.
...@@ -370,12 +385,12 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo( ...@@ -370,12 +385,12 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
switch (details.constness()) { switch (details.constness()) {
case PropertyConstness::kMutable: case PropertyConstness::kMutable:
return PropertyAccessInfo::DataField( return PropertyAccessInfo::DataField(
MapHandles{receiver_map}, std::move(unrecorded_dependencies), zone(), receiver_map, std::move(unrecorded_dependencies), field_index,
field_index, field_representation, field_type, field_map, holder); field_representation, field_type, field_map, holder);
case PropertyConstness::kConst: case PropertyConstness::kConst:
return PropertyAccessInfo::DataConstant( return PropertyAccessInfo::DataConstant(
MapHandles{receiver_map}, std::move(unrecorded_dependencies), zone(), receiver_map, std::move(unrecorded_dependencies), field_index,
field_index, field_representation, field_type, field_map, holder); field_representation, field_type, field_map, holder);
} }
UNREACHABLE(); UNREACHABLE();
} }
...@@ -398,17 +413,19 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo( ...@@ -398,17 +413,19 @@ PropertyAccessInfo 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 {}; return PropertyAccessInfo::Invalid(zone());
} }
return PropertyAccessInfo::ModuleExport(MapHandles{receiver_map}, cell); return PropertyAccessInfo::ModuleExport(zone(), receiver_map, cell);
} }
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.
return PropertyAccessInfo::AccessorConstant(MapHandles{receiver_map}, return PropertyAccessInfo::AccessorConstant(zone(), receiver_map,
Handle<Object>(), holder); Handle<Object>(), holder);
} }
Handle<Object> accessors(descriptors->GetStrongValue(number), isolate()); Handle<Object> accessors(descriptors->GetStrongValue(number), isolate());
if (!accessors->IsAccessorPair()) return {}; if (!accessors->IsAccessorPair()) {
return PropertyAccessInfo::Invalid(zone());
}
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(),
...@@ -418,16 +435,20 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo( ...@@ -418,16 +435,20 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo(
if (!optimization.is_simple_api_call() || if (!optimization.is_simple_api_call() ||
optimization.IsCrossContextLazyAccessorPair( optimization.IsCrossContextLazyAccessorPair(
*broker()->native_context().object(), *map)) { *broker()->native_context().object(), *map)) {
return {}; return PropertyAccessInfo::Invalid(zone());
} }
CallOptimization::HolderLookup lookup; CallOptimization::HolderLookup lookup;
holder = optimization.LookupHolderOfExpectedType(receiver_map, &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, 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 {}; if (V8_UNLIKELY(TracingFlags::is_runtime_stats_enabled())) {
return PropertyAccessInfo::Invalid(zone());
}
} }
if (access_mode == AccessMode::kLoad) { if (access_mode == AccessMode::kLoad) {
Handle<Name> cached_property_name; Handle<Name> cached_property_name;
...@@ -438,18 +459,22 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo( ...@@ -438,18 +459,22 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo(
if (!access_info.IsInvalid()) return access_info; if (!access_info.IsInvalid()) return access_info;
} }
} }
return PropertyAccessInfo::AccessorConstant(MapHandles{receiver_map}, return PropertyAccessInfo::AccessorConstant(zone(), receiver_map, accessor,
accessor, holder); holder);
} }
PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
Handle<Map> map, Handle<Name> name, AccessMode access_mode) const { Handle<Map> map, Handle<Name> name, AccessMode access_mode) const {
CHECK(name->IsUniqueName()); 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}. // 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. // 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) {
...@@ -469,7 +494,9 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -469,7 +494,9 @@ PropertyAccessInfo 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()) return {}; if (details.IsReadOnly()) {
return PropertyAccessInfo::Invalid(zone());
}
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
...@@ -485,7 +512,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -485,7 +512,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
} 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 {}; return PropertyAccessInfo::Invalid(zone());
} }
} else { } else {
DCHECK_EQ(kDescriptor, details.location()); DCHECK_EQ(kDescriptor, details.location());
...@@ -502,7 +529,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -502,7 +529,7 @@ PropertyAccessInfo 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 {}; return PropertyAccessInfo::Invalid(zone());
} }
// Don't search on the prototype when storing in literals. // Don't search on the prototype when storing in literals.
...@@ -511,7 +538,9 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -511,7 +538,9 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
} }
// Don't lookup private symbols on the prototype chain. // 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. // Walk up the prototype chain.
if (!map->prototype()->IsJSObject()) { if (!map->prototype()->IsJSObject()) {
...@@ -532,9 +561,9 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -532,9 +561,9 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// The property was not found (access returns undefined or throws // The property was not found (access returns undefined or throws
// depending 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)
return PropertyAccessInfo::NotFound(MapHandles{receiver_map}, holder); return PropertyAccessInfo::NotFound(zone(), receiver_map, holder);
} else { } else {
return {}; return PropertyAccessInfo::Invalid(zone());
} }
} }
Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate()); Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
...@@ -546,13 +575,16 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -546,13 +575,16 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
map = handle(map_prototype->map(), isolate()); map = handle(map_prototype->map(), isolate());
holder = map_prototype; holder = map_prototype;
if (!CanInlinePropertyAccess(map)) return {}; if (!CanInlinePropertyAccess(map)) {
return PropertyAccessInfo::Invalid(zone());
}
// 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
// the prototype maps are stable here. // the prototype maps are stable here.
CHECK(map->is_stable()); CHECK(map->is_stable());
} }
UNREACHABLE();
} }
PropertyAccessInfo AccessInfoFactory::FinalizePropertyAccessInfosAsOne( PropertyAccessInfo AccessInfoFactory::FinalizePropertyAccessInfosAsOne(
...@@ -566,7 +598,7 @@ PropertyAccessInfo AccessInfoFactory::FinalizePropertyAccessInfosAsOne( ...@@ -566,7 +598,7 @@ PropertyAccessInfo AccessInfoFactory::FinalizePropertyAccessInfosAsOne(
return result; return result;
} }
} }
return {}; return PropertyAccessInfo::Invalid(zone());
} }
void AccessInfoFactory::ComputePropertyAccessInfos( void AccessInfoFactory::ComputePropertyAccessInfos(
...@@ -640,28 +672,26 @@ Maybe<ElementsKind> GeneralizeElementsKind(ElementsKind this_kind, ...@@ -640,28 +672,26 @@ Maybe<ElementsKind> GeneralizeElementsKind(ElementsKind this_kind,
} // namespace } // namespace
bool AccessInfoFactory::ConsolidateElementLoad( base::Optional<ElementAccessInfo> AccessInfoFactory::ConsolidateElementLoad(
ElementAccessFeedback const& processed, ElementAccessFeedback const& processed) const {
ElementAccessInfo* access_info) const {
ElementAccessFeedback::MapIterator it = processed.all_maps(broker()); ElementAccessFeedback::MapIterator it = processed.all_maps(broker());
MapRef first_map = it.current(); MapRef first_map = it.current();
InstanceType instance_type = first_map.instance_type(); InstanceType instance_type = first_map.instance_type();
ElementsKind elements_kind = first_map.elements_kind(); ElementsKind elements_kind = first_map.elements_kind();
MapHandles maps; ZoneVector<Handle<Map>> maps(zone());
for (; !it.done(); it.advance()) { for (; !it.done(); it.advance()) {
MapRef map = it.current(); MapRef map = it.current();
if (map.instance_type() != instance_type || !CanInlineElementAccess(map)) { if (map.instance_type() != instance_type || !CanInlineElementAccess(map)) {
return false; return base::nullopt;
} }
if (!GeneralizeElementsKind(elements_kind, map.elements_kind()) if (!GeneralizeElementsKind(elements_kind, map.elements_kind())
.To(&elements_kind)) { .To(&elements_kind)) {
return false; return base::nullopt;
} }
maps.push_back(map.object()); maps.push_back(map.object());
} }
*access_info = ElementAccessInfo(maps, elements_kind); return ElementAccessInfo(std::move(maps), elements_kind, zone());
return true;
} }
PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor( PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor(
...@@ -669,9 +699,9 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor( ...@@ -669,9 +699,9 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor(
// 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())) {
return PropertyAccessInfo::StringLength(MapHandles{map}); return PropertyAccessInfo::StringLength(zone(), map);
} }
return {}; return PropertyAccessInfo::Invalid(zone());
} }
// Check for special JSObject field accessors. // Check for special JSObject field accessors.
FieldIndex field_index; FieldIndex field_index;
...@@ -698,10 +728,10 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor( ...@@ -698,10 +728,10 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor(
} }
} }
// Special fields are always mutable. // Special fields are always mutable.
return PropertyAccessInfo::DataField(MapHandles{map}, {}, field_index, return PropertyAccessInfo::DataField(zone(), map, {{}, zone()}, field_index,
field_representation, field_type); field_representation, field_type);
} }
return {}; return PropertyAccessInfo::Invalid(zone());
} }
PropertyAccessInfo AccessInfoFactory::LookupTransition( PropertyAccessInfo AccessInfoFactory::LookupTransition(
...@@ -709,16 +739,22 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition( ...@@ -709,16 +739,22 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
// 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 {}; if (transition.is_null()) {
return PropertyAccessInfo::Invalid(zone());
}
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 {}; if (details.IsReadOnly()) {
return PropertyAccessInfo::Invalid(zone());
}
// TODO(bmeurer): Handle transition to data constant? // 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(); 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,
...@@ -728,8 +764,8 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition( ...@@ -728,8 +764,8 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
MachineRepresentation field_representation = MachineRepresentation field_representation =
MachineType::RepCompressedTagged(); MachineType::RepCompressedTagged();
MapRef transition_map_ref(broker(), transition_map); MapRef transition_map_ref(broker(), transition_map);
std::vector<CompilationDependencies::Dependency const*> ZoneVector<CompilationDependencies::Dependency const*>
unrecorded_dependencies; unrecorded_dependencies(zone());
if (details_representation.IsSmi()) { if (details_representation.IsSmi()) {
field_type = Type::SignedSmall(); field_type = Type::SignedSmall();
field_representation = MachineType::RepCompressedTaggedSigned(); field_representation = MachineType::RepCompressedTaggedSigned();
...@@ -749,7 +785,7 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition( ...@@ -749,7 +785,7 @@ PropertyAccessInfo 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 {}; return PropertyAccessInfo::Invalid(zone());
} }
transition_map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later. transition_map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later.
unrecorded_dependencies.push_back( unrecorded_dependencies.push_back(
...@@ -770,7 +806,7 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition( ...@@ -770,7 +806,7 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
MapRef(broker(), transition_map))); MapRef(broker(), transition_map)));
// Transitioning stores are never stores to constant fields. // Transitioning stores are never stores to constant fields.
return PropertyAccessInfo::DataField( return PropertyAccessInfo::DataField(
MapHandles{map}, std::move(unrecorded_dependencies), field_index, zone(), map, std::move(unrecorded_dependencies), field_index,
field_representation, field_type, field_map, holder, transition_map); field_representation, field_type, field_map, holder, transition_map);
} }
......
...@@ -29,22 +29,21 @@ class ElementAccessFeedback; ...@@ -29,22 +29,21 @@ class ElementAccessFeedback;
class Type; class Type;
class TypeCache; class TypeCache;
// Whether we are loading a property or storing to a property.
// For a store during literal creation, do not walk up the prototype chain.
enum class AccessMode { kLoad, kStore, kStoreInLiteral, kHas };
std::ostream& operator<<(std::ostream&, AccessMode); std::ostream& operator<<(std::ostream&, AccessMode);
// This class encapsulates all information required to access a certain element. // This class encapsulates all information required to access a certain element.
class ElementAccessInfo final { class ElementAccessInfo final {
public: public:
ElementAccessInfo(); ElementAccessInfo(ZoneVector<Handle<Map>>&& receiver_maps,
ElementAccessInfo(MapHandles const& receiver_maps, ElementsKind elements_kind, Zone* zone);
ElementsKind elements_kind);
ElementsKind elements_kind() const { return elements_kind_; } ElementsKind elements_kind() const { return elements_kind_; }
MapHandles const& receiver_maps() const { return receiver_maps_; } ZoneVector<Handle<Map>> const& receiver_maps() const {
MapHandles const& transition_sources() const { return transition_sources_; } return receiver_maps_;
}
ZoneVector<Handle<Map>> const& transition_sources() const {
return transition_sources_;
}
void AddTransitionSource(Handle<Map> map) { void AddTransitionSource(Handle<Map> map) {
CHECK_EQ(receiver_maps_.size(), 1); CHECK_EQ(receiver_maps_.size(), 1);
...@@ -53,8 +52,8 @@ class ElementAccessInfo final { ...@@ -53,8 +52,8 @@ class ElementAccessInfo final {
private: private:
ElementsKind elements_kind_; ElementsKind elements_kind_;
MapHandles receiver_maps_; ZoneVector<Handle<Map>> receiver_maps_;
MapHandles transition_sources_; ZoneVector<Handle<Map>> transition_sources_;
}; };
// This class encapsulates all information required to access a certain // This class encapsulates all information required to access a certain
...@@ -71,31 +70,31 @@ class PropertyAccessInfo final { ...@@ -71,31 +70,31 @@ class PropertyAccessInfo final {
kStringLength kStringLength
}; };
static PropertyAccessInfo NotFound(MapHandles const& receiver_maps, static PropertyAccessInfo NotFound(Zone* zone, Handle<Map> receiver_map,
MaybeHandle<JSObject> holder); MaybeHandle<JSObject> holder);
static PropertyAccessInfo DataField( static PropertyAccessInfo DataField(
MapHandles const& receiver_maps, Zone* zone, Handle<Map> receiver_map,
std::vector<CompilationDependencies::Dependency const*>&& ZoneVector<CompilationDependencies::Dependency const*>&&
unrecorded_dependencies, unrecorded_dependencies,
FieldIndex field_index, MachineRepresentation field_representation, FieldIndex field_index, MachineRepresentation field_representation,
Type field_type, MaybeHandle<Map> field_map = MaybeHandle<Map>(), Type field_type, MaybeHandle<Map> field_map = MaybeHandle<Map>(),
MaybeHandle<JSObject> holder = MaybeHandle<JSObject>(), MaybeHandle<JSObject> holder = MaybeHandle<JSObject>(),
MaybeHandle<Map> transition_map = MaybeHandle<Map>()); MaybeHandle<Map> transition_map = MaybeHandle<Map>());
static PropertyAccessInfo DataConstant( static PropertyAccessInfo DataConstant(
MapHandles const& receiver_maps, Zone* zone, Handle<Map> receiver_map,
std::vector<CompilationDependencies::Dependency const*>&& ZoneVector<CompilationDependencies::Dependency const*>&&
unrecorded_dependencies, unrecorded_dependencies,
FieldIndex field_index, MachineRepresentation field_representation, FieldIndex field_index, MachineRepresentation field_representation,
Type field_type, MaybeHandle<Map> field_map, Type field_type, MaybeHandle<Map> field_map,
MaybeHandle<JSObject> holder); MaybeHandle<JSObject> holder);
static PropertyAccessInfo AccessorConstant(MapHandles const& receiver_maps, static PropertyAccessInfo AccessorConstant(Zone* zone,
Handle<Map> receiver_map,
Handle<Object> constant, Handle<Object> constant,
MaybeHandle<JSObject> holder); MaybeHandle<JSObject> holder);
static PropertyAccessInfo ModuleExport(MapHandles const& receiver_maps, static PropertyAccessInfo ModuleExport(Zone* zone, Handle<Map> receiver_map,
Handle<Cell> cell); Handle<Cell> cell);
static PropertyAccessInfo StringLength(MapHandles const& receiver_maps); static PropertyAccessInfo StringLength(Zone* zone, Handle<Map> receiver_map);
static PropertyAccessInfo Invalid(Zone* zone);
PropertyAccessInfo();
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;
...@@ -127,24 +126,28 @@ class PropertyAccessInfo final { ...@@ -127,24 +126,28 @@ class PropertyAccessInfo final {
return field_representation_; return field_representation_;
} }
MaybeHandle<Map> field_map() const { return field_map_; } MaybeHandle<Map> field_map() const { return field_map_; }
MapHandles const& receiver_maps() const { return receiver_maps_; } ZoneVector<Handle<Map>> const& receiver_maps() const {
return receiver_maps_;
}
Handle<Cell> export_cell() const; Handle<Cell> export_cell() const;
private: private:
PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder, explicit PropertyAccessInfo(Zone* zone);
MapHandles const& receiver_maps); PropertyAccessInfo(Zone* zone, Kind kind, MaybeHandle<JSObject> holder,
PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder, ZoneVector<Handle<Map>>&& receiver_maps);
Handle<Object> constant, MapHandles const& receiver_maps); PropertyAccessInfo(Zone* zone, Kind kind, MaybeHandle<JSObject> holder,
Handle<Object> constant,
ZoneVector<Handle<Map>>&& receiver_maps);
PropertyAccessInfo( PropertyAccessInfo(
Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map, Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map,
FieldIndex field_index, MachineRepresentation field_representation, FieldIndex field_index, MachineRepresentation field_representation,
Type field_type, MaybeHandle<Map> field_map, Type field_type, MaybeHandle<Map> field_map,
MapHandles const& receiver_maps, ZoneVector<Handle<Map>>&& receiver_maps,
std::vector<CompilationDependencies::Dependency const*>&& dependencies); ZoneVector<CompilationDependencies::Dependency const*>&& dependencies);
Kind kind_; Kind kind_;
MapHandles receiver_maps_; ZoneVector<Handle<Map>> receiver_maps_;
std::vector<CompilationDependencies::Dependency const*> ZoneVector<CompilationDependencies::Dependency const*>
unrecorded_dependencies_; unrecorded_dependencies_;
Handle<Object> constant_; Handle<Object> constant_;
MaybeHandle<Map> transition_map_; MaybeHandle<Map> transition_map_;
...@@ -162,8 +165,8 @@ class AccessInfoFactory final { ...@@ -162,8 +165,8 @@ class AccessInfoFactory final {
AccessInfoFactory(JSHeapBroker* broker, CompilationDependencies* dependencies, AccessInfoFactory(JSHeapBroker* broker, CompilationDependencies* dependencies,
Zone* zone); Zone* zone);
bool ComputeElementAccessInfo(Handle<Map> map, AccessMode access_mode, base::Optional<ElementAccessInfo> ComputeElementAccessInfo(
ElementAccessInfo* access_info) const; Handle<Map> map, AccessMode access_mode) const;
bool ComputeElementAccessInfos( bool ComputeElementAccessInfos(
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;
...@@ -192,8 +195,8 @@ class AccessInfoFactory final { ...@@ -192,8 +195,8 @@ class AccessInfoFactory final {
ZoneVector<PropertyAccessInfo> infos, AccessMode access_mode) const; ZoneVector<PropertyAccessInfo> infos, AccessMode access_mode) const;
private: private:
bool ConsolidateElementLoad(ElementAccessFeedback const& processed, base::Optional<ElementAccessInfo> ConsolidateElementLoad(
ElementAccessInfo* access_info) const; ElementAccessFeedback const& processed) const;
PropertyAccessInfo LookupSpecialFieldAccessor(Handle<Map> map, PropertyAccessInfo LookupSpecialFieldAccessor(Handle<Map> map,
Handle<Name> name) const; Handle<Name> name) const;
PropertyAccessInfo LookupTransition(Handle<Map> map, Handle<Name> name, PropertyAccessInfo LookupTransition(Handle<Map> map, Handle<Name> name,
......
...@@ -599,7 +599,7 @@ void CompilationDependencies::DependOnStablePrototypeChains( ...@@ -599,7 +599,7 @@ void CompilationDependencies::DependOnStablePrototypeChains(
} }
} }
template void CompilationDependencies::DependOnStablePrototypeChains( template void CompilationDependencies::DependOnStablePrototypeChains(
MapHandles const& receiver_maps, WhereToStart start, ZoneVector<Handle<Map>> const& receiver_maps, WhereToStart start,
base::Optional<JSObjectRef> last_prototype); base::Optional<JSObjectRef> last_prototype);
template void CompilationDependencies::DependOnStablePrototypeChains( template void CompilationDependencies::DependOnStablePrototypeChains(
ZoneHandleSet<Map> const& receiver_maps, WhereToStart start, ZoneHandleSet<Map> const& receiver_maps, WhereToStart start,
......
...@@ -6749,17 +6749,15 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) { ...@@ -6749,17 +6749,15 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
MapHandles const& regexp_maps = inference.GetMaps(); MapHandles const& regexp_maps = inference.GetMaps();
// Compute property access info for "exec" on {resolution}. // Compute property access info for "exec" on {resolution}.
PropertyAccessInfo ai_exec;
{
ZoneVector<PropertyAccessInfo> access_infos(graph()->zone()); ZoneVector<PropertyAccessInfo> access_infos(graph()->zone());
AccessInfoFactory access_info_factory(broker(), dependencies(), AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone()); graph()->zone());
access_info_factory.ComputePropertyAccessInfos( access_info_factory.ComputePropertyAccessInfos(
MapHandles(regexp_maps.begin(), regexp_maps.end()), MapHandles(regexp_maps.begin(), regexp_maps.end()),
factory()->exec_string(), AccessMode::kLoad, &access_infos); factory()->exec_string(), AccessMode::kLoad, &access_infos);
ai_exec = access_info_factory.FinalizePropertyAccessInfosAsOne( PropertyAccessInfo ai_exec =
access_infos, AccessMode::kLoad); access_info_factory.FinalizePropertyAccessInfosAsOne(access_infos,
} AccessMode::kLoad);
if (ai_exec.IsInvalid()) return inference.NoChange(); if (ai_exec.IsInvalid()) return inference.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.
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "src/bootstrapper.h" #include "src/bootstrapper.h"
#include "src/boxed-float.h" #include "src/boxed-float.h"
#include "src/code-factory.h" #include "src/code-factory.h"
#include "src/compiler/access-info.h"
#include "src/compiler/graph-reducer.h" #include "src/compiler/graph-reducer.h"
#include "src/compiler/per-isolate-compiler-cache.h" #include "src/compiler/per-isolate-compiler-cache.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
...@@ -3256,6 +3257,9 @@ bool CanInlineElementAccess(MapRef const& map) { ...@@ -3256,6 +3257,9 @@ bool CanInlineElementAccess(MapRef const& map) {
return false; return false;
} }
InsufficientFeedback::InsufficientFeedback()
: ProcessedFeedback(kInsufficient) {}
GlobalAccessFeedback::GlobalAccessFeedback(PropertyCellRef cell) GlobalAccessFeedback::GlobalAccessFeedback(PropertyCellRef cell)
: ProcessedFeedback(kGlobalAccess), : ProcessedFeedback(kGlobalAccess),
cell_or_context_(cell), cell_or_context_(cell),
...@@ -3336,6 +3340,14 @@ ElementAccessFeedback::MapIterator ElementAccessFeedback::all_maps( ...@@ -3336,6 +3340,14 @@ ElementAccessFeedback::MapIterator ElementAccessFeedback::all_maps(
return MapIterator(*this, broker); return MapIterator(*this, broker);
} }
NamedAccessFeedback::NamedAccessFeedback(
NameRef const& name, ZoneVector<PropertyAccessInfo> const& access_infos)
: ProcessedFeedback(kNamedAccess),
name_(name),
access_infos_(access_infos) {
CHECK(!access_infos.empty());
}
FeedbackSource::FeedbackSource(FeedbackNexus const& nexus) FeedbackSource::FeedbackSource(FeedbackNexus const& nexus)
: vector(nexus.vector_handle()), slot(nexus.slot()) {} : vector(nexus.vector_handle()), slot(nexus.slot()) {}
...@@ -3377,6 +3389,8 @@ GlobalAccessFeedback const* JSHeapBroker::GetGlobalAccessFeedback( ...@@ -3377,6 +3389,8 @@ GlobalAccessFeedback const* JSHeapBroker::GetGlobalAccessFeedback(
ElementAccessFeedback const* JSHeapBroker::ProcessFeedbackMapsForElementAccess( ElementAccessFeedback const* JSHeapBroker::ProcessFeedbackMapsForElementAccess(
MapHandles const& maps) { MapHandles const& maps) {
DCHECK(!maps.empty());
// Collect possible transition targets. // Collect possible transition targets.
MapHandles possible_transition_targets; MapHandles possible_transition_targets;
possible_transition_targets.reserve(maps.size()); possible_transition_targets.reserve(maps.size());
...@@ -3388,8 +3402,6 @@ ElementAccessFeedback const* JSHeapBroker::ProcessFeedbackMapsForElementAccess( ...@@ -3388,8 +3402,6 @@ ElementAccessFeedback const* JSHeapBroker::ProcessFeedbackMapsForElementAccess(
} }
} }
if (maps.empty()) return nullptr;
ElementAccessFeedback* result = new (zone()) ElementAccessFeedback(zone()); ElementAccessFeedback* result = new (zone()) ElementAccessFeedback(zone());
// Separate the actual receiver maps and the possible transition sources. // Separate the actual receiver maps and the possible transition sources.
......
...@@ -37,6 +37,10 @@ class VectorSlotPair; ...@@ -37,6 +37,10 @@ class VectorSlotPair;
namespace compiler { namespace compiler {
// Whether we are loading a property or storing to a property.
// For a store during literal creation, do not walk up the prototype chain.
enum class AccessMode { kLoad, kStore, kStoreInLiteral, kHas };
enum class OddballType : uint8_t { enum class OddballType : uint8_t {
kNone, // Not an Oddball. kNone, // Not an Oddball.
kBoolean, // True or False. kBoolean, // True or False.
...@@ -97,6 +101,7 @@ class CompilationDependencies; ...@@ -97,6 +101,7 @@ class CompilationDependencies;
class JSHeapBroker; class JSHeapBroker;
class ObjectData; class ObjectData;
class PerIsolateCompilerCache; class PerIsolateCompilerCache;
class PropertyAccessInfo;
#define FORWARD_DECL(Name) class Name##Ref; #define FORWARD_DECL(Name) class Name##Ref;
HEAP_BROKER_OBJECT_LIST(FORWARD_DECL) HEAP_BROKER_OBJECT_LIST(FORWARD_DECL)
#undef FORWARD_DECL #undef FORWARD_DECL
...@@ -704,7 +709,7 @@ class InternalizedStringRef : public StringRef { ...@@ -704,7 +709,7 @@ class InternalizedStringRef : public StringRef {
class ProcessedFeedback : public ZoneObject { class ProcessedFeedback : public ZoneObject {
public: public:
enum Kind { kElementAccess, kGlobalAccess }; enum Kind { kInsufficient, kGlobalAccess, kNamedAccess, kElementAccess };
Kind kind() const { return kind_; } Kind kind() const { return kind_; }
protected: protected:
...@@ -714,6 +719,11 @@ class ProcessedFeedback : public ZoneObject { ...@@ -714,6 +719,11 @@ class ProcessedFeedback : public ZoneObject {
Kind const kind_; Kind const kind_;
}; };
class InsufficientFeedback final : public ProcessedFeedback {
public:
InsufficientFeedback();
};
class GlobalAccessFeedback : public ProcessedFeedback { class GlobalAccessFeedback : public ProcessedFeedback {
public: public:
explicit GlobalAccessFeedback(PropertyCellRef cell); explicit GlobalAccessFeedback(PropertyCellRef cell);
...@@ -765,6 +775,21 @@ class ElementAccessFeedback : public ProcessedFeedback { ...@@ -765,6 +775,21 @@ class ElementAccessFeedback : public ProcessedFeedback {
MapIterator all_maps(JSHeapBroker* broker) const; MapIterator all_maps(JSHeapBroker* broker) const;
}; };
class NamedAccessFeedback : public ProcessedFeedback {
public:
NamedAccessFeedback(NameRef const& name,
ZoneVector<PropertyAccessInfo> const& access_infos);
NameRef const& name() const { return name_; }
ZoneVector<PropertyAccessInfo> const& access_infos() const {
return access_infos_;
}
private:
NameRef const name_;
ZoneVector<PropertyAccessInfo> const access_infos_;
};
struct FeedbackSource { struct FeedbackSource {
FeedbackSource(Handle<FeedbackVector> vector_, FeedbackSlot slot_) FeedbackSource(Handle<FeedbackVector> vector_, FeedbackSlot slot_)
: vector(vector_), slot(slot_) {} : vector(vector_), slot(slot_) {}
......
...@@ -41,7 +41,7 @@ namespace compiler { ...@@ -41,7 +41,7 @@ namespace compiler {
namespace { namespace {
bool HasNumberMaps(JSHeapBroker* broker, MapHandles const& maps) { bool HasNumberMaps(JSHeapBroker* broker, ZoneVector<Handle<Map>> const& maps) {
for (auto map : maps) { for (auto map : maps) {
MapRef map_ref(broker, map); MapRef map_ref(broker, map);
if (map_ref.IsHeapNumberMap()) return true; if (map_ref.IsHeapNumberMap()) return true;
...@@ -49,7 +49,8 @@ bool HasNumberMaps(JSHeapBroker* broker, MapHandles const& maps) { ...@@ -49,7 +49,8 @@ bool HasNumberMaps(JSHeapBroker* broker, MapHandles const& maps) {
return false; return false;
} }
bool HasOnlyJSArrayMaps(JSHeapBroker* broker, MapHandles const& maps) { bool HasOnlyJSArrayMaps(JSHeapBroker* broker,
ZoneVector<Handle<Map>> const& maps) {
for (auto map : maps) { for (auto map : maps) {
MapRef map_ref(broker, map); MapRef map_ref(broker, map);
if (!map_ref.IsJSArrayMap()) return false; if (!map_ref.IsJSArrayMap()) return false;
...@@ -57,6 +58,17 @@ bool HasOnlyJSArrayMaps(JSHeapBroker* broker, MapHandles const& maps) { ...@@ -57,6 +58,17 @@ bool HasOnlyJSArrayMaps(JSHeapBroker* broker, MapHandles const& maps) {
return true; return true;
} }
void TryUpdateThenDropDeprecated(Isolate* isolate, MapHandles* maps) {
for (auto it = maps->begin(); it != maps->end();) {
if (Map::TryUpdate(isolate, *it).ToHandle(&*it)) {
DCHECK(!(*it)->is_deprecated());
++it;
} else {
it = maps->erase(it);
}
}
}
} // namespace } // namespace
JSNativeContextSpecialization::JSNativeContextSpecialization( JSNativeContextSpecialization::JSNativeContextSpecialization(
...@@ -703,17 +715,15 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) { ...@@ -703,17 +715,15 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) {
MapHandles const& resolution_maps = inference.GetMaps(); MapHandles const& resolution_maps = inference.GetMaps();
// Compute property access info for "then" on {resolution}. // Compute property access info for "then" on {resolution}.
PropertyAccessInfo access_info;
{
ZoneVector<PropertyAccessInfo> access_infos(graph()->zone()); ZoneVector<PropertyAccessInfo> access_infos(graph()->zone());
AccessInfoFactory access_info_factory(broker(), dependencies(), AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone()); graph()->zone());
access_info_factory.ComputePropertyAccessInfos( access_info_factory.ComputePropertyAccessInfos(
resolution_maps, factory()->then_string(), AccessMode::kLoad, resolution_maps, factory()->then_string(), AccessMode::kLoad,
&access_infos); &access_infos);
access_info = access_info_factory.FinalizePropertyAccessInfosAsOne( PropertyAccessInfo access_info =
access_infos, AccessMode::kLoad); access_info_factory.FinalizePropertyAccessInfosAsOne(access_infos,
} AccessMode::kLoad);
if (access_info.IsInvalid()) return inference.NoChange(); if (access_info.IsInvalid()) return inference.NoChange();
// Only optimize when {resolution} definitely doesn't have a "then" property. // Only optimize when {resolution} definitely doesn't have a "then" property.
...@@ -1049,8 +1059,8 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) { ...@@ -1049,8 +1059,8 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
} }
Reduction JSNativeContextSpecialization::ReduceNamedAccess( Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* node, Node* value, MapHandles const& receiver_maps, Node* node, Node* value, NamedAccessFeedback const& feedback,
NameRef const& name, AccessMode access_mode, Node* key) { AccessMode access_mode, Node* key) {
DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
node->opcode() == IrOpcode::kJSStoreNamed || node->opcode() == IrOpcode::kJSStoreNamed ||
node->opcode() == IrOpcode::kJSLoadProperty || node->opcode() == IrOpcode::kJSLoadProperty ||
...@@ -1063,31 +1073,27 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( ...@@ -1063,31 +1073,27 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node); Node* control = NodeProperties::GetControlInput(node);
ZoneVector<PropertyAccessInfo> access_infos(zone());
AccessInfoFactory access_info_factory(broker(), dependencies(), zone());
if (!access_info_factory.FinalizePropertyAccessInfos(
feedback.access_infos(), access_mode, &access_infos)) {
return NoChange();
}
// Check if we have an access o.x or o.x=v where o is the current // Check if we have an access o.x or o.x=v where o is the current
// native contexts' global proxy, and turn that into a direct access // native contexts' global proxy, and turn that into a direct access
// to the current native contexts' global object instead. // to the current native context's global object instead.
if (receiver_maps.size() == 1) { if (access_infos.size() == 1 && access_infos[0].receiver_maps().size() == 1) {
MapRef receiver_map(broker(), receiver_maps.front()); MapRef receiver_map(broker(), access_infos[0].receiver_maps()[0]);
if (receiver_map.IsMapOfCurrentGlobalProxy()) { if (receiver_map.IsMapOfCurrentGlobalProxy()) {
return ReduceGlobalAccess(node, receiver, value, name, access_mode, key); return ReduceGlobalAccess(node, receiver, value, feedback.name(),
} access_mode, key);
} }
// Compute property access infos for the receiver maps.
AccessInfoFactory access_info_factory(broker(), dependencies(),
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());
if (!access_info_factory.FinalizePropertyAccessInfos(
raw_access_infos, access_mode, &access_infos)) {
return NoChange();
} }
// 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(feedback.name(), key, effect, control);
} }
// Collect call nodes to rewire exception edges. // Collect call nodes to rewire exception edges.
...@@ -1141,7 +1147,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( ...@@ -1141,7 +1147,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
// Generate the actual property access. // Generate the actual property access.
ValueEffectControl continuation = BuildPropertyAccess( ValueEffectControl continuation = BuildPropertyAccess(
receiver, value, context, frame_state, effect, control, name, receiver, value, context, frame_state, effect, control, feedback.name(),
if_exceptions, access_info, access_mode); if_exceptions, access_info, access_mode);
value = continuation.value(); value = continuation.value();
effect = continuation.effect(); effect = continuation.effect();
...@@ -1186,7 +1192,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( ...@@ -1186,7 +1192,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* this_control = fallthrough_control; Node* this_control = fallthrough_control;
// Perform map check on {receiver}. // Perform map check on {receiver}.
MapHandles const& receiver_maps = access_info.receiver_maps(); ZoneVector<Handle<Map>> const& receiver_maps =
access_info.receiver_maps();
{ {
// Whether to insert a dedicated MapGuard node into the // Whether to insert a dedicated MapGuard node into the
// effect to be able to learn from the control flow. // effect to be able to learn from the control flow.
...@@ -1257,9 +1264,10 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( ...@@ -1257,9 +1264,10 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
} }
// Generate the actual property access. // Generate the actual property access.
ValueEffectControl continuation = BuildPropertyAccess( ValueEffectControl continuation =
this_receiver, this_value, context, frame_state, this_effect, BuildPropertyAccess(this_receiver, this_value, context, frame_state,
this_control, name, if_exceptions, access_info, access_mode); this_effect, this_control, feedback.name(),
if_exceptions, access_info, access_mode);
values.push_back(continuation.value()); values.push_back(continuation.value());
effects.push_back(continuation.effect()); effects.push_back(continuation.effect());
controls.push_back(continuation.control()); controls.push_back(continuation.control());
...@@ -1326,18 +1334,38 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus( ...@@ -1326,18 +1334,38 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
return ReduceGlobalAccess(node, nullptr, value, name, access_mode); return ReduceGlobalAccess(node, nullptr, value, name, access_mode);
} }
// Extract receiver maps from the IC using the {nexus}. ProcessedFeedback const* processed = nullptr;
if (FLAG_concurrent_inlining) {
processed = broker()->GetFeedback(FeedbackSource(nexus));
// TODO(neis): Infer maps from the graph and consolidate with feedback/hints
// and filter impossible candidates based on inferred root map.
} else {
if (nexus.ic_state() == UNINITIALIZED) {
processed = new (zone()) InsufficientFeedback();
} else {
MapHandles receiver_maps; MapHandles receiver_maps;
if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) { if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
return NoChange(); processed = new (zone()) InsufficientFeedback();
} else if (receiver_maps.empty()) { } else if (!receiver_maps.empty()) {
ZoneVector<PropertyAccessInfo> access_infos(zone());
AccessInfoFactory access_info_factory(broker(), dependencies(), zone());
access_info_factory.ComputePropertyAccessInfos(
receiver_maps, name.object(), access_mode, &access_infos);
processed = new (zone()) NamedAccessFeedback(name, access_infos);
}
}
}
if (processed == nullptr) return NoChange();
if (processed->kind() == ProcessedFeedback::kInsufficient) {
return ReduceSoftDeoptimize( return ReduceSoftDeoptimize(
node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess); node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
} }
DCHECK(!nexus.IsUninitialized());
// Try to lower the named access based on the {receiver_maps}. CHECK_EQ(processed->kind(), ProcessedFeedback::kNamedAccess);
return ReduceNamedAccess(node, value, receiver_maps, name, access_mode); return ReduceNamedAccess(node, value,
*static_cast<NamedAccessFeedback const*>(processed),
access_mode);
} }
Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) { Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
...@@ -1475,7 +1503,9 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( ...@@ -1475,7 +1503,9 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
Node* frame_state = Node* frame_state =
NodeProperties::FindFrameStateBefore(node, jsgraph()->Dead()); NodeProperties::FindFrameStateBefore(node, jsgraph()->Dead());
if (HasOnlyStringMaps(broker(), receiver_maps)) { ZoneVector<Handle<Map>> maps(receiver_maps.begin(), receiver_maps.end(),
zone());
if (HasOnlyStringMaps(broker(), maps)) {
return ReduceElementAccessOnString(node, index, value, access_mode, return ReduceElementAccessOnString(node, index, value, access_mode,
load_mode); load_mode);
} }
...@@ -1624,7 +1654,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( ...@@ -1624,7 +1654,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
} }
// Perform map check(s) on {receiver}. // Perform map check(s) on {receiver}.
MapHandles const& receiver_maps = access_info.receiver_maps(); ZoneVector<Handle<Map>> const& receiver_maps =
access_info.receiver_maps();
if (j == access_infos.size() - 1) { if (j == access_infos.size() - 1) {
// Last map check on the fallthrough control path, do a // Last map check on the fallthrough control path, do a
// conditional eager deoptimization exit here. // conditional eager deoptimization exit here.
...@@ -1790,15 +1821,13 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess( ...@@ -1790,15 +1821,13 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
if (reduction.Changed()) return reduction; if (reduction.Changed()) return reduction;
} }
// Extract receiver maps from the {nexus}.
MapHandles receiver_maps; MapHandles receiver_maps;
if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) { if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
return NoChange();
} else if (receiver_maps.empty()) {
return ReduceSoftDeoptimize( return ReduceSoftDeoptimize(
node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess); node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
} else if (receiver_maps.empty()) {
return NoChange();
} }
DCHECK(!nexus.IsUninitialized());
// Check if we have feedback for a named access. // Check if we have feedback for a named access.
base::Optional<NameRef> name = GetNameFeedback(broker(), nexus); base::Optional<NameRef> name = GetNameFeedback(broker(), nexus);
...@@ -1819,6 +1848,268 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess( ...@@ -1819,6 +1848,268 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
return NoChange(); return NoChange();
} }
Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* node, Node* value, MapHandles const& receiver_maps,
NameRef const& name, AccessMode access_mode, Node* key) {
DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
node->opcode() == IrOpcode::kJSStoreNamed ||
node->opcode() == IrOpcode::kJSLoadProperty ||
node->opcode() == IrOpcode::kJSStoreProperty ||
node->opcode() == IrOpcode::kJSStoreNamedOwn ||
node->opcode() == IrOpcode::kJSHasProperty);
Node* receiver = NodeProperties::GetValueInput(node, 0);
Node* context = NodeProperties::GetContextInput(node);
Node* frame_state = NodeProperties::GetFrameStateInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Check if we have an access o.x or o.x=v where o is the current
// native contexts' global proxy, and turn that into a direct access
// to the current native contexts' global object instead.
if (receiver_maps.size() == 1) {
MapRef receiver_map(broker(), receiver_maps.front());
if (receiver_map.IsMapOfCurrentGlobalProxy()) {
return ReduceGlobalAccess(node, receiver, value, name, access_mode, key);
}
}
// Compute property access infos for the receiver maps.
AccessInfoFactory access_info_factory(broker(), dependencies(),
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());
if (!access_info_factory.FinalizePropertyAccessInfos(
raw_access_infos, access_mode, &access_infos)) {
return NoChange();
}
// Ensure that {key} matches the specified {name} (if {key} is given).
if (key != nullptr) {
effect = BuildCheckEqualsName(name, key, effect, control);
}
// Collect call nodes to rewire exception edges.
ZoneVector<Node*> if_exception_nodes(zone());
ZoneVector<Node*>* if_exceptions = nullptr;
Node* if_exception = nullptr;
if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
if_exceptions = &if_exception_nodes;
}
PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
// Check for the monomorphic cases.
if (access_infos.size() == 1) {
PropertyAccessInfo access_info = access_infos.front();
// Try to build string check or number check if possible.
// Otherwise build a map check.
if (!access_builder.TryBuildStringCheck(broker(),
access_info.receiver_maps(),
&receiver, &effect, control) &&
!access_builder.TryBuildNumberCheck(broker(),
access_info.receiver_maps(),
&receiver, &effect, control)) {
if (HasNumberMaps(broker(), access_info.receiver_maps())) {
// We need to also let Smi {receiver}s through in this case, so
// we construct a diamond, guarded by the Sminess of the {receiver}
// and if {receiver} is not a Smi just emit a sequence of map checks.
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
Node* branch = graph()->NewNode(common()->Branch(), check, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue = effect;
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* efalse = effect;
{
access_builder.BuildCheckMaps(receiver, &efalse, if_false,
access_info.receiver_maps());
}
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
effect =
graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
} else {
receiver =
access_builder.BuildCheckHeapObject(receiver, &effect, control);
access_builder.BuildCheckMaps(receiver, &effect, control,
access_info.receiver_maps());
}
}
// Generate the actual property access.
ValueEffectControl continuation = BuildPropertyAccess(
receiver, value, context, frame_state, effect, control, name,
if_exceptions, access_info, access_mode);
value = continuation.value();
effect = continuation.effect();
control = continuation.control();
} else {
// The final states for every polymorphic branch. We join them with
// Merge+Phi+EffectPhi at the bottom.
ZoneVector<Node*> values(zone());
ZoneVector<Node*> effects(zone());
ZoneVector<Node*> controls(zone());
// Check if {receiver} may be a number.
bool receiverissmi_possible = false;
for (PropertyAccessInfo const& access_info : access_infos) {
if (HasNumberMaps(broker(), access_info.receiver_maps())) {
receiverissmi_possible = true;
break;
}
}
// Ensure that {receiver} is a heap object.
Node* receiverissmi_control = nullptr;
Node* receiverissmi_effect = effect;
if (receiverissmi_possible) {
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
Node* branch = graph()->NewNode(common()->Branch(), check, control);
control = graph()->NewNode(common()->IfFalse(), branch);
receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch);
receiverissmi_effect = effect;
} else {
receiver =
access_builder.BuildCheckHeapObject(receiver, &effect, control);
}
// Generate code for the various different property access patterns.
Node* fallthrough_control = control;
for (size_t j = 0; j < access_infos.size(); ++j) {
PropertyAccessInfo const& access_info = access_infos[j];
Node* this_value = value;
Node* this_receiver = receiver;
Node* this_effect = effect;
Node* this_control = fallthrough_control;
// Perform map check on {receiver}.
ZoneVector<Handle<Map>> const& receiver_maps =
access_info.receiver_maps();
{
// Whether to insert a dedicated MapGuard node into the
// effect to be able to learn from the control flow.
bool insert_map_guard = true;
// Check maps for the {receiver}s.
if (j == access_infos.size() - 1) {
// Last map check on the fallthrough control path, do a
// conditional eager deoptimization exit here.
access_builder.BuildCheckMaps(receiver, &this_effect, this_control,
receiver_maps);
fallthrough_control = nullptr;
// Don't insert a MapGuard in this case, as the CheckMaps
// node already gives you all the information you need
// along the effect chain.
insert_map_guard = false;
} else {
// Explicitly branch on the {receiver_maps}.
ZoneHandleSet<Map> maps;
for (Handle<Map> map : receiver_maps) {
maps.insert(map, graph()->zone());
}
Node* check = this_effect =
graph()->NewNode(simplified()->CompareMaps(maps), receiver,
this_effect, this_control);
Node* branch =
graph()->NewNode(common()->Branch(), check, this_control);
fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
this_control = graph()->NewNode(common()->IfTrue(), branch);
}
// The Number case requires special treatment to also deal with Smis.
if (HasNumberMaps(broker(), receiver_maps)) {
// Join this check with the "receiver is smi" check above.
DCHECK_NOT_NULL(receiverissmi_effect);
DCHECK_NOT_NULL(receiverissmi_control);
this_control = graph()->NewNode(common()->Merge(2), this_control,
receiverissmi_control);
this_effect = graph()->NewNode(common()->EffectPhi(2), this_effect,
receiverissmi_effect, this_control);
receiverissmi_effect = receiverissmi_control = nullptr;
// The {receiver} can also be a Smi in this case, so
// a MapGuard doesn't make sense for this at all.
insert_map_guard = false;
}
// Introduce a MapGuard to learn from this on the effect chain.
if (insert_map_guard) {
ZoneHandleSet<Map> maps;
for (auto receiver_map : receiver_maps) {
maps.insert(receiver_map, graph()->zone());
}
this_effect = graph()->NewNode(simplified()->MapGuard(maps), receiver,
this_effect, this_control);
}
// If all {receiver_maps} are Strings we also need to rename the
// {receiver} here to make sure that TurboFan knows that along this
// path the {this_receiver} is a String. This is because we want
// strict checking of types, for example for StringLength operators.
if (HasOnlyStringMaps(broker(), receiver_maps)) {
this_receiver = this_effect =
graph()->NewNode(common()->TypeGuard(Type::String()), receiver,
this_effect, this_control);
}
}
// Generate the actual property access.
ValueEffectControl continuation = BuildPropertyAccess(
this_receiver, this_value, context, frame_state, this_effect,
this_control, name, if_exceptions, access_info, access_mode);
values.push_back(continuation.value());
effects.push_back(continuation.effect());
controls.push_back(continuation.control());
}
DCHECK_NULL(fallthrough_control);
// Generate the final merge point for all (polymorphic) branches.
int const control_count = static_cast<int>(controls.size());
if (control_count == 0) {
value = effect = control = jsgraph()->Dead();
} else if (control_count == 1) {
value = values.front();
effect = effects.front();
control = controls.front();
} else {
control = graph()->NewNode(common()->Merge(control_count), control_count,
&controls.front());
values.push_back(control);
value = graph()->NewNode(
common()->Phi(MachineRepresentation::kTagged, control_count),
control_count + 1, &values.front());
effects.push_back(control);
effect = graph()->NewNode(common()->EffectPhi(control_count),
control_count + 1, &effects.front());
}
}
// Properly rewire IfException edges if {node} is inside a try-block.
if (!if_exception_nodes.empty()) {
DCHECK_NOT_NULL(if_exception);
DCHECK_EQ(if_exceptions, &if_exception_nodes);
int const if_exception_count = static_cast<int>(if_exceptions->size());
Node* merge = graph()->NewNode(common()->Merge(if_exception_count),
if_exception_count, &if_exceptions->front());
if_exceptions->push_back(merge);
Node* ephi =
graph()->NewNode(common()->EffectPhi(if_exception_count),
if_exception_count + 1, &if_exceptions->front());
Node* phi = graph()->NewNode(
common()->Phi(MachineRepresentation::kTagged, if_exception_count),
if_exception_count + 1, &if_exceptions->front());
ReplaceWithValue(if_exception, phi, ephi, merge);
}
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize( Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize(
Node* node, DeoptimizeReason reason) { Node* node, DeoptimizeReason reason) {
if (!(flags() & kBailoutOnUninitialized)) return NoChange(); if (!(flags() & kBailoutOnUninitialized)) return NoChange();
...@@ -2490,18 +2781,15 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreInArrayLiteral( ...@@ -2490,18 +2781,15 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreInArrayLiteral(
// Extract the keyed access store mode from the keyed store IC. // Extract the keyed access store mode from the keyed store IC.
KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode(); KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode();
// Extract receiver maps from the {nexus}.
MapHandles receiver_maps; MapHandles receiver_maps;
if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) { if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
return NoChange();
} else if (receiver_maps.empty()) {
return ReduceSoftDeoptimize( return ReduceSoftDeoptimize(
node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess); node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
} else if (receiver_maps.empty()) {
return NoChange();
} }
DCHECK(!nexus.IsUninitialized());
DCHECK_EQ(ELEMENT, nexus.GetKeyType()); DCHECK_EQ(ELEMENT, nexus.GetKeyType());
DCHECK_NE(MEGAMORPHIC, nexus.ic_state());
if (nexus.ic_state() == MEGAMORPHIC) return NoChange();
// Try to lower the element access based on the {receiver_maps}. // Try to lower the element access based on the {receiver_maps}.
return ReduceElementAccess(node, index, value, nexus, receiver_maps, return ReduceElementAccess(node, index, value, nexus, receiver_maps,
...@@ -2548,7 +2836,7 @@ JSNativeContextSpecialization::BuildElementAccess( ...@@ -2548,7 +2836,7 @@ JSNativeContextSpecialization::BuildElementAccess(
// TODO(bmeurer): We currently specialize based on elements kind. We should // TODO(bmeurer): We currently specialize based on elements kind. We should
// also be able to properly support strings and other JSObjects here. // also be able to properly support strings and other JSObjects here.
ElementsKind elements_kind = access_info.elements_kind(); ElementsKind elements_kind = access_info.elements_kind();
MapHandles const& receiver_maps = access_info.receiver_maps(); ZoneVector<Handle<Map>> const& receiver_maps = access_info.receiver_maps();
if (IsFixedTypedArrayElementsKind(elements_kind)) { if (IsFixedTypedArrayElementsKind(elements_kind)) {
Node* buffer; Node* buffer;
...@@ -3226,7 +3514,7 @@ Node* JSNativeContextSpecialization::BuildCheckEqualsName(NameRef const& name, ...@@ -3226,7 +3514,7 @@ Node* JSNativeContextSpecialization::BuildCheckEqualsName(NameRef const& name,
} }
bool JSNativeContextSpecialization::CanTreatHoleAsUndefined( bool JSNativeContextSpecialization::CanTreatHoleAsUndefined(
MapHandles const& receiver_maps) { ZoneVector<Handle<Map>> const& receiver_maps) {
// Check if all {receiver_maps} have one of the initial Array.prototype // Check if all {receiver_maps} have one of the initial Array.prototype
// or Object.prototype objects as their prototype (in any of the current // or Object.prototype objects as their prototype (in any of the current
// native contexts, as the global Array protector works isolate-wide). // native contexts, as the global Array protector works isolate-wide).
...@@ -3244,24 +3532,12 @@ bool JSNativeContextSpecialization::CanTreatHoleAsUndefined( ...@@ -3244,24 +3532,12 @@ bool JSNativeContextSpecialization::CanTreatHoleAsUndefined(
return dependencies()->DependOnNoElementsProtector(); return dependencies()->DependOnNoElementsProtector();
} }
namespace { // Returns false iff we have insufficient feedback (uninitialized or obsolete).
void TryUpdateThenDropDeprecated(Isolate* isolate, MapHandles* maps) {
for (auto it = maps->begin(); it != maps->end();) {
if (Map::TryUpdate(isolate, *it).ToHandle(&*it)) {
DCHECK(!(*it)->is_deprecated());
++it;
} else {
it = maps->erase(it);
}
}
}
} // namespace
bool JSNativeContextSpecialization::ExtractReceiverMaps( bool JSNativeContextSpecialization::ExtractReceiverMaps(
Node* receiver, Node* effect, FeedbackNexus const& nexus, Node* receiver, Node* effect, FeedbackNexus const& nexus,
MapHandles* receiver_maps) { MapHandles* receiver_maps) {
DCHECK(receiver_maps->empty()); DCHECK(receiver_maps->empty());
if (nexus.IsUninitialized()) return true; if (nexus.IsUninitialized()) return false;
// See if we can infer a concrete type for the {receiver}. Solely relying on // See if we can infer a concrete type for the {receiver}. Solely relying on
// the inference is not safe for keyed stores, because we would potentially // the inference is not safe for keyed stores, because we would potentially
...@@ -3276,8 +3552,8 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps( ...@@ -3276,8 +3552,8 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps(
} }
} }
// Try to extract some maps from the {nexus}. if (nexus.ExtractMaps(receiver_maps) == 0) return true;
if (nexus.ExtractMaps(receiver_maps) != 0) {
// Try to filter impossible candidates based on inferred root map. // Try to filter impossible candidates based on inferred root map.
Handle<Map> root_map; Handle<Map> root_map;
if (InferReceiverRootMap(receiver).ToHandle(&root_map)) { if (InferReceiverRootMap(receiver).ToHandle(&root_map)) {
...@@ -3292,10 +3568,7 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps( ...@@ -3292,10 +3568,7 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps(
receiver_maps->end()); receiver_maps->end());
} }
TryUpdateThenDropDeprecated(isolate(), receiver_maps); TryUpdateThenDropDeprecated(isolate(), receiver_maps);
return true; return !receiver_maps->empty();
}
return false;
} }
bool JSNativeContextSpecialization::InferReceiverMaps( bool JSNativeContextSpecialization::InferReceiverMaps(
......
...@@ -107,10 +107,15 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final ...@@ -107,10 +107,15 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
FeedbackNexus const& nexus, FeedbackNexus const& nexus,
NameRef const& name, NameRef const& name,
AccessMode access_mode); AccessMode access_mode);
Reduction ReduceNamedAccess(Node* node, Node* value,
NamedAccessFeedback const& processed,
AccessMode access_mode, Node* key = nullptr);
// TODO(neis): This second version of ReduceNamedAccess is here only
// temporarily while keyed access is not fully brokerized yet.
Reduction ReduceNamedAccess(Node* node, Node* value, Reduction ReduceNamedAccess(Node* node, Node* value,
MapHandles const& receiver_maps, MapHandles const& receiver_maps,
NameRef const& name, AccessMode access_mode, NameRef const& name, AccessMode access_mode,
Node* key = nullptr); Node* key);
Reduction ReduceGlobalAccess(Node* node, Node* receiver, Node* value, Reduction ReduceGlobalAccess(Node* node, Node* receiver, Node* value,
NameRef const& name, AccessMode access_mode, NameRef const& name, AccessMode access_mode,
Node* key = nullptr); Node* key = nullptr);
...@@ -214,7 +219,7 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final ...@@ -214,7 +219,7 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
// Checks if we can turn the hole into undefined when loading an element // Checks if we can turn the hole into undefined when loading an element
// from an object with one of the {receiver_maps}; sets up appropriate // from an object with one of the {receiver_maps}; sets up appropriate
// code dependencies and might use the array protector cell. // code dependencies and might use the array protector cell.
bool CanTreatHoleAsUndefined(MapHandles const& receiver_maps); bool CanTreatHoleAsUndefined(ZoneVector<Handle<Map>> const& receiver_maps);
// Extract receiver maps from {nexus} and filter based on {receiver} if // Extract receiver maps from {nexus} and filter based on {receiver} if
// possible. // possible.
......
...@@ -1248,8 +1248,8 @@ struct SerializationPhase { ...@@ -1248,8 +1248,8 @@ struct SerializationPhase {
void Run(PipelineData* data, Zone* temp_zone) { void Run(PipelineData* data, Zone* temp_zone) {
SerializerForBackgroundCompilation serializer( SerializerForBackgroundCompilation serializer(
data->broker(), temp_zone, data->info()->closure(), data->broker(), data->dependencies(), temp_zone,
data->info()->is_source_positions_enabled()); data->info()->closure(), data->info()->is_source_positions_enabled());
serializer.Run(); serializer.Run();
} }
}; };
......
...@@ -32,7 +32,8 @@ SimplifiedOperatorBuilder* PropertyAccessBuilder::simplified() const { ...@@ -32,7 +32,8 @@ SimplifiedOperatorBuilder* PropertyAccessBuilder::simplified() const {
return jsgraph()->simplified(); return jsgraph()->simplified();
} }
bool HasOnlyStringMaps(JSHeapBroker* broker, MapHandles const& maps) { bool HasOnlyStringMaps(JSHeapBroker* broker,
ZoneVector<Handle<Map>> const& maps) {
for (auto map : maps) { for (auto map : maps) {
MapRef map_ref(broker, map); MapRef map_ref(broker, map);
if (!map_ref.IsStringMap()) return false; if (!map_ref.IsStringMap()) return false;
...@@ -42,7 +43,8 @@ bool HasOnlyStringMaps(JSHeapBroker* broker, MapHandles const& maps) { ...@@ -42,7 +43,8 @@ bool HasOnlyStringMaps(JSHeapBroker* broker, MapHandles const& maps) {
namespace { namespace {
bool HasOnlyNumberMaps(JSHeapBroker* broker, MapHandles const& maps) { bool HasOnlyNumberMaps(JSHeapBroker* broker,
ZoneVector<Handle<Map>> const& maps) {
for (auto map : maps) { for (auto map : maps) {
MapRef map_ref(broker, map); MapRef map_ref(broker, map);
if (map_ref.instance_type() != HEAP_NUMBER_TYPE) return false; if (map_ref.instance_type() != HEAP_NUMBER_TYPE) return false;
...@@ -52,10 +54,9 @@ bool HasOnlyNumberMaps(JSHeapBroker* broker, MapHandles const& maps) { ...@@ -52,10 +54,9 @@ bool HasOnlyNumberMaps(JSHeapBroker* broker, MapHandles const& maps) {
} // namespace } // namespace
bool PropertyAccessBuilder::TryBuildStringCheck(JSHeapBroker* broker, bool PropertyAccessBuilder::TryBuildStringCheck(
MapHandles const& maps, JSHeapBroker* broker, ZoneVector<Handle<Map>> const& maps, Node** receiver,
Node** receiver, Node** effect, Node** effect, Node* control) {
Node* control) {
if (HasOnlyStringMaps(broker, maps)) { if (HasOnlyStringMaps(broker, maps)) {
// Monormorphic string access (ignoring the fact that there are multiple // Monormorphic string access (ignoring the fact that there are multiple
// String maps). // String maps).
...@@ -67,10 +68,9 @@ bool PropertyAccessBuilder::TryBuildStringCheck(JSHeapBroker* broker, ...@@ -67,10 +68,9 @@ bool PropertyAccessBuilder::TryBuildStringCheck(JSHeapBroker* broker,
return false; return false;
} }
bool PropertyAccessBuilder::TryBuildNumberCheck(JSHeapBroker* broker, bool PropertyAccessBuilder::TryBuildNumberCheck(
MapHandles const& maps, JSHeapBroker* broker, ZoneVector<Handle<Map>> const& maps, Node** receiver,
Node** receiver, Node** effect, Node** effect, Node* control) {
Node* control) {
if (HasOnlyNumberMaps(broker, maps)) { if (HasOnlyNumberMaps(broker, maps)) {
// Monomorphic number access (we also deal with Smis here). // Monomorphic number access (we also deal with Smis here).
*receiver = *effect = *receiver = *effect =
...@@ -143,9 +143,9 @@ Node* PropertyAccessBuilder::BuildCheckHeapObject(Node* receiver, Node** effect, ...@@ -143,9 +143,9 @@ Node* PropertyAccessBuilder::BuildCheckHeapObject(Node* receiver, Node** effect,
return receiver; return receiver;
} }
void PropertyAccessBuilder::BuildCheckMaps(Node* receiver, Node** effect, void PropertyAccessBuilder::BuildCheckMaps(
Node* control, Node* receiver, Node** effect, Node* control,
MapHandles const& receiver_maps) { ZoneVector<Handle<Map>> const& receiver_maps) {
HeapObjectMatcher m(receiver); HeapObjectMatcher m(receiver);
if (m.HasValue()) { if (m.HasValue()) {
MapRef receiver_map = m.Ref(broker()).map(); MapRef receiver_map = m.Ref(broker()).map();
......
...@@ -33,15 +33,17 @@ class PropertyAccessBuilder { ...@@ -33,15 +33,17 @@ class PropertyAccessBuilder {
// Builds the appropriate string check if the maps are only string // Builds the appropriate string check if the maps are only string
// maps. // maps.
bool TryBuildStringCheck(JSHeapBroker* broker, MapHandles const& maps, bool TryBuildStringCheck(JSHeapBroker* broker,
Node** receiver, Node** effect, Node* control); ZoneVector<Handle<Map>> const& maps, Node** receiver,
Node** effect, Node* control);
// Builds a number check if all maps are number maps. // Builds a number check if all maps are number maps.
bool TryBuildNumberCheck(JSHeapBroker* broker, MapHandles const& maps, bool TryBuildNumberCheck(JSHeapBroker* broker,
Node** receiver, Node** effect, Node* control); ZoneVector<Handle<Map>> const& maps, Node** receiver,
Node** effect, Node* control);
Node* BuildCheckHeapObject(Node* receiver, Node** effect, Node* control); Node* BuildCheckHeapObject(Node* receiver, Node** effect, Node* control);
void BuildCheckMaps(Node* receiver, Node** effect, Node* control, void BuildCheckMaps(Node* receiver, Node** effect, Node* control,
std::vector<Handle<Map>> const& receiver_maps); ZoneVector<Handle<Map>> const& receiver_maps);
Node* BuildCheckValue(Node* receiver, Node** effect, Node* control, Node* BuildCheckValue(Node* receiver, Node** effect, Node* control,
Handle<HeapObject> value); Handle<HeapObject> value);
...@@ -72,7 +74,8 @@ class PropertyAccessBuilder { ...@@ -72,7 +74,8 @@ class PropertyAccessBuilder {
CompilationDependencies* dependencies_; CompilationDependencies* dependencies_;
}; };
bool HasOnlyStringMaps(JSHeapBroker* broker, MapHandles const& maps); bool HasOnlyStringMaps(JSHeapBroker* broker,
ZoneVector<Handle<Map>> const& maps);
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
......
...@@ -247,9 +247,10 @@ int SerializerForBackgroundCompilation::Environment::RegisterToLocalIndex( ...@@ -247,9 +247,10 @@ int SerializerForBackgroundCompilation::Environment::RegisterToLocalIndex(
} }
SerializerForBackgroundCompilation::SerializerForBackgroundCompilation( SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
JSHeapBroker* broker, Zone* zone, Handle<JSFunction> closure, JSHeapBroker* broker, CompilationDependencies* dependencies, Zone* zone,
bool collect_source_positions) Handle<JSFunction> closure, bool collect_source_positions)
: broker_(broker), : broker_(broker),
dependencies_(dependencies),
zone_(zone), zone_(zone),
collect_source_positions_(collect_source_positions), collect_source_positions_(collect_source_positions),
environment_(new (zone) Environment(zone, {closure, broker_->isolate()})), environment_(new (zone) Environment(zone, {closure, broker_->isolate()})),
...@@ -258,10 +259,11 @@ SerializerForBackgroundCompilation::SerializerForBackgroundCompilation( ...@@ -258,10 +259,11 @@ SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
} }
SerializerForBackgroundCompilation::SerializerForBackgroundCompilation( SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
JSHeapBroker* broker, Zone* zone, CompilationSubject function, JSHeapBroker* broker, CompilationDependencies* dependencies, Zone* zone,
base::Optional<Hints> new_target, const HintsVector& arguments, CompilationSubject function, base::Optional<Hints> new_target,
bool collect_source_positions) const HintsVector& arguments, bool collect_source_positions)
: broker_(broker), : broker_(broker),
dependencies_(dependencies),
zone_(zone), zone_(zone),
collect_source_positions_(collect_source_positions), collect_source_positions_(collect_source_positions),
environment_(new (zone) Environment(zone, broker_->isolate(), function, environment_(new (zone) Environment(zone, broker_->isolate(), function,
...@@ -580,7 +582,7 @@ Hints SerializerForBackgroundCompilation::RunChildSerializer( ...@@ -580,7 +582,7 @@ Hints SerializerForBackgroundCompilation::RunChildSerializer(
<< *environment()); << *environment());
SerializerForBackgroundCompilation child_serializer( SerializerForBackgroundCompilation child_serializer(
broker(), zone(), function, new_target, arguments, broker(), dependencies(), zone(), function, new_target, arguments,
collect_source_positions()); collect_source_positions());
return child_serializer.Run(); return child_serializer.Run();
} }
...@@ -790,6 +792,29 @@ MapHandles GetRelevantReceiverMaps(Isolate* isolate, MapContainer const& maps) { ...@@ -790,6 +792,29 @@ MapHandles GetRelevantReceiverMaps(Isolate* isolate, MapContainer const& maps) {
} }
} // namespace } // namespace
ElementAccessFeedback const*
SerializerForBackgroundCompilation::ProcessFeedbackMapsForElementAccess(
const MapHandles& maps, AccessMode mode) {
ElementAccessFeedback const* result =
broker()->ProcessFeedbackMapsForElementAccess(maps);
for (ElementAccessFeedback::MapIterator it = result->all_maps(broker());
!it.done(); it.advance()) {
switch (mode) {
case AccessMode::kHas:
case AccessMode::kLoad:
it.current().SerializeForElementLoad();
break;
case AccessMode::kStore:
it.current().SerializeForElementStore();
break;
case AccessMode::kStoreInLiteral:
// This operation is fairly local and simple, nothing to serialize.
break;
}
}
return result;
}
// Note: We never use the same feedback slot for multiple access modes. // Note: We never use the same feedback slot for multiple access modes.
void SerializerForBackgroundCompilation::ProcessFeedbackForKeyedPropertyAccess( void SerializerForBackgroundCompilation::ProcessFeedbackForKeyedPropertyAccess(
FeedbackSlot slot, AccessMode mode) { FeedbackSlot slot, AccessMode mode) {
...@@ -800,36 +825,28 @@ void SerializerForBackgroundCompilation::ProcessFeedbackForKeyedPropertyAccess( ...@@ -800,36 +825,28 @@ void SerializerForBackgroundCompilation::ProcessFeedbackForKeyedPropertyAccess(
FeedbackSource source(nexus); FeedbackSource source(nexus);
if (broker()->HasFeedback(source)) return; if (broker()->HasFeedback(source)) return;
ProcessedFeedback const* processed = nullptr;
if (nexus.ic_state() == UNINITIALIZED) {
processed = new (broker()->zone()) InsufficientFeedback();
} else {
if (nexus.GetKeyType() == PROPERTY) { if (nexus.GetKeyType() == PROPERTY) {
CHECK_NE(mode, AccessMode::kStoreInLiteral); CHECK_NE(mode, AccessMode::kStoreInLiteral);
return; // TODO(neis): Support named access. // TODO(neis): Support named access.
} } else {
DCHECK_EQ(nexus.GetKeyType(), ELEMENT); DCHECK_EQ(nexus.GetKeyType(), ELEMENT);
CHECK(nexus.GetName().is_null()); DCHECK(nexus.GetName().is_null());
MapHandles maps; MapHandles maps;
nexus.ExtractMaps(&maps); if (nexus.ExtractMaps(&maps) != 0) {
ElementAccessFeedback const* processed = maps = GetRelevantReceiverMaps(broker()->isolate(), maps);
broker()->ProcessFeedbackMapsForElementAccess( if (maps.empty()) {
GetRelevantReceiverMaps(broker()->isolate(), maps)); processed = new (broker()->zone()) InsufficientFeedback();
broker()->SetFeedback(source, processed); } else {
if (processed == nullptr) return; processed = ProcessFeedbackMapsForElementAccess(maps, mode);
}
for (ElementAccessFeedback::MapIterator it = processed->all_maps(broker()); }
!it.done(); it.advance()) {
switch (mode) {
case AccessMode::kHas:
case AccessMode::kLoad:
it.current().SerializeForElementLoad();
break;
case AccessMode::kStore:
it.current().SerializeForElementStore();
break;
case AccessMode::kStoreInLiteral:
// This operation is fairly local and simple, nothing to serialize.
break;
} }
} }
broker()->SetFeedback(source, processed);
} }
void SerializerForBackgroundCompilation::ProcessKeyedPropertyAccess( void SerializerForBackgroundCompilation::ProcessKeyedPropertyAccess(
...@@ -878,7 +895,7 @@ void SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess( ...@@ -878,7 +895,7 @@ void SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess(
// Note: We never use the same feedback slot for multiple names. // Note: We never use the same feedback slot for multiple names.
void SerializerForBackgroundCompilation::ProcessFeedbackForNamedPropertyAccess( void SerializerForBackgroundCompilation::ProcessFeedbackForNamedPropertyAccess(
FeedbackSlot slot, NameRef const& name) { FeedbackSlot slot, NameRef const& name, AccessMode mode) {
if (slot.IsInvalid()) return; if (slot.IsInvalid()) return;
if (environment()->function().feedback_vector.is_null()) return; if (environment()->function().feedback_vector.is_null()) return;
...@@ -886,15 +903,31 @@ void SerializerForBackgroundCompilation::ProcessFeedbackForNamedPropertyAccess( ...@@ -886,15 +903,31 @@ void SerializerForBackgroundCompilation::ProcessFeedbackForNamedPropertyAccess(
FeedbackSource source(nexus); FeedbackSource source(nexus);
if (broker()->HasFeedback(source)) return; if (broker()->HasFeedback(source)) return;
ProcessedFeedback const* processed = nullptr;
if (nexus.ic_state() == UNINITIALIZED) {
processed = new (broker()->zone()) InsufficientFeedback();
} else {
MapHandles maps; MapHandles maps;
nexus.ExtractMaps(&maps); if (nexus.ExtractMaps(&maps) != 0) {
for (Handle<Map> map : GetRelevantReceiverMaps(broker()->isolate(), maps)) { ZoneVector<PropertyAccessInfo> access_infos(broker()->zone());
ProcessMapForNamedPropertyAccess(MapRef(broker(), map), name); for (Handle<Map> map :
GetRelevantReceiverMaps(broker()->isolate(), maps)) {
MapRef map_ref(broker(), map);
ProcessMapForNamedPropertyAccess(map_ref, name);
AccessInfoFactory access_info_factory(broker(), dependencies(),
broker()->zone());
access_infos.push_back(access_info_factory.ComputePropertyAccessInfo(
map, name.object(), mode));
} }
if (access_infos.empty()) {
// NamedProperty support is still WIP. For now we don't have any actual data processed = new (broker()->zone()) InsufficientFeedback();
// to store, so use nullptr to at least record that we processed the feedback. } else {
broker()->SetFeedback(source, nullptr); processed =
new (broker()->zone()) NamedAccessFeedback(name, access_infos);
}
}
}
broker()->SetFeedback(source, processed);
} }
void SerializerForBackgroundCompilation::VisitLdaKeyedProperty( void SerializerForBackgroundCompilation::VisitLdaKeyedProperty(
...@@ -909,7 +942,7 @@ void SerializerForBackgroundCompilation::VisitLdaKeyedProperty( ...@@ -909,7 +942,7 @@ void SerializerForBackgroundCompilation::VisitLdaKeyedProperty(
void SerializerForBackgroundCompilation::ProcessNamedPropertyAccess( void SerializerForBackgroundCompilation::ProcessNamedPropertyAccess(
Hints const& receiver, NameRef const& name, FeedbackSlot slot, Hints const& receiver, NameRef const& name, FeedbackSlot slot,
AccessMode mode) { AccessMode mode) {
if (!slot.IsInvalid()) ProcessFeedbackForNamedPropertyAccess(slot, name); ProcessFeedbackForNamedPropertyAccess(slot, name, mode);
for (Handle<Map> map : for (Handle<Map> map :
GetRelevantReceiverMaps(broker()->isolate(), receiver.maps())) { GetRelevantReceiverMaps(broker()->isolate(), receiver.maps())) {
...@@ -956,6 +989,11 @@ void SerializerForBackgroundCompilation::VisitStaNamedProperty( ...@@ -956,6 +989,11 @@ void SerializerForBackgroundCompilation::VisitStaNamedProperty(
ProcessNamedPropertyAccess(iterator, AccessMode::kStore); ProcessNamedPropertyAccess(iterator, AccessMode::kStore);
} }
void SerializerForBackgroundCompilation::VisitStaNamedOwnProperty(
BytecodeArrayIterator* iterator) {
ProcessNamedPropertyAccess(iterator, AccessMode::kStoreInLiteral);
}
void SerializerForBackgroundCompilation::VisitTestIn( void SerializerForBackgroundCompilation::VisitTestIn(
BytecodeArrayIterator* iterator) { BytecodeArrayIterator* iterator) {
Hints const& receiver = environment()->accumulator_hints(); Hints const& receiver = environment()->accumulator_hints();
......
...@@ -189,6 +189,7 @@ namespace compiler { ...@@ -189,6 +189,7 @@ namespace compiler {
V(StaGlobal) \ V(StaGlobal) \
V(StaInArrayLiteral) \ V(StaInArrayLiteral) \
V(StaKeyedProperty) \ V(StaKeyedProperty) \
V(StaNamedOwnProperty) \
V(StaNamedProperty) \ V(StaNamedProperty) \
V(Star) \ V(Star) \
V(TestIn) \ V(TestIn) \
...@@ -270,16 +271,18 @@ using HintsVector = ZoneVector<Hints>; ...@@ -270,16 +271,18 @@ using HintsVector = ZoneVector<Hints>;
// optimizations in the compiler, is copied to the heap broker. // optimizations in the compiler, is copied to the heap broker.
class SerializerForBackgroundCompilation { class SerializerForBackgroundCompilation {
public: public:
SerializerForBackgroundCompilation(JSHeapBroker* broker, Zone* zone, SerializerForBackgroundCompilation(JSHeapBroker* broker,
Handle<JSFunction> closure, CompilationDependencies* dependencies,
Zone* zone, Handle<JSFunction> closure,
bool collect_source_positions); bool collect_source_positions);
Hints Run(); // NOTE: Returns empty for an already-serialized function. Hints Run(); // NOTE: Returns empty for an already-serialized function.
class Environment; class Environment;
private: private:
SerializerForBackgroundCompilation(JSHeapBroker* broker, Zone* zone, SerializerForBackgroundCompilation(JSHeapBroker* broker,
CompilationSubject function, CompilationDependencies* dependencies,
Zone* zone, CompilationSubject function,
base::Optional<Hints> new_target, base::Optional<Hints> new_target,
const HintsVector& arguments, const HintsVector& arguments,
bool collect_source_positions); bool collect_source_positions);
...@@ -311,8 +314,11 @@ class SerializerForBackgroundCompilation { ...@@ -311,8 +314,11 @@ class SerializerForBackgroundCompilation {
GlobalAccessFeedback const* ProcessFeedbackForGlobalAccess(FeedbackSlot slot); GlobalAccessFeedback const* ProcessFeedbackForGlobalAccess(FeedbackSlot slot);
void ProcessFeedbackForKeyedPropertyAccess(FeedbackSlot slot, void ProcessFeedbackForKeyedPropertyAccess(FeedbackSlot slot,
AccessMode mode); AccessMode mode);
ElementAccessFeedback const* ProcessFeedbackMapsForElementAccess(
const MapHandles& maps, AccessMode mode);
void ProcessFeedbackForNamedPropertyAccess(FeedbackSlot slot, void ProcessFeedbackForNamedPropertyAccess(FeedbackSlot slot,
NameRef const& name); NameRef const& name,
AccessMode mode);
void ProcessMapForNamedPropertyAccess(MapRef const& map, NameRef const& name); void ProcessMapForNamedPropertyAccess(MapRef const& map, NameRef const& name);
Hints RunChildSerializer(CompilationSubject function, Hints RunChildSerializer(CompilationSubject function,
...@@ -320,6 +326,7 @@ class SerializerForBackgroundCompilation { ...@@ -320,6 +326,7 @@ class SerializerForBackgroundCompilation {
const HintsVector& arguments, bool with_spread); const HintsVector& arguments, bool with_spread);
JSHeapBroker* broker() const { return broker_; } JSHeapBroker* broker() const { return broker_; }
CompilationDependencies* dependencies() const { return dependencies_; }
Zone* zone() const { return zone_; } Zone* zone() const { return zone_; }
// The following flag is initialized from OptimizedCompilationInfo's // The following flag is initialized from OptimizedCompilationInfo's
// {is_source_positions_enabled}. // {is_source_positions_enabled}.
...@@ -327,6 +334,7 @@ class SerializerForBackgroundCompilation { ...@@ -327,6 +334,7 @@ class SerializerForBackgroundCompilation {
Environment* environment() const { return environment_; } Environment* environment() const { return environment_; }
JSHeapBroker* const broker_; JSHeapBroker* const broker_;
CompilationDependencies* const dependencies_;
Zone* const zone_; Zone* const zone_;
bool const collect_source_positions_; bool const collect_source_positions_;
Environment* const environment_; Environment* const environment_;
......
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