[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:
Georg Neis 2019-07-29 19:30:17 +02:00 committed by Commit Bot
parent e016562bf9
commit 6636420fce
6 changed files with 260 additions and 79 deletions

View File

@ -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()

View File

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

View File

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

View File

@ -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();
} }

View File

@ -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(

View 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());
})();