Commit 1277bb5c authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[compiler] Support GetPropertyAccessInfo in a concurrent setting

Until this CL, the JSHeapBroker::GetPropertyAccessInfo (GPAI) process
was as follows:

 1. GPAI is called on the main thread (MT) during the serialization
    phase to create and cache PAIs.
 2. GPAI is called again from the background thread (BT); only cached
    PAIs from step 1 are usable.

As part of concurrent inlining, the goal is to move GPAI fully to the
background thread. This CL takes a major step in that direction by
making GPAI itself callable from the BT without resorting solely to PAIs
that were previously cached on the MT.

There are two main reasons why GPAI previously had to run on the MT:

 a) Concurrent access to Maps and other heap objects.
 b) Serialization and creation of ObjectRefs for objects discovered
    during GPAI.

This CL addresses only reason a) and leaves b) for future work. This
is done by keeping the two-pass approach, s.t. the initial call of
GPAI on the MT discovers and serializes objects. We then clear all
cached PAIs. The second call of GPAI on the BT thus runs full logic in a
concurrent setting.

Once all relevant objects (= maps and prototypes) no longer require
MT-serialization, reason b) is also addressed and the first pass can be
removed.

The new logic is implemented behind the runtime flag
--turbo-concurrent-get-property-access-info (default true), intended
to be removed in the future.

