[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
|
||||
// - receiver, which is the [[BoundTargetFunction]]
|
||||
// - 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* bound_this = (node->op()->ValueInputCount() < 3)
|
||||
? jsgraph()->UndefinedConstant()
|
||||
|
@ -2155,8 +2155,9 @@ JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone,
|
||||
tracing_enabled_(tracing_enabled),
|
||||
feedback_(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
|
||||
// initial capacity is redundant in the normal use case (concurrent
|
||||
// compilation enabled, standard objects to be serialized), as the map
|
||||
@ -4138,8 +4139,29 @@ base::Optional<NameRef> JSHeapBroker::GetNameFeedback(
|
||||
PropertyAccessInfo JSHeapBroker::GetAccessInfoForLoadingThen(MapRef map) {
|
||||
auto access_info = ais_for_loading_then_.find(map);
|
||||
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(
|
||||
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 access_info->second;
|
||||
@ -4157,30 +4179,27 @@ void JSHeapBroker::CreateAccessInfoForLoadingThen(
|
||||
}
|
||||
}
|
||||
|
||||
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 access_info->second;
|
||||
PropertyAccessInfo const& JSHeapBroker::CreateAccessInfoForLoadingHasInstance(
|
||||
MapRef map, CompilationDependencies* dependencies) {
|
||||
auto it = ais_for_loading_has_instance_.find(map);
|
||||
if (it != ais_for_loading_has_instance_.end()) return it->second;
|
||||
|
||||
AccessInfoFactory access_info_factory(this, dependencies, zone());
|
||||
auto access_info = access_info_factory.ComputePropertyAccessInfo(
|
||||
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(
|
||||
MapRef map, CompilationDependencies* dependencies) {
|
||||
auto access_info = ais_for_loading_exec_.find(map);
|
||||
if (access_info != ais_for_loading_exec_.end()) {
|
||||
return access_info->second;
|
||||
}
|
||||
auto it = ais_for_loading_exec_.find(map);
|
||||
if (it != ais_for_loading_exec_.end()) return it->second;
|
||||
|
||||
ZoneVector<PropertyAccessInfo> access_infos(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);
|
||||
|
||||
auto inserted_ai = ais_for_loading_exec_.insert(std::make_pair(map, ai_exec));
|
||||
return inserted_ai.first->second;
|
||||
return ais_for_loading_exec_.insert({map, access_info}).first->second;
|
||||
}
|
||||
|
||||
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
|
||||
// PropertyAccessInfo.
|
||||
PropertyAccessInfo GetAccessInfoForLoadingThen(MapRef map);
|
||||
void CreateAccessInfoForLoadingThen(MapRef map,
|
||||
CompilationDependencies* dependencies);
|
||||
PropertyAccessInfo GetAccessInfoForLoadingExec(MapRef map);
|
||||
PropertyAccessInfo GetAccessInfoForLoadingHasInstance(MapRef map);
|
||||
PropertyAccessInfo GetAccessInfoForLoadingThen(MapRef map);
|
||||
PropertyAccessInfo const& CreateAccessInfoForLoadingExec(
|
||||
MapRef map, CompilationDependencies* dependencies);
|
||||
PropertyAccessInfo const& CreateAccessInfoForLoadingHasInstance(
|
||||
MapRef map, CompilationDependencies* dependencies);
|
||||
void CreateAccessInfoForLoadingThen(MapRef map,
|
||||
CompilationDependencies* dependencies);
|
||||
|
||||
std::ostream& Trace();
|
||||
void IncrementTracingIndentation();
|
||||
@ -156,8 +159,9 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
|
||||
typedef ZoneUnorderedMap<MapRef, PropertyAccessInfo, ObjectRef::Hash,
|
||||
ObjectRef::Equal>
|
||||
MapToAccessInfos;
|
||||
MapToAccessInfos ais_for_loading_then_;
|
||||
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 kInitialRefsBucketCount = 1024; // must be power of 2
|
||||
|
@ -398,22 +398,31 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
|
||||
// we have feedback from the InstanceOfIC.
|
||||
Handle<JSObject> receiver;
|
||||
HeapObjectMatcher m(constructor);
|
||||
if (m.HasValue() && m.Value()->IsJSObject()) {
|
||||
receiver = Handle<JSObject>::cast(m.Value());
|
||||
if (m.HasValue() && m.Ref(broker()).IsJSObject()) {
|
||||
receiver = m.Ref(broker()).AsJSObject().object();
|
||||
} else if (p.feedback().IsValid()) {
|
||||
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
|
||||
if (!nexus.GetConstructorFeedback().ToHandle(&receiver)) return NoChange();
|
||||
if (!nexus.GetConstructorFeedback().ToHandle(&receiver)) {
|
||||
return NoChange();
|
||||
}
|
||||
} else {
|
||||
return NoChange();
|
||||
}
|
||||
Handle<Map> receiver_map(receiver->map(), isolate());
|
||||
|
||||
// Compute property access info for @@hasInstance on the constructor.
|
||||
JSObjectRef receiver_ref(broker(), receiver);
|
||||
MapRef receiver_map = receiver_ref.map();
|
||||
|
||||
PropertyAccessInfo access_info = PropertyAccessInfo::Invalid(graph()->zone());
|
||||
if (FLAG_concurrent_inlining) {
|
||||
access_info = broker()->GetAccessInfoForLoadingHasInstance(receiver_map);
|
||||
} else {
|
||||
AccessInfoFactory access_info_factory(broker(), dependencies(),
|
||||
graph()->zone());
|
||||
PropertyAccessInfo access_info =
|
||||
access_info_factory.ComputePropertyAccessInfo(
|
||||
receiver_map, factory()->has_instance_symbol(), AccessMode::kLoad);
|
||||
access_info = access_info_factory.ComputePropertyAccessInfo(
|
||||
receiver_map.object(), factory()->has_instance_symbol(),
|
||||
AccessMode::kLoad);
|
||||
}
|
||||
|
||||
if (access_info.IsInvalid()) return NoChange();
|
||||
access_info.RecordDependencies(dependencies());
|
||||
|
||||
@ -422,7 +431,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
|
||||
if (access_info.IsNotFound()) {
|
||||
// If there's no @@hasInstance handler, the OrdinaryHasInstance operation
|
||||
// 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(),
|
||||
kStartAtPrototype);
|
||||
@ -441,17 +450,15 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
|
||||
}
|
||||
|
||||
if (access_info.IsDataConstant()) {
|
||||
// Determine actual holder.
|
||||
Handle<JSObject> holder;
|
||||
bool found_on_proto = access_info.holder().ToHandle(&holder);
|
||||
if (!found_on_proto) holder = receiver;
|
||||
|
||||
FieldIndex field_index = access_info.field_index();
|
||||
Handle<Object> constant = JSObject::FastPropertyAt(
|
||||
holder, access_info.field_representation(), field_index);
|
||||
if (!constant->IsCallable()) {
|
||||
JSObjectRef holder_ref =
|
||||
found_on_proto ? JSObjectRef(broker(), holder) : receiver_ref;
|
||||
base::Optional<ObjectRef> constant = holder_ref.GetOwnDataProperty(
|
||||
access_info.field_representation(), access_info.field_index());
|
||||
if (!constant.has_value() || !constant->IsHeapObject() ||
|
||||
!constant->AsHeapObject().map().is_callable())
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
if (found_on_proto) {
|
||||
dependencies()->DependOnStablePrototypeChains(
|
||||
@ -459,8 +466,6 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
|
||||
JSObjectRef(broker(), holder));
|
||||
}
|
||||
|
||||
DCHECK(constant->IsCallable());
|
||||
|
||||
// Check that {constructor} is actually {receiver}.
|
||||
constructor =
|
||||
access_builder.BuildCheckValue(constructor, &effect, control, receiver);
|
||||
@ -480,7 +485,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
|
||||
0, frame_state, ContinuationFrameStateMode::LAZY);
|
||||
|
||||
// Call the @@hasInstance handler.
|
||||
Node* target = jsgraph()->Constant(constant);
|
||||
Node* target = jsgraph()->Constant(*constant);
|
||||
node->InsertInput(graph()->zone(), 0, target);
|
||||
node->ReplaceInput(1, constructor);
|
||||
node->ReplaceInput(2, object);
|
||||
@ -615,7 +620,7 @@ Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
|
||||
// of the instanceof operator again.
|
||||
JSBoundFunctionRef function = m.Ref(broker()).AsJSBoundFunction();
|
||||
if (FLAG_concurrent_inlining && !function.serialized()) {
|
||||
TRACE_BROKER_MISSING(broker(), "data for function " << function);
|
||||
TRACE_BROKER_MISSING(broker(), "data for JSBoundFunction " << function);
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
@ -634,7 +639,7 @@ Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
|
||||
|
||||
JSFunctionRef function = m.Ref(broker()).AsJSFunction();
|
||||
if (FLAG_concurrent_inlining && !function.serialized()) {
|
||||
TRACE_BROKER_MISSING(broker(), "data for function " << function);
|
||||
TRACE_BROKER_MISSING(broker(), "data for JSFunction " << function);
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
|
@ -373,11 +373,17 @@ class SerializerForBackgroundCompilation {
|
||||
FeedbackSlot slot, AccessMode mode);
|
||||
void ProcessMapHintsForPromises(Hints const& receiver_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);
|
||||
PropertyAccessInfo ProcessMapForRegExpTest(MapRef map);
|
||||
void ProcessHintsForFunctionCall(Hints const& target_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);
|
||||
NamedAccessFeedback const* ProcessFeedbackMapsForNamedAccess(
|
||||
@ -1676,14 +1682,19 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
|
||||
break;
|
||||
case Builtins::kObjectPrototypeIsPrototypeOf:
|
||||
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;
|
||||
case Builtins::kFastFunctionPrototypeBind:
|
||||
if (arguments.size() >= 2 &&
|
||||
if (arguments.size() >= 1 &&
|
||||
speculation_mode != SpeculationMode::kDisallowSpeculation) {
|
||||
Hints const& receiver_hints = arguments[1];
|
||||
ProcessHintsForFunctionBind(receiver_hints);
|
||||
ProcessHintsForFunctionBind(arguments[0]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -1691,8 +1702,22 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
|
||||
}
|
||||
}
|
||||
|
||||
void SerializerForBackgroundCompilation::ProcessHintsForObjectIsPrototypeOf(
|
||||
Hints const& value_hints) {
|
||||
void SerializerForBackgroundCompilation::ProcessHintsForOrdinaryHasInstance(
|
||||
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) {
|
||||
MapRef map(broker(), map_handle);
|
||||
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;
|
||||
Handle<HeapObject> object(Handle<HeapObject>::cast(hint));
|
||||
processMap(handle(object->map(), broker()->isolate()));
|
||||
}
|
||||
for (auto map_hint : value_hints.maps()) {
|
||||
for (auto map_hint : instance_hints.maps()) {
|
||||
processMap(map_hint);
|
||||
}
|
||||
}
|
||||
@ -2237,14 +2262,67 @@ void SerializerForBackgroundCompilation::VisitTestIn(
|
||||
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(
|
||||
BytecodeArrayIterator* iterator) {
|
||||
Hints const& lhs =
|
||||
environment()->register_hints(iterator->GetRegisterOperand(0));
|
||||
Hints const& rhs = environment()->accumulator_hints();
|
||||
Hints& rhs = environment()->accumulator_hints();
|
||||
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();
|
||||
FeedbackNexus nexus(feedback_vector, slot);
|
||||
@ -2252,21 +2330,16 @@ void SerializerForBackgroundCompilation::VisitTestInstanceOf(
|
||||
Handle<JSObject> constructor;
|
||||
if (rhs_feedback.IsValid() &&
|
||||
nexus.GetConstructorFeedback().ToHandle(&constructor)) {
|
||||
if (constructor->IsJSBoundFunction()) {
|
||||
JSBoundFunctionRef(broker(), constructor).Serialize();
|
||||
} else if (constructor->IsJSFunction()) {
|
||||
JSFunctionRef(broker(), constructor).Serialize();
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
rhs.AddConstant(constructor);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(neis): Support full instanceof semantics.
|
||||
|
||||
ProcessHintsForObjectIsPrototypeOf(lhs);
|
||||
|
||||
// TODO(neis): Process rhs hints.
|
||||
USE(rhs);
|
||||
bool walk_prototypes = false;
|
||||
for (Handle<Object> constant : rhs.constants()) {
|
||||
ProcessConstantForInstanceOf(ObjectRef(broker(), constant),
|
||||
&walk_prototypes);
|
||||
}
|
||||
if (walk_prototypes) ProcessHintsForHasInPrototypeChain(lhs);
|
||||
}
|
||||
|
||||
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