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 {
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