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,
base::Optional<ElementAccessInfo> AccessInfoFactory::ComputeElementAccessInfo(
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}.
MapRef map_ref(broker(), map);
MapRef map_ref(broker(), data);
if (!CanInlineElementAccess(map_ref)) return base::nullopt;
ElementsKind const elements_kind = map_ref.elements_kind();
return ElementAccessInfo({{map}, zone()}, elements_kind, zone());
......@@ -438,15 +441,21 @@ 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 PropertyAccessInfo::Invalid(zone());
return Invalid();
}
FieldIndex field_index =
FieldIndex::ForPropertyIndex(*map, index, details_representation);
Type field_type = Type::NonInternal();
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());
map_ref.SerializeOwnDescriptor(descriptor);
if (!map_ref.TrySerializeOwnDescriptor(descriptor)) {
return Invalid();
}
if (details_representation.IsSmi()) {
field_type = Type::SignedSmall();
unrecorded_dependencies.push_back(
......@@ -460,12 +469,13 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
} else if (details_representation.IsHeapObject()) {
// Extract the field type from the property details (make sure its
// representation is TaggedPointer to reflect the heap object case).
Handle<FieldType> descriptors_field_type(
descriptors->GetFieldType(descriptor), isolate());
Handle<FieldType> descriptors_field_type =
broker()->CanonicalPersistentHandle(
descriptors->GetFieldType(descriptor));
if (descriptors_field_type->IsNone()) {
// Store is not safe if the field type was cleared.
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
......@@ -476,8 +486,11 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
descriptor));
if (descriptors_field_type->IsClass()) {
// Remember the field map, and try to infer a useful type.
Handle<Map> map(descriptors_field_type->AsClass(), isolate());
field_type = Type::For(MapRef(broker(), map));
Handle<Map> map = broker()->CanonicalPersistentHandle(
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);
}
} else {
......@@ -497,11 +510,11 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
// of turboprop.
constness = PropertyConstness::kMutable;
} else {
map_ref.SerializeOwnDescriptor(descriptor);
constness = dependencies()->DependOnFieldConstness(map_ref, descriptor);
}
Handle<Map> field_owner_map(map->FindFieldOwner(isolate(), descriptor),
isolate());
// TODO(v8:11670): Make FindFieldOwner and friends robust wrt concurrency.
Handle<Map> field_owner_map = broker()->CanonicalPersistentHandle(
map->FindFieldOwner(isolate(), descriptor));
switch (constness) {
case PropertyConstness::kMutable:
return PropertyAccessInfo::DataField(
......@@ -527,13 +540,14 @@ PropertyAccessInfo AccessorAccessInfoHelper(
AccessMode access_mode, AccessorsObjectGetter get_accessors) {
if (map->instance_type() == JS_MODULE_NAMESPACE_TYPE) {
DCHECK(map->is_prototype_map());
Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(map->prototype_info()),
isolate);
Handle<JSModuleNamespace> module_namespace(
JSModuleNamespace::cast(proto_info->module_namespace()), isolate);
Handle<Cell> cell(Cell::cast(module_namespace->module().exports().Lookup(
isolate, name, Smi::ToInt(name->GetHash()))),
isolate);
Handle<PrototypeInfo> proto_info = broker->CanonicalPersistentHandle(
PrototypeInfo::cast(map->prototype_info()));
Handle<JSModuleNamespace> module_namespace =
broker->CanonicalPersistentHandle(
JSModuleNamespace::cast(proto_info->module_namespace()));
Handle<Cell> cell = broker->CanonicalPersistentHandle(
Cell::cast(module_namespace->module().exports().Lookup(
isolate, name, Smi::ToInt(name->GetHash()))));
if (cell->value().IsTheHole(isolate)) {
// This module has not been fully initialized yet.
return PropertyAccessInfo::Invalid(zone);
......@@ -548,16 +562,20 @@ PropertyAccessInfo AccessorAccessInfoHelper(
return PropertyAccessInfo::FastAccessorConstant(zone, receiver_map,
Handle<Object>(), holder);
}
Handle<Object> accessors = get_accessors();
if (!accessors->IsAccessorPair()) {
Handle<Object> maybe_accessors = get_accessors();
if (!maybe_accessors->IsAccessorPair()) {
return PropertyAccessInfo::Invalid(zone);
}
Handle<Object> accessor(access_mode == AccessMode::kLoad
? Handle<AccessorPair>::cast(accessors)->getter()
: Handle<AccessorPair>::cast(accessors)->setter(),
isolate);
Handle<AccessorPair> accessors = Handle<AccessorPair>::cast(maybe_accessors);
Handle<Object> accessor = broker->CanonicalPersistentHandle(
access_mode == AccessMode::kLoad ? accessors->getter()
: accessors->setter());
ObjectData* data = broker->TryGetOrCreateData(accessor);
if (data == nullptr) return PropertyAccessInfo::Invalid(zone);
if (!accessor->IsJSFunction()) {
CallOptimization optimization(isolate, accessor);
CallOptimization optimization(broker->local_isolate_or_isolate(), accessor);
if (!optimization.is_simple_api_call() ||
optimization.IsCrossContextLazyAccessorPair(
*broker->target_native_context().object(), *map)) {
......@@ -565,7 +583,9 @@ PropertyAccessInfo AccessorAccessInfoHelper(
}
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) {
return PropertyAccessInfo::Invalid(zone);
}
......@@ -574,9 +594,11 @@ PropertyAccessInfo AccessorAccessInfoHelper(
DCHECK_IMPLIES(lookup == CallOptimization::kHolderFound, !holder.is_null());
}
if (access_mode == AccessMode::kLoad) {
Handle<Name> cached_property_name;
if (FunctionTemplateInfo::TryGetCachedPropertyName(isolate, accessor)
.ToHandle(&cached_property_name)) {
base::Optional<Name> maybe_cached_property_name =
FunctionTemplateInfo::TryGetCachedPropertyName(isolate, *accessor);
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(
map, cached_property_name, access_mode);
if (!access_info.IsInvalid()) return access_info;
......@@ -598,12 +620,13 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo(
MaybeHandle<JSObject> holder, InternalIndex descriptor,
AccessMode access_mode) const {
DCHECK(descriptor.is_found());
Handle<DescriptorArray> descriptors(
holder_map->instance_descriptors(kRelaxedLoad), isolate());
Handle<DescriptorArray> descriptors = broker()->CanonicalPersistentHandle(
holder_map->instance_descriptors(kRelaxedLoad));
SLOW_DCHECK(descriptor == descriptors->Search(*name, *holder_map));
auto get_accessors = [&]() {
return handle(descriptors->GetStrongValue(descriptor), isolate());
return broker()->CanonicalPersistentHandle(
descriptors->GetStrongValue(descriptor));
};
return AccessorAccessInfoHelper(isolate(), zone(), broker(), this,
receiver_map, name, holder_map, holder,
......@@ -620,7 +643,7 @@ PropertyAccessInfo AccessInfoFactory::ComputeDictionaryProtoAccessInfo(
// We can only inline accesses to constant properties.
if (details.constness() != PropertyConstness::kConst) {
return PropertyAccessInfo::Invalid(zone());
return Invalid();
}
if (details.kind() == PropertyKind::kData) {
......@@ -631,7 +654,7 @@ PropertyAccessInfo AccessInfoFactory::ComputeDictionaryProtoAccessInfo(
auto get_accessors = [&]() {
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,
receiver_map, name, holder_map, holder,
access_mode, get_accessors);
......@@ -704,12 +727,12 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
MapUpdaterMutexDepthScope mumd_scope(this);
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}.
if (!CanInlinePropertyAccess(map, access_mode)) {
return PropertyAccessInfo::Invalid(zone());
return Invalid();
}
// We support fast inline cases for certain JSObject getters.
......@@ -729,7 +752,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
PropertyDetails details = PropertyDetails::Empty();
InternalIndex index = InternalIndex::NotFound();
if (!TryLoadPropertyDetails(map, holder, name, &index, &details)) {
return PropertyAccessInfo::Invalid(zone());
return Invalid();
}
if (index.is_found()) {
......@@ -739,7 +762,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// Don't bother optimizing stores to read-only properties.
if (details.IsReadOnly()) {
return PropertyAccessInfo::Invalid(zone());
return Invalid();
}
if (details.kind() == kData && !holder.is_null()) {
// This is a store to a property not found on the receiver but on a
......@@ -758,7 +781,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// reaching a dictionary mode prototype holding the property . Due to
// this only being an intermediate state, we don't stupport these kind
// of heterogenous prototype chains.
return PropertyAccessInfo::Invalid(zone());
return Invalid();
}
// TryLoadPropertyDetails only succeeds if we know the holder.
......@@ -781,7 +804,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// due to the complications of checking dictionary mode prototypes for
// modification, we don't attempt to support dictionary mode prototypes
// occuring before a fast mode holder on the chain.
return PropertyAccessInfo::Invalid(zone());
return Invalid();
}
if (details.location() == kField) {
if (details.kind() == kData) {
......@@ -790,7 +813,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
} else {
DCHECK_EQ(kAccessor, details.kind());
// TODO(turbofan): Add support for general accessors?
return PropertyAccessInfo::Invalid(zone());
return Invalid();
}
} else {
DCHECK_EQ(kDescriptor, details.location());
......@@ -806,9 +829,17 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// Don't search on the prototype chain for special indices in case of
// integer indexed exotic objects (see ES6 section 9.4.5).
if (map->IsJSTypedArrayMap() && name->IsString() &&
IsSpecialIndex(String::cast(*name))) {
return PropertyAccessInfo::Invalid(zone());
if (map->IsJSTypedArrayMap() && name->IsString()) {
if (broker()->IsMainThread()) {
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.
......@@ -818,7 +849,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// Don't lookup private symbols on the prototype chain.
if (name->IsPrivate()) {
return PropertyAccessInfo::Invalid(zone());
return Invalid();
}
if (V8_DICT_PROPERTY_CONST_TRACKING_BOOL && !holder.is_null()) {
......@@ -833,21 +864,30 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
}
// 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
// time we use it, we use the same Map.
Handle<Map> map_prototype_map(map->prototype().synchronized_map(),
isolate());
Handle<Map> map_prototype_map = broker()->CanonicalPersistentHandle(
map->prototype().synchronized_map());
if (!map_prototype_map->IsJSObjectMap()) {
// Perform the implicit ToObject for primitives here.
// Implemented according to ES6 section 7.3.2 GetV (V, P).
Handle<JSFunction> constructor;
if (Map::GetConstructorFunction(
map, broker()->target_native_context().object())
.ToHandle(&constructor)) {
map = handle(constructor->initial_map(), isolate());
map_prototype_map =
handle(map->prototype().synchronized_map(), isolate());
base::Optional<JSFunction> maybe_constructor =
Map::GetConstructorFunction(
*map, *broker()->target_native_context().object());
if (maybe_constructor.has_value()) {
map = broker()->CanonicalPersistentHandle(
maybe_constructor->initial_map());
map_prototype_map = broker()->CanonicalPersistentHandle(
map->prototype().synchronized_map());
DCHECK(map_prototype_map->IsJSObjectMap());
} else if (map->prototype().IsNull()) {
if (dictionary_prototype_on_chain) {
......@@ -856,7 +896,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// with dictionary mode prototypes on the chain, either. This is again
// just due to how we currently deal with dependencies for dictionary
// properties during finalization.
return PropertyAccessInfo::Invalid(zone());
return Invalid();
}
// Store to property not found on the receiver or any prototype, we need
......@@ -870,16 +910,17 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
// Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver)
return PropertyAccessInfo::NotFound(zone(), receiver_map, holder);
} 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;
CHECK(!map->is_deprecated());
if (!CanInlinePropertyAccess(map, access_mode)) {
return PropertyAccessInfo::Invalid(zone());
return Invalid();
}
// Successful lookup on prototype chain needs to guarantee that all the
......@@ -901,7 +942,7 @@ PropertyAccessInfo AccessInfoFactory::FinalizePropertyAccessInfosAsOne(
return result;
}
}
return PropertyAccessInfo::Invalid(zone());
return Invalid();
}
void AccessInfoFactory::ComputePropertyAccessInfos(
......@@ -982,14 +1023,19 @@ base::Optional<ElementAccessInfo> AccessInfoFactory::ConsolidateElementLoad(
if (feedback.transition_groups().empty()) return base::nullopt;
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();
ElementsKind elements_kind = first_map.elements_kind();
ZoneVector<Handle<Map>> maps(zone());
for (auto const& group : feedback.transition_groups()) {
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 ||
!CanInlineElementAccess(map)) {
return base::nullopt;
......@@ -1012,7 +1058,7 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor(
if (Name::Equals(isolate(), name, isolate()->factory()->length_string())) {
return PropertyAccessInfo::StringLength(zone(), map);
}
return PropertyAccessInfo::Invalid(zone());
return Invalid();
}
// Check for special JSObject field accessors.
FieldIndex field_index;
......@@ -1041,7 +1087,7 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor(
return PropertyAccessInfo::DataField(zone(), map, {{}, zone()}, field_index,
field_representation, field_type, map);
}
return PropertyAccessInfo::Invalid(zone());
return Invalid();
}
PropertyAccessInfo AccessInfoFactory::LookupTransition(
......@@ -1051,21 +1097,21 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
TransitionsAccessor(isolate(), map, broker()->is_concurrent_inlining())
.SearchTransition(*name, kData, NONE);
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();
Handle<DescriptorArray> descriptors(
transition_map->instance_descriptors(kAcquireLoad), isolate());
Handle<DescriptorArray> descriptors = broker()->CanonicalPersistentHandle(
transition_map->instance_descriptors(kAcquireLoad));
PropertyDetails const details = descriptors->GetDetails(number);
// Don't bother optimizing stores to read-only properties.
if (details.IsReadOnly()) {
return PropertyAccessInfo::Invalid(zone());
return Invalid();
}
// TODO(bmeurer): Handle transition to data constant?
if (details.location() != kField) {
return PropertyAccessInfo::Invalid(zone());
return Invalid();
}
int const index = details.field_index();
Representation details_representation = details.representation();
......@@ -1073,30 +1119,40 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
details_representation);
Type field_type = Type::NonInternal();
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());
if (details_representation.IsSmi()) {
field_type = Type::SignedSmall();
transition_map_ref.SerializeOwnDescriptor(number);
if (!transition_map_ref.TrySerializeOwnDescriptor(number)) {
return Invalid();
}
unrecorded_dependencies.push_back(
dependencies()->FieldRepresentationDependencyOffTheRecord(
transition_map_ref, number));
} else if (details_representation.IsDouble()) {
field_type = type_cache_->kFloat64;
transition_map_ref.SerializeOwnDescriptor(number);
if (!transition_map_ref.TrySerializeOwnDescriptor(number)) {
return Invalid();
}
unrecorded_dependencies.push_back(
dependencies()->FieldRepresentationDependencyOffTheRecord(
transition_map_ref, number));
} else if (details_representation.IsHeapObject()) {
// Extract the field type from the property details (make sure its
// representation is TaggedPointer to reflect the heap object case).
Handle<FieldType> descriptors_field_type(descriptors->GetFieldType(number),
isolate());
Handle<FieldType> descriptors_field_type =
broker()->CanonicalPersistentHandle(descriptors->GetFieldType(number));
if (descriptors_field_type->IsNone()) {
// 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(
dependencies()->FieldRepresentationDependencyOffTheRecord(
transition_map_ref, number));
......@@ -1105,14 +1161,21 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
dependencies()->FieldTypeDependencyOffTheRecord(transition_map_ref,
number));
// Remember the field map, and try to infer a useful type.
Handle<Map> map(descriptors_field_type->AsClass(), isolate());
field_type = Type::For(MapRef(broker(), map));
Handle<Map> map = broker()->CanonicalPersistentHandle(
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);
}
}
unrecorded_dependencies.push_back(
dependencies()->TransitionDependencyOffTheRecord(
MapRef(broker(), transition_map)));
{
ObjectData* data = broker()->TryGetOrCreateData(transition_map);
if (data == nullptr) return Invalid();
unrecorded_dependencies.push_back(
dependencies()->TransitionDependencyOffTheRecord(
MapRef(broker(), data)));
}
transition_map_ref.SerializeBackPointer(); // For BuildPropertyStore.
// Transitioning stores *may* store to const fields. The resulting
// DataConstant access infos can be distinguished from later, i.e. redundant,
......
......@@ -305,6 +305,10 @@ class AccessInfoFactory final {
MaybeHandle<JSObject> holder, InternalIndex descriptor,
AccessMode access_mode) const;
PropertyAccessInfo Invalid() const {
return PropertyAccessInfo::Invalid(zone());
}
void MergePropertyAccessInfos(ZoneVector<PropertyAccessInfo> infos,
AccessMode access_mode,
ZoneVector<PropertyAccessInfo>* result) const;
......
......@@ -34,6 +34,10 @@ class V8_EXPORT_PRIVATE CompilationDependencies : public ZoneObject {
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
// stays the initial map.
MapRef DependOnInitialMap(const JSFunctionRef& function);
......
......@@ -263,7 +263,8 @@ FunctionTemplateInfoData::FunctionTemplateInfoData(
function_template_info->signature().IsUndefined(broker->isolate());
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();
}
......@@ -1143,8 +1144,12 @@ class MapData : public HeapObjectData {
// Serialize a single (or all) own slot(s) of the descriptor array and recurse
// on field owner(s).
bool TrySerializeOwnDescriptor(JSHeapBroker* broker,
InternalIndex descriptor_index);
void SerializeOwnDescriptor(JSHeapBroker* broker,
InternalIndex descriptor_index);
InternalIndex descriptor_index) {
CHECK(TrySerializeOwnDescriptor(broker, descriptor_index));
}
void SerializeOwnDescriptors(JSHeapBroker* broker);
ObjectData* GetStrongValue(InternalIndex descriptor_index) const;
ObjectData* instance_descriptors() const { return instance_descriptors_; }
......@@ -1164,7 +1169,10 @@ class MapData : public HeapObjectData {
return backpointer_;
}
void SerializePrototype(JSHeapBroker* broker);
bool TrySerializePrototype(JSHeapBroker* broker);
void SerializePrototype(JSHeapBroker* broker) {
CHECK(TrySerializePrototype(broker));
}
bool serialized_prototype() const { return serialized_prototype_; }
ObjectData* prototype() const {
CHECK(serialized_prototype_);
......@@ -2253,14 +2261,16 @@ void MapData::SerializeBackPointer(JSHeapBroker* broker) {
backpointer_ = broker->GetOrCreateData(map->GetBackPointer());
}
void MapData::SerializePrototype(JSHeapBroker* broker) {
if (serialized_prototype_) return;
serialized_prototype_ = true;
bool MapData::TrySerializePrototype(JSHeapBroker* broker) {
if (serialized_prototype_) return true;
TraceScope tracer(broker, this, "MapData::SerializePrototype");
Handle<Map> map = Handle<Map>::cast(object());
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) {
......@@ -2275,15 +2285,16 @@ void MapData::SerializeOwnDescriptors(JSHeapBroker* broker) {
}
}
void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
InternalIndex descriptor_index) {
bool MapData::TrySerializeOwnDescriptor(JSHeapBroker* broker,
InternalIndex descriptor_index) {
TraceScope tracer(broker, this, "MapData::SerializeOwnDescriptor");
Handle<Map> map = Handle<Map>::cast(object());
Isolate* isolate = broker->isolate();
if (instance_descriptors_ == nullptr) {
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()) {
......@@ -2294,11 +2305,12 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
Handle<DescriptorArray> descriptors = broker->CanonicalPersistentHandle(
map->instance_descriptors(kAcquireLoad));
if (descriptors->GetDetails(descriptor_index).location() == kField) {
Handle<Map> owner(map->FindFieldOwner(isolate, descriptor_index),
isolate);
Handle<Map> owner = broker->CanonicalPersistentHandle(
map->FindFieldOwner(isolate, descriptor_index));
if (!owner.equals(map)) {
broker->GetOrCreateData(owner)->AsMap()->SerializeOwnDescriptor(
broker, descriptor_index);
ObjectData* data = broker->TryGetOrCreateData(owner);
if (data == nullptr) return false;
data->AsMap()->SerializeOwnDescriptor(broker, descriptor_index);
}
}
} else {
......@@ -2306,6 +2318,8 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
instance_descriptors()->AsDescriptorArray();
descriptors->SerializeDescriptor(broker, map, descriptor_index);
}
return true;
}
void MapData::SerializeRootMap(JSHeapBroker* broker) {
......@@ -3415,9 +3429,12 @@ HolderLookupResult FunctionTemplateInfoRef::LookupHolderOfExpectedType(
}
HolderLookupResult result;
CallOptimization call_optimization(broker()->isolate(), object());
Handle<JSObject> holder = call_optimization.LookupHolderOfExpectedType(
receiver_map.object(), &result.lookup);
CallOptimization call_optimization(broker()->local_isolate_or_isolate(),
object());
Handle<JSObject> holder = broker()->CanonicalPersistentHandle(
call_optimization.LookupHolderOfExpectedType(
broker()->local_isolate_or_isolate(), receiver_map.object(),
&result.lookup));
switch (result.lookup) {
case CallOptimization::kHolderFound: {
......@@ -4075,12 +4092,6 @@ NameRef DescriptorArrayRef::GetPropertyKey(
ObjectRef DescriptorArrayRef::GetFieldType(
InternalIndex descriptor_index) const {
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(
object()->GetFieldType(descriptor_index)));
}
......@@ -4371,15 +4382,21 @@ ScopeInfoRef SharedFunctionInfoRef::scope_info() const {
void JSObjectRef::SerializeObjectCreateMap() {
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());
}
void MapRef::SerializeOwnDescriptor(InternalIndex descriptor_index) {
bool MapRef::TrySerializeOwnDescriptor(InternalIndex descriptor_index) {
CHECK_LT(descriptor_index.as_int(), NumberOfOwnDescriptors());
if (data_->should_access_heap()) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
data()->AsMap()->SerializeOwnDescriptor(broker(), descriptor_index);
if (data_->should_access_heap()) return true;
CHECK_IMPLIES(!FLAG_turbo_concurrent_get_property_access_info,
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 {
......@@ -4395,16 +4412,20 @@ bool MapRef::serialized_own_descriptor(InternalIndex descriptor_index) const {
void MapRef::SerializeBackPointer() {
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());
}
void MapRef::SerializePrototype() {
if (data_->should_access_heap()) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
data()->AsMap()->SerializePrototype(broker());
bool MapRef::TrySerializePrototype() {
if (data_->should_access_heap()) return true;
CHECK_IMPLIES(!FLAG_turbo_concurrent_get_property_access_info,
broker()->mode() == JSHeapBroker::kSerializing);
return data()->AsMap()->TrySerializePrototype(broker());
}
void MapRef::SerializePrototype() { CHECK(TrySerializePrototype()); }
bool MapRef::serialized_prototype() const {
if (data_->should_access_heap()) return true;
CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
......
......@@ -704,6 +704,7 @@ class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef {
void SerializeBackPointer();
HeapObjectRef GetBackPointer() const;
bool TrySerializePrototype();
void SerializePrototype();
bool serialized_prototype() const;
HeapObjectRef prototype() const;
......@@ -715,6 +716,7 @@ class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef {
ZoneVector<MapRef>* prototype_maps);
// Concerning the underlying instance_descriptors:
bool TrySerializeOwnDescriptor(InternalIndex descriptor_index);
void SerializeOwnDescriptor(InternalIndex descriptor_index);
bool serialized_own_descriptor(InternalIndex descriptor_index) const;
MapRef FindFieldOwner(InternalIndex descriptor_index) const;
......
......@@ -7708,7 +7708,7 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
MapRef map_ref(broker(), map);
PropertyAccessInfo access_info = broker()->GetPropertyAccessInfo(
map_ref, NameRef(broker(), isolate()->factory()->exec_string()),
AccessMode::kLoad);
AccessMode::kLoad, dependencies());
access_infos.push_back(access_info);
}
} else {
......
......@@ -224,6 +224,13 @@ bool JSHeapBroker::IsArrayOrObjectPrototype(const JSObjectRef& object) const {
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(
Handle<Object> object,
ObjectRef::BackgroundSerialization background_serialization) {
......@@ -1060,7 +1067,8 @@ PropertyAccessInfo JSHeapBroker::GetPropertyAccessInfo(
auto it = property_access_infos_.find(target);
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 "
<< access_mode << " of property " << name
<< " on map " << map);
......@@ -1072,7 +1080,8 @@ PropertyAccessInfo JSHeapBroker::GetPropertyAccessInfo(
PropertyAccessInfo access_info = factory.ComputePropertyAccessInfo(
map.object(), name.object(), access_mode);
if (is_concurrent_inlining_) {
CHECK_EQ(mode(), kSerializing);
CHECK_IMPLIES(!FLAG_turbo_concurrent_get_property_access_info,
mode() == kSerializing);
TRACE(this, "Storing PropertyAccessInfo for "
<< access_mode << " of property " << name << " on map "
<< map);
......
......@@ -146,7 +146,7 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
void PrintRefsAnalysis() const;
#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);
// Never returns nullptr.
......@@ -165,6 +165,10 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
Handle<Object>, bool crash_on_error = false,
ObjectRef::BackgroundSerialization background_serialization =
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
// %ObjectPrototype%.
......@@ -241,6 +245,21 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
FeedbackSource const& source,
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);
bool ShouldBeSerializedForCompilation(const SharedFunctionInfoRef& shared,
......@@ -258,6 +277,14 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
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
// one if it does not exist.
// If we have the canonical map, we can create the canonical & persistent
......@@ -292,6 +319,7 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
template <typename T>
Handle<T> CanonicalPersistentHandle(Handle<T> object) {
if (object.is_null()) return object; // Can't deref a null handle.
return CanonicalPersistentHandle<T>(*object);
}
......
......@@ -420,7 +420,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
access_info = broker()->GetPropertyAccessInfo(
receiver_map,
NameRef(broker(), isolate()->factory()->has_instance_symbol()),
AccessMode::kLoad);
AccessMode::kLoad, dependencies());
} else {
AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone());
......@@ -744,7 +744,7 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) {
MapRef map_ref(broker(), map);
access_infos.push_back(broker()->GetPropertyAccessInfo(
map_ref, NameRef(broker(), isolate()->factory()->then_string()),
AccessMode::kLoad));
AccessMode::kLoad, dependencies()));
}
}
PropertyAccessInfo access_info =
......
......@@ -1563,6 +1563,10 @@ struct SerializationPhase {
ContextRef(data->broker(),
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(
if (!map->IsJSReceiverMap()) {
// Perform the implicit ToObject for primitives here.
// Implemented according to ES6 section 7.3.2 GetV (V, P).
Handle<JSFunction> constructor =
JSFunction constructor =
Map::GetConstructorFunction(
map, broker()->target_native_context().object())
.ToHandleChecked();
map = handle(constructor->initial_map(), isolate());
*map, *broker()->target_native_context().object())
.value();
map = handle(constructor.initial_map(), isolate());
DCHECK(map->IsJSObjectMap());
}
dependencies()->DependOnConstantInDictionaryPrototypeChain(
......
......@@ -659,6 +659,9 @@ DEFINE_NEG_IMPLICATION(stress_concurrent_inlining, lazy_feedback_allocation)
DEFINE_WEAK_VALUE_IMPLICATION(stress_concurrent_inlining, interrupt_budget,
15 * KB)
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,
"maximum levels for nesting child serializers")
DEFINE_WEAK_IMPLICATION(future, concurrent_inlining)
......
......@@ -8,12 +8,9 @@
namespace v8 {
namespace internal {
CallOptimization::CallOptimization(Isolate* isolate, Handle<Object> function) {
constant_function_ = Handle<JSFunction>::null();
is_simple_api_call_ = false;
accept_any_receiver_ = false;
expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
api_call_info_ = Handle<CallHandlerInfo>::null();
template <class LocalIsolate>
CallOptimization::CallOptimization(LocalIsolate* isolate,
Handle<Object> function) {
if (function->IsJSFunction()) {
Initialize(isolate, Handle<JSFunction>::cast(function));
} else if (function->IsFunctionTemplateInfo()) {
......@@ -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 {
if (is_constant_call()) {
return constant_function_->context().native_context();
......@@ -36,8 +39,10 @@ bool CallOptimization::IsCrossContextLazyAccessorPair(Context native_context,
return native_context != GetAccessorContext(holder_map);
}
template <class LocalIsolate>
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());
if (!object_map->IsJSObjectMap()) {
*holder_lookup = kHolderNotFound;
......@@ -50,8 +55,8 @@ Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
}
if (object_map->IsJSGlobalProxyMap() && !object_map->prototype().IsNull()) {
JSObject raw_prototype = JSObject::cast(object_map->prototype());
Handle<JSObject> prototype(raw_prototype, raw_prototype.GetIsolate());
object_map = handle(prototype->map(), prototype->GetIsolate());
Handle<JSObject> prototype(raw_prototype, isolate);
object_map = handle(prototype->map(), isolate);
if (expected_receiver_type_->IsTemplateFor(*object_map)) {
*holder_lookup = kHolderFound;
return prototype;
......@@ -61,6 +66,14 @@ Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
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(
Handle<JSObject> api_holder, Handle<JSObject> holder,
HolderLookup holder_lookup) const {
......@@ -87,8 +100,10 @@ bool CallOptimization::IsCompatibleReceiverMap(
UNREACHABLE();
}
template <class LocalIsolate>
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);
if (call_code.IsUndefined(isolate)) return;
api_call_info_ = handle(CallHandlerInfo::cast(call_code), isolate);
......@@ -102,7 +117,8 @@ void CallOptimization::Initialize(
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) {
if (function.is_null() || !function->is_compiled()) return;
......@@ -110,7 +126,8 @@ void CallOptimization::Initialize(Isolate* isolate,
AnalyzePossibleApiFunction(isolate, function);
}
void CallOptimization::AnalyzePossibleApiFunction(Isolate* isolate,
template <class LocalIsolate>
void CallOptimization::AnalyzePossibleApiFunction(LocalIsolate* isolate,
Handle<JSFunction> function) {
if (!function->shared().IsApiFunction()) return;
Handle<FunctionTemplateInfo> info(function->shared().get_api_func_data(),
......
......@@ -10,10 +10,12 @@
namespace v8 {
namespace internal {
// Holds information about possible function call optimizations.
class CallOptimization {
public:
CallOptimization(Isolate* isolate, Handle<Object> function);
template <class LocalIsolate>
CallOptimization(LocalIsolate* isolate, Handle<Object> function);
Context GetAccessorContext(Map holder_map) const;
bool IsCrossContextLazyAccessorPair(Context native_context,
......@@ -43,20 +45,26 @@ class CallOptimization {
}
enum HolderLookup { kHolderNotFound, kHolderIsReceiver, kHolderFound };
template <class LocalIsolate>
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,
Handle<JSObject> holder, HolderLookup) const;
private:
void Initialize(Isolate* isolate, Handle<JSFunction> function);
void Initialize(Isolate* isolate,
template <class LocalIsolate>
void Initialize(LocalIsolate* isolate, Handle<JSFunction> function);
template <class LocalIsolate>
void Initialize(LocalIsolate* isolate,
Handle<FunctionTemplateInfo> function_template_info);
// Determines whether the given function can be called using the
// fast api call builtin.
void AnalyzePossibleApiFunction(Isolate* isolate,
template <class LocalIsolate>
void AnalyzePossibleApiFunction(LocalIsolate* isolate,
Handle<JSFunction> function);
Handle<JSFunction> constant_function_;
......@@ -65,9 +73,10 @@ class CallOptimization {
// TODO(gsathya): Change these to be a bitfield and do a single fast check
// rather than two checks.
bool is_simple_api_call_;
bool accept_any_receiver_;
bool is_simple_api_call_ = false;
bool accept_any_receiver_ = false;
};
} // namespace internal
} // namespace v8
......
......@@ -605,7 +605,7 @@ bool IC::UpdateMegaDOMIC(const MaybeObjectHandle& handler, Handle<Name> name) {
// Check if the receiver is the holder
CallOptimization::HolderLookup holder_lookup;
call_optimization.LookupHolderOfExpectedType(map, &holder_lookup);
call_optimization.LookupHolderOfExpectedType(isolate(), map, &holder_lookup);
if (holder_lookup != CallOptimization::kHolderIsReceiver) return false;
Handle<Context> accessor_context(call_optimization.GetAccessorContext(*map),
......@@ -947,7 +947,8 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
if (call_optimization.is_simple_api_call()) {
CallOptimization::HolderLookup holder_lookup;
Handle<JSObject> api_holder =
call_optimization.LookupHolderOfExpectedType(map, &holder_lookup);
call_optimization.LookupHolderOfExpectedType(isolate(), map,
&holder_lookup);
if (!call_optimization.IsCompatibleReceiverMap(api_holder, holder,
holder_lookup) ||
......@@ -1810,7 +1811,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
CallOptimization::HolderLookup holder_lookup;
Handle<JSObject> api_holder =
call_optimization.LookupHolderOfExpectedType(
lookup_start_object_map(), &holder_lookup);
isolate(), lookup_start_object_map(), &holder_lookup);
if (call_optimization.IsCompatibleReceiverMap(api_holder, holder,
holder_lookup)) {
Handle<Smi> smi_handler = StoreHandler::StoreApiSetter(
......
......@@ -1254,13 +1254,13 @@ bool LookupIterator::LookupCachedProperty(Handle<AccessorPair> accessor_pair) {
DCHECK_EQ(state(), LookupIterator::ACCESSOR);
DCHECK(GetAccessors()->IsAccessorPair(isolate_));
Handle<Object> getter(accessor_pair->getter(isolate_), isolate());
MaybeHandle<Name> maybe_name =
FunctionTemplateInfo::TryGetCachedPropertyName(isolate(), getter);
if (maybe_name.is_null()) return false;
base::Optional<Name> maybe_name =
FunctionTemplateInfo::TryGetCachedPropertyName(
isolate(), accessor_pair->getter(isolate_));
if (!maybe_name.has_value()) return false;
// We have found a cached property! Modify the iterator accordingly.
name_ = maybe_name.ToHandleChecked();
name_ = handle(maybe_name.value(), isolate_);
Restart();
CHECK_EQ(state(), LookupIterator::DATA);
return true;
......
......@@ -45,17 +45,16 @@ Map Map::GetPrototypeChainRootMap(Isolate* isolate) const {
}
// static
MaybeHandle<JSFunction> Map::GetConstructorFunction(
Handle<Map> map, Handle<Context> native_context) {
if (map->IsPrimitiveMap()) {
int const constructor_function_index = map->GetConstructorFunctionIndex();
base::Optional<JSFunction> Map::GetConstructorFunction(Map map,
Context native_context) {
DisallowGarbageCollection no_gc;
if (map.IsPrimitiveMap()) {
int const constructor_function_index = map.GetConstructorFunctionIndex();
if (constructor_function_index != kNoConstructorFunctionIndex) {
return handle(
JSFunction::cast(native_context->get(constructor_function_index)),
native_context->GetIsolate());
return JSFunction::cast(native_context.get(constructor_function_index));
}
}
return MaybeHandle<JSFunction>();
return {};
}
Map Map::GetInstanceTypeMap(ReadOnlyRoots roots, InstanceType type) {
......
......@@ -211,8 +211,8 @@ class Map : public HeapObject {
static const int kNoConstructorFunctionIndex = 0;
inline int GetConstructorFunctionIndex() const;
inline void SetConstructorFunctionIndex(int value);
static MaybeHandle<JSFunction> GetConstructorFunction(
Handle<Map> map, Handle<Context> native_context);
static base::Optional<JSFunction> GetConstructorFunction(
Map map, Context native_context);
// Retrieve interceptors.
DECL_GETTER(GetNamedInterceptor, InterceptorInfo)
......
......@@ -6647,17 +6647,14 @@ AccessCheckInfo AccessCheckInfo::Get(Isolate* isolate,
return AccessCheckInfo::cast(data_obj);
}
MaybeHandle<Name> FunctionTemplateInfo::TryGetCachedPropertyName(
Isolate* isolate, Handle<Object> getter) {
if (getter->IsFunctionTemplateInfo()) {
Handle<FunctionTemplateInfo> fti =
Handle<FunctionTemplateInfo>::cast(getter);
// Check if the accessor uses a cached property.
if (!fti->cached_property_name().IsTheHole(isolate)) {
return handle(Name::cast(fti->cached_property_name()), isolate);
}
}
return MaybeHandle<Name>();
base::Optional<Name> FunctionTemplateInfo::TryGetCachedPropertyName(
Isolate* isolate, Object getter) {
DisallowGarbageCollection no_gc;
if (!getter.IsFunctionTemplateInfo()) return {};
// Check if the accessor uses a cached property.
Object maybe_name = FunctionTemplateInfo::cast(getter).cached_property_name();
if (maybe_name.IsTheHole(isolate)) return {};
return Name::cast(maybe_name);
}
Address Smi::LexicographicCompare(Isolate* isolate, Smi x, Smi y) {
......
......@@ -160,8 +160,8 @@ class FunctionTemplateInfo
inline bool BreakAtEntry();
// Helper function for cached accessors.
static MaybeHandle<Name> TryGetCachedPropertyName(Isolate* isolate,
Handle<Object> getter);
static base::Optional<Name> TryGetCachedPropertyName(Isolate* isolate,
Object getter);
// Bit position in the flag, from least significant bit position.
DEFINE_TORQUE_GENERATED_FUNCTION_TEMPLATE_INFO_FLAGS()
......
......@@ -27,7 +27,7 @@
// Flags: --track-fields --track-double-fields --allow-natives-syntax
// Flags: --concurrent-recompilation --block-concurrent-recompilation
// Flags: --no-always-opt
// Flags: --no-always-opt --no-turbo-concurrent-get-property-access-info
if (!%IsConcurrentRecompilationSupported()) {
print("Concurrent recompilation is disabled. Skipping this test.");
......
......@@ -27,7 +27,7 @@
// Flags: --allow-natives-syntax --no-always-opt
// Flags: --concurrent-recompilation --block-concurrent-recompilation
// Flags: --no-always-opt
// Flags: --no-always-opt --no-turbo-concurrent-get-property-access-info
if (!%IsConcurrentRecompilationSupported()) {
print("Concurrent recompilation is disabled. Skipping this test.");
......
......@@ -29,6 +29,7 @@
// Flags: --concurrent-recompilation --block-concurrent-recompilation
// Flags: --nostress-opt --no-always-opt
// Flags: --no-turbo-direct-heap-access
// Flags: --no-turbo-concurrent-get-property-access-info
// --nostress-opt is in place because this particular optimization
// (guaranteeing that the Array prototype chain has no elements) is
......
......@@ -5,6 +5,7 @@
// Flags: --allow-natives-syntax --opt --no-always-opt
// Flags: --no-stress-flush-bytecode
// Flags: --block-concurrent-recompilation
// Flags: --no-turbo-concurrent-get-property-access-info
//
// Tests tracking of constness of properties stored in dictionary
// 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