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
This diff is collapsed.
...@@ -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