[turbofan] Second part of brokerization/serialization for instanceof
Serialize for all cases of JSNativeContextSpecialization::ReduceJSInstanceOf. Bug: v8:7790 Change-Id: I147991353b86619808257a92961b7051105511f1 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1722558 Commit-Queue: Georg Neis <neis@chromium.org> Reviewed-by: Maya Lekova <mslekova@chromium.org> Cr-Commit-Position: refs/heads/master@{#62965}
This commit is contained in:
parent
e016562bf9
commit
6636420fce
@ -507,7 +507,7 @@ Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
|
|||||||
// - target, which is Function.prototype.bind JSFunction
|
// - target, which is Function.prototype.bind JSFunction
|
||||||
// - receiver, which is the [[BoundTargetFunction]]
|
// - receiver, which is the [[BoundTargetFunction]]
|
||||||
// - bound_this (optional), which is the [[BoundThis]]
|
// - bound_this (optional), which is the [[BoundThis]]
|
||||||
// - and all the remaining value inouts are [[BoundArguments]]
|
// - and all the remaining value inputs are [[BoundArguments]]
|
||||||
Node* receiver = NodeProperties::GetValueInput(node, 1);
|
Node* receiver = NodeProperties::GetValueInput(node, 1);
|
||||||
Node* bound_this = (node->op()->ValueInputCount() < 3)
|
Node* bound_this = (node->op()->ValueInputCount() < 3)
|
||||||
? jsgraph()->UndefinedConstant()
|
? jsgraph()->UndefinedConstant()
|
||||||
|
@ -2155,8 +2155,9 @@ JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone,
|
|||||||
tracing_enabled_(tracing_enabled),
|
tracing_enabled_(tracing_enabled),
|
||||||
feedback_(zone()),
|
feedback_(zone()),
|
||||||
bytecode_analyses_(zone()),
|
bytecode_analyses_(zone()),
|
||||||
ais_for_loading_then_(zone()),
|
ais_for_loading_exec_(zone()),
|
||||||
ais_for_loading_exec_(zone()) {
|
ais_for_loading_has_instance_(zone()),
|
||||||
|
ais_for_loading_then_(zone()) {
|
||||||
// Note that this initialization of the refs_ pointer with the minimal
|
// Note that this initialization of the refs_ pointer with the minimal
|
||||||
// initial capacity is redundant in the normal use case (concurrent
|
// initial capacity is redundant in the normal use case (concurrent
|
||||||
// compilation enabled, standard objects to be serialized), as the map
|
// compilation enabled, standard objects to be serialized), as the map
|
||||||
@ -4138,8 +4139,29 @@ base::Optional<NameRef> JSHeapBroker::GetNameFeedback(
|
|||||||
PropertyAccessInfo JSHeapBroker::GetAccessInfoForLoadingThen(MapRef map) {
|
PropertyAccessInfo JSHeapBroker::GetAccessInfoForLoadingThen(MapRef map) {
|
||||||
auto access_info = ais_for_loading_then_.find(map);
|
auto access_info = ais_for_loading_then_.find(map);
|
||||||
if (access_info == ais_for_loading_then_.end()) {
|
if (access_info == ais_for_loading_then_.end()) {
|
||||||
|
TRACE_BROKER_MISSING(this,
|
||||||
|
"access info for property 'then' on map " << map);
|
||||||
|
return PropertyAccessInfo::Invalid(zone());
|
||||||
|
}
|
||||||
|
return access_info->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyAccessInfo JSHeapBroker::GetAccessInfoForLoadingHasInstance(
|
||||||
|
MapRef map) {
|
||||||
|
auto access_info = ais_for_loading_has_instance_.find(map);
|
||||||
|
if (access_info == ais_for_loading_has_instance_.end()) {
|
||||||
TRACE_BROKER_MISSING(
|
TRACE_BROKER_MISSING(
|
||||||
this, "access info for reducing JSResolvePromise with map " << map);
|
this, "access info for property Symbol.hasInstance on map " << map);
|
||||||
|
return PropertyAccessInfo::Invalid(zone());
|
||||||
|
}
|
||||||
|
return access_info->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyAccessInfo JSHeapBroker::GetAccessInfoForLoadingExec(MapRef map) {
|
||||||
|
auto access_info = ais_for_loading_exec_.find(map);
|
||||||
|
if (access_info == ais_for_loading_exec_.end()) {
|
||||||
|
TRACE_BROKER_MISSING(this,
|
||||||
|
"access info for property 'exec' on map " << map);
|
||||||
return PropertyAccessInfo::Invalid(zone());
|
return PropertyAccessInfo::Invalid(zone());
|
||||||
}
|
}
|
||||||
return access_info->second;
|
return access_info->second;
|
||||||
@ -4157,30 +4179,27 @@ void JSHeapBroker::CreateAccessInfoForLoadingThen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyAccessInfo JSHeapBroker::GetAccessInfoForLoadingExec(MapRef map) {
|
PropertyAccessInfo const& JSHeapBroker::CreateAccessInfoForLoadingHasInstance(
|
||||||
auto access_info = ais_for_loading_exec_.find(map);
|
MapRef map, CompilationDependencies* dependencies) {
|
||||||
if (access_info == ais_for_loading_exec_.end()) {
|
auto it = ais_for_loading_has_instance_.find(map);
|
||||||
TRACE_BROKER_MISSING(this,
|
if (it != ais_for_loading_has_instance_.end()) return it->second;
|
||||||
"access info for property 'exec' on map " << map);
|
|
||||||
return PropertyAccessInfo::Invalid(zone());
|
AccessInfoFactory access_info_factory(this, dependencies, zone());
|
||||||
}
|
auto access_info = access_info_factory.ComputePropertyAccessInfo(
|
||||||
return access_info->second;
|
map.object(), isolate()->factory()->has_instance_symbol(),
|
||||||
|
AccessMode::kLoad);
|
||||||
|
return ais_for_loading_has_instance_.insert({map, access_info}).first->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyAccessInfo const& JSHeapBroker::CreateAccessInfoForLoadingExec(
|
PropertyAccessInfo const& JSHeapBroker::CreateAccessInfoForLoadingExec(
|
||||||
MapRef map, CompilationDependencies* dependencies) {
|
MapRef map, CompilationDependencies* dependencies) {
|
||||||
auto access_info = ais_for_loading_exec_.find(map);
|
auto it = ais_for_loading_exec_.find(map);
|
||||||
if (access_info != ais_for_loading_exec_.end()) {
|
if (it != ais_for_loading_exec_.end()) return it->second;
|
||||||
return access_info->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZoneVector<PropertyAccessInfo> access_infos(zone());
|
|
||||||
AccessInfoFactory access_info_factory(this, dependencies, zone());
|
AccessInfoFactory access_info_factory(this, dependencies, zone());
|
||||||
PropertyAccessInfo ai_exec = access_info_factory.ComputePropertyAccessInfo(
|
auto access_info = access_info_factory.ComputePropertyAccessInfo(
|
||||||
map.object(), isolate()->factory()->exec_string(), AccessMode::kLoad);
|
map.object(), isolate()->factory()->exec_string(), AccessMode::kLoad);
|
||||||
|
return ais_for_loading_exec_.insert({map, access_info}).first->second;
|
||||||
auto inserted_ai = ais_for_loading_exec_.insert(std::make_pair(map, ai_exec));
|
|
||||||
return inserted_ai.first->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementAccessFeedback const* ProcessedFeedback::AsElementAccess() const {
|
ElementAccessFeedback const* ProcessedFeedback::AsElementAccess() const {
|
||||||
|
@ -117,12 +117,15 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
|
|||||||
|
|
||||||
// If there is no result stored for {map}, we return an Invalid
|
// If there is no result stored for {map}, we return an Invalid
|
||||||
// PropertyAccessInfo.
|
// PropertyAccessInfo.
|
||||||
PropertyAccessInfo GetAccessInfoForLoadingThen(MapRef map);
|
|
||||||
void CreateAccessInfoForLoadingThen(MapRef map,
|
|
||||||
CompilationDependencies* dependencies);
|
|
||||||
PropertyAccessInfo GetAccessInfoForLoadingExec(MapRef map);
|
PropertyAccessInfo GetAccessInfoForLoadingExec(MapRef map);
|
||||||
|
PropertyAccessInfo GetAccessInfoForLoadingHasInstance(MapRef map);
|
||||||
|
PropertyAccessInfo GetAccessInfoForLoadingThen(MapRef map);
|
||||||
PropertyAccessInfo const& CreateAccessInfoForLoadingExec(
|
PropertyAccessInfo const& CreateAccessInfoForLoadingExec(
|
||||||
MapRef map, CompilationDependencies* dependencies);
|
MapRef map, CompilationDependencies* dependencies);
|
||||||
|
PropertyAccessInfo const& CreateAccessInfoForLoadingHasInstance(
|
||||||
|
MapRef map, CompilationDependencies* dependencies);
|
||||||
|
void CreateAccessInfoForLoadingThen(MapRef map,
|
||||||
|
CompilationDependencies* dependencies);
|
||||||
|
|
||||||
std::ostream& Trace();
|
std::ostream& Trace();
|
||||||
void IncrementTracingIndentation();
|
void IncrementTracingIndentation();
|
||||||
@ -156,8 +159,9 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
|
|||||||
typedef ZoneUnorderedMap<MapRef, PropertyAccessInfo, ObjectRef::Hash,
|
typedef ZoneUnorderedMap<MapRef, PropertyAccessInfo, ObjectRef::Hash,
|
||||||
ObjectRef::Equal>
|
ObjectRef::Equal>
|
||||||
MapToAccessInfos;
|
MapToAccessInfos;
|
||||||
MapToAccessInfos ais_for_loading_then_;
|
|
||||||
MapToAccessInfos ais_for_loading_exec_;
|
MapToAccessInfos ais_for_loading_exec_;
|
||||||
|
MapToAccessInfos ais_for_loading_has_instance_;
|
||||||
|
MapToAccessInfos ais_for_loading_then_;
|
||||||
|
|
||||||
static const size_t kMinimalRefsBucketCount = 8; // must be power of 2
|
static const size_t kMinimalRefsBucketCount = 8; // must be power of 2
|
||||||
static const size_t kInitialRefsBucketCount = 1024; // must be power of 2
|
static const size_t kInitialRefsBucketCount = 1024; // must be power of 2
|
||||||
|
@ -398,22 +398,31 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
|
|||||||
// we have feedback from the InstanceOfIC.
|
// we have feedback from the InstanceOfIC.
|
||||||
Handle<JSObject> receiver;
|
Handle<JSObject> receiver;
|
||||||
HeapObjectMatcher m(constructor);
|
HeapObjectMatcher m(constructor);
|
||||||
if (m.HasValue() && m.Value()->IsJSObject()) {
|
if (m.HasValue() && m.Ref(broker()).IsJSObject()) {
|
||||||
receiver = Handle<JSObject>::cast(m.Value());
|
receiver = m.Ref(broker()).AsJSObject().object();
|
||||||
} else if (p.feedback().IsValid()) {
|
} else if (p.feedback().IsValid()) {
|
||||||
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
|
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
|
||||||
if (!nexus.GetConstructorFeedback().ToHandle(&receiver)) return NoChange();
|
if (!nexus.GetConstructorFeedback().ToHandle(&receiver)) {
|
||||||
|
return NoChange();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return NoChange();
|
return NoChange();
|
||||||
}
|
}
|
||||||
Handle<Map> receiver_map(receiver->map(), isolate());
|
|
||||||
|
|
||||||
// Compute property access info for @@hasInstance on the constructor.
|
JSObjectRef receiver_ref(broker(), receiver);
|
||||||
AccessInfoFactory access_info_factory(broker(), dependencies(),
|
MapRef receiver_map = receiver_ref.map();
|
||||||
graph()->zone());
|
|
||||||
PropertyAccessInfo access_info =
|
PropertyAccessInfo access_info = PropertyAccessInfo::Invalid(graph()->zone());
|
||||||
access_info_factory.ComputePropertyAccessInfo(
|
if (FLAG_concurrent_inlining) {
|
||||||
receiver_map, factory()->has_instance_symbol(), AccessMode::kLoad);
|
access_info = broker()->GetAccessInfoForLoadingHasInstance(receiver_map);
|
||||||
|
} else {
|
||||||
|
AccessInfoFactory access_info_factory(broker(), dependencies(),
|
||||||
|
graph()->zone());
|
||||||
|
access_info = access_info_factory.ComputePropertyAccessInfo(
|
||||||
|
receiver_map.object(), factory()->has_instance_symbol(),
|
||||||
|
AccessMode::kLoad);
|
||||||
|
}
|
||||||
|
|
||||||
if (access_info.IsInvalid()) return NoChange();
|
if (access_info.IsInvalid()) return NoChange();
|
||||||
access_info.RecordDependencies(dependencies());
|
access_info.RecordDependencies(dependencies());
|
||||||
|
|
||||||
@ -422,7 +431,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
|
|||||||
if (access_info.IsNotFound()) {
|
if (access_info.IsNotFound()) {
|
||||||
// If there's no @@hasInstance handler, the OrdinaryHasInstance operation
|
// If there's no @@hasInstance handler, the OrdinaryHasInstance operation
|
||||||
// takes over, but that requires the constructor to be callable.
|
// takes over, but that requires the constructor to be callable.
|
||||||
if (!receiver_map->is_callable()) return NoChange();
|
if (!receiver_map.is_callable()) return NoChange();
|
||||||
|
|
||||||
dependencies()->DependOnStablePrototypeChains(access_info.receiver_maps(),
|
dependencies()->DependOnStablePrototypeChains(access_info.receiver_maps(),
|
||||||
kStartAtPrototype);
|
kStartAtPrototype);
|
||||||
@ -441,17 +450,15 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (access_info.IsDataConstant()) {
|
if (access_info.IsDataConstant()) {
|
||||||
// Determine actual holder.
|
|
||||||
Handle<JSObject> holder;
|
Handle<JSObject> holder;
|
||||||
bool found_on_proto = access_info.holder().ToHandle(&holder);
|
bool found_on_proto = access_info.holder().ToHandle(&holder);
|
||||||
if (!found_on_proto) holder = receiver;
|
JSObjectRef holder_ref =
|
||||||
|
found_on_proto ? JSObjectRef(broker(), holder) : receiver_ref;
|
||||||
FieldIndex field_index = access_info.field_index();
|
base::Optional<ObjectRef> constant = holder_ref.GetOwnDataProperty(
|
||||||
Handle<Object> constant = JSObject::FastPropertyAt(
|
access_info.field_representation(), access_info.field_index());
|
||||||
holder, access_info.field_representation(), field_index);
|
if (!constant.has_value() || !constant->IsHeapObject() ||
|
||||||
if (!constant->IsCallable()) {
|
!constant->AsHeapObject().map().is_callable())
|
||||||
return NoChange();
|
return NoChange();
|
||||||
}
|
|
||||||
|
|
||||||
if (found_on_proto) {
|
if (found_on_proto) {
|
||||||
dependencies()->DependOnStablePrototypeChains(
|
dependencies()->DependOnStablePrototypeChains(
|
||||||
@ -459,8 +466,6 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
|
|||||||
JSObjectRef(broker(), holder));
|
JSObjectRef(broker(), holder));
|
||||||
}
|
}
|
||||||
|
|
||||||
DCHECK(constant->IsCallable());
|
|
||||||
|
|
||||||
// Check that {constructor} is actually {receiver}.
|
// Check that {constructor} is actually {receiver}.
|
||||||
constructor =
|
constructor =
|
||||||
access_builder.BuildCheckValue(constructor, &effect, control, receiver);
|
access_builder.BuildCheckValue(constructor, &effect, control, receiver);
|
||||||
@ -480,7 +485,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
|
|||||||
0, frame_state, ContinuationFrameStateMode::LAZY);
|
0, frame_state, ContinuationFrameStateMode::LAZY);
|
||||||
|
|
||||||
// Call the @@hasInstance handler.
|
// Call the @@hasInstance handler.
|
||||||
Node* target = jsgraph()->Constant(constant);
|
Node* target = jsgraph()->Constant(*constant);
|
||||||
node->InsertInput(graph()->zone(), 0, target);
|
node->InsertInput(graph()->zone(), 0, target);
|
||||||
node->ReplaceInput(1, constructor);
|
node->ReplaceInput(1, constructor);
|
||||||
node->ReplaceInput(2, object);
|
node->ReplaceInput(2, object);
|
||||||
@ -615,7 +620,7 @@ Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
|
|||||||
// of the instanceof operator again.
|
// of the instanceof operator again.
|
||||||
JSBoundFunctionRef function = m.Ref(broker()).AsJSBoundFunction();
|
JSBoundFunctionRef function = m.Ref(broker()).AsJSBoundFunction();
|
||||||
if (FLAG_concurrent_inlining && !function.serialized()) {
|
if (FLAG_concurrent_inlining && !function.serialized()) {
|
||||||
TRACE_BROKER_MISSING(broker(), "data for function " << function);
|
TRACE_BROKER_MISSING(broker(), "data for JSBoundFunction " << function);
|
||||||
return NoChange();
|
return NoChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -634,7 +639,7 @@ Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
|
|||||||
|
|
||||||
JSFunctionRef function = m.Ref(broker()).AsJSFunction();
|
JSFunctionRef function = m.Ref(broker()).AsJSFunction();
|
||||||
if (FLAG_concurrent_inlining && !function.serialized()) {
|
if (FLAG_concurrent_inlining && !function.serialized()) {
|
||||||
TRACE_BROKER_MISSING(broker(), "data for function " << function);
|
TRACE_BROKER_MISSING(broker(), "data for JSFunction " << function);
|
||||||
return NoChange();
|
return NoChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,11 +373,17 @@ class SerializerForBackgroundCompilation {
|
|||||||
FeedbackSlot slot, AccessMode mode);
|
FeedbackSlot slot, AccessMode mode);
|
||||||
void ProcessMapHintsForPromises(Hints const& receiver_hints);
|
void ProcessMapHintsForPromises(Hints const& receiver_hints);
|
||||||
void ProcessHintsForPromiseResolve(Hints const& resolution_hints);
|
void ProcessHintsForPromiseResolve(Hints const& resolution_hints);
|
||||||
void ProcessHintsForObjectIsPrototypeOf(Hints const& value_hints);
|
void ProcessHintsForHasInPrototypeChain(Hints const& instance_hints);
|
||||||
void ProcessHintsForRegExpTest(Hints const& regexp_hints);
|
void ProcessHintsForRegExpTest(Hints const& regexp_hints);
|
||||||
PropertyAccessInfo ProcessMapForRegExpTest(MapRef map);
|
PropertyAccessInfo ProcessMapForRegExpTest(MapRef map);
|
||||||
void ProcessHintsForFunctionCall(Hints const& target_hints);
|
void ProcessHintsForFunctionCall(Hints const& target_hints);
|
||||||
void ProcessHintsForFunctionBind(Hints const& receiver_hints);
|
void ProcessHintsForFunctionBind(Hints const& receiver_hints);
|
||||||
|
void ProcessConstantForOrdinaryHasInstance(HeapObjectRef const& constructor,
|
||||||
|
bool* walk_prototypes);
|
||||||
|
void ProcessConstantForInstanceOf(ObjectRef const& constant,
|
||||||
|
bool* walk_prototypes);
|
||||||
|
void ProcessHintsForOrdinaryHasInstance(Hints const& constructor_hints,
|
||||||
|
Hints const& instance_hints);
|
||||||
|
|
||||||
GlobalAccessFeedback const* ProcessFeedbackForGlobalAccess(FeedbackSlot slot);
|
GlobalAccessFeedback const* ProcessFeedbackForGlobalAccess(FeedbackSlot slot);
|
||||||
NamedAccessFeedback const* ProcessFeedbackMapsForNamedAccess(
|
NamedAccessFeedback const* ProcessFeedbackMapsForNamedAccess(
|
||||||
@ -1676,14 +1682,19 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
|
|||||||
break;
|
break;
|
||||||
case Builtins::kObjectPrototypeIsPrototypeOf:
|
case Builtins::kObjectPrototypeIsPrototypeOf:
|
||||||
if (arguments.size() >= 2) {
|
if (arguments.size() >= 2) {
|
||||||
ProcessHintsForObjectIsPrototypeOf(arguments[1]);
|
ProcessHintsForHasInPrototypeChain(arguments[1]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Builtins::kFunctionPrototypeHasInstance:
|
||||||
|
// For JSCallReducer::ReduceFunctionPrototypeHasInstance.
|
||||||
|
if (arguments.size() >= 2) {
|
||||||
|
ProcessHintsForOrdinaryHasInstance(arguments[0], arguments[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Builtins::kFastFunctionPrototypeBind:
|
case Builtins::kFastFunctionPrototypeBind:
|
||||||
if (arguments.size() >= 2 &&
|
if (arguments.size() >= 1 &&
|
||||||
speculation_mode != SpeculationMode::kDisallowSpeculation) {
|
speculation_mode != SpeculationMode::kDisallowSpeculation) {
|
||||||
Hints const& receiver_hints = arguments[1];
|
ProcessHintsForFunctionBind(arguments[0]);
|
||||||
ProcessHintsForFunctionBind(receiver_hints);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -1691,8 +1702,22 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerializerForBackgroundCompilation::ProcessHintsForObjectIsPrototypeOf(
|
void SerializerForBackgroundCompilation::ProcessHintsForOrdinaryHasInstance(
|
||||||
Hints const& value_hints) {
|
Hints const& constructor_hints, Hints const& instance_hints) {
|
||||||
|
bool walk_prototypes = false;
|
||||||
|
for (Handle<Object> constructor : constructor_hints.constants()) {
|
||||||
|
// For JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance.
|
||||||
|
if (constructor->IsHeapObject()) {
|
||||||
|
ProcessConstantForOrdinaryHasInstance(
|
||||||
|
HeapObjectRef(broker(), constructor), &walk_prototypes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// For JSNativeContextSpecialization::ReduceJSHasInPrototypeChain.
|
||||||
|
if (walk_prototypes) ProcessHintsForHasInPrototypeChain(instance_hints);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerializerForBackgroundCompilation::ProcessHintsForHasInPrototypeChain(
|
||||||
|
Hints const& instance_hints) {
|
||||||
auto processMap = [&](Handle<Map> map_handle) {
|
auto processMap = [&](Handle<Map> map_handle) {
|
||||||
MapRef map(broker(), map_handle);
|
MapRef map(broker(), map_handle);
|
||||||
while (map.IsJSObjectMap()) {
|
while (map.IsJSObjectMap()) {
|
||||||
@ -1701,12 +1726,12 @@ void SerializerForBackgroundCompilation::ProcessHintsForObjectIsPrototypeOf(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto hint : value_hints.constants()) {
|
for (auto hint : instance_hints.constants()) {
|
||||||
if (!hint->IsHeapObject()) continue;
|
if (!hint->IsHeapObject()) continue;
|
||||||
Handle<HeapObject> object(Handle<HeapObject>::cast(hint));
|
Handle<HeapObject> object(Handle<HeapObject>::cast(hint));
|
||||||
processMap(handle(object->map(), broker()->isolate()));
|
processMap(handle(object->map(), broker()->isolate()));
|
||||||
}
|
}
|
||||||
for (auto map_hint : value_hints.maps()) {
|
for (auto map_hint : instance_hints.maps()) {
|
||||||
processMap(map_hint);
|
processMap(map_hint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2237,36 +2262,84 @@ void SerializerForBackgroundCompilation::VisitTestIn(
|
|||||||
ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kHas);
|
ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kHas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance.
|
||||||
|
void SerializerForBackgroundCompilation::ProcessConstantForOrdinaryHasInstance(
|
||||||
|
HeapObjectRef const& constructor, bool* walk_prototypes) {
|
||||||
|
if (constructor.IsJSBoundFunction()) {
|
||||||
|
constructor.AsJSBoundFunction().Serialize();
|
||||||
|
ProcessConstantForInstanceOf(
|
||||||
|
constructor.AsJSBoundFunction().bound_target_function(),
|
||||||
|
walk_prototypes);
|
||||||
|
} else if (constructor.IsJSFunction()) {
|
||||||
|
constructor.AsJSFunction().Serialize();
|
||||||
|
*walk_prototypes =
|
||||||
|
*walk_prototypes ||
|
||||||
|
(constructor.map().has_prototype_slot() &&
|
||||||
|
constructor.AsJSFunction().has_prototype() &&
|
||||||
|
!constructor.AsJSFunction().PrototypeRequiresRuntimeLookup());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerializerForBackgroundCompilation::ProcessConstantForInstanceOf(
|
||||||
|
ObjectRef const& constructor, bool* walk_prototypes) {
|
||||||
|
if (!constructor.IsHeapObject()) return;
|
||||||
|
HeapObjectRef constructor_heap_object = constructor.AsHeapObject();
|
||||||
|
|
||||||
|
PropertyAccessInfo const& access_info =
|
||||||
|
broker()->CreateAccessInfoForLoadingHasInstance(
|
||||||
|
constructor_heap_object.map(), dependencies());
|
||||||
|
|
||||||
|
if (access_info.IsNotFound()) {
|
||||||
|
ProcessConstantForOrdinaryHasInstance(constructor_heap_object,
|
||||||
|
walk_prototypes);
|
||||||
|
} else if (access_info.IsDataConstant()) {
|
||||||
|
Handle<JSObject> holder;
|
||||||
|
bool found_on_proto = access_info.holder().ToHandle(&holder);
|
||||||
|
JSObjectRef holder_ref = found_on_proto ? JSObjectRef(broker(), holder)
|
||||||
|
: constructor.AsJSObject();
|
||||||
|
base::Optional<ObjectRef> constant = holder_ref.GetOwnDataProperty(
|
||||||
|
access_info.field_representation(), access_info.field_index(), true);
|
||||||
|
CHECK(constant.has_value());
|
||||||
|
if (constant->IsJSFunction()) {
|
||||||
|
JSFunctionRef function = constant->AsJSFunction();
|
||||||
|
function.Serialize();
|
||||||
|
if (function.shared().HasBuiltinId() &&
|
||||||
|
function.shared().builtin_id() ==
|
||||||
|
Builtins::kFunctionPrototypeHasInstance) {
|
||||||
|
// For JSCallReducer::ReduceFunctionPrototypeHasInstance.
|
||||||
|
ProcessConstantForOrdinaryHasInstance(constructor_heap_object,
|
||||||
|
walk_prototypes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SerializerForBackgroundCompilation::VisitTestInstanceOf(
|
void SerializerForBackgroundCompilation::VisitTestInstanceOf(
|
||||||
BytecodeArrayIterator* iterator) {
|
BytecodeArrayIterator* iterator) {
|
||||||
Hints const& lhs =
|
Hints const& lhs =
|
||||||
environment()->register_hints(iterator->GetRegisterOperand(0));
|
environment()->register_hints(iterator->GetRegisterOperand(0));
|
||||||
Hints const& rhs = environment()->accumulator_hints();
|
Hints& rhs = environment()->accumulator_hints();
|
||||||
FeedbackSlot slot = iterator->GetSlotOperand(1);
|
FeedbackSlot slot = iterator->GetSlotOperand(1);
|
||||||
|
|
||||||
// Inspect feedback (about the rhs of the operator).
|
// Incorporate feedback (about the rhs of the operator) into hints.
|
||||||
Handle<FeedbackVector> feedback_vector =
|
{
|
||||||
environment()->function().feedback_vector();
|
Handle<FeedbackVector> feedback_vector =
|
||||||
FeedbackNexus nexus(feedback_vector, slot);
|
environment()->function().feedback_vector();
|
||||||
VectorSlotPair rhs_feedback(feedback_vector, slot, nexus.ic_state());
|
FeedbackNexus nexus(feedback_vector, slot);
|
||||||
Handle<JSObject> constructor;
|
VectorSlotPair rhs_feedback(feedback_vector, slot, nexus.ic_state());
|
||||||
if (rhs_feedback.IsValid() &&
|
Handle<JSObject> constructor;
|
||||||
nexus.GetConstructorFeedback().ToHandle(&constructor)) {
|
if (rhs_feedback.IsValid() &&
|
||||||
if (constructor->IsJSBoundFunction()) {
|
nexus.GetConstructorFeedback().ToHandle(&constructor)) {
|
||||||
JSBoundFunctionRef(broker(), constructor).Serialize();
|
rhs.AddConstant(constructor);
|
||||||
} else if (constructor->IsJSFunction()) {
|
|
||||||
JSFunctionRef(broker(), constructor).Serialize();
|
|
||||||
} else {
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(neis): Support full instanceof semantics.
|
bool walk_prototypes = false;
|
||||||
|
for (Handle<Object> constant : rhs.constants()) {
|
||||||
ProcessHintsForObjectIsPrototypeOf(lhs);
|
ProcessConstantForInstanceOf(ObjectRef(broker(), constant),
|
||||||
|
&walk_prototypes);
|
||||||
// TODO(neis): Process rhs hints.
|
}
|
||||||
USE(rhs);
|
if (walk_prototypes) ProcessHintsForHasInPrototypeChain(lhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerializerForBackgroundCompilation::VisitStaKeyedProperty(
|
void SerializerForBackgroundCompilation::VisitStaKeyedProperty(
|
||||||
|
80
test/mjsunit/compiler/instanceof4.js
Normal file
80
test/mjsunit/compiler/instanceof4.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// Copyright 2019 the V8 project authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// Flags: --allow-natives-syntax
|
||||||
|
|
||||||
|
|
||||||
|
(function testFunctionPrototypeHasInstance() {
|
||||||
|
class A {};
|
||||||
|
var a = new A;
|
||||||
|
|
||||||
|
function foo() {
|
||||||
|
return A[Symbol.hasInstance](a);
|
||||||
|
};
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(foo);
|
||||||
|
assertTrue(foo());
|
||||||
|
assertTrue(foo());
|
||||||
|
%OptimizeFunctionOnNextCall(foo);
|
||||||
|
assertTrue(foo());
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function testFunctionPrototypeHasInstanceWithInference() {
|
||||||
|
class A {};
|
||||||
|
var a = new A;
|
||||||
|
a.bla = 42;
|
||||||
|
|
||||||
|
function foo() {
|
||||||
|
a.bla;
|
||||||
|
return A[Symbol.hasInstance](a);
|
||||||
|
};
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(foo);
|
||||||
|
assertTrue(foo());
|
||||||
|
assertTrue(foo());
|
||||||
|
%OptimizeFunctionOnNextCall(foo);
|
||||||
|
assertTrue(foo());
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function testFunctionPrototypeHasInstanceWithBoundFunction() {
|
||||||
|
class A {};
|
||||||
|
var a = new A;
|
||||||
|
var f = A.bind({});
|
||||||
|
|
||||||
|
function foo() {
|
||||||
|
return f[Symbol.hasInstance](a);
|
||||||
|
};
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(foo);
|
||||||
|
assertTrue(foo());
|
||||||
|
assertTrue(foo());
|
||||||
|
%OptimizeFunctionOnNextCall(foo);
|
||||||
|
assertTrue(foo());
|
||||||
|
|
||||||
|
// JSCallReducer::ReduceFunctionPrototypeHasInstance ->
|
||||||
|
// JSNative...::ReduceJSOrdinaryHasInstance ->
|
||||||
|
// JSNative...::ReduceJSInstanceOf (on bound_target_function)
|
||||||
|
// ~~~~~>
|
||||||
|
// JSCallReducer::ReduceFunctionPrototypeHasInstance
|
||||||
|
// JSNative...::ReduceJSOrdinaryHasInstance ->
|
||||||
|
// JSNative...::ReduceJSHasInPrototypeChain
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function testSimpleInstanceOf() {
|
||||||
|
class A {};
|
||||||
|
var a = new A;
|
||||||
|
|
||||||
|
function foo() {
|
||||||
|
return a instanceof A;
|
||||||
|
};
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(foo);
|
||||||
|
assertTrue(foo());
|
||||||
|
assertTrue(foo());
|
||||||
|
%OptimizeFunctionOnNextCall(foo);
|
||||||
|
assertTrue(foo());
|
||||||
|
})();
|
Loading…
Reference in New Issue
Block a user