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) {
UNREACHABLE();
}
ElementAccessInfo::ElementAccessInfo() = default;
ElementAccessInfo::ElementAccessInfo(MapHandles const& receiver_maps,
ElementsKind elements_kind)
: elements_kind_(elements_kind), receiver_maps_(receiver_maps) {
ElementAccessInfo::ElementAccessInfo(ZoneVector<Handle<Map>>&& receiver_maps,
ElementsKind elements_kind, Zone* zone)
: elements_kind_(elements_kind),
receiver_maps_(receiver_maps),
transition_sources_(zone) {
CHECK(!receiver_maps.empty());
}
// static
PropertyAccessInfo PropertyAccessInfo::NotFound(MapHandles const& receiver_maps,
PropertyAccessInfo PropertyAccessInfo::Invalid(Zone* zone) {
return PropertyAccessInfo(zone);
}
// static
PropertyAccessInfo PropertyAccessInfo::NotFound(Zone* zone,
Handle<Map> receiver_map,
MaybeHandle<JSObject> holder) {
return PropertyAccessInfo(kNotFound, holder, receiver_maps);
return PropertyAccessInfo(zone, kNotFound, holder, {{receiver_map}, zone});
}
// static
PropertyAccessInfo PropertyAccessInfo::DataField(
MapHandles const& receiver_maps,
std::vector<CompilationDependencies::Dependency const*>&& dependencies,
Zone* zone, Handle<Map> receiver_map,
ZoneVector<CompilationDependencies::Dependency const*>&& dependencies,
FieldIndex field_index, MachineRepresentation field_representation,
Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder,
MaybeHandle<Map> transition_map) {
return PropertyAccessInfo(kDataField, holder, transition_map, field_index,
field_representation, field_type, field_map,
receiver_maps, std::move(dependencies));
{{receiver_map}, zone}, std::move(dependencies));
}
// static
PropertyAccessInfo PropertyAccessInfo::DataConstant(
MapHandles const& receiver_maps,
std::vector<CompilationDependencies::Dependency const*>&& dependencies,
Zone* zone, Handle<Map> receiver_map,
ZoneVector<CompilationDependencies::Dependency const*>&& dependencies,
FieldIndex field_index, MachineRepresentation field_representation,
Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder) {
return PropertyAccessInfo(kDataConstant, holder, MaybeHandle<Map>(),
field_index, field_representation, field_type,
field_map, receiver_maps, std::move(dependencies));
field_map, {{receiver_map}, zone},
std::move(dependencies));
}
// static
PropertyAccessInfo PropertyAccessInfo::AccessorConstant(
MapHandles const& receiver_maps, Handle<Object> constant,
Zone* zone, Handle<Map> receiver_map, Handle<Object> constant,
MaybeHandle<JSObject> holder) {
return PropertyAccessInfo(kAccessorConstant, holder, constant, receiver_maps);
return PropertyAccessInfo(zone, kAccessorConstant, holder, constant,
{{receiver_map}, zone});
}
// static
PropertyAccessInfo PropertyAccessInfo::ModuleExport(
MapHandles const& receiver_maps, Handle<Cell> cell) {
return PropertyAccessInfo(kModuleExport, MaybeHandle<JSObject>(), cell,
receiver_maps);
PropertyAccessInfo PropertyAccessInfo::ModuleExport(Zone* zone,
Handle<Map> receiver_map,
Handle<Cell> cell) {
return PropertyAccessInfo(zone, kModuleExport, MaybeHandle<JSObject>(), cell,
{{receiver_map}, zone});
}
// static
PropertyAccessInfo PropertyAccessInfo::StringLength(
MapHandles const& receiver_maps) {
return PropertyAccessInfo(kStringLength, MaybeHandle<JSObject>(),
receiver_maps);
PropertyAccessInfo PropertyAccessInfo::StringLength(Zone* zone,
Handle<Map> receiver_map) {
return PropertyAccessInfo(zone, kStringLength, MaybeHandle<JSObject>(),
{{receiver_map}, zone});
}
PropertyAccessInfo::PropertyAccessInfo()
PropertyAccessInfo::PropertyAccessInfo(Zone* zone)
: kind_(kInvalid),
receiver_maps_(zone),
unrecorded_dependencies_(zone),
field_representation_(MachineRepresentation::kNone),
field_type_(Type::None()) {}
PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
MapHandles const& receiver_maps)
PropertyAccessInfo::PropertyAccessInfo(Zone* zone, Kind kind,
MaybeHandle<JSObject> holder,
ZoneVector<Handle<Map>>&& receiver_maps)
: kind_(kind),
receiver_maps_(receiver_maps),
unrecorded_dependencies_(zone),
holder_(holder),
field_representation_(MachineRepresentation::kNone),
field_type_(Type::None()) {}
PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
PropertyAccessInfo::PropertyAccessInfo(Zone* zone, Kind kind,
MaybeHandle<JSObject> holder,
Handle<Object> constant,
MapHandles const& receiver_maps)
ZoneVector<Handle<Map>>&& receiver_maps)
: kind_(kind),
receiver_maps_(receiver_maps),
unrecorded_dependencies_(zone),
constant_(constant),
holder_(holder),
field_representation_(MachineRepresentation::kNone),
......@@ -140,8 +155,8 @@ PropertyAccessInfo::PropertyAccessInfo(
Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map,
FieldIndex field_index, MachineRepresentation field_representation,
Type field_type, MaybeHandle<Map> field_map,
MapHandles const& receiver_maps,
std::vector<CompilationDependencies::Dependency const*>&&
ZoneVector<Handle<Map>>&& receiver_maps,
ZoneVector<CompilationDependencies::Dependency const*>&&
unrecorded_dependencies)
: kind_(kind),
receiver_maps_(receiver_maps),
......@@ -254,15 +269,13 @@ AccessInfoFactory::AccessInfoFactory(JSHeapBroker* broker,
type_cache_(TypeCache::Get()),
zone_(zone) {}
bool AccessInfoFactory::ComputeElementAccessInfo(
Handle<Map> map, AccessMode access_mode,
ElementAccessInfo* access_info) const {
base::Optional<ElementAccessInfo> AccessInfoFactory::ComputeElementAccessInfo(
Handle<Map> map, AccessMode access_mode) const {
// Check if it is safe to inline element access for the {map}.
MapRef map_ref(broker(), map);
if (!CanInlineElementAccess(map_ref)) return false;
if (!CanInlineElementAccess(map_ref)) return base::nullopt;
ElementsKind const elements_kind = map_ref.elements_kind();
*access_info = ElementAccessInfo(MapHandles{map}, elements_kind);
return true;
return ElementAccessInfo({{map}, zone()}, elements_kind, zone());
}
bool AccessInfoFactory::ComputeElementAccessInfos(
......@@ -279,29 +292,29 @@ bool AccessInfoFactory::ComputeElementAccessInfos(
// double), always use the "worst case" code without a transition. This is
// much faster than transitioning the elements to the worst case, trading a
// TransitionElementsKind for a CheckMaps, avoiding mutation of the array.
ElementAccessInfo access_info;
if (ConsolidateElementLoad(*processed, &access_info)) {
access_infos->push_back(access_info);
base::Optional<ElementAccessInfo> access_info =
ConsolidateElementLoad(*processed);
if (access_info.has_value()) {
access_infos->push_back(*access_info);
return true;
}
}
for (Handle<Map> receiver_map : processed->receiver_maps) {
// Compute the element access information.
ElementAccessInfo access_info;
if (!ComputeElementAccessInfo(receiver_map, access_mode, &access_info)) {
return false;
}
base::Optional<ElementAccessInfo> access_info =
ComputeElementAccessInfo(receiver_map, access_mode);
if (!access_info.has_value()) return false;
// Collect the possible transitions for the {receiver_map}.
for (auto transition : processed->transitions) {
if (transition.second.equals(receiver_map)) {
access_info.AddTransitionSource(transition.first);
access_info->AddTransitionSource(transition.first);
}
}
// Schedule the access information.
access_infos->push_back(access_info);
access_infos->push_back(*access_info);
}
return true;
}
......@@ -320,7 +333,7 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
// fields for which the representation has not yet been
// determined by the runtime. So we need to catch this case
// here and fall back to use the regular IC logic instead.
return {};
return PropertyAccessInfo::Invalid(zone());
}
FieldIndex field_index =
FieldIndex::ForPropertyIndex(*map, index, details_representation);
......@@ -329,8 +342,8 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
MachineType::RepCompressedTagged();
MaybeHandle<Map> field_map;
MapRef map_ref(broker(), map);
std::vector<CompilationDependencies::Dependency const*>
unrecorded_dependencies;
ZoneVector<CompilationDependencies::Dependency const*>
unrecorded_dependencies(zone());
if (details_representation.IsSmi()) {
field_type = Type::SignedSmall();
field_representation = MachineType::RepCompressedTaggedSigned();
......@@ -349,7 +362,9 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
isolate());
if (descriptors_field_type->IsNone()) {
// Store is not safe if the field type was cleared.
if (access_mode == AccessMode::kStore) return {};
if (access_mode == AccessMode::kStore) {
return PropertyAccessInfo::Invalid(zone());
}
// The field type was cleared by the GC, so we don't know anything
// about the contents now.
......@@ -370,12 +385,12 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
switch (details.constness()) {
case PropertyConstness::kMutable:
return PropertyAccessInfo::DataField(
MapHandles{receiver_map}, std::move(unrecorded_dependencies),
field_index, field_representation, field_type, field_map, holder);
zone(), receiver_map, std::move(unrecorded_dependencies), field_index,
field_representation, field_type, field_map, holder);
case PropertyConstness::kConst:
return PropertyAccessInfo::DataConstant(
MapHandles{receiver_map}, std::move(unrecorded_dependencies),
field_index, field_representation, field_type, field_map, holder);
zone(), receiver_map, std::move(unrecorded_dependencies), field_index,
field_representation, field_type, field_map, holder);
}
UNREACHABLE();
}
......@@ -398,17 +413,19 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo(
isolate());
if (cell->value()->IsTheHole(isolate())) {
// This module has not been fully initialized yet.
return {};
return PropertyAccessInfo::Invalid(zone());
}
return PropertyAccessInfo::ModuleExport(MapHandles{receiver_map}, cell);
return PropertyAccessInfo::ModuleExport(zone(), receiver_map, cell);
}
if (access_mode == AccessMode::kHas) {
// HasProperty checks don't call getter/setters, existence is sufficient.
return PropertyAccessInfo::AccessorConstant(MapHandles{receiver_map},
return PropertyAccessInfo::AccessorConstant(zone(), receiver_map,
Handle<Object>(), holder);
}
Handle<Object> accessors(descriptors->GetStrongValue(number), isolate());
if (!accessors->IsAccessorPair()) return {};
if (!accessors->IsAccessorPair()) {
return PropertyAccessInfo::Invalid(zone());
}
Handle<Object> accessor(access_mode == AccessMode::kLoad
? Handle<AccessorPair>::cast(accessors)->getter()
: Handle<AccessorPair>::cast(accessors)->setter(),
......@@ -418,16 +435,20 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo(
if (!optimization.is_simple_api_call() ||
optimization.IsCrossContextLazyAccessorPair(
*broker()->native_context().object(), *map)) {
return {};
return PropertyAccessInfo::Invalid(zone());
}
CallOptimization::HolderLookup lookup;
holder = optimization.LookupHolderOfExpectedType(receiver_map, &lookup);
if (lookup == CallOptimization::kHolderNotFound) return {};
if (lookup == CallOptimization::kHolderNotFound) {
return PropertyAccessInfo::Invalid(zone());
}
DCHECK_IMPLIES(lookup == CallOptimization::kHolderIsReceiver,
holder.is_null());
DCHECK_IMPLIES(lookup == CallOptimization::kHolderFound, !holder.is_null());
if (V8_UNLIKELY(TracingFlags::is_runtime_stats_enabled())) return {};
if (V8_UNLIKELY(TracingFlags::is_runtime_stats_enabled())) {
return PropertyAccessInfo::Invalid(zone());
}
}
if (access_mode == AccessMode::kLoad) {
Handle<Name> cached_property_name;
......@@ -438,18 +459,22 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo(
if (!access_info.IsInvalid()) return access_info;
}
}
return PropertyAccessInfo::AccessorConstant(MapHandles{receiver_map},
accessor, holder);
return PropertyAccessInfo::AccessorConstant(zone(), receiver_map, accessor,
holder);
}
PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
Handle<Map> map, Handle<Name> name, AccessMode access_mode) const {
CHECK(name->IsUniqueName());
if (access_mode == AccessMode::kHas && !map->IsJSReceiverMap()) return {};
if (access_mode == AccessMode::kHas && !map->IsJSReceiverMap()) {
return PropertyAccessInfo::Invalid(zone());
}
// Check if it is safe to inline property access for the {map}.
if (!CanInlinePropertyAccess(map)) return {};
if (!CanInlinePropertyAccess(map)) {
return PropertyAccessInfo::Invalid(zone());
}
// We support fast inline cases for certain JSObject getters.
if (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) {
......@@ -469,7 +494,9 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
if (access_mode == AccessMode::kStore ||
access_mode == AccessMode::kStoreInLiteral) {
// Don't bother optimizing stores to read-only properties.
if (details.IsReadOnly()) return {};
if (details.IsReadOnly()) {
return PropertyAccessInfo::Invalid(zone());
}
if (details.kind() == kData && !holder.is_null()) {
// This is a store to a property not found on the receiver but on a
// prototype. According to ES6 section 9.1.9 [[Set]], we need to
......@@ -485,7 +512,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
} else {
DCHECK_EQ(kAccessor, details.kind());
// TODO(turbofan): Add support for general accessors?
return {};
return PropertyAccessInfo::Invalid(zone());
}
} else {
DCHECK_EQ(kDescriptor, details.location());
......@@ -502,7 +529,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// integer indexed exotic objects (see ES6 section 9.4.5).
if (map->IsJSTypedArrayMap() && name->IsString() &&
IsSpecialIndex(String::cast(*name))) {
return {};
return PropertyAccessInfo::Invalid(zone());
}
// Don't search on the prototype when storing in literals.
......@@ -511,7 +538,9 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
}
// Don't lookup private symbols on the prototype chain.
if (name->IsPrivate()) return {};
if (name->IsPrivate()) {
return PropertyAccessInfo::Invalid(zone());
}
// Walk up the prototype chain.
if (!map->prototype()->IsJSObject()) {
......@@ -532,9 +561,9 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// The property was not found (access returns undefined or throws
// depending on the language mode of the load operation.
// Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver)
return PropertyAccessInfo::NotFound(MapHandles{receiver_map}, holder);
return PropertyAccessInfo::NotFound(zone(), receiver_map, holder);
} else {
return {};
return PropertyAccessInfo::Invalid(zone());
}
}
Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
......@@ -546,13 +575,16 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
map = handle(map_prototype->map(), isolate());
holder = map_prototype;
if (!CanInlinePropertyAccess(map)) return {};
if (!CanInlinePropertyAccess(map)) {
return PropertyAccessInfo::Invalid(zone());
}
// Successful lookup on prototype chain needs to guarantee that all
// the prototypes up to the holder have stable maps. Let us make sure
// the prototype maps are stable here.
CHECK(map->is_stable());
}
UNREACHABLE();
}
PropertyAccessInfo AccessInfoFactory::FinalizePropertyAccessInfosAsOne(
......@@ -566,7 +598,7 @@ PropertyAccessInfo AccessInfoFactory::FinalizePropertyAccessInfosAsOne(
return result;
}
}
return {};
return PropertyAccessInfo::Invalid(zone());
}
void AccessInfoFactory::ComputePropertyAccessInfos(
......@@ -640,28 +672,26 @@ Maybe<ElementsKind> GeneralizeElementsKind(ElementsKind this_kind,
} // namespace
bool AccessInfoFactory::ConsolidateElementLoad(
ElementAccessFeedback const& processed,
ElementAccessInfo* access_info) const {
base::Optional<ElementAccessInfo> AccessInfoFactory::ConsolidateElementLoad(
ElementAccessFeedback const& processed) const {
ElementAccessFeedback::MapIterator it = processed.all_maps(broker());
MapRef first_map = it.current();
InstanceType instance_type = first_map.instance_type();
ElementsKind elements_kind = first_map.elements_kind();
MapHandles maps;
ZoneVector<Handle<Map>> maps(zone());
for (; !it.done(); it.advance()) {
MapRef map = it.current();
if (map.instance_type() != instance_type || !CanInlineElementAccess(map)) {
return false;
return base::nullopt;
}
if (!GeneralizeElementsKind(elements_kind, map.elements_kind())
.To(&elements_kind)) {
return false;
return base::nullopt;
}
maps.push_back(map.object());
}
*access_info = ElementAccessInfo(maps, elements_kind);
return true;
return ElementAccessInfo(std::move(maps), elements_kind, zone());
}
PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor(
......@@ -669,9 +699,9 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor(
// Check for String::length field accessor.
if (map->IsStringMap()) {
if (Name::Equals(isolate(), name, isolate()->factory()->length_string())) {
return PropertyAccessInfo::StringLength(MapHandles{map});
return PropertyAccessInfo::StringLength(zone(), map);
}
return {};
return PropertyAccessInfo::Invalid(zone());
}
// Check for special JSObject field accessors.
FieldIndex field_index;
......@@ -698,10 +728,10 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor(
}
}
// Special fields are always mutable.
return PropertyAccessInfo::DataField(MapHandles{map}, {}, field_index,
return PropertyAccessInfo::DataField(zone(), map, {{}, zone()}, field_index,
field_representation, field_type);
}
return {};
return PropertyAccessInfo::Invalid(zone());
}
PropertyAccessInfo AccessInfoFactory::LookupTransition(
......@@ -709,16 +739,22 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
// Check if the {map} has a data transition with the given {name}.
Map transition =
TransitionsAccessor(isolate(), map).SearchTransition(*name, kData, NONE);
if (transition.is_null()) return {};
if (transition.is_null()) {
return PropertyAccessInfo::Invalid(zone());
}
Handle<Map> transition_map(transition, isolate());
int const number = transition_map->LastAdded();
PropertyDetails const details =
transition_map->instance_descriptors()->GetDetails(number);
// Don't bother optimizing stores to read-only properties.
if (details.IsReadOnly()) return {};
if (details.IsReadOnly()) {
return PropertyAccessInfo::Invalid(zone());
}
// TODO(bmeurer): Handle transition to data constant?
if (details.location() != kField) return {};
if (details.location() != kField) {
return PropertyAccessInfo::Invalid(zone());
}
int const index = details.field_index();
Representation details_representation = details.representation();
FieldIndex field_index = FieldIndex::ForPropertyIndex(*transition_map, index,
......@@ -728,8 +764,8 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
MachineRepresentation field_representation =
MachineType::RepCompressedTagged();
MapRef transition_map_ref(broker(), transition_map);
std::vector<CompilationDependencies::Dependency const*>
unrecorded_dependencies;
ZoneVector<CompilationDependencies::Dependency const*>
unrecorded_dependencies(zone());
if (details_representation.IsSmi()) {
field_type = Type::SignedSmall();
field_representation = MachineType::RepCompressedTaggedSigned();
......@@ -749,7 +785,7 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
isolate());
if (descriptors_field_type->IsNone()) {
// Store is not safe if the field type was cleared.
return {};
return PropertyAccessInfo::Invalid(zone());
}
transition_map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later.
unrecorded_dependencies.push_back(
......@@ -770,7 +806,7 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
MapRef(broker(), transition_map)));
// Transitioning stores are never stores to constant fields.
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);
}
......
......@@ -29,22 +29,21 @@ class ElementAccessFeedback;
class Type;
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);
// This class encapsulates all information required to access a certain element.
class ElementAccessInfo final {
public:
ElementAccessInfo();
ElementAccessInfo(MapHandles const& receiver_maps,
ElementsKind elements_kind);
ElementAccessInfo(ZoneVector<Handle<Map>>&& receiver_maps,
ElementsKind elements_kind, Zone* zone);
ElementsKind elements_kind() const { return elements_kind_; }
MapHandles const& receiver_maps() const { return receiver_maps_; }
MapHandles const& transition_sources() const { return transition_sources_; }
ZoneVector<Handle<Map>> const& receiver_maps() const {
return receiver_maps_;
}
ZoneVector<Handle<Map>> const& transition_sources() const {
return transition_sources_;
}
void AddTransitionSource(Handle<Map> map) {
CHECK_EQ(receiver_maps_.size(), 1);
......@@ -53,8 +52,8 @@ class ElementAccessInfo final {
private:
ElementsKind elements_kind_;
MapHandles receiver_maps_;
MapHandles transition_sources_;
ZoneVector<Handle<Map>> receiver_maps_;
ZoneVector<Handle<Map>> transition_sources_;
};
// This class encapsulates all information required to access a certain
......@@ -71,31 +70,31 @@ class PropertyAccessInfo final {
kStringLength
};
static PropertyAccessInfo NotFound(MapHandles const& receiver_maps,
static PropertyAccessInfo NotFound(Zone* zone, Handle<Map> receiver_map,
MaybeHandle<JSObject> holder);
static PropertyAccessInfo DataField(
MapHandles const& receiver_maps,
std::vector<CompilationDependencies::Dependency const*>&&
Zone* zone, Handle<Map> receiver_map,
ZoneVector<CompilationDependencies::Dependency const*>&&
unrecorded_dependencies,
FieldIndex field_index, MachineRepresentation field_representation,
Type field_type, MaybeHandle<Map> field_map = MaybeHandle<Map>(),
MaybeHandle<JSObject> holder = MaybeHandle<JSObject>(),
MaybeHandle<Map> transition_map = MaybeHandle<Map>());
static PropertyAccessInfo DataConstant(
MapHandles const& receiver_maps,
std::vector<CompilationDependencies::Dependency const*>&&
Zone* zone, Handle<Map> receiver_map,
ZoneVector<CompilationDependencies::Dependency const*>&&
unrecorded_dependencies,
FieldIndex field_index, MachineRepresentation field_representation,
Type field_type, MaybeHandle<Map> field_map,
MaybeHandle<JSObject> holder);
static PropertyAccessInfo AccessorConstant(MapHandles const& receiver_maps,
static PropertyAccessInfo AccessorConstant(Zone* zone,
Handle<Map> receiver_map,
Handle<Object> constant,
MaybeHandle<JSObject> holder);
static PropertyAccessInfo ModuleExport(MapHandles const& receiver_maps,
static PropertyAccessInfo ModuleExport(Zone* zone, Handle<Map> receiver_map,
Handle<Cell> cell);
static PropertyAccessInfo StringLength(MapHandles const& receiver_maps);
PropertyAccessInfo();
static PropertyAccessInfo StringLength(Zone* zone, Handle<Map> receiver_map);
static PropertyAccessInfo Invalid(Zone* zone);
bool Merge(PropertyAccessInfo const* that, AccessMode access_mode,
Zone* zone) V8_WARN_UNUSED_RESULT;
......@@ -127,24 +126,28 @@ class PropertyAccessInfo final {
return field_representation_;
}
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;
private:
PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
MapHandles const& receiver_maps);
PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
Handle<Object> constant, MapHandles const& receiver_maps);
explicit PropertyAccessInfo(Zone* zone);
PropertyAccessInfo(Zone* zone, Kind kind, MaybeHandle<JSObject> holder,
ZoneVector<Handle<Map>>&& receiver_maps);
PropertyAccessInfo(Zone* zone, Kind kind, MaybeHandle<JSObject> holder,
Handle<Object> constant,
ZoneVector<Handle<Map>>&& receiver_maps);
PropertyAccessInfo(
Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map,
FieldIndex field_index, MachineRepresentation field_representation,
Type field_type, MaybeHandle<Map> field_map,
MapHandles const& receiver_maps,
std::vector<CompilationDependencies::Dependency const*>&& dependencies);
ZoneVector<Handle<Map>>&& receiver_maps,
ZoneVector<CompilationDependencies::Dependency const*>&& dependencies);
Kind kind_;
MapHandles receiver_maps_;
std::vector<CompilationDependencies::Dependency const*>
ZoneVector<Handle<Map>> receiver_maps_;
ZoneVector<CompilationDependencies::Dependency const*>
unrecorded_dependencies_;
Handle<Object> constant_;
MaybeHandle<Map> transition_map_;
......@@ -162,8 +165,8 @@ class AccessInfoFactory final {
AccessInfoFactory(JSHeapBroker* broker, CompilationDependencies* dependencies,
Zone* zone);
bool ComputeElementAccessInfo(Handle<Map> map, AccessMode access_mode,
ElementAccessInfo* access_info) const;
base::Optional<ElementAccessInfo> ComputeElementAccessInfo(
Handle<Map> map, AccessMode access_mode) const;
bool ComputeElementAccessInfos(
FeedbackNexus nexus, MapHandles const& maps, AccessMode access_mode,
ZoneVector<ElementAccessInfo>* access_infos) const;
......@@ -192,8 +195,8 @@ class AccessInfoFactory final {
ZoneVector<PropertyAccessInfo> infos, AccessMode access_mode) const;
private:
bool ConsolidateElementLoad(ElementAccessFeedback const& processed,
ElementAccessInfo* access_info) const;
base::Optional<ElementAccessInfo> ConsolidateElementLoad(
ElementAccessFeedback const& processed) const;
PropertyAccessInfo LookupSpecialFieldAccessor(Handle<Map> map,
Handle<Name> name) const;
PropertyAccessInfo LookupTransition(Handle<Map> map, Handle<Name> name,
......
......@@ -599,7 +599,7 @@ 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);
template void CompilationDependencies::DependOnStablePrototypeChains(
ZoneHandleSet<Map> const& receiver_maps, WhereToStart start,
......
......@@ -6749,17 +6749,15 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
MapHandles const& regexp_maps = inference.GetMaps();
// Compute property access info for "exec" on {resolution}.
PropertyAccessInfo ai_exec;
{
ZoneVector<PropertyAccessInfo> access_infos(graph()->zone());
AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone());
access_info_factory.ComputePropertyAccessInfos(
MapHandles(regexp_maps.begin(), regexp_maps.end()),
factory()->exec_string(), AccessMode::kLoad, &access_infos);
ai_exec = access_info_factory.FinalizePropertyAccessInfosAsOne(
access_infos, AccessMode::kLoad);
}
ZoneVector<PropertyAccessInfo> access_infos(graph()->zone());
AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone());
access_info_factory.ComputePropertyAccessInfos(
MapHandles(regexp_maps.begin(), regexp_maps.end()),
factory()->exec_string(), AccessMode::kLoad, &access_infos);
PropertyAccessInfo ai_exec =
access_info_factory.FinalizePropertyAccessInfosAsOne(access_infos,
AccessMode::kLoad);
if (ai_exec.IsInvalid()) return inference.NoChange();
// If "exec" has been modified on {regexp}, we can't do anything.
......
......@@ -13,6 +13,7 @@
#include "src/bootstrapper.h"
#include "src/boxed-float.h"
#include "src/code-factory.h"
#include "src/compiler/access-info.h"
#include "src/compiler/graph-reducer.h"
#include "src/compiler/per-isolate-compiler-cache.h"
#include "src/objects-inl.h"
......@@ -3256,6 +3257,9 @@ bool CanInlineElementAccess(MapRef const& map) {
return false;
}
InsufficientFeedback::InsufficientFeedback()
: ProcessedFeedback(kInsufficient) {}
GlobalAccessFeedback::GlobalAccessFeedback(PropertyCellRef cell)
: ProcessedFeedback(kGlobalAccess),
cell_or_context_(cell),
......@@ -3336,6 +3340,14 @@ ElementAccessFeedback::MapIterator ElementAccessFeedback::all_maps(
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)
: vector(nexus.vector_handle()), slot(nexus.slot()) {}
......@@ -3377,6 +3389,8 @@ GlobalAccessFeedback const* JSHeapBroker::GetGlobalAccessFeedback(
ElementAccessFeedback const* JSHeapBroker::ProcessFeedbackMapsForElementAccess(
MapHandles const& maps) {
DCHECK(!maps.empty());
// Collect possible transition targets.
MapHandles possible_transition_targets;
possible_transition_targets.reserve(maps.size());
......@@ -3388,8 +3402,6 @@ ElementAccessFeedback const* JSHeapBroker::ProcessFeedbackMapsForElementAccess(
}
}
if (maps.empty()) return nullptr;
ElementAccessFeedback* result = new (zone()) ElementAccessFeedback(zone());
// Separate the actual receiver maps and the possible transition sources.
......
......@@ -37,6 +37,10 @@ class VectorSlotPair;
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 {
kNone, // Not an Oddball.
kBoolean, // True or False.
......@@ -97,6 +101,7 @@ class CompilationDependencies;
class JSHeapBroker;
class ObjectData;
class PerIsolateCompilerCache;
class PropertyAccessInfo;
#define FORWARD_DECL(Name) class Name##Ref;
HEAP_BROKER_OBJECT_LIST(FORWARD_DECL)
#undef FORWARD_DECL
......@@ -704,7 +709,7 @@ class InternalizedStringRef : public StringRef {
class ProcessedFeedback : public ZoneObject {
public:
enum Kind { kElementAccess, kGlobalAccess };
enum Kind { kInsufficient, kGlobalAccess, kNamedAccess, kElementAccess };
Kind kind() const { return kind_; }
protected:
......@@ -714,6 +719,11 @@ class ProcessedFeedback : public ZoneObject {
Kind const kind_;
};
class InsufficientFeedback final : public ProcessedFeedback {
public:
InsufficientFeedback();
};
class GlobalAccessFeedback : public ProcessedFeedback {
public:
explicit GlobalAccessFeedback(PropertyCellRef cell);
......@@ -765,6 +775,21 @@ class ElementAccessFeedback : public ProcessedFeedback {
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 {
FeedbackSource(Handle<FeedbackVector> vector_, FeedbackSlot slot_)
: vector(vector_), slot(slot_) {}
......
......@@ -41,7 +41,7 @@ namespace compiler {
namespace {
bool HasNumberMaps(JSHeapBroker* broker, MapHandles const& maps) {
bool HasNumberMaps(JSHeapBroker* broker, ZoneVector<Handle<Map>> const& maps) {
for (auto map : maps) {
MapRef map_ref(broker, map);
if (map_ref.IsHeapNumberMap()) return true;
......@@ -49,7 +49,8 @@ bool HasNumberMaps(JSHeapBroker* broker, MapHandles const& maps) {
return false;
}
bool HasOnlyJSArrayMaps(JSHeapBroker* broker, MapHandles const& maps) {
bool HasOnlyJSArrayMaps(JSHeapBroker* broker,
ZoneVector<Handle<Map>> const& maps) {
for (auto map : maps) {
MapRef map_ref(broker, map);
if (!map_ref.IsJSArrayMap()) return false;
......@@ -57,6 +58,17 @@ bool HasOnlyJSArrayMaps(JSHeapBroker* broker, MapHandles const& maps) {
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
JSNativeContextSpecialization::JSNativeContextSpecialization(
......@@ -703,17 +715,15 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) {
MapHandles const& resolution_maps = inference.GetMaps();
// Compute property access info for "then" on {resolution}.
PropertyAccessInfo access_info;
{
ZoneVector<PropertyAccessInfo> access_infos(graph()->zone());
AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone());
access_info_factory.ComputePropertyAccessInfos(
resolution_maps, factory()->then_string(), AccessMode::kLoad,
&access_infos);
access_info = access_info_factory.FinalizePropertyAccessInfosAsOne(
access_infos, AccessMode::kLoad);
}
ZoneVector<PropertyAccessInfo> access_infos(graph()->zone());
AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone());
access_info_factory.ComputePropertyAccessInfos(
resolution_maps, factory()->then_string(), AccessMode::kLoad,
&access_infos);
PropertyAccessInfo access_info =
access_info_factory.FinalizePropertyAccessInfosAsOne(access_infos,
AccessMode::kLoad);
if (access_info.IsInvalid()) return inference.NoChange();
// Only optimize when {resolution} definitely doesn't have a "then" property.
......@@ -1049,8 +1059,8 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
}
Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* node, Node* value, MapHandles const& receiver_maps,
NameRef const& name, AccessMode access_mode, Node* key) {
Node* node, Node* value, NamedAccessFeedback const& feedback,
AccessMode access_mode, Node* key) {
DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
node->opcode() == IrOpcode::kJSStoreNamed ||
node->opcode() == IrOpcode::kJSLoadProperty ||
......@@ -1063,31 +1073,27 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* effect = NodeProperties::GetEffectInput(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
// 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());
// to the current native context's global object instead.
if (access_infos.size() == 1 && access_infos[0].receiver_maps().size() == 1) {
MapRef receiver_map(broker(), access_infos[0].receiver_maps()[0]);
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) {
effect = BuildCheckEqualsName(name, key, effect, control);
effect = BuildCheckEqualsName(feedback.name(), key, effect, control);
}
// Collect call nodes to rewire exception edges.
......@@ -1141,7 +1147,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
// Generate the actual property access.
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);
value = continuation.value();
effect = continuation.effect();
......@@ -1186,7 +1192,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* this_control = fallthrough_control;
// 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
// effect to be able to learn from the control flow.
......@@ -1257,9 +1264,10 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
}
// 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);
ValueEffectControl continuation =
BuildPropertyAccess(this_receiver, this_value, context, frame_state,
this_effect, this_control, feedback.name(),
if_exceptions, access_info, access_mode);
values.push_back(continuation.value());
effects.push_back(continuation.effect());
controls.push_back(continuation.control());
......@@ -1326,18 +1334,38 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
return ReduceGlobalAccess(node, nullptr, value, name, access_mode);
}
// Extract receiver maps from the IC using the {nexus}.
MapHandles receiver_maps;
if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
return NoChange();
} else if (receiver_maps.empty()) {
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;
if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
processed = new (zone()) InsufficientFeedback();
} 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(
node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
}
DCHECK(!nexus.IsUninitialized());
// Try to lower the named access based on the {receiver_maps}.
return ReduceNamedAccess(node, value, receiver_maps, name, access_mode);
CHECK_EQ(processed->kind(), ProcessedFeedback::kNamedAccess);
return ReduceNamedAccess(node, value,
*static_cast<NamedAccessFeedback const*>(processed),
access_mode);
}
Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
......@@ -1475,7 +1503,9 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
Node* frame_state =
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,
load_mode);
}
......@@ -1624,7 +1654,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
}
// 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) {
// Last map check on the fallthrough control path, do a
// conditional eager deoptimization exit here.
......@@ -1790,15 +1821,13 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
if (reduction.Changed()) return reduction;
}
// Extract receiver maps from the {nexus}.
MapHandles receiver_maps;
if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
return NoChange();
} else if (receiver_maps.empty()) {
return ReduceSoftDeoptimize(
node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
} else if (receiver_maps.empty()) {
return NoChange();
}
DCHECK(!nexus.IsUninitialized());
// Check if we have feedback for a named access.
base::Optional<NameRef> name = GetNameFeedback(broker(), nexus);
......@@ -1819,6 +1848,268 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
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(
Node* node, DeoptimizeReason reason) {
if (!(flags() & kBailoutOnUninitialized)) return NoChange();
......@@ -2490,18 +2781,15 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreInArrayLiteral(
// Extract the keyed access store mode from the keyed store IC.
KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode();
// Extract receiver maps from the {nexus}.
MapHandles receiver_maps;
if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
return NoChange();
} else if (receiver_maps.empty()) {
return ReduceSoftDeoptimize(
node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
} else if (receiver_maps.empty()) {
return NoChange();
}
DCHECK(!nexus.IsUninitialized());
DCHECK_EQ(ELEMENT, nexus.GetKeyType());
if (nexus.ic_state() == MEGAMORPHIC) return NoChange();
DCHECK_NE(MEGAMORPHIC, nexus.ic_state());
// Try to lower the element access based on the {receiver_maps}.
return ReduceElementAccess(node, index, value, nexus, receiver_maps,
......@@ -2548,7 +2836,7 @@ JSNativeContextSpecialization::BuildElementAccess(
// TODO(bmeurer): We currently specialize based on elements kind. We should
// also be able to properly support strings and other JSObjects here.
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)) {
Node* buffer;
......@@ -3226,7 +3514,7 @@ Node* JSNativeContextSpecialization::BuildCheckEqualsName(NameRef const& name,
}
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
// or Object.prototype objects as their prototype (in any of the current
// native contexts, as the global Array protector works isolate-wide).
......@@ -3244,24 +3532,12 @@ bool JSNativeContextSpecialization::CanTreatHoleAsUndefined(
return dependencies()->DependOnNoElementsProtector();
}
namespace {
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
// Returns false iff we have insufficient feedback (uninitialized or obsolete).
bool JSNativeContextSpecialization::ExtractReceiverMaps(
Node* receiver, Node* effect, FeedbackNexus const& nexus,
MapHandles* receiver_maps) {
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
// the inference is not safe for keyed stores, because we would potentially
......@@ -3276,26 +3552,23 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps(
}
}
// Try to extract some maps from the {nexus}.
if (nexus.ExtractMaps(receiver_maps) != 0) {
// Try to filter impossible candidates based on inferred root map.
Handle<Map> root_map;
if (InferReceiverRootMap(receiver).ToHandle(&root_map)) {
DCHECK(!root_map->is_abandoned_prototype_map());
Isolate* isolate = this->isolate();
receiver_maps->erase(
std::remove_if(receiver_maps->begin(), receiver_maps->end(),
[root_map, isolate](Handle<Map> map) {
return map->is_abandoned_prototype_map() ||
map->FindRootMap(isolate) != *root_map;
}),
receiver_maps->end());
}
TryUpdateThenDropDeprecated(isolate(), receiver_maps);
return true;
}
if (nexus.ExtractMaps(receiver_maps) == 0) return true;
return false;
// Try to filter impossible candidates based on inferred root map.
Handle<Map> root_map;
if (InferReceiverRootMap(receiver).ToHandle(&root_map)) {
DCHECK(!root_map->is_abandoned_prototype_map());
Isolate* isolate = this->isolate();
receiver_maps->erase(
std::remove_if(receiver_maps->begin(), receiver_maps->end(),
[root_map, isolate](Handle<Map> map) {
return map->is_abandoned_prototype_map() ||
map->FindRootMap(isolate) != *root_map;
}),
receiver_maps->end());
}
TryUpdateThenDropDeprecated(isolate(), receiver_maps);
return !receiver_maps->empty();
}
bool JSNativeContextSpecialization::InferReceiverMaps(
......
......@@ -107,10 +107,15 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
FeedbackNexus const& nexus,
NameRef const& name,
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,
MapHandles const& receiver_maps,
NameRef const& name, AccessMode access_mode,
Node* key = nullptr);
Node* key);
Reduction ReduceGlobalAccess(Node* node, Node* receiver, Node* value,
NameRef const& name, AccessMode access_mode,
Node* key = nullptr);
......@@ -214,7 +219,7 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
// 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
// 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
// possible.
......
......@@ -1248,8 +1248,8 @@ struct SerializationPhase {
void Run(PipelineData* data, Zone* temp_zone) {
SerializerForBackgroundCompilation serializer(
data->broker(), temp_zone, data->info()->closure(),
data->info()->is_source_positions_enabled());
data->broker(), data->dependencies(), temp_zone,
data->info()->closure(), data->info()->is_source_positions_enabled());
serializer.Run();
}
};
......
......@@ -32,7 +32,8 @@ SimplifiedOperatorBuilder* PropertyAccessBuilder::simplified() const {
return jsgraph()->simplified();
}
bool HasOnlyStringMaps(JSHeapBroker* broker, MapHandles const& maps) {
bool HasOnlyStringMaps(JSHeapBroker* broker,
ZoneVector<Handle<Map>> const& maps) {
for (auto map : maps) {
MapRef map_ref(broker, map);
if (!map_ref.IsStringMap()) return false;
......@@ -42,7 +43,8 @@ bool HasOnlyStringMaps(JSHeapBroker* broker, MapHandles const& maps) {
namespace {
bool HasOnlyNumberMaps(JSHeapBroker* broker, MapHandles const& maps) {
bool HasOnlyNumberMaps(JSHeapBroker* broker,
ZoneVector<Handle<Map>> const& maps) {
for (auto map : maps) {
MapRef map_ref(broker, map);
if (map_ref.instance_type() != HEAP_NUMBER_TYPE) return false;
......@@ -52,10 +54,9 @@ bool HasOnlyNumberMaps(JSHeapBroker* broker, MapHandles const& maps) {
} // namespace
bool PropertyAccessBuilder::TryBuildStringCheck(JSHeapBroker* broker,
MapHandles const& maps,
Node** receiver, Node** effect,
Node* control) {
bool PropertyAccessBuilder::TryBuildStringCheck(
JSHeapBroker* broker, ZoneVector<Handle<Map>> const& maps, Node** receiver,
Node** effect, Node* control) {
if (HasOnlyStringMaps(broker, maps)) {
// Monormorphic string access (ignoring the fact that there are multiple
// String maps).
......@@ -67,10 +68,9 @@ bool PropertyAccessBuilder::TryBuildStringCheck(JSHeapBroker* broker,
return false;
}
bool PropertyAccessBuilder::TryBuildNumberCheck(JSHeapBroker* broker,
MapHandles const& maps,
Node** receiver, Node** effect,
Node* control) {
bool PropertyAccessBuilder::TryBuildNumberCheck(
JSHeapBroker* broker, ZoneVector<Handle<Map>> const& maps, Node** receiver,
Node** effect, Node* control) {
if (HasOnlyNumberMaps(broker, maps)) {
// Monomorphic number access (we also deal with Smis here).
*receiver = *effect =
......@@ -143,9 +143,9 @@ Node* PropertyAccessBuilder::BuildCheckHeapObject(Node* receiver, Node** effect,
return receiver;
}
void PropertyAccessBuilder::BuildCheckMaps(Node* receiver, Node** effect,
Node* control,
MapHandles const& receiver_maps) {
void PropertyAccessBuilder::BuildCheckMaps(
Node* receiver, Node** effect, Node* control,
ZoneVector<Handle<Map>> const& receiver_maps) {
HeapObjectMatcher m(receiver);
if (m.HasValue()) {
MapRef receiver_map = m.Ref(broker()).map();
......
......@@ -33,15 +33,17 @@ class PropertyAccessBuilder {
// Builds the appropriate string check if the maps are only string
// maps.
bool TryBuildStringCheck(JSHeapBroker* broker, MapHandles const& maps,
Node** receiver, Node** effect, Node* control);
bool TryBuildStringCheck(JSHeapBroker* broker,
ZoneVector<Handle<Map>> const& maps, Node** receiver,
Node** effect, Node* control);
// Builds a number check if all maps are number maps.
bool TryBuildNumberCheck(JSHeapBroker* broker, MapHandles const& maps,
Node** receiver, Node** effect, Node* control);
bool TryBuildNumberCheck(JSHeapBroker* broker,
ZoneVector<Handle<Map>> const& maps, Node** receiver,
Node** effect, Node* control);
Node* BuildCheckHeapObject(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,
Handle<HeapObject> value);
......@@ -72,7 +74,8 @@ class PropertyAccessBuilder {
CompilationDependencies* dependencies_;
};
bool HasOnlyStringMaps(JSHeapBroker* broker, MapHandles const& maps);
bool HasOnlyStringMaps(JSHeapBroker* broker,
ZoneVector<Handle<Map>> const& maps);
} // namespace compiler
} // namespace internal
......
......@@ -247,9 +247,10 @@ int SerializerForBackgroundCompilation::Environment::RegisterToLocalIndex(
}
SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
JSHeapBroker* broker, Zone* zone, Handle<JSFunction> closure,
bool collect_source_positions)
JSHeapBroker* broker, CompilationDependencies* dependencies, Zone* zone,
Handle<JSFunction> closure, bool collect_source_positions)
: broker_(broker),
dependencies_(dependencies),
zone_(zone),
collect_source_positions_(collect_source_positions),
environment_(new (zone) Environment(zone, {closure, broker_->isolate()})),
......@@ -258,10 +259,11 @@ SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
}
SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
JSHeapBroker* broker, Zone* zone, CompilationSubject function,
base::Optional<Hints> new_target, const HintsVector& arguments,
bool collect_source_positions)
JSHeapBroker* broker, CompilationDependencies* dependencies, Zone* zone,
CompilationSubject function, base::Optional<Hints> new_target,
const HintsVector& arguments, bool collect_source_positions)
: broker_(broker),
dependencies_(dependencies),
zone_(zone),
collect_source_positions_(collect_source_positions),
environment_(new (zone) Environment(zone, broker_->isolate(), function,
......@@ -580,7 +582,7 @@ Hints SerializerForBackgroundCompilation::RunChildSerializer(
<< *environment());
SerializerForBackgroundCompilation child_serializer(
broker(), zone(), function, new_target, arguments,
broker(), dependencies(), zone(), function, new_target, arguments,
collect_source_positions());
return child_serializer.Run();
}
......@@ -790,32 +792,12 @@ MapHandles GetRelevantReceiverMaps(Isolate* isolate, MapContainer const& maps) {
}
} // namespace
// Note: We never use the same feedback slot for multiple access modes.
void SerializerForBackgroundCompilation::ProcessFeedbackForKeyedPropertyAccess(
FeedbackSlot slot, AccessMode mode) {
if (slot.IsInvalid()) return;
if (environment()->function().feedback_vector.is_null()) return;
FeedbackNexus nexus(environment()->function().feedback_vector, slot);
FeedbackSource source(nexus);
if (broker()->HasFeedback(source)) return;
if (nexus.GetKeyType() == PROPERTY) {
CHECK_NE(mode, AccessMode::kStoreInLiteral);
return; // TODO(neis): Support named access.
}
DCHECK_EQ(nexus.GetKeyType(), ELEMENT);
CHECK(nexus.GetName().is_null());
MapHandles maps;
nexus.ExtractMaps(&maps);
ElementAccessFeedback const* processed =
broker()->ProcessFeedbackMapsForElementAccess(
GetRelevantReceiverMaps(broker()->isolate(), maps));
broker()->SetFeedback(source, processed);
if (processed == nullptr) return;
for (ElementAccessFeedback::MapIterator it = processed->all_maps(broker());
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:
......@@ -830,6 +812,41 @@ void SerializerForBackgroundCompilation::ProcessFeedbackForKeyedPropertyAccess(
break;
}
}
return result;
}
// Note: We never use the same feedback slot for multiple access modes.
void SerializerForBackgroundCompilation::ProcessFeedbackForKeyedPropertyAccess(
FeedbackSlot slot, AccessMode mode) {
if (slot.IsInvalid()) return;
if (environment()->function().feedback_vector.is_null()) return;
FeedbackNexus nexus(environment()->function().feedback_vector, slot);
FeedbackSource source(nexus);
if (broker()->HasFeedback(source)) return;
ProcessedFeedback const* processed = nullptr;
if (nexus.ic_state() == UNINITIALIZED) {
processed = new (broker()->zone()) InsufficientFeedback();
} else {
if (nexus.GetKeyType() == PROPERTY) {
CHECK_NE(mode, AccessMode::kStoreInLiteral);
// TODO(neis): Support named access.
} else {
DCHECK_EQ(nexus.GetKeyType(), ELEMENT);
DCHECK(nexus.GetName().is_null());
MapHandles maps;
if (nexus.ExtractMaps(&maps) != 0) {
maps = GetRelevantReceiverMaps(broker()->isolate(), maps);
if (maps.empty()) {
processed = new (broker()->zone()) InsufficientFeedback();
} else {
processed = ProcessFeedbackMapsForElementAccess(maps, mode);
}
}
}
}
broker()->SetFeedback(source, processed);
}
void SerializerForBackgroundCompilation::ProcessKeyedPropertyAccess(
......@@ -878,7 +895,7 @@ void SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess(
// Note: We never use the same feedback slot for multiple names.
void SerializerForBackgroundCompilation::ProcessFeedbackForNamedPropertyAccess(
FeedbackSlot slot, NameRef const& name) {
FeedbackSlot slot, NameRef const& name, AccessMode mode) {
if (slot.IsInvalid()) return;
if (environment()->function().feedback_vector.is_null()) return;
......@@ -886,15 +903,31 @@ void SerializerForBackgroundCompilation::ProcessFeedbackForNamedPropertyAccess(
FeedbackSource source(nexus);
if (broker()->HasFeedback(source)) return;
MapHandles maps;
nexus.ExtractMaps(&maps);
for (Handle<Map> map : GetRelevantReceiverMaps(broker()->isolate(), maps)) {
ProcessMapForNamedPropertyAccess(MapRef(broker(), map), name);
ProcessedFeedback const* processed = nullptr;
if (nexus.ic_state() == UNINITIALIZED) {
processed = new (broker()->zone()) InsufficientFeedback();
} else {
MapHandles maps;
if (nexus.ExtractMaps(&maps) != 0) {
ZoneVector<PropertyAccessInfo> access_infos(broker()->zone());
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()) {
processed = new (broker()->zone()) InsufficientFeedback();
} else {
processed =
new (broker()->zone()) NamedAccessFeedback(name, access_infos);
}
}
}
// NamedProperty support is still WIP. For now we don't have any actual data
// to store, so use nullptr to at least record that we processed the feedback.
broker()->SetFeedback(source, nullptr);
broker()->SetFeedback(source, processed);
}
void SerializerForBackgroundCompilation::VisitLdaKeyedProperty(
......@@ -909,7 +942,7 @@ void SerializerForBackgroundCompilation::VisitLdaKeyedProperty(
void SerializerForBackgroundCompilation::ProcessNamedPropertyAccess(
Hints const& receiver, NameRef const& name, FeedbackSlot slot,
AccessMode mode) {
if (!slot.IsInvalid()) ProcessFeedbackForNamedPropertyAccess(slot, name);
ProcessFeedbackForNamedPropertyAccess(slot, name, mode);
for (Handle<Map> map :
GetRelevantReceiverMaps(broker()->isolate(), receiver.maps())) {
......@@ -956,6 +989,11 @@ void SerializerForBackgroundCompilation::VisitStaNamedProperty(
ProcessNamedPropertyAccess(iterator, AccessMode::kStore);
}
void SerializerForBackgroundCompilation::VisitStaNamedOwnProperty(
BytecodeArrayIterator* iterator) {
ProcessNamedPropertyAccess(iterator, AccessMode::kStoreInLiteral);
}
void SerializerForBackgroundCompilation::VisitTestIn(
BytecodeArrayIterator* iterator) {
Hints const& receiver = environment()->accumulator_hints();
......
......@@ -189,6 +189,7 @@ namespace compiler {
V(StaGlobal) \
V(StaInArrayLiteral) \
V(StaKeyedProperty) \
V(StaNamedOwnProperty) \
V(StaNamedProperty) \
V(Star) \
V(TestIn) \
......@@ -270,16 +271,18 @@ using HintsVector = ZoneVector<Hints>;
// optimizations in the compiler, is copied to the heap broker.
class SerializerForBackgroundCompilation {
public:
SerializerForBackgroundCompilation(JSHeapBroker* broker, Zone* zone,
Handle<JSFunction> closure,
SerializerForBackgroundCompilation(JSHeapBroker* broker,
CompilationDependencies* dependencies,
Zone* zone, Handle<JSFunction> closure,
bool collect_source_positions);
Hints Run(); // NOTE: Returns empty for an already-serialized function.
class Environment;
private:
SerializerForBackgroundCompilation(JSHeapBroker* broker, Zone* zone,
CompilationSubject function,
SerializerForBackgroundCompilation(JSHeapBroker* broker,
CompilationDependencies* dependencies,
Zone* zone, CompilationSubject function,
base::Optional<Hints> new_target,
const HintsVector& arguments,
bool collect_source_positions);
......@@ -311,8 +314,11 @@ class SerializerForBackgroundCompilation {
GlobalAccessFeedback const* ProcessFeedbackForGlobalAccess(FeedbackSlot slot);
void ProcessFeedbackForKeyedPropertyAccess(FeedbackSlot slot,
AccessMode mode);
ElementAccessFeedback const* ProcessFeedbackMapsForElementAccess(
const MapHandles& maps, AccessMode mode);
void ProcessFeedbackForNamedPropertyAccess(FeedbackSlot slot,
NameRef const& name);
NameRef const& name,
AccessMode mode);
void ProcessMapForNamedPropertyAccess(MapRef const& map, NameRef const& name);
Hints RunChildSerializer(CompilationSubject function,
......@@ -320,6 +326,7 @@ class SerializerForBackgroundCompilation {
const HintsVector& arguments, bool with_spread);
JSHeapBroker* broker() const { return broker_; }
CompilationDependencies* dependencies() const { return dependencies_; }
Zone* zone() const { return zone_; }
// The following flag is initialized from OptimizedCompilationInfo's
// {is_source_positions_enabled}.
......@@ -327,6 +334,7 @@ class SerializerForBackgroundCompilation {
Environment* environment() const { return environment_; }
JSHeapBroker* const broker_;
CompilationDependencies* const dependencies_;
Zone* const zone_;
bool const collect_source_positions_;
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