Bug: v8:7790
Change-Id: Idbdbfe091d7316529246a686bb6d71c2a0f06f8b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2817793
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Auto-Submit: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74120}
parent 0499aa54
...@@ -384,8 +384,11 @@ AccessInfoFactory::AccessInfoFactory(JSHeapBroker* broker, ...@@ -384,8 +384,11 @@ AccessInfoFactory::AccessInfoFactory(JSHeapBroker* broker,
base::Optional<ElementAccessInfo> AccessInfoFactory::ComputeElementAccessInfo( base::Optional<ElementAccessInfo> AccessInfoFactory::ComputeElementAccessInfo(
Handle<Map> map, AccessMode access_mode) const { Handle<Map> map, AccessMode access_mode) const {
ObjectData* data = broker()->TryGetOrCreateData(map);
if (data == nullptr) return {};
// 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(), data);
if (!CanInlineElementAccess(map_ref)) return base::nullopt; if (!CanInlineElementAccess(map_ref)) return base::nullopt;
ElementsKind const elements_kind = map_ref.elements_kind(); ElementsKind const elements_kind = map_ref.elements_kind();
return ElementAccessInfo({{map}, zone()}, elements_kind, zone()); return ElementAccessInfo({{map}, zone()}, elements_kind, zone());
...@@ -438,15 +441,21 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo( ...@@ -438,15 +441,21 @@ 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 PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
FieldIndex field_index = FieldIndex field_index =
FieldIndex::ForPropertyIndex(*map, index, details_representation); FieldIndex::ForPropertyIndex(*map, index, details_representation);
Type field_type = Type::NonInternal(); Type field_type = Type::NonInternal();
MaybeHandle<Map> field_map; MaybeHandle<Map> field_map;
MapRef map_ref(broker(), map);
ObjectData* data = broker()->TryGetOrCreateData(map);
if (data == nullptr) return Invalid();
MapRef map_ref(broker(), data);
ZoneVector<CompilationDependency const*> unrecorded_dependencies(zone()); ZoneVector<CompilationDependency const*> unrecorded_dependencies(zone());
map_ref.SerializeOwnDescriptor(descriptor); if (!map_ref.TrySerializeOwnDescriptor(descriptor)) {
return Invalid();
}
if (details_representation.IsSmi()) { if (details_representation.IsSmi()) {
field_type = Type::SignedSmall(); field_type = Type::SignedSmall();
unrecorded_dependencies.push_back( unrecorded_dependencies.push_back(
...@@ -460,12 +469,13 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo( ...@@ -460,12 +469,13 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
} else if (details_representation.IsHeapObject()) { } else if (details_representation.IsHeapObject()) {
// Extract the field type from the property details (make sure its // Extract the field type from the property details (make sure its
// representation is TaggedPointer to reflect the heap object case). // representation is TaggedPointer to reflect the heap object case).
Handle<FieldType> descriptors_field_type( Handle<FieldType> descriptors_field_type =
descriptors->GetFieldType(descriptor), isolate()); broker()->CanonicalPersistentHandle(
descriptors->GetFieldType(descriptor));
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) { if (access_mode == AccessMode::kStore) {
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
// 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
...@@ -476,8 +486,11 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo( ...@@ -476,8 +486,11 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
descriptor)); descriptor));
if (descriptors_field_type->IsClass()) { if (descriptors_field_type->IsClass()) {
// Remember the field map, and try to infer a useful type. // Remember the field map, and try to infer a useful type.
Handle<Map> map(descriptors_field_type->AsClass(), isolate()); Handle<Map> map = broker()->CanonicalPersistentHandle(
field_type = Type::For(MapRef(broker(), map)); descriptors_field_type->AsClass());
ObjectData* data = broker()->TryGetOrCreateData(map);
if (data == nullptr) return Invalid();
field_type = Type::For(MapRef(broker(), data));
field_map = MaybeHandle<Map>(map); field_map = MaybeHandle<Map>(map);
} }
} else { } else {
...@@ -497,11 +510,11 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo( ...@@ -497,11 +510,11 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
// of turboprop. // of turboprop.
constness = PropertyConstness::kMutable; constness = PropertyConstness::kMutable;
} else { } else {
map_ref.SerializeOwnDescriptor(descriptor);
constness = dependencies()->DependOnFieldConstness(map_ref, descriptor); constness = dependencies()->DependOnFieldConstness(map_ref, descriptor);
} }
Handle<Map> field_owner_map(map->FindFieldOwner(isolate(), descriptor), // TODO(v8:11670): Make FindFieldOwner and friends robust wrt concurrency.
isolate()); Handle<Map> field_owner_map = broker()->CanonicalPersistentHandle(
map->FindFieldOwner(isolate(), descriptor));
switch (constness) { switch (constness) {
case PropertyConstness::kMutable: case PropertyConstness::kMutable:
return PropertyAccessInfo::DataField( return PropertyAccessInfo::DataField(
...@@ -527,13 +540,14 @@ PropertyAccessInfo AccessorAccessInfoHelper( ...@@ -527,13 +540,14 @@ PropertyAccessInfo AccessorAccessInfoHelper(
AccessMode access_mode, AccessorsObjectGetter get_accessors) { AccessMode access_mode, AccessorsObjectGetter get_accessors) {
if (map->instance_type() == JS_MODULE_NAMESPACE_TYPE) { if (map->instance_type() == JS_MODULE_NAMESPACE_TYPE) {
DCHECK(map->is_prototype_map()); DCHECK(map->is_prototype_map());
Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(map->prototype_info()), Handle<PrototypeInfo> proto_info = broker->CanonicalPersistentHandle(
isolate); PrototypeInfo::cast(map->prototype_info()));
Handle<JSModuleNamespace> module_namespace( Handle<JSModuleNamespace> module_namespace =
JSModuleNamespace::cast(proto_info->module_namespace()), isolate); broker->CanonicalPersistentHandle(
Handle<Cell> cell(Cell::cast(module_namespace->module().exports().Lookup( JSModuleNamespace::cast(proto_info->module_namespace()));
isolate, name, Smi::ToInt(name->GetHash()))), Handle<Cell> cell = broker->CanonicalPersistentHandle(
isolate); Cell::cast(module_namespace->module().exports().Lookup(
isolate, name, Smi::ToInt(name->GetHash()))));
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 PropertyAccessInfo::Invalid(zone); return PropertyAccessInfo::Invalid(zone);
...@@ -548,16 +562,20 @@ PropertyAccessInfo AccessorAccessInfoHelper( ...@@ -548,16 +562,20 @@ PropertyAccessInfo AccessorAccessInfoHelper(
return PropertyAccessInfo::FastAccessorConstant(zone, receiver_map, return PropertyAccessInfo::FastAccessorConstant(zone, receiver_map,
Handle<Object>(), holder); Handle<Object>(), holder);
} }
Handle<Object> accessors = get_accessors(); Handle<Object> maybe_accessors = get_accessors();
if (!accessors->IsAccessorPair()) { if (!maybe_accessors->IsAccessorPair()) {
return PropertyAccessInfo::Invalid(zone); return PropertyAccessInfo::Invalid(zone);
} }
Handle<Object> accessor(access_mode == AccessMode::kLoad Handle<AccessorPair> accessors = Handle<AccessorPair>::cast(maybe_accessors);
? Handle<AccessorPair>::cast(accessors)->getter() Handle<Object> accessor = broker->CanonicalPersistentHandle(
: Handle<AccessorPair>::cast(accessors)->setter(), access_mode == AccessMode::kLoad ? accessors->getter()
isolate); : accessors->setter());
ObjectData* data = broker->TryGetOrCreateData(accessor);
if (data == nullptr) return PropertyAccessInfo::Invalid(zone);
if (!accessor->IsJSFunction()) { if (!accessor->IsJSFunction()) {
CallOptimization optimization(isolate, accessor); CallOptimization optimization(broker->local_isolate_or_isolate(), accessor);
if (!optimization.is_simple_api_call() || if (!optimization.is_simple_api_call() ||
optimization.IsCrossContextLazyAccessorPair( optimization.IsCrossContextLazyAccessorPair(
*broker->target_native_context().object(), *map)) { *broker->target_native_context().object(), *map)) {
...@@ -565,7 +583,9 @@ PropertyAccessInfo AccessorAccessInfoHelper( ...@@ -565,7 +583,9 @@ PropertyAccessInfo AccessorAccessInfoHelper(
} }
CallOptimization::HolderLookup lookup; CallOptimization::HolderLookup lookup;
holder = optimization.LookupHolderOfExpectedType(receiver_map, &lookup); holder = broker->CanonicalPersistentHandle(
optimization.LookupHolderOfExpectedType(
broker->local_isolate_or_isolate(), receiver_map, &lookup));
if (lookup == CallOptimization::kHolderNotFound) { if (lookup == CallOptimization::kHolderNotFound) {
return PropertyAccessInfo::Invalid(zone); return PropertyAccessInfo::Invalid(zone);
} }
...@@ -574,9 +594,11 @@ PropertyAccessInfo AccessorAccessInfoHelper( ...@@ -574,9 +594,11 @@ PropertyAccessInfo AccessorAccessInfoHelper(
DCHECK_IMPLIES(lookup == CallOptimization::kHolderFound, !holder.is_null()); DCHECK_IMPLIES(lookup == CallOptimization::kHolderFound, !holder.is_null());
} }
if (access_mode == AccessMode::kLoad) { if (access_mode == AccessMode::kLoad) {
Handle<Name> cached_property_name; base::Optional<Name> maybe_cached_property_name =
if (FunctionTemplateInfo::TryGetCachedPropertyName(isolate, accessor) FunctionTemplateInfo::TryGetCachedPropertyName(isolate, *accessor);
.ToHandle(&cached_property_name)) { if (maybe_cached_property_name.has_value()) {
Handle<Name> cached_property_name =
broker->CanonicalPersistentHandle(maybe_cached_property_name.value());
PropertyAccessInfo access_info = ai_factory->ComputePropertyAccessInfo( PropertyAccessInfo access_info = ai_factory->ComputePropertyAccessInfo(
map, cached_property_name, access_mode); map, cached_property_name, access_mode);
if (!access_info.IsInvalid()) return access_info; if (!access_info.IsInvalid()) return access_info;
...@@ -598,12 +620,13 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo( ...@@ -598,12 +620,13 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo(
MaybeHandle<JSObject> holder, InternalIndex descriptor, MaybeHandle<JSObject> holder, InternalIndex descriptor,
AccessMode access_mode) const { AccessMode access_mode) const {
DCHECK(descriptor.is_found()); DCHECK(descriptor.is_found());
Handle<DescriptorArray> descriptors( Handle<DescriptorArray> descriptors = broker()->CanonicalPersistentHandle(
holder_map->instance_descriptors(kRelaxedLoad), isolate()); holder_map->instance_descriptors(kRelaxedLoad));
SLOW_DCHECK(descriptor == descriptors->Search(*name, *holder_map)); SLOW_DCHECK(descriptor == descriptors->Search(*name, *holder_map));
auto get_accessors = [&]() { auto get_accessors = [&]() {
return handle(descriptors->GetStrongValue(descriptor), isolate()); return broker()->CanonicalPersistentHandle(
descriptors->GetStrongValue(descriptor));
}; };
return AccessorAccessInfoHelper(isolate(), zone(), broker(), this, return AccessorAccessInfoHelper(isolate(), zone(), broker(), this,
receiver_map, name, holder_map, holder, receiver_map, name, holder_map, holder,
...@@ -620,7 +643,7 @@ PropertyAccessInfo AccessInfoFactory::ComputeDictionaryProtoAccessInfo( ...@@ -620,7 +643,7 @@ PropertyAccessInfo AccessInfoFactory::ComputeDictionaryProtoAccessInfo(
// We can only inline accesses to constant properties. // We can only inline accesses to constant properties.
if (details.constness() != PropertyConstness::kConst) { if (details.constness() != PropertyConstness::kConst) {
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
if (details.kind() == PropertyKind::kData) { if (details.kind() == PropertyKind::kData) {
...@@ -631,7 +654,7 @@ PropertyAccessInfo AccessInfoFactory::ComputeDictionaryProtoAccessInfo( ...@@ -631,7 +654,7 @@ PropertyAccessInfo AccessInfoFactory::ComputeDictionaryProtoAccessInfo(
auto get_accessors = [&]() { auto get_accessors = [&]() {
return JSObject::DictionaryPropertyAt(holder, dictionary_index); return JSObject::DictionaryPropertyAt(holder, dictionary_index);
}; };
Handle<Map> holder_map = handle(holder->map(), isolate()); Handle<Map> holder_map = broker()->CanonicalPersistentHandle(holder->map());
return AccessorAccessInfoHelper(isolate(), zone(), broker(), this, return AccessorAccessInfoHelper(isolate(), zone(), broker(), this,
receiver_map, name, holder_map, holder, receiver_map, name, holder_map, holder,
access_mode, get_accessors); access_mode, get_accessors);
...@@ -704,12 +727,12 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -704,12 +727,12 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
MapUpdaterMutexDepthScope mumd_scope(this); MapUpdaterMutexDepthScope mumd_scope(this);
if (access_mode == AccessMode::kHas && !map->IsJSReceiverMap()) { if (access_mode == AccessMode::kHas && !map->IsJSReceiverMap()) {
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
// 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, access_mode)) { if (!CanInlinePropertyAccess(map, access_mode)) {
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
// We support fast inline cases for certain JSObject getters. // We support fast inline cases for certain JSObject getters.
...@@ -729,7 +752,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -729,7 +752,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
PropertyDetails details = PropertyDetails::Empty(); PropertyDetails details = PropertyDetails::Empty();
InternalIndex index = InternalIndex::NotFound(); InternalIndex index = InternalIndex::NotFound();
if (!TryLoadPropertyDetails(map, holder, name, &index, &details)) { if (!TryLoadPropertyDetails(map, holder, name, &index, &details)) {
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
if (index.is_found()) { if (index.is_found()) {
...@@ -739,7 +762,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -739,7 +762,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// Don't bother optimizing stores to read-only properties. // Don't bother optimizing stores to read-only properties.
if (details.IsReadOnly()) { if (details.IsReadOnly()) {
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
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
...@@ -758,7 +781,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -758,7 +781,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// reaching a dictionary mode prototype holding the property . Due to // reaching a dictionary mode prototype holding the property . Due to
// this only being an intermediate state, we don't stupport these kind // this only being an intermediate state, we don't stupport these kind
// of heterogenous prototype chains. // of heterogenous prototype chains.
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
// TryLoadPropertyDetails only succeeds if we know the holder. // TryLoadPropertyDetails only succeeds if we know the holder.
...@@ -781,7 +804,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -781,7 +804,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// due to the complications of checking dictionary mode prototypes for // due to the complications of checking dictionary mode prototypes for
// modification, we don't attempt to support dictionary mode prototypes // modification, we don't attempt to support dictionary mode prototypes
// occuring before a fast mode holder on the chain. // occuring before a fast mode holder on the chain.
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
if (details.location() == kField) { if (details.location() == kField) {
if (details.kind() == kData) { if (details.kind() == kData) {
...@@ -790,7 +813,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -790,7 +813,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 PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
} else { } else {
DCHECK_EQ(kDescriptor, details.location()); DCHECK_EQ(kDescriptor, details.location());
...@@ -806,9 +829,17 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -806,9 +829,17 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// Don't search on the prototype chain for special indices in case of // Don't search on the prototype chain for special indices in case of
// 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))) { if (broker()->IsMainThread()) {
return PropertyAccessInfo::Invalid(zone()); if (IsSpecialIndex(String::cast(*name))) {
return Invalid();
}
} else {
// TODO(jgruber): We are being conservative here since we can't access
// string contents from background threads. Should that become possible
// in the future, remove this bailout.
return Invalid();
}
} }
// Don't search on the prototype when storing in literals. // Don't search on the prototype when storing in literals.
...@@ -818,7 +849,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -818,7 +849,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// Don't lookup private symbols on the prototype chain. // Don't lookup private symbols on the prototype chain.
if (name->IsPrivate()) { if (name->IsPrivate()) {
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
if (V8_DICT_PROPERTY_CONST_TRACKING_BOOL && !holder.is_null()) { if (V8_DICT_PROPERTY_CONST_TRACKING_BOOL && !holder.is_null()) {
...@@ -833,21 +864,30 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -833,21 +864,30 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
} }
// Walk up the prototype chain. // Walk up the prototype chain.
MapRef(broker(), map).SerializePrototype(); ObjectData* data = broker()->TryGetOrCreateData(
map, false, ObjectRef::BackgroundSerialization::kAllowed);
if (data == nullptr) return Invalid();
if (!MapRef(broker(), data).TrySerializePrototype()) {
return Invalid();
}
// Acquire synchronously the map's prototype's map to guarantee that every // Acquire synchronously the map's prototype's map to guarantee that every
// time we use it, we use the same Map. // time we use it, we use the same Map.
Handle<Map> map_prototype_map(map->prototype().synchronized_map(), Handle<Map> map_prototype_map = broker()->CanonicalPersistentHandle(
isolate()); map->prototype().synchronized_map());
if (!map_prototype_map->IsJSObjectMap()) { if (!map_prototype_map->IsJSObjectMap()) {
// Perform the implicit ToObject for primitives here. // Perform the implicit ToObject for primitives here.
// Implemented according to ES6 section 7.3.2 GetV (V, P). // Implemented according to ES6 section 7.3.2 GetV (V, P).
Handle<JSFunction> constructor; Handle<JSFunction> constructor;
if (Map::GetConstructorFunction( base::Optional<JSFunction> maybe_constructor =
map, broker()->target_native_context().object()) Map::GetConstructorFunction(
.ToHandle(&constructor)) { *map, *broker()->target_native_context().object());
map = handle(constructor->initial_map(), isolate()); if (maybe_constructor.has_value()) {
map_prototype_map = map = broker()->CanonicalPersistentHandle(
handle(map->prototype().synchronized_map(), isolate()); maybe_constructor->initial_map());
map_prototype_map = broker()->CanonicalPersistentHandle(
map->prototype().synchronized_map());
DCHECK(map_prototype_map->IsJSObjectMap()); DCHECK(map_prototype_map->IsJSObjectMap());
} else if (map->prototype().IsNull()) { } else if (map->prototype().IsNull()) {
if (dictionary_prototype_on_chain) { if (dictionary_prototype_on_chain) {
...@@ -856,7 +896,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -856,7 +896,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// with dictionary mode prototypes on the chain, either. This is again // with dictionary mode prototypes on the chain, either. This is again
// just due to how we currently deal with dependencies for dictionary // just due to how we currently deal with dependencies for dictionary
// properties during finalization. // properties during finalization.
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
// Store to property not found on the receiver or any prototype, we need // Store to property not found on the receiver or any prototype, we need
...@@ -870,16 +910,17 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -870,16 +910,17 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// 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(zone(), receiver_map, holder); return PropertyAccessInfo::NotFound(zone(), receiver_map, holder);
} else { } else {
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
} }
holder = handle(JSObject::cast(map->prototype()), isolate()); holder =
broker()->CanonicalPersistentHandle(JSObject::cast(map->prototype()));
map = map_prototype_map; map = map_prototype_map;
CHECK(!map->is_deprecated()); CHECK(!map->is_deprecated());
if (!CanInlinePropertyAccess(map, access_mode)) { if (!CanInlinePropertyAccess(map, access_mode)) {
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
// Successful lookup on prototype chain needs to guarantee that all the // Successful lookup on prototype chain needs to guarantee that all the
...@@ -901,7 +942,7 @@ PropertyAccessInfo AccessInfoFactory::FinalizePropertyAccessInfosAsOne( ...@@ -901,7 +942,7 @@ PropertyAccessInfo AccessInfoFactory::FinalizePropertyAccessInfosAsOne(
return result; return result;
} }
} }
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
void AccessInfoFactory::ComputePropertyAccessInfos( void AccessInfoFactory::ComputePropertyAccessInfos(
...@@ -982,14 +1023,19 @@ base::Optional<ElementAccessInfo> AccessInfoFactory::ConsolidateElementLoad( ...@@ -982,14 +1023,19 @@ base::Optional<ElementAccessInfo> AccessInfoFactory::ConsolidateElementLoad(
if (feedback.transition_groups().empty()) return base::nullopt; if (feedback.transition_groups().empty()) return base::nullopt;
DCHECK(!feedback.transition_groups().front().empty()); DCHECK(!feedback.transition_groups().front().empty());
MapRef first_map(broker(), feedback.transition_groups().front().front()); ObjectData* data = broker()->TryGetOrCreateData(
feedback.transition_groups().front().front());
if (data == nullptr) return {};
MapRef first_map(broker(), data);
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();
ZoneVector<Handle<Map>> maps(zone()); ZoneVector<Handle<Map>> maps(zone());
for (auto const& group : feedback.transition_groups()) { for (auto const& group : feedback.transition_groups()) {
for (Handle<Map> map_handle : group) { for (Handle<Map> map_handle : group) {
MapRef map(broker(), map_handle); ObjectData* data = broker()->TryGetOrCreateData(map_handle);
if (data == nullptr) return {};
MapRef map(broker(), data);
if (map.instance_type() != instance_type || if (map.instance_type() != instance_type ||
!CanInlineElementAccess(map)) { !CanInlineElementAccess(map)) {
return base::nullopt; return base::nullopt;
...@@ -1012,7 +1058,7 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor( ...@@ -1012,7 +1058,7 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor(
if (Name::Equals(isolate(), name, isolate()->factory()->length_string())) { if (Name::Equals(isolate(), name, isolate()->factory()->length_string())) {
return PropertyAccessInfo::StringLength(zone(), map); return PropertyAccessInfo::StringLength(zone(), map);
} }
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
// Check for special JSObject field accessors. // Check for special JSObject field accessors.
FieldIndex field_index; FieldIndex field_index;
...@@ -1041,7 +1087,7 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor( ...@@ -1041,7 +1087,7 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor(
return PropertyAccessInfo::DataField(zone(), map, {{}, zone()}, field_index, return PropertyAccessInfo::DataField(zone(), map, {{}, zone()}, field_index,
field_representation, field_type, map); field_representation, field_type, map);
} }
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
PropertyAccessInfo AccessInfoFactory::LookupTransition( PropertyAccessInfo AccessInfoFactory::LookupTransition(
...@@ -1051,21 +1097,21 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition( ...@@ -1051,21 +1097,21 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
TransitionsAccessor(isolate(), map, broker()->is_concurrent_inlining()) TransitionsAccessor(isolate(), map, broker()->is_concurrent_inlining())
.SearchTransition(*name, kData, NONE); .SearchTransition(*name, kData, NONE);
if (transition.is_null()) { if (transition.is_null()) {
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
Handle<Map> transition_map(transition, isolate()); Handle<Map> transition_map = broker()->CanonicalPersistentHandle(transition);
InternalIndex const number = transition_map->LastAdded(); InternalIndex const number = transition_map->LastAdded();
Handle<DescriptorArray> descriptors( Handle<DescriptorArray> descriptors = broker()->CanonicalPersistentHandle(
transition_map->instance_descriptors(kAcquireLoad), isolate()); transition_map->instance_descriptors(kAcquireLoad));
PropertyDetails const details = descriptors->GetDetails(number); PropertyDetails const details = descriptors->GetDetails(number);
// Don't bother optimizing stores to read-only properties. // Don't bother optimizing stores to read-only properties.
if (details.IsReadOnly()) { if (details.IsReadOnly()) {
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
// TODO(bmeurer): Handle transition to data constant? // TODO(bmeurer): Handle transition to data constant?
if (details.location() != kField) { if (details.location() != kField) {
return PropertyAccessInfo::Invalid(zone()); return Invalid();
} }
int const index = details.field_index(); int const index = details.field_index();
Representation details_representation = details.representation(); Representation details_representation = details.representation();
...@@ -1073,30 +1119,40 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition( ...@@ -1073,30 +1119,40 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
details_representation); details_representation);
Type field_type = Type::NonInternal(); Type field_type = Type::NonInternal();
MaybeHandle<Map> field_map; MaybeHandle<Map> field_map;
MapRef transition_map_ref(broker(), transition_map);
ObjectData* data = broker()->TryGetOrCreateData(transition_map);
if (data == nullptr) return Invalid();
MapRef transition_map_ref(broker(), data);
ZoneVector<CompilationDependency const*> unrecorded_dependencies(zone()); ZoneVector<CompilationDependency const*> unrecorded_dependencies(zone());
if (details_representation.IsSmi()) { if (details_representation.IsSmi()) {
field_type = Type::SignedSmall(); field_type = Type::SignedSmall();
transition_map_ref.SerializeOwnDescriptor(number); if (!transition_map_ref.TrySerializeOwnDescriptor(number)) {
return Invalid();
}
unrecorded_dependencies.push_back( unrecorded_dependencies.push_back(
dependencies()->FieldRepresentationDependencyOffTheRecord( dependencies()->FieldRepresentationDependencyOffTheRecord(
transition_map_ref, number)); transition_map_ref, number));
} else if (details_representation.IsDouble()) { } else if (details_representation.IsDouble()) {
field_type = type_cache_->kFloat64; field_type = type_cache_->kFloat64;
transition_map_ref.SerializeOwnDescriptor(number); if (!transition_map_ref.TrySerializeOwnDescriptor(number)) {
return Invalid();
}
unrecorded_dependencies.push_back( unrecorded_dependencies.push_back(
dependencies()->FieldRepresentationDependencyOffTheRecord( dependencies()->FieldRepresentationDependencyOffTheRecord(
transition_map_ref, number)); transition_map_ref, number));
} else if (details_representation.IsHeapObject()) { } else if (details_representation.IsHeapObject()) {
// Extract the field type from the property details (make sure its // Extract the field type from the property details (make sure its
// representation is TaggedPointer to reflect the heap object case). // representation is TaggedPointer to reflect the heap object case).
Handle<FieldType> descriptors_field_type(descriptors->GetFieldType(number), Handle<FieldType> descriptors_field_type =
isolate()); broker()->CanonicalPersistentHandle(descriptors->GetFieldType(number));
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 PropertyAccessInfo::Invalid(zone()); return Invalid();
}
if (!transition_map_ref.TrySerializeOwnDescriptor(number)) {
return Invalid();
} }
transition_map_ref.SerializeOwnDescriptor(number);
unrecorded_dependencies.push_back( unrecorded_dependencies.push_back(
dependencies()->FieldRepresentationDependencyOffTheRecord( dependencies()->FieldRepresentationDependencyOffTheRecord(
transition_map_ref, number)); transition_map_ref, number));
...@@ -1105,14 +1161,21 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition( ...@@ -1105,14 +1161,21 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
dependencies()->FieldTypeDependencyOffTheRecord(transition_map_ref, dependencies()->FieldTypeDependencyOffTheRecord(transition_map_ref,
number)); number));
// Remember the field map, and try to infer a useful type. // Remember the field map, and try to infer a useful type.
Handle<Map> map(descriptors_field_type->AsClass(), isolate()); Handle<Map> map = broker()->CanonicalPersistentHandle(
field_type = Type::For(MapRef(broker(), map)); descriptors_field_type->AsClass());
ObjectData* data = broker()->TryGetOrCreateData(map);
if (data == nullptr) return Invalid();
field_type = Type::For(MapRef(broker(), data));
field_map = MaybeHandle<Map>(map); field_map = MaybeHandle<Map>(map);
} }
} }
{
ObjectData* data = broker()->TryGetOrCreateData(transition_map);
if (data == nullptr) return Invalid();
unrecorded_dependencies.push_back( unrecorded_dependencies.push_back(
dependencies()->TransitionDependencyOffTheRecord( dependencies()->TransitionDependencyOffTheRecord(
MapRef(broker(), transition_map))); MapRef(broker(), data)));
}
transition_map_ref.SerializeBackPointer(); // For BuildPropertyStore. transition_map_ref.SerializeBackPointer(); // For BuildPropertyStore.
// Transitioning stores *may* store to const fields. The resulting // Transitioning stores *may* store to const fields. The resulting
// DataConstant access infos can be distinguished from later, i.e. redundant, // DataConstant access infos can be distinguished from later, i.e. redundant,
......
...@@ -305,6 +305,10 @@ class AccessInfoFactory final { ...@@ -305,6 +305,10 @@ class AccessInfoFactory final {
MaybeHandle<JSObject> holder, InternalIndex descriptor, MaybeHandle<JSObject> holder, InternalIndex descriptor,
AccessMode access_mode) const; AccessMode access_mode) const;
PropertyAccessInfo Invalid() const {
return PropertyAccessInfo::Invalid(zone());
}
void MergePropertyAccessInfos(ZoneVector<PropertyAccessInfo> infos, void MergePropertyAccessInfos(ZoneVector<PropertyAccessInfo> infos,
AccessMode access_mode, AccessMode access_mode,
ZoneVector<PropertyAccessInfo>* result) const; ZoneVector<PropertyAccessInfo>* result) const;
......
...@@ -34,6 +34,10 @@ class V8_EXPORT_PRIVATE CompilationDependencies : public ZoneObject { ...@@ -34,6 +34,10 @@ class V8_EXPORT_PRIVATE CompilationDependencies : public ZoneObject {
V8_WARN_UNUSED_RESULT bool Commit(Handle<Code> code); V8_WARN_UNUSED_RESULT bool Commit(Handle<Code> code);
// TODO(jgruber): Remove this method once GetPropertyAccessInfo no longer
// uses the two-phase approach between serialization and compilation.
void ClearForConcurrentGetPropertyAccessInfo() { dependencies_.clear(); }
// Return the initial map of {function} and record the assumption that it // Return the initial map of {function} and record the assumption that it
// stays the initial map. // stays the initial map.
MapRef DependOnInitialMap(const JSFunctionRef& function); MapRef DependOnInitialMap(const JSFunctionRef& function);
......
...@@ -263,7 +263,8 @@ FunctionTemplateInfoData::FunctionTemplateInfoData( ...@@ -263,7 +263,8 @@ FunctionTemplateInfoData::FunctionTemplateInfoData(
function_template_info->signature().IsUndefined(broker->isolate()); function_template_info->signature().IsUndefined(broker->isolate());
accept_any_receiver_ = function_template_info->accept_any_receiver(); accept_any_receiver_ = function_template_info->accept_any_receiver();
CallOptimization call_optimization(broker->isolate(), object); CallOptimization call_optimization(broker->local_isolate_or_isolate(),
object);
has_call_code_ = call_optimization.is_simple_api_call(); has_call_code_ = call_optimization.is_simple_api_call();
} }
...@@ -1143,8 +1144,12 @@ class MapData : public HeapObjectData { ...@@ -1143,8 +1144,12 @@ class MapData : public HeapObjectData {
// Serialize a single (or all) own slot(s) of the descriptor array and recurse // Serialize a single (or all) own slot(s) of the descriptor array and recurse
// on field owner(s). // on field owner(s).
void SerializeOwnDescriptor(JSHeapBroker* broker, bool TrySerializeOwnDescriptor(JSHeapBroker* broker,
InternalIndex descriptor_index); InternalIndex descriptor_index);
void SerializeOwnDescriptor(JSHeapBroker* broker,
InternalIndex descriptor_index) {
CHECK(TrySerializeOwnDescriptor(broker, descriptor_index));
}
void SerializeOwnDescriptors(JSHeapBroker* broker); void SerializeOwnDescriptors(JSHeapBroker* broker);
ObjectData* GetStrongValue(InternalIndex descriptor_index) const; ObjectData* GetStrongValue(InternalIndex descriptor_index) const;
ObjectData* instance_descriptors() const { return instance_descriptors_; } ObjectData* instance_descriptors() const { return instance_descriptors_; }
...@@ -1164,7 +1169,10 @@ class MapData : public HeapObjectData { ...@@ -1164,7 +1169,10 @@ class MapData : public HeapObjectData {
return backpointer_; return backpointer_;
} }
void SerializePrototype(JSHeapBroker* broker); bool TrySerializePrototype(JSHeapBroker* broker);
void SerializePrototype(JSHeapBroker* broker) {
CHECK(TrySerializePrototype(broker));
}
bool serialized_prototype() const { return serialized_prototype_; } bool serialized_prototype() const { return serialized_prototype_; }
ObjectData* prototype() const { ObjectData* prototype() const {
CHECK(serialized_prototype_); CHECK(serialized_prototype_);
...@@ -2253,14 +2261,16 @@ void MapData::SerializeBackPointer(JSHeapBroker* broker) { ...@@ -2253,14 +2261,16 @@ void MapData::SerializeBackPointer(JSHeapBroker* broker) {
backpointer_ = broker->GetOrCreateData(map->GetBackPointer()); backpointer_ = broker->GetOrCreateData(map->GetBackPointer());
} }
void MapData::SerializePrototype(JSHeapBroker* broker) { bool MapData::TrySerializePrototype(JSHeapBroker* broker) {
if (serialized_prototype_) return; if (serialized_prototype_) return true;
serialized_prototype_ = true;
TraceScope tracer(broker, this, "MapData::SerializePrototype"); TraceScope tracer(broker, this, "MapData::SerializePrototype");
Handle<Map> map = Handle<Map>::cast(object()); Handle<Map> map = Handle<Map>::cast(object());
DCHECK_NULL(prototype_); DCHECK_NULL(prototype_);
prototype_ = broker->GetOrCreateData(map->prototype()); prototype_ = broker->TryGetOrCreateData(map->prototype());
if (prototype_ == nullptr) return false;
serialized_prototype_ = true;
return true;
} }
void MapData::SerializeOwnDescriptors(JSHeapBroker* broker) { void MapData::SerializeOwnDescriptors(JSHeapBroker* broker) {
...@@ -2275,7 +2285,7 @@ void MapData::SerializeOwnDescriptors(JSHeapBroker* broker) { ...@@ -2275,7 +2285,7 @@ void MapData::SerializeOwnDescriptors(JSHeapBroker* broker) {
} }
} }
void MapData::SerializeOwnDescriptor(JSHeapBroker* broker, bool MapData::TrySerializeOwnDescriptor(JSHeapBroker* broker,
InternalIndex descriptor_index) { InternalIndex descriptor_index) {
TraceScope tracer(broker, this, "MapData::SerializeOwnDescriptor"); TraceScope tracer(broker, this, "MapData::SerializeOwnDescriptor");
Handle<Map> map = Handle<Map>::cast(object()); Handle<Map> map = Handle<Map>::cast(object());
...@@ -2283,7 +2293,8 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker, ...@@ -2283,7 +2293,8 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
if (instance_descriptors_ == nullptr) { if (instance_descriptors_ == nullptr) {
instance_descriptors_ = instance_descriptors_ =
broker->GetOrCreateData(map->instance_descriptors(isolate)); broker->TryGetOrCreateData(map->instance_descriptors(isolate));
if (instance_descriptors_ == nullptr) return false;
} }
if (instance_descriptors()->should_access_heap()) { if (instance_descriptors()->should_access_heap()) {
...@@ -2294,11 +2305,12 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker, ...@@ -2294,11 +2305,12 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
Handle<DescriptorArray> descriptors = broker->CanonicalPersistentHandle( Handle<DescriptorArray> descriptors = broker->CanonicalPersistentHandle(
map->instance_descriptors(kAcquireLoad)); map->instance_descriptors(kAcquireLoad));
if (descriptors->GetDetails(descriptor_index).location() == kField) { if (descriptors->GetDetails(descriptor_index).location() == kField) {
Handle<Map> owner(map->FindFieldOwner(isolate, descriptor_index), Handle<Map> owner = broker->CanonicalPersistentHandle(
isolate); map->FindFieldOwner(isolate, descriptor_index));
if (!owner.equals(map)) { if (!owner.equals(map)) {
broker->GetOrCreateData(owner)->AsMap()->SerializeOwnDescriptor( ObjectData* data = broker->TryGetOrCreateData(owner);
broker, descriptor_index); if (data == nullptr) return false;
data->AsMap()->SerializeOwnDescriptor(broker, descriptor_index);
} }
} }
} else { } else {
...@@ -2306,6 +2318,8 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker, ...@@ -2306,6 +2318,8 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
instance_descriptors()->AsDescriptorArray(); instance_descriptors()->AsDescriptorArray();
descriptors->SerializeDescriptor(broker, map, descriptor_index); descriptors->SerializeDescriptor(broker, map, descriptor_index);
} }
return true;
} }
void MapData::SerializeRootMap(JSHeapBroker* broker) { void MapData::SerializeRootMap(JSHeapBroker* broker) {
...@@ -3415,9 +3429,12 @@ HolderLookupResult FunctionTemplateInfoRef::LookupHolderOfExpectedType( ...@@ -3415,9 +3429,12 @@ HolderLookupResult FunctionTemplateInfoRef::LookupHolderOfExpectedType(
} }
HolderLookupResult result; HolderLookupResult result;
CallOptimization call_optimization(broker()->isolate(), object()); CallOptimization call_optimization(broker()->local_isolate_or_isolate(),
Handle<JSObject> holder = call_optimization.LookupHolderOfExpectedType( object());
receiver_map.object(), &result.lookup); Handle<JSObject> holder = broker()->CanonicalPersistentHandle(
call_optimization.LookupHolderOfExpectedType(
broker()->local_isolate_or_isolate(), receiver_map.object(),
&result.lookup));
switch (result.lookup) { switch (result.lookup) {
case CallOptimization::kHolderFound: { case CallOptimization::kHolderFound: {
...@@ -4075,12 +4092,6 @@ NameRef DescriptorArrayRef::GetPropertyKey( ...@@ -4075,12 +4092,6 @@ NameRef DescriptorArrayRef::GetPropertyKey(
ObjectRef DescriptorArrayRef::GetFieldType( ObjectRef DescriptorArrayRef::GetFieldType(
InternalIndex descriptor_index) const { InternalIndex descriptor_index) const {
if (data_->should_access_heap()) { if (data_->should_access_heap()) {
// This method only gets called for the creation of FieldTypeDependencies.
// These calls happen when the broker is either disabled or serializing,
// which means that GetOrCreateData would be able to successfully create the
// ObjectRef for the cases where we haven't seen the FieldType before.
DCHECK(broker()->mode() == JSHeapBroker::kDisabled ||
broker()->mode() == JSHeapBroker::kSerializing);
return ObjectRef(broker(), broker()->CanonicalPersistentHandle( return ObjectRef(broker(), broker()->CanonicalPersistentHandle(
object()->GetFieldType(descriptor_index))); object()->GetFieldType(descriptor_index)));
} }
...@@ -4371,15 +4382,21 @@ ScopeInfoRef SharedFunctionInfoRef::scope_info() const { ...@@ -4371,15 +4382,21 @@ ScopeInfoRef SharedFunctionInfoRef::scope_info() const {
void JSObjectRef::SerializeObjectCreateMap() { void JSObjectRef::SerializeObjectCreateMap() {
if (data_->should_access_heap()) return; if (data_->should_access_heap()) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); CHECK_IMPLIES(!FLAG_turbo_concurrent_get_property_access_info,
broker()->mode() == JSHeapBroker::kSerializing);
data()->AsJSObject()->SerializeObjectCreateMap(broker()); data()->AsJSObject()->SerializeObjectCreateMap(broker());
} }
void MapRef::SerializeOwnDescriptor(InternalIndex descriptor_index) { bool MapRef::TrySerializeOwnDescriptor(InternalIndex descriptor_index) {
CHECK_LT(descriptor_index.as_int(), NumberOfOwnDescriptors()); CHECK_LT(descriptor_index.as_int(), NumberOfOwnDescriptors());
if (data_->should_access_heap()) return; if (data_->should_access_heap()) return true;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); CHECK_IMPLIES(!FLAG_turbo_concurrent_get_property_access_info,
data()->AsMap()->SerializeOwnDescriptor(broker(), descriptor_index); broker()->mode() == JSHeapBroker::kSerializing);
return data()->AsMap()->TrySerializeOwnDescriptor(broker(), descriptor_index);
}
void MapRef::SerializeOwnDescriptor(InternalIndex descriptor_index) {
CHECK(TrySerializeOwnDescriptor(descriptor_index));
} }
bool MapRef::serialized_own_descriptor(InternalIndex descriptor_index) const { bool MapRef::serialized_own_descriptor(InternalIndex descriptor_index) const {
...@@ -4395,16 +4412,20 @@ bool MapRef::serialized_own_descriptor(InternalIndex descriptor_index) const { ...@@ -4395,16 +4412,20 @@ bool MapRef::serialized_own_descriptor(InternalIndex descriptor_index) const {
void MapRef::SerializeBackPointer() { void MapRef::SerializeBackPointer() {
if (data_->should_access_heap()) return; if (data_->should_access_heap()) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); CHECK_IMPLIES(!FLAG_turbo_concurrent_get_property_access_info,
broker()->mode() == JSHeapBroker::kSerializing);
data()->AsMap()->SerializeBackPointer(broker()); data()->AsMap()->SerializeBackPointer(broker());
} }
void MapRef::SerializePrototype() { bool MapRef::TrySerializePrototype() {
if (data_->should_access_heap()) return; if (data_->should_access_heap()) return true;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); CHECK_IMPLIES(!FLAG_turbo_concurrent_get_property_access_info,
data()->AsMap()->SerializePrototype(broker()); broker()->mode() == JSHeapBroker::kSerializing);
return data()->AsMap()->TrySerializePrototype(broker());
} }
void MapRef::SerializePrototype() { CHECK(TrySerializePrototype()); }
bool MapRef::serialized_prototype() const { bool MapRef::serialized_prototype() const {
if (data_->should_access_heap()) return true; if (data_->should_access_heap()) return true;
CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled); CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
......
...@@ -704,6 +704,7 @@ class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef { ...@@ -704,6 +704,7 @@ class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef {
void SerializeBackPointer(); void SerializeBackPointer();
HeapObjectRef GetBackPointer() const; HeapObjectRef GetBackPointer() const;
bool TrySerializePrototype();
void SerializePrototype(); void SerializePrototype();
bool serialized_prototype() const; bool serialized_prototype() const;
HeapObjectRef prototype() const; HeapObjectRef prototype() const;
...@@ -715,6 +716,7 @@ class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef { ...@@ -715,6 +716,7 @@ class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef {
ZoneVector<MapRef>* prototype_maps); ZoneVector<MapRef>* prototype_maps);
// Concerning the underlying instance_descriptors: // Concerning the underlying instance_descriptors:
bool TrySerializeOwnDescriptor(InternalIndex descriptor_index);
void SerializeOwnDescriptor(InternalIndex descriptor_index); void SerializeOwnDescriptor(InternalIndex descriptor_index);
bool serialized_own_descriptor(InternalIndex descriptor_index) const; bool serialized_own_descriptor(InternalIndex descriptor_index) const;
MapRef FindFieldOwner(InternalIndex descriptor_index) const; MapRef FindFieldOwner(InternalIndex descriptor_index) const;
......
...@@ -7708,7 +7708,7 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) { ...@@ -7708,7 +7708,7 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
MapRef map_ref(broker(), map); MapRef map_ref(broker(), map);
PropertyAccessInfo access_info = broker()->GetPropertyAccessInfo( PropertyAccessInfo access_info = broker()->GetPropertyAccessInfo(
map_ref, NameRef(broker(), isolate()->factory()->exec_string()), map_ref, NameRef(broker(), isolate()->factory()->exec_string()),
AccessMode::kLoad); AccessMode::kLoad, dependencies());
access_infos.push_back(access_info); access_infos.push_back(access_info);
} }
} else { } else {
......
...@@ -224,6 +224,13 @@ bool JSHeapBroker::IsArrayOrObjectPrototype(const JSObjectRef& object) const { ...@@ -224,6 +224,13 @@ bool JSHeapBroker::IsArrayOrObjectPrototype(const JSObjectRef& object) const {
array_and_object_prototypes_.end(); array_and_object_prototypes_.end();
} }
ObjectData* JSHeapBroker::TryGetOrCreateData(
Object object, bool crash_on_error,
ObjectRef::BackgroundSerialization background_serialization) {
return TryGetOrCreateData(CanonicalPersistentHandle(object), crash_on_error,
background_serialization);
}
ObjectData* JSHeapBroker::GetOrCreateData( ObjectData* JSHeapBroker::GetOrCreateData(
Handle<Object> object, Handle<Object> object,
ObjectRef::BackgroundSerialization background_serialization) { ObjectRef::BackgroundSerialization background_serialization) {
...@@ -1060,7 +1067,8 @@ PropertyAccessInfo JSHeapBroker::GetPropertyAccessInfo( ...@@ -1060,7 +1067,8 @@ PropertyAccessInfo JSHeapBroker::GetPropertyAccessInfo(
auto it = property_access_infos_.find(target); auto it = property_access_infos_.find(target);
if (it != property_access_infos_.end()) return it->second; if (it != property_access_infos_.end()) return it->second;
if (policy == SerializationPolicy::kAssumeSerialized) { if (policy == SerializationPolicy::kAssumeSerialized &&
!FLAG_turbo_concurrent_get_property_access_info) {
TRACE_BROKER_MISSING(this, "PropertyAccessInfo for " TRACE_BROKER_MISSING(this, "PropertyAccessInfo for "
<< access_mode << " of property " << name << access_mode << " of property " << name
<< " on map " << map); << " on map " << map);
...@@ -1072,7 +1080,8 @@ PropertyAccessInfo JSHeapBroker::GetPropertyAccessInfo( ...@@ -1072,7 +1080,8 @@ PropertyAccessInfo JSHeapBroker::GetPropertyAccessInfo(
PropertyAccessInfo access_info = factory.ComputePropertyAccessInfo( PropertyAccessInfo access_info = factory.ComputePropertyAccessInfo(
map.object(), name.object(), access_mode); map.object(), name.object(), access_mode);
if (is_concurrent_inlining_) { if (is_concurrent_inlining_) {
CHECK_EQ(mode(), kSerializing); CHECK_IMPLIES(!FLAG_turbo_concurrent_get_property_access_info,
mode() == kSerializing);
TRACE(this, "Storing PropertyAccessInfo for " TRACE(this, "Storing PropertyAccessInfo for "
<< access_mode << " of property " << name << " on map " << access_mode << " of property " << name << " on map "
<< map); << map);
......
...@@ -146,7 +146,7 @@ class V8_EXPORT_PRIVATE JSHeapBroker { ...@@ -146,7 +146,7 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
void PrintRefsAnalysis() const; void PrintRefsAnalysis() const;
#endif // DEBUG #endif // DEBUG
// Retruns the handle from root index table for read only heap objects. // Returns the handle from root index table for read only heap objects.
Handle<Object> GetRootHandle(Object object); Handle<Object> GetRootHandle(Object object);
// Never returns nullptr. // Never returns nullptr.
...@@ -165,6 +165,10 @@ class V8_EXPORT_PRIVATE JSHeapBroker { ...@@ -165,6 +165,10 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
Handle<Object>, bool crash_on_error = false, Handle<Object>, bool crash_on_error = false,
ObjectRef::BackgroundSerialization background_serialization = ObjectRef::BackgroundSerialization background_serialization =
ObjectRef::BackgroundSerialization::kDisallowed); ObjectRef::BackgroundSerialization::kDisallowed);
ObjectData* TryGetOrCreateData(
Object object, bool crash_on_error = false,
ObjectRef::BackgroundSerialization background_serialization =
ObjectRef::BackgroundSerialization::kDisallowed);
// Check if {object} is any native context's %ArrayPrototype% or // Check if {object} is any native context's %ArrayPrototype% or
// %ObjectPrototype%. // %ObjectPrototype%.
...@@ -241,6 +245,21 @@ class V8_EXPORT_PRIVATE JSHeapBroker { ...@@ -241,6 +245,21 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
FeedbackSource const& source, FeedbackSource const& source,
SerializationPolicy policy = SerializationPolicy::kAssumeSerialized); SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
// Used to separate the problem of a concurrent GetPropertyAccessInfo (GPAI)
// from serialization. GPAI is currently called both during the serialization
// phase, and on the background thread. While some crucial objects (like
// JSObject) still must be serialized, we do the following:
// - Run GPAI during serialization to discover and serialize required objects.
// - After the serialization phase, clear cached property access infos.
// - On the background thread, rerun GPAI in a concurrent setting. The cache
// has been cleared, thus the actual logic runs again.
// Once all required object kinds no longer require serialization, this
// should be removed together with all GPAI calls during serialization.
void ClearCachedPropertyAccessInfos() {
CHECK(FLAG_turbo_concurrent_get_property_access_info);
property_access_infos_.clear();
}
StringRef GetTypedArrayStringTag(ElementsKind kind); StringRef GetTypedArrayStringTag(ElementsKind kind);
bool ShouldBeSerializedForCompilation(const SharedFunctionInfoRef& shared, bool ShouldBeSerializedForCompilation(const SharedFunctionInfoRef& shared,
...@@ -258,6 +277,14 @@ class V8_EXPORT_PRIVATE JSHeapBroker { ...@@ -258,6 +277,14 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
LocalIsolate* local_isolate() const { return local_isolate_; } LocalIsolate* local_isolate() const { return local_isolate_; }
// TODO(jgruber): Consider always having local_isolate_ set to a real value.
// This seems not entirely trivial since we currently reset local_isolate_ to
// nullptr at some point in the JSHeapBroker lifecycle.
LocalIsolate* local_isolate_or_isolate() const {
return local_isolate() != nullptr ? local_isolate()
: isolate()->AsLocalIsolate();
}
// Return the corresponding canonical persistent handle for {object}. Create // Return the corresponding canonical persistent handle for {object}. Create
// one if it does not exist. // one if it does not exist.
// If we have the canonical map, we can create the canonical & persistent // If we have the canonical map, we can create the canonical & persistent
...@@ -292,6 +319,7 @@ class V8_EXPORT_PRIVATE JSHeapBroker { ...@@ -292,6 +319,7 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
template <typename T> template <typename T>
Handle<T> CanonicalPersistentHandle(Handle<T> object) { Handle<T> CanonicalPersistentHandle(Handle<T> object) {
if (object.is_null()) return object; // Can't deref a null handle.
return CanonicalPersistentHandle<T>(*object); return CanonicalPersistentHandle<T>(*object);
} }
......
...@@ -420,7 +420,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) { ...@@ -420,7 +420,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
access_info = broker()->GetPropertyAccessInfo( access_info = broker()->GetPropertyAccessInfo(
receiver_map, receiver_map,
NameRef(broker(), isolate()->factory()->has_instance_symbol()), NameRef(broker(), isolate()->factory()->has_instance_symbol()),
AccessMode::kLoad); AccessMode::kLoad, dependencies());
} else { } else {
AccessInfoFactory access_info_factory(broker(), dependencies(), AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone()); graph()->zone());
...@@ -744,7 +744,7 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) { ...@@ -744,7 +744,7 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) {
MapRef map_ref(broker(), map); MapRef map_ref(broker(), map);
access_infos.push_back(broker()->GetPropertyAccessInfo( access_infos.push_back(broker()->GetPropertyAccessInfo(
map_ref, NameRef(broker(), isolate()->factory()->then_string()), map_ref, NameRef(broker(), isolate()->factory()->then_string()),
AccessMode::kLoad)); AccessMode::kLoad, dependencies()));
} }
} }
PropertyAccessInfo access_info = PropertyAccessInfo access_info =
......
...@@ -1563,6 +1563,10 @@ struct SerializationPhase { ...@@ -1563,6 +1563,10 @@ struct SerializationPhase {
ContextRef(data->broker(), ContextRef(data->broker(),
data->specialization_context().FromJust().context); data->specialization_context().FromJust().context);
} }
if (FLAG_turbo_concurrent_get_property_access_info) {
data->broker()->ClearCachedPropertyAccessInfos();
data->dependencies()->ClearForConcurrentGetPropertyAccessInfo();
}
} }
}; };
......
...@@ -163,11 +163,11 @@ Node* PropertyAccessBuilder::FoldLoadDictPrototypeConstant( ...@@ -163,11 +163,11 @@ Node* PropertyAccessBuilder::FoldLoadDictPrototypeConstant(
if (!map->IsJSReceiverMap()) { if (!map->IsJSReceiverMap()) {
// Perform the implicit ToObject for primitives here. // Perform the implicit ToObject for primitives here.
// Implemented according to ES6 section 7.3.2 GetV (V, P). // Implemented according to ES6 section 7.3.2 GetV (V, P).
Handle<JSFunction> constructor = JSFunction constructor =
Map::GetConstructorFunction( Map::GetConstructorFunction(
map, broker()->target_native_context().object()) *map, *broker()->target_native_context().object())
.ToHandleChecked(); .value();
map = handle(constructor->initial_map(), isolate()); map = handle(constructor.initial_map(), isolate());
DCHECK(map->IsJSObjectMap()); DCHECK(map->IsJSObjectMap());
} }
dependencies()->DependOnConstantInDictionaryPrototypeChain( dependencies()->DependOnConstantInDictionaryPrototypeChain(
......
...@@ -659,6 +659,9 @@ DEFINE_NEG_IMPLICATION(stress_concurrent_inlining, lazy_feedback_allocation) ...@@ -659,6 +659,9 @@ DEFINE_NEG_IMPLICATION(stress_concurrent_inlining, lazy_feedback_allocation)
DEFINE_WEAK_VALUE_IMPLICATION(stress_concurrent_inlining, interrupt_budget, DEFINE_WEAK_VALUE_IMPLICATION(stress_concurrent_inlining, interrupt_budget,
15 * KB) 15 * KB)
DEFINE_IMPLICATION(concurrent_inlining, turbo_direct_heap_access) DEFINE_IMPLICATION(concurrent_inlining, turbo_direct_heap_access)
DEFINE_BOOL(
turbo_concurrent_get_property_access_info, false,
"concurrently call GetPropertyAccessInfo (only with --concurrent-inlining)")
DEFINE_INT(max_serializer_nesting, 25, DEFINE_INT(max_serializer_nesting, 25,
"maximum levels for nesting child serializers") "maximum levels for nesting child serializers")
DEFINE_WEAK_IMPLICATION(future, concurrent_inlining) DEFINE_WEAK_IMPLICATION(future, concurrent_inlining)
......
...@@ -8,12 +8,9 @@ ...@@ -8,12 +8,9 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
CallOptimization::CallOptimization(Isolate* isolate, Handle<Object> function) { template <class LocalIsolate>
constant_function_ = Handle<JSFunction>::null(); CallOptimization::CallOptimization(LocalIsolate* isolate,
is_simple_api_call_ = false; Handle<Object> function) {
accept_any_receiver_ = false;
expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
api_call_info_ = Handle<CallHandlerInfo>::null();
if (function->IsJSFunction()) { if (function->IsJSFunction()) {
Initialize(isolate, Handle<JSFunction>::cast(function)); Initialize(isolate, Handle<JSFunction>::cast(function));
} else if (function->IsFunctionTemplateInfo()) { } else if (function->IsFunctionTemplateInfo()) {
...@@ -21,6 +18,12 @@ CallOptimization::CallOptimization(Isolate* isolate, Handle<Object> function) { ...@@ -21,6 +18,12 @@ CallOptimization::CallOptimization(Isolate* isolate, Handle<Object> function) {
} }
} }
// Instantiations.
template CallOptimization::CallOptimization(Isolate* isolate,
Handle<Object> function);
template CallOptimization::CallOptimization(LocalIsolate* isolate,
Handle<Object> function);
Context CallOptimization::GetAccessorContext(Map holder_map) const { Context CallOptimization::GetAccessorContext(Map holder_map) const {
if (is_constant_call()) { if (is_constant_call()) {
return constant_function_->context().native_context(); return constant_function_->context().native_context();
...@@ -36,8 +39,10 @@ bool CallOptimization::IsCrossContextLazyAccessorPair(Context native_context, ...@@ -36,8 +39,10 @@ bool CallOptimization::IsCrossContextLazyAccessorPair(Context native_context,
return native_context != GetAccessorContext(holder_map); return native_context != GetAccessorContext(holder_map);
} }
template <class LocalIsolate>
Handle<JSObject> CallOptimization::LookupHolderOfExpectedType( Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
Handle<Map> object_map, HolderLookup* holder_lookup) const { LocalIsolate* isolate, Handle<Map> object_map,
HolderLookup* holder_lookup) const {
DCHECK(is_simple_api_call()); DCHECK(is_simple_api_call());
if (!object_map->IsJSObjectMap()) { if (!object_map->IsJSObjectMap()) {
*holder_lookup = kHolderNotFound; *holder_lookup = kHolderNotFound;
...@@ -50,8 +55,8 @@ Handle<JSObject> CallOptimization::LookupHolderOfExpectedType( ...@@ -50,8 +55,8 @@ Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
} }
if (object_map->IsJSGlobalProxyMap() && !object_map->prototype().IsNull()) { if (object_map->IsJSGlobalProxyMap() && !object_map->prototype().IsNull()) {
JSObject raw_prototype = JSObject::cast(object_map->prototype()); JSObject raw_prototype = JSObject::cast(object_map->prototype());
Handle<JSObject> prototype(raw_prototype, raw_prototype.GetIsolate()); Handle<JSObject> prototype(raw_prototype, isolate);
object_map = handle(prototype->map(), prototype->GetIsolate()); object_map = handle(prototype->map(), isolate);
if (expected_receiver_type_->IsTemplateFor(*object_map)) { if (expected_receiver_type_->IsTemplateFor(*object_map)) {
*holder_lookup = kHolderFound; *holder_lookup = kHolderFound;
return prototype; return prototype;
...@@ -61,6 +66,14 @@ Handle<JSObject> CallOptimization::LookupHolderOfExpectedType( ...@@ -61,6 +66,14 @@ Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
return Handle<JSObject>::null(); return Handle<JSObject>::null();
} }
// Instantiations.
template Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
Isolate* isolate, Handle<Map> object_map,
HolderLookup* holder_lookup) const;
template Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
LocalIsolate* isolate, Handle<Map> object_map,
HolderLookup* holder_lookup) const;
bool CallOptimization::IsCompatibleReceiverMap( bool CallOptimization::IsCompatibleReceiverMap(
Handle<JSObject> api_holder, Handle<JSObject> holder, Handle<JSObject> api_holder, Handle<JSObject> holder,
HolderLookup holder_lookup) const { HolderLookup holder_lookup) const {
...@@ -87,8 +100,10 @@ bool CallOptimization::IsCompatibleReceiverMap( ...@@ -87,8 +100,10 @@ bool CallOptimization::IsCompatibleReceiverMap(
UNREACHABLE(); UNREACHABLE();
} }
template <class LocalIsolate>
void CallOptimization::Initialize( void CallOptimization::Initialize(
Isolate* isolate, Handle<FunctionTemplateInfo> function_template_info) { LocalIsolate* isolate,
Handle<FunctionTemplateInfo> function_template_info) {
HeapObject call_code = function_template_info->call_code(kAcquireLoad); HeapObject call_code = function_template_info->call_code(kAcquireLoad);
if (call_code.IsUndefined(isolate)) return; if (call_code.IsUndefined(isolate)) return;
api_call_info_ = handle(CallHandlerInfo::cast(call_code), isolate); api_call_info_ = handle(CallHandlerInfo::cast(call_code), isolate);
...@@ -102,7 +117,8 @@ void CallOptimization::Initialize( ...@@ -102,7 +117,8 @@ void CallOptimization::Initialize(
accept_any_receiver_ = function_template_info->accept_any_receiver(); accept_any_receiver_ = function_template_info->accept_any_receiver();
} }
void CallOptimization::Initialize(Isolate* isolate, template <class LocalIsolate>
void CallOptimization::Initialize(LocalIsolate* isolate,
Handle<JSFunction> function) { Handle<JSFunction> function) {
if (function.is_null() || !function->is_compiled()) return; if (function.is_null() || !function->is_compiled()) return;
...@@ -110,7 +126,8 @@ void CallOptimization::Initialize(Isolate* isolate, ...@@ -110,7 +126,8 @@ void CallOptimization::Initialize(Isolate* isolate,
AnalyzePossibleApiFunction(isolate, function); AnalyzePossibleApiFunction(isolate, function);
} }
void CallOptimization::AnalyzePossibleApiFunction(Isolate* isolate, template <class LocalIsolate>
void CallOptimization::AnalyzePossibleApiFunction(LocalIsolate* isolate,
Handle<JSFunction> function) { Handle<JSFunction> function) {
if (!function->shared().IsApiFunction()) return; if (!function->shared().IsApiFunction()) return;
Handle<FunctionTemplateInfo> info(function->shared().get_api_func_data(), Handle<FunctionTemplateInfo> info(function->shared().get_api_func_data(),
......
...@@ -10,10 +10,12 @@ ...@@ -10,10 +10,12 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// Holds information about possible function call optimizations. // Holds information about possible function call optimizations.
class CallOptimization { class CallOptimization {
public: public:
CallOptimization(Isolate* isolate, Handle<Object> function); template <class LocalIsolate>
CallOptimization(LocalIsolate* isolate, Handle<Object> function);
Context GetAccessorContext(Map holder_map) const; Context GetAccessorContext(Map holder_map) const;
bool IsCrossContextLazyAccessorPair(Context native_context, bool IsCrossContextLazyAccessorPair(Context native_context,
...@@ -43,20 +45,26 @@ class CallOptimization { ...@@ -43,20 +45,26 @@ class CallOptimization {
} }
enum HolderLookup { kHolderNotFound, kHolderIsReceiver, kHolderFound }; enum HolderLookup { kHolderNotFound, kHolderIsReceiver, kHolderFound };
template <class LocalIsolate>
Handle<JSObject> LookupHolderOfExpectedType( Handle<JSObject> LookupHolderOfExpectedType(
Handle<Map> receiver_map, HolderLookup* holder_lookup) const; LocalIsolate* isolate, Handle<Map> receiver_map,
HolderLookup* holder_lookup) const;
bool IsCompatibleReceiverMap(Handle<JSObject> api_holder, bool IsCompatibleReceiverMap(Handle<JSObject> api_holder,
Handle<JSObject> holder, HolderLookup) const; Handle<JSObject> holder, HolderLookup) const;
private: private:
void Initialize(Isolate* isolate, Handle<JSFunction> function); template <class LocalIsolate>
void Initialize(Isolate* isolate, void Initialize(LocalIsolate* isolate, Handle<JSFunction> function);
template <class LocalIsolate>
void Initialize(LocalIsolate* isolate,
Handle<FunctionTemplateInfo> function_template_info); Handle<FunctionTemplateInfo> function_template_info);
// Determines whether the given function can be called using the // Determines whether the given function can be called using the
// fast api call builtin. // fast api call builtin.
void AnalyzePossibleApiFunction(Isolate* isolate, template <class LocalIsolate>
void AnalyzePossibleApiFunction(LocalIsolate* isolate,
Handle<JSFunction> function); Handle<JSFunction> function);
Handle<JSFunction> constant_function_; Handle<JSFunction> constant_function_;
...@@ -65,9 +73,10 @@ class CallOptimization { ...@@ -65,9 +73,10 @@ class CallOptimization {
// TODO(gsathya): Change these to be a bitfield and do a single fast check // TODO(gsathya): Change these to be a bitfield and do a single fast check
// rather than two checks. // rather than two checks.
bool is_simple_api_call_; bool is_simple_api_call_ = false;
bool accept_any_receiver_; bool accept_any_receiver_ = false;
}; };
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -605,7 +605,7 @@ bool IC::UpdateMegaDOMIC(const MaybeObjectHandle& handler, Handle<Name> name) { ...@@ -605,7 +605,7 @@ bool IC::UpdateMegaDOMIC(const MaybeObjectHandle& handler, Handle<Name> name) {
// Check if the receiver is the holder // Check if the receiver is the holder
CallOptimization::HolderLookup holder_lookup; CallOptimization::HolderLookup holder_lookup;
call_optimization.LookupHolderOfExpectedType(map, &holder_lookup); call_optimization.LookupHolderOfExpectedType(isolate(), map, &holder_lookup);
if (holder_lookup != CallOptimization::kHolderIsReceiver) return false; if (holder_lookup != CallOptimization::kHolderIsReceiver) return false;
Handle<Context> accessor_context(call_optimization.GetAccessorContext(*map), Handle<Context> accessor_context(call_optimization.GetAccessorContext(*map),
...@@ -947,7 +947,8 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -947,7 +947,8 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
if (call_optimization.is_simple_api_call()) { if (call_optimization.is_simple_api_call()) {
CallOptimization::HolderLookup holder_lookup; CallOptimization::HolderLookup holder_lookup;
Handle<JSObject> api_holder = Handle<JSObject> api_holder =
call_optimization.LookupHolderOfExpectedType(map, &holder_lookup); call_optimization.LookupHolderOfExpectedType(isolate(), map,
&holder_lookup);
if (!call_optimization.IsCompatibleReceiverMap(api_holder, holder, if (!call_optimization.IsCompatibleReceiverMap(api_holder, holder,
holder_lookup) || holder_lookup) ||
...@@ -1810,7 +1811,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1810,7 +1811,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
CallOptimization::HolderLookup holder_lookup; CallOptimization::HolderLookup holder_lookup;
Handle<JSObject> api_holder = Handle<JSObject> api_holder =
call_optimization.LookupHolderOfExpectedType( call_optimization.LookupHolderOfExpectedType(
lookup_start_object_map(), &holder_lookup); isolate(), lookup_start_object_map(), &holder_lookup);
if (call_optimization.IsCompatibleReceiverMap(api_holder, holder, if (call_optimization.IsCompatibleReceiverMap(api_holder, holder,
holder_lookup)) { holder_lookup)) {
Handle<Smi> smi_handler = StoreHandler::StoreApiSetter( Handle<Smi> smi_handler = StoreHandler::StoreApiSetter(
......
...@@ -1254,13 +1254,13 @@ bool LookupIterator::LookupCachedProperty(Handle<AccessorPair> accessor_pair) { ...@@ -1254,13 +1254,13 @@ bool LookupIterator::LookupCachedProperty(Handle<AccessorPair> accessor_pair) {
DCHECK_EQ(state(), LookupIterator::ACCESSOR); DCHECK_EQ(state(), LookupIterator::ACCESSOR);
DCHECK(GetAccessors()->IsAccessorPair(isolate_)); DCHECK(GetAccessors()->IsAccessorPair(isolate_));
Handle<Object> getter(accessor_pair->getter(isolate_), isolate()); base::Optional<Name> maybe_name =
MaybeHandle<Name> maybe_name = FunctionTemplateInfo::TryGetCachedPropertyName(
FunctionTemplateInfo::TryGetCachedPropertyName(isolate(), getter); isolate(), accessor_pair->getter(isolate_));
if (maybe_name.is_null()) return false; if (!maybe_name.has_value()) return false;
// We have found a cached property! Modify the iterator accordingly. // We have found a cached property! Modify the iterator accordingly.
name_ = maybe_name.ToHandleChecked(); name_ = handle(maybe_name.value(), isolate_);
Restart(); Restart();
CHECK_EQ(state(), LookupIterator::DATA); CHECK_EQ(state(), LookupIterator::DATA);
return true; return true;
......
...@@ -45,17 +45,16 @@ Map Map::GetPrototypeChainRootMap(Isolate* isolate) const { ...@@ -45,17 +45,16 @@ Map Map::GetPrototypeChainRootMap(Isolate* isolate) const {
} }
// static // static
MaybeHandle<JSFunction> Map::GetConstructorFunction( base::Optional<JSFunction> Map::GetConstructorFunction(Map map,
Handle<Map> map, Handle<Context> native_context) { Context native_context) {
if (map->IsPrimitiveMap()) { DisallowGarbageCollection no_gc;
int const constructor_function_index = map->GetConstructorFunctionIndex(); if (map.IsPrimitiveMap()) {
int const constructor_function_index = map.GetConstructorFunctionIndex();
if (constructor_function_index != kNoConstructorFunctionIndex) { if (constructor_function_index != kNoConstructorFunctionIndex) {
return handle( return JSFunction::cast(native_context.get(constructor_function_index));
JSFunction::cast(native_context->get(constructor_function_index)),
native_context->GetIsolate());
} }
} }
return MaybeHandle<JSFunction>(); return {};
} }
Map Map::GetInstanceTypeMap(ReadOnlyRoots roots, InstanceType type) { Map Map::GetInstanceTypeMap(ReadOnlyRoots roots, InstanceType type) {
......
...@@ -211,8 +211,8 @@ class Map : public HeapObject { ...@@ -211,8 +211,8 @@ class Map : public HeapObject {
static const int kNoConstructorFunctionIndex = 0; static const int kNoConstructorFunctionIndex = 0;
inline int GetConstructorFunctionIndex() const; inline int GetConstructorFunctionIndex() const;
inline void SetConstructorFunctionIndex(int value); inline void SetConstructorFunctionIndex(int value);
static MaybeHandle<JSFunction> GetConstructorFunction( static base::Optional<JSFunction> GetConstructorFunction(
Handle<Map> map, Handle<Context> native_context); Map map, Context native_context);
// Retrieve interceptors. // Retrieve interceptors.
DECL_GETTER(GetNamedInterceptor, InterceptorInfo) DECL_GETTER(GetNamedInterceptor, InterceptorInfo)
......
...@@ -6647,17 +6647,14 @@ AccessCheckInfo AccessCheckInfo::Get(Isolate* isolate, ...@@ -6647,17 +6647,14 @@ AccessCheckInfo AccessCheckInfo::Get(Isolate* isolate,
return AccessCheckInfo::cast(data_obj); return AccessCheckInfo::cast(data_obj);
} }
MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName( base::Optional<Name> FunctionTemplateInfo::TryGetCachedPropertyName(
Isolate* isolate, Handle<Object> getter) { Isolate* isolate, Object getter) {
if (getter->IsFunctionTemplateInfo()) { DisallowGarbageCollection no_gc;
Handle<FunctionTemplateInfo> fti = if (!getter.IsFunctionTemplateInfo()) return {};
Handle<FunctionTemplateInfo>::cast(getter);
// Check if the accessor uses a cached property. // Check if the accessor uses a cached property.
if (!fti->cached_property_name().IsTheHole(isolate)) { Object maybe_name = FunctionTemplateInfo::cast(getter).cached_property_name();
return handle(Name::cast(fti->cached_property_name()), isolate); if (maybe_name.IsTheHole(isolate)) return {};
} return Name::cast(maybe_name);
}
return MaybeHandle<Name>();
} }
Address Smi::LexicographicCompare(Isolate* isolate, Smi x, Smi y) { Address Smi::LexicographicCompare(Isolate* isolate, Smi x, Smi y) {
......
...@@ -160,8 +160,8 @@ class FunctionTemplateInfo ...@@ -160,8 +160,8 @@ class FunctionTemplateInfo
inline bool BreakAtEntry(); inline bool BreakAtEntry();
// Helper function for cached accessors. // Helper function for cached accessors.
static MaybeHandle<Name> TryGetCachedPropertyName(Isolate* isolate, static base::Optional<Name> TryGetCachedPropertyName(Isolate* isolate,
Handle<Object> getter); Object getter);
// Bit position in the flag, from least significant bit position. // Bit position in the flag, from least significant bit position.
DEFINE_TORQUE_GENERATED_FUNCTION_TEMPLATE_INFO_FLAGS() DEFINE_TORQUE_GENERATED_FUNCTION_TEMPLATE_INFO_FLAGS()
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
// Flags: --track-fields --track-double-fields --allow-natives-syntax // Flags: --track-fields --track-double-fields --allow-natives-syntax
// Flags: --concurrent-recompilation --block-concurrent-recompilation // Flags: --concurrent-recompilation --block-concurrent-recompilation
// Flags: --no-always-opt // Flags: --no-always-opt --no-turbo-concurrent-get-property-access-info
if (!%IsConcurrentRecompilationSupported()) { if (!%IsConcurrentRecompilationSupported()) {
print("Concurrent recompilation is disabled. Skipping this test."); print("Concurrent recompilation is disabled. Skipping this test.");
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
// Flags: --allow-natives-syntax --no-always-opt // Flags: --allow-natives-syntax --no-always-opt
// Flags: --concurrent-recompilation --block-concurrent-recompilation // Flags: --concurrent-recompilation --block-concurrent-recompilation
// Flags: --no-always-opt // Flags: --no-always-opt --no-turbo-concurrent-get-property-access-info
if (!%IsConcurrentRecompilationSupported()) { if (!%IsConcurrentRecompilationSupported()) {
print("Concurrent recompilation is disabled. Skipping this test."); print("Concurrent recompilation is disabled. Skipping this test.");
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
// Flags: --concurrent-recompilation --block-concurrent-recompilation // Flags: --concurrent-recompilation --block-concurrent-recompilation
// Flags: --nostress-opt --no-always-opt // Flags: --nostress-opt --no-always-opt
// Flags: --no-turbo-direct-heap-access // Flags: --no-turbo-direct-heap-access
// Flags: --no-turbo-concurrent-get-property-access-info
// --nostress-opt is in place because this particular optimization // --nostress-opt is in place because this particular optimization
// (guaranteeing that the Array prototype chain has no elements) is // (guaranteeing that the Array prototype chain has no elements) is
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
// Flags: --allow-natives-syntax --opt --no-always-opt // Flags: --allow-natives-syntax --opt --no-always-opt
// Flags: --no-stress-flush-bytecode // Flags: --no-stress-flush-bytecode
// Flags: --block-concurrent-recompilation // Flags: --block-concurrent-recompilation
// Flags: --no-turbo-concurrent-get-property-access-info
// //
// Tests tracking of constness of properties stored in dictionary // Tests tracking of constness of properties stored in dictionary
// mode prototypes. // mode prototypes.
......
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