Commit f9512482 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[turbofan] First part of brokerization/serialization for instanceof

- Move SerializePrototype out of DependOnStablePrototypes into
  ComputePropertyAccessInfo.
- Brokerize JSNativeContextSpecialization::InferHasInPrototypeChain.
- Brokerize JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance
  (modulo the call to ReduceJSInstanceOf).
- Brokerize JSNativeContextSpecialization::ReduceJSHasInPrototypeChain.
- Serialize for JSCallReducer::ReduceObjectPrototypeIsPrototypeOf.
- Serialize for JSNativeContextSpecialization::ReduceJSInstanceOf. This
  is still incomplete.

Bug: v8:7790
Change-Id: Ic56eab5ddd8d725a13d2980e5b55db53ae82e822
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1709408
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62920}
parent f42b1a5d
...@@ -537,6 +537,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo( ...@@ -537,6 +537,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
} }
// Walk up the prototype chain. // Walk up the prototype chain.
MapRef(broker(), map).SerializePrototype();
if (!map->prototype().IsJSObject()) { if (!map->prototype().IsJSObject()) {
// Perform the implicit ToObject for primitives here. // Perform the implicit ToObject for primitives here.
// Implemented according to ES6 section 7.3.2 GetV (V, P). // Implemented according to ES6 section 7.3.2 GetV (V, P).
......
...@@ -550,13 +550,7 @@ namespace { ...@@ -550,13 +550,7 @@ namespace {
// This function expects to never see a JSProxy. // This function expects to never see a JSProxy.
void DependOnStablePrototypeChain(CompilationDependencies* deps, MapRef map, void DependOnStablePrototypeChain(CompilationDependencies* deps, MapRef map,
base::Optional<JSObjectRef> last_prototype) { base::Optional<JSObjectRef> last_prototype) {
// TODO(neis): Remove heap access (SerializePrototype call).
AllowCodeDependencyChange dependency_change_;
AllowHandleAllocation handle_allocation_;
AllowHandleDereference handle_dereference_;
AllowHeapAllocation heap_allocation_;
while (true) { while (true) {
map.SerializePrototype();
HeapObjectRef proto = map.prototype(); HeapObjectRef proto = map.prototype();
if (!proto.IsJSObject()) { if (!proto.IsJSObject()) {
CHECK_EQ(proto.map().oddball_type(), OddballType::kNull); CHECK_EQ(proto.map().oddball_type(), OddballType::kNull);
......
...@@ -70,6 +70,8 @@ enum class OddballType : uint8_t { ...@@ -70,6 +70,8 @@ enum class OddballType : uint8_t {
V(InternalizedString) \ V(InternalizedString) \
V(String) \ V(String) \
V(Symbol) \ V(Symbol) \
/* Subtypes of JSReceiver */ \
V(JSObject) \
/* Subtypes of HeapObject */ \ /* Subtypes of HeapObject */ \
V(AccessorInfo) \ V(AccessorInfo) \
V(AllocationSite) \ V(AllocationSite) \
...@@ -83,7 +85,7 @@ enum class OddballType : uint8_t { ...@@ -83,7 +85,7 @@ enum class OddballType : uint8_t {
V(FixedArrayBase) \ V(FixedArrayBase) \
V(FunctionTemplateInfo) \ V(FunctionTemplateInfo) \
V(HeapNumber) \ V(HeapNumber) \
V(JSObject) \ V(JSReceiver) \
V(Map) \ V(Map) \
V(MutableHeapNumber) \ V(MutableHeapNumber) \
V(Name) \ V(Name) \
...@@ -223,9 +225,15 @@ class PropertyCellRef : public HeapObjectRef { ...@@ -223,9 +225,15 @@ class PropertyCellRef : public HeapObjectRef {
ObjectRef value() const; ObjectRef value() const;
}; };
class JSObjectRef : public HeapObjectRef { class JSReceiverRef : public HeapObjectRef {
public: public:
using HeapObjectRef::HeapObjectRef; using HeapObjectRef::HeapObjectRef;
Handle<JSReceiver> object() const;
};
class JSObjectRef : public JSReceiverRef {
public:
using JSReceiverRef::JSReceiverRef;
Handle<JSObject> object() const; Handle<JSObject> object() const;
uint64_t RawFastDoublePropertyAsBitsAt(FieldIndex index) const; uint64_t RawFastDoublePropertyAsBitsAt(FieldIndex index) const;
...@@ -261,9 +269,10 @@ class JSBoundFunctionRef : public JSObjectRef { ...@@ -261,9 +269,10 @@ class JSBoundFunctionRef : public JSObjectRef {
Handle<JSBoundFunction> object() const; Handle<JSBoundFunction> object() const;
void Serialize(); void Serialize();
bool serialized() const;
// The following are available only after calling Serialize(). // The following are available only after calling Serialize().
ObjectRef bound_target_function() const; JSReceiverRef bound_target_function() const;
ObjectRef bound_this() const; ObjectRef bound_this() const;
FixedArrayRef bound_arguments() const; FixedArrayRef bound_arguments() const;
}; };
......
...@@ -847,6 +847,8 @@ Reduction JSCallReducer::ReduceObjectPrototypeHasOwnProperty(Node* node) { ...@@ -847,6 +847,8 @@ Reduction JSCallReducer::ReduceObjectPrototypeHasOwnProperty(Node* node) {
// ES #sec-object.prototype.isprototypeof // ES #sec-object.prototype.isprototypeof
Reduction JSCallReducer::ReduceObjectPrototypeIsPrototypeOf(Node* node) { Reduction JSCallReducer::ReduceObjectPrototypeIsPrototypeOf(Node* node) {
DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
Node* receiver = NodeProperties::GetValueInput(node, 1); Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* value = node->op()->ValueInputCount() > 2 Node* value = node->op()->ValueInputCount() > 2
......
...@@ -256,7 +256,14 @@ class JSObjectField { ...@@ -256,7 +256,14 @@ class JSObjectField {
uint64_t number_bits_ = 0; uint64_t number_bits_ = 0;
}; };
class JSObjectData : public HeapObjectData { class JSReceiverData : public HeapObjectData {
public:
JSReceiverData(JSHeapBroker* broker, ObjectData** storage,
Handle<JSReceiver> object)
: HeapObjectData(broker, storage, object) {}
};
class JSObjectData : public JSReceiverData {
public: public:
JSObjectData(JSHeapBroker* broker, ObjectData** storage, JSObjectData(JSHeapBroker* broker, ObjectData** storage,
Handle<JSObject> object); Handle<JSObject> object);
...@@ -462,6 +469,7 @@ class JSBoundFunctionData : public JSObjectData { ...@@ -462,6 +469,7 @@ class JSBoundFunctionData : public JSObjectData {
Handle<JSBoundFunction> object); Handle<JSBoundFunction> object);
void Serialize(JSHeapBroker* broker); void Serialize(JSHeapBroker* broker);
bool serialized() const { return serialized_; }
ObjectData* bound_target_function() const { return bound_target_function_; } ObjectData* bound_target_function() const { return bound_target_function_; }
ObjectData* bound_this() const { return bound_this_; } ObjectData* bound_this() const { return bound_this_; }
...@@ -1309,21 +1317,26 @@ void JSBoundFunctionData::Serialize(JSHeapBroker* broker) { ...@@ -1309,21 +1317,26 @@ void JSBoundFunctionData::Serialize(JSHeapBroker* broker) {
Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(object()); Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(object());
DCHECK_NULL(bound_target_function_); DCHECK_NULL(bound_target_function_);
DCHECK_NULL(bound_this_);
DCHECK_NULL(bound_arguments_);
bound_target_function_ = bound_target_function_ =
broker->GetOrCreateData(function->bound_target_function()); broker->GetOrCreateData(function->bound_target_function());
bound_this_ = broker->GetOrCreateData(function->bound_this()); if (bound_target_function_->IsJSBoundFunction()) {
bound_target_function_->AsJSBoundFunction()->Serialize(broker);
} else if (bound_target_function_->IsJSFunction()) {
bound_target_function_->AsJSFunction()->Serialize(broker);
}
DCHECK_NULL(bound_arguments_);
bound_arguments_ = bound_arguments_ =
broker->GetOrCreateData(function->bound_arguments())->AsFixedArray(); broker->GetOrCreateData(function->bound_arguments())->AsFixedArray();
bound_arguments_->SerializeContents(broker); bound_arguments_->SerializeContents(broker);
DCHECK_NULL(bound_this_);
bound_this_ = broker->GetOrCreateData(function->bound_this());
} }
JSObjectData::JSObjectData(JSHeapBroker* broker, ObjectData** storage, JSObjectData::JSObjectData(JSHeapBroker* broker, ObjectData** storage,
Handle<JSObject> object) Handle<JSObject> object)
: HeapObjectData(broker, storage, object), : JSReceiverData(broker, storage, object),
inobject_fields_(broker->zone()), inobject_fields_(broker->zone()),
own_constant_elements_(broker->zone()), own_constant_elements_(broker->zone()),
own_properties_(broker->zone()) {} own_properties_(broker->zone()) {}
...@@ -2979,7 +2992,7 @@ BIMODAL_ACCESSOR(HeapObject, Map, map) ...@@ -2979,7 +2992,7 @@ BIMODAL_ACCESSOR(HeapObject, Map, map)
BIMODAL_ACCESSOR(JSArray, Object, length) BIMODAL_ACCESSOR(JSArray, Object, length)
BIMODAL_ACCESSOR(JSBoundFunction, Object, bound_target_function) BIMODAL_ACCESSOR(JSBoundFunction, JSReceiver, bound_target_function)
BIMODAL_ACCESSOR(JSBoundFunction, Object, bound_this) BIMODAL_ACCESSOR(JSBoundFunction, Object, bound_this)
BIMODAL_ACCESSOR(JSBoundFunction, FixedArray, bound_arguments) BIMODAL_ACCESSOR(JSBoundFunction, FixedArray, bound_arguments)
...@@ -3792,6 +3805,11 @@ void JSBoundFunctionRef::Serialize() { ...@@ -3792,6 +3805,11 @@ void JSBoundFunctionRef::Serialize() {
data()->AsJSBoundFunction()->Serialize(broker()); data()->AsJSBoundFunction()->Serialize(broker());
} }
bool JSBoundFunctionRef::serialized() const {
CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
return data()->AsJSBoundFunction()->serialized();
}
void PropertyCellRef::Serialize() { void PropertyCellRef::Serialize() {
if (broker()->mode() == JSHeapBroker::kDisabled) return; if (broker()->mode() == JSHeapBroker::kDisabled) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
......
...@@ -381,6 +381,10 @@ Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor( ...@@ -381,6 +381,10 @@ Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor(
} }
Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) { Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
// TODO(neis): Eliminate heap accesses.
AllowHandleDereference allow_handle_dereference;
AllowHandleAllocation allow_handle_allocation;
DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode()); DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode());
FeedbackParameter const& p = FeedbackParameterOf(node->op()); FeedbackParameter const& p = FeedbackParameterOf(node->op());
Node* object = NodeProperties::GetValueInput(node, 0); Node* object = NodeProperties::GetValueInput(node, 0);
...@@ -502,7 +506,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) { ...@@ -502,7 +506,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
JSNativeContextSpecialization::InferHasInPrototypeChainResult JSNativeContextSpecialization::InferHasInPrototypeChainResult
JSNativeContextSpecialization::InferHasInPrototypeChain( JSNativeContextSpecialization::InferHasInPrototypeChain(
Node* receiver, Node* effect, Handle<HeapObject> prototype) { Node* receiver, Node* effect, HeapObjectRef const& prototype) {
ZoneHandleSet<Map> receiver_maps; ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result = NodeProperties::InferReceiverMapsResult result =
NodeProperties::InferReceiverMapsUnsafe(broker(), receiver, effect, NodeProperties::InferReceiverMapsUnsafe(broker(), receiver, effect,
...@@ -515,28 +519,31 @@ JSNativeContextSpecialization::InferHasInPrototypeChain( ...@@ -515,28 +519,31 @@ JSNativeContextSpecialization::InferHasInPrototypeChain(
bool all = true; bool all = true;
bool none = true; bool none = true;
for (size_t i = 0; i < receiver_maps.size(); ++i) { for (size_t i = 0; i < receiver_maps.size(); ++i) {
Handle<Map> receiver_map = receiver_maps[i]; MapRef map(broker(), receiver_maps[i]);
if (receiver_map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) { while (true) {
return kMayBeInPrototypeChain; if (IsSpecialReceiverInstanceType(map.instance_type())) {
} return kMayBeInPrototypeChain;
if (result == NodeProperties::kUnreliableReceiverMaps && }
!receiver_map->is_stable()) { if (result == NodeProperties::kUnreliableReceiverMaps &&
return kMayBeInPrototypeChain; !map.is_stable()) {
} return kMayBeInPrototypeChain;
for (PrototypeIterator it(isolate(), receiver_map);; it.Advance()) { }
if (it.IsAtEnd()) { if (!map.IsJSObjectMap()) {
all = false; all = false;
break; break;
} }
Handle<HeapObject> current = if (FLAG_concurrent_inlining && !map.serialized_prototype()) {
PrototypeIterator::GetCurrent<HeapObject>(it); TRACE_BROKER_MISSING(broker(), "prototype data for map " << map);
if (current.is_identical_to(prototype)) { return kMayBeInPrototypeChain;
}
if (map.prototype().equals(prototype)) {
none = false; none = false;
break; break;
} }
if (!current->map().is_stable() || map = map.prototype().map();
current->map().instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) { if (map.oddball_type() == OddballType::kNull) {
return kMayBeInPrototypeChain; all = false;
break;
} }
} }
} }
...@@ -552,8 +559,8 @@ JSNativeContextSpecialization::InferHasInPrototypeChain( ...@@ -552,8 +559,8 @@ JSNativeContextSpecialization::InferHasInPrototypeChain(
// might be a different object each time, so it's much simpler to include // might be a different object each time, so it's much simpler to include
// {prototype}. That does, however, mean that we must check {prototype}'s // {prototype}. That does, however, mean that we must check {prototype}'s
// map stability. // map stability.
if (!prototype->map().is_stable()) return kMayBeInPrototypeChain; if (!prototype.map().is_stable()) return kMayBeInPrototypeChain;
last_prototype.emplace(broker(), Handle<JSObject>::cast(prototype)); last_prototype = prototype.AsJSObject();
} }
WhereToStart start = result == NodeProperties::kUnreliableReceiverMaps WhereToStart start = result == NodeProperties::kUnreliableReceiverMaps
? kStartAtReceiver ? kStartAtReceiver
...@@ -568,6 +575,8 @@ JSNativeContextSpecialization::InferHasInPrototypeChain( ...@@ -568,6 +575,8 @@ JSNativeContextSpecialization::InferHasInPrototypeChain(
Reduction JSNativeContextSpecialization::ReduceJSHasInPrototypeChain( Reduction JSNativeContextSpecialization::ReduceJSHasInPrototypeChain(
Node* node) { Node* node) {
DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSHasInPrototypeChain, node->opcode()); DCHECK_EQ(IrOpcode::kJSHasInPrototypeChain, node->opcode());
Node* value = NodeProperties::GetValueInput(node, 0); Node* value = NodeProperties::GetValueInput(node, 0);
Node* prototype = NodeProperties::GetValueInput(node, 1); Node* prototype = NodeProperties::GetValueInput(node, 1);
...@@ -578,7 +587,7 @@ Reduction JSNativeContextSpecialization::ReduceJSHasInPrototypeChain( ...@@ -578,7 +587,7 @@ Reduction JSNativeContextSpecialization::ReduceJSHasInPrototypeChain(
HeapObjectMatcher m(prototype); HeapObjectMatcher m(prototype);
if (m.HasValue()) { if (m.HasValue()) {
InferHasInPrototypeChainResult result = InferHasInPrototypeChainResult result =
InferHasInPrototypeChain(value, effect, m.Value()); InferHasInPrototypeChain(value, effect, m.Ref(broker()));
if (result != kMayBeInPrototypeChain) { if (result != kMayBeInPrototypeChain) {
Node* value = jsgraph()->BooleanConstant(result == kIsInPrototypeChain); Node* value = jsgraph()->BooleanConstant(result == kIsInPrototypeChain);
ReplaceWithValue(node, value); ReplaceWithValue(node, value);
...@@ -591,6 +600,8 @@ Reduction JSNativeContextSpecialization::ReduceJSHasInPrototypeChain( ...@@ -591,6 +600,8 @@ Reduction JSNativeContextSpecialization::ReduceJSHasInPrototypeChain(
Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance( Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
Node* node) { Node* node) {
DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode()); DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
Node* constructor = NodeProperties::GetValueInput(node, 0); Node* constructor = NodeProperties::GetValueInput(node, 0);
Node* object = NodeProperties::GetValueInput(node, 1); Node* object = NodeProperties::GetValueInput(node, 1);
...@@ -599,34 +610,41 @@ Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance( ...@@ -599,34 +610,41 @@ Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
HeapObjectMatcher m(constructor); HeapObjectMatcher m(constructor);
if (!m.HasValue()) return NoChange(); if (!m.HasValue()) return NoChange();
// Check if the {constructor} is a JSBoundFunction. if (m.Ref(broker()).IsJSBoundFunction()) {
if (m.Value()->IsJSBoundFunction()) { // OrdinaryHasInstance on bound functions turns into a recursive invocation
// OrdinaryHasInstance on bound functions turns into a recursive // of the instanceof operator again.
// invocation of the instanceof operator again. JSBoundFunctionRef function = m.Ref(broker()).AsJSBoundFunction();
// ES6 section 7.3.19 OrdinaryHasInstance (C, O) step 2. if (FLAG_concurrent_inlining && !function.serialized()) {
Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(m.Value()); TRACE_BROKER_MISSING(broker(), "data for function " << function);
Handle<JSReceiver> bound_target_function(function->bound_target_function(), return NoChange();
isolate()); }
JSReceiverRef bound_target_function = function.bound_target_function();
NodeProperties::ReplaceValueInput(node, object, 0); NodeProperties::ReplaceValueInput(node, object, 0);
NodeProperties::ReplaceValueInput( NodeProperties::ReplaceValueInput(
node, jsgraph()->HeapConstant(bound_target_function), 1); node, jsgraph()->Constant(bound_target_function), 1);
NodeProperties::ChangeOp(node, javascript()->InstanceOf(VectorSlotPair())); NodeProperties::ChangeOp(node, javascript()->InstanceOf(VectorSlotPair()));
Reduction const reduction = ReduceJSInstanceOf(node); Reduction const reduction = ReduceJSInstanceOf(node);
return reduction.Changed() ? reduction : Changed(node); return reduction.Changed() ? reduction : Changed(node);
} }
// Optimize if we currently know the "prototype" property. if (m.Ref(broker()).IsJSFunction()) {
if (m.Value()->IsJSFunction()) { // Optimize if we currently know the "prototype" property.
JSFunctionRef function = m.Ref(broker()).AsJSFunction(); JSFunctionRef function = m.Ref(broker()).AsJSFunction();
// TODO(neis): This is a temporary hack needed because the copy reducer if (FLAG_concurrent_inlining && !function.serialized()) {
// runs only after this pass. TRACE_BROKER_MISSING(broker(), "data for function " << function);
function.Serialize(); return NoChange();
}
// TODO(neis): Remove the has_prototype_slot condition once the broker is // TODO(neis): Remove the has_prototype_slot condition once the broker is
// always enabled. // always enabled.
if (!function.map().has_prototype_slot() || !function.has_prototype() || if (!function.map().has_prototype_slot() || !function.has_prototype() ||
function.PrototypeRequiresRuntimeLookup()) { function.PrototypeRequiresRuntimeLookup()) {
return NoChange(); return NoChange();
} }
ObjectRef prototype = dependencies()->DependOnPrototypeProperty(function); ObjectRef prototype = dependencies()->DependOnPrototypeProperty(function);
Node* prototype_constant = jsgraph()->Constant(prototype); Node* prototype_constant = jsgraph()->Constant(prototype);
......
...@@ -234,7 +234,7 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final ...@@ -234,7 +234,7 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
kMayBeInPrototypeChain kMayBeInPrototypeChain
}; };
InferHasInPrototypeChainResult InferHasInPrototypeChain( InferHasInPrototypeChainResult InferHasInPrototypeChain(
Node* receiver, Node* effect, Handle<HeapObject> prototype); Node* receiver, Node* effect, HeapObjectRef const& prototype);
Graph* graph() const; Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; } JSGraph* jsgraph() const { return jsgraph_; }
......
...@@ -92,7 +92,6 @@ namespace compiler { ...@@ -92,7 +92,6 @@ namespace compiler {
V(TestEqualStrict) \ V(TestEqualStrict) \
V(TestGreaterThan) \ V(TestGreaterThan) \
V(TestGreaterThanOrEqual) \ V(TestGreaterThanOrEqual) \
V(TestInstanceOf) \
V(TestLessThan) \ V(TestLessThan) \
V(TestLessThanOrEqual) \ V(TestLessThanOrEqual) \
V(TestNull) \ V(TestNull) \
...@@ -208,6 +207,7 @@ namespace compiler { ...@@ -208,6 +207,7 @@ namespace compiler {
V(SwitchOnGeneratorState) \ V(SwitchOnGeneratorState) \
V(SwitchOnSmiNoFeedback) \ V(SwitchOnSmiNoFeedback) \
V(TestIn) \ V(TestIn) \
V(TestInstanceOf) \
CLEAR_ACCUMULATOR_LIST(V) \ CLEAR_ACCUMULATOR_LIST(V) \
CLEAR_ENVIRONMENT_LIST(V) \ CLEAR_ENVIRONMENT_LIST(V) \
CONDITIONAL_JUMPS_LIST(V) \ CONDITIONAL_JUMPS_LIST(V) \
...@@ -374,6 +374,7 @@ class SerializerForBackgroundCompilation { ...@@ -374,6 +374,7 @@ 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 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);
...@@ -1659,7 +1660,7 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall( ...@@ -1659,7 +1660,7 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
ProcessHintsForPromiseResolve(resolution_hints); ProcessHintsForPromiseResolve(resolution_hints);
} }
break; break;
case Builtins::kRegExpPrototypeTest: { case Builtins::kRegExpPrototypeTest:
// For JSCallReducer::ReduceRegExpPrototypeTest. // For JSCallReducer::ReduceRegExpPrototypeTest.
if (arguments.size() >= 1 && if (arguments.size() >= 1 &&
speculation_mode != SpeculationMode::kDisallowSpeculation) { speculation_mode != SpeculationMode::kDisallowSpeculation) {
...@@ -1667,7 +1668,6 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall( ...@@ -1667,7 +1668,6 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
ProcessHintsForRegExpTest(regexp_hints); ProcessHintsForRegExpTest(regexp_hints);
} }
break; break;
}
case Builtins::kFunctionPrototypeCall: case Builtins::kFunctionPrototypeCall:
if (arguments.size() >= 1 && if (arguments.size() >= 1 &&
speculation_mode != SpeculationMode::kDisallowSpeculation) { speculation_mode != SpeculationMode::kDisallowSpeculation) {
...@@ -1675,6 +1675,11 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall( ...@@ -1675,6 +1675,11 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
ProcessHintsForFunctionCall(target_hints); ProcessHintsForFunctionCall(target_hints);
} }
break; break;
case Builtins::kObjectPrototypeIsPrototypeOf:
if (arguments.size() >= 2) {
ProcessHintsForObjectIsPrototypeOf(arguments[1]);
}
break;
case Builtins::kFastFunctionPrototypeBind: case Builtins::kFastFunctionPrototypeBind:
if (arguments.size() >= 2 && if (arguments.size() >= 2 &&
speculation_mode != SpeculationMode::kDisallowSpeculation) { speculation_mode != SpeculationMode::kDisallowSpeculation) {
...@@ -1687,6 +1692,26 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall( ...@@ -1687,6 +1692,26 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
} }
} }
void SerializerForBackgroundCompilation::ProcessHintsForObjectIsPrototypeOf(
Hints const& value_hints) {
auto processMap = [&](Handle<Map> map_handle) {
MapRef map(broker(), map_handle);
while (map.IsJSObjectMap()) {
map.SerializePrototype();
map = map.prototype().map();
}
};
for (auto hint : value_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()) {
processMap(map_hint);
}
}
void SerializerForBackgroundCompilation::ProcessHintsForPromiseResolve( void SerializerForBackgroundCompilation::ProcessHintsForPromiseResolve(
Hints const& resolution_hints) { Hints const& resolution_hints) {
auto processMap = [&](Handle<Map> map) { auto processMap = [&](Handle<Map> map) {
...@@ -2213,6 +2238,38 @@ void SerializerForBackgroundCompilation::VisitTestIn( ...@@ -2213,6 +2238,38 @@ void SerializerForBackgroundCompilation::VisitTestIn(
ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kHas); ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kHas);
} }
void SerializerForBackgroundCompilation::VisitTestInstanceOf(
BytecodeArrayIterator* iterator) {
Hints const& lhs =
environment()->register_hints(iterator->GetRegisterOperand(0));
Hints const& rhs = environment()->accumulator_hints();
FeedbackSlot slot = iterator->GetSlotOperand(1);
// Inspect feedback (about the rhs of the operator).
Handle<FeedbackVector> feedback_vector =
environment()->function().feedback_vector();
FeedbackNexus nexus(feedback_vector, slot);
VectorSlotPair rhs_feedback(feedback_vector, slot, nexus.ic_state());
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();
}
}
// TODO(neis): Support full instanceof semantics.
ProcessHintsForObjectIsPrototypeOf(lhs);
// TODO(neis): Process rhs hints.
USE(rhs);
}
void SerializerForBackgroundCompilation::VisitStaKeyedProperty( void SerializerForBackgroundCompilation::VisitStaKeyedProperty(
BytecodeArrayIterator* iterator) { BytecodeArrayIterator* iterator) {
Hints const& receiver = Hints const& receiver =
......
...@@ -160,3 +160,16 @@ ...@@ -160,3 +160,16 @@
%OptimizeFunctionOnNextCall(foo); %OptimizeFunctionOnNextCall(foo);
assertTrue(foo()); assertTrue(foo());
})(); })();
(function() {
function A() {}
A.prototype = {};
var a = {__proto__: new A, gaga: 42};
function foo() { a.gaga; return A.prototype.isPrototypeOf(a); }
%PrepareFunctionForOptimization(foo);
assertTrue(foo());
assertTrue(foo());
%OptimizeFunctionOnNextCall(foo);
assertTrue(foo());
})();
...@@ -5,19 +5,77 @@ ...@@ -5,19 +5,77 @@
// Flags: --allow-natives-syntax // Flags: --allow-natives-syntax
(function() { (function() {
class A {} class A {};
function foo(a, fn) { function foo(a, fn) {
const C = a.constructor; const C = a.constructor;
fn(a); fn(a);
return a instanceof C; return a instanceof C;
}; };
%PrepareFunctionForOptimization(foo);
assertTrue(foo(new A(), a => {})); %PrepareFunctionForOptimization(foo);
assertTrue(foo(new A(), a => {})); assertTrue(foo(new A(), a => {}));
%OptimizeFunctionOnNextCall(foo); assertTrue(foo(new A(), a => {}));
assertTrue(foo(new A(), a => {})); %OptimizeFunctionOnNextCall(foo);
assertFalse(foo(new A(), a => { assertTrue(foo(new A(), a => {}));
a.__proto__ = {}; assertFalse(foo(new A(), a => { a.__proto__ = {}; }));
})); })();
(function() {
class A {};
A.__proto__ = {};
A.prototype = {};
function foo() {
var x = Object.create(Object.create(Object.create(A.prototype)));
return x instanceof A;
};
%PrepareFunctionForOptimization(foo);
assertTrue(foo());
assertTrue(foo());
%OptimizeFunctionOnNextCall(foo);
assertTrue(foo());
})();
(function() {
class A {};
A.prototype = {};
A.__proto__ = {};
var a = {__proto__: new A, gaga: 42};
function foo() {
A.bla; // Make A.__proto__ fast again.
a.gaga;
return a instanceof A;
};
%PrepareFunctionForOptimization(foo);
assertTrue(foo());
assertTrue(foo());
%OptimizeFunctionOnNextCall(foo);
assertTrue(foo());
})();
(function() {
class A {};
A.prototype = {};
A.__proto__ = {};
const boundA = Function.prototype.bind.call(A, {});
boundA.prototype = {};
boundA.__proto__ = {};
var a = {__proto__: new boundA, gaga: 42};
function foo() {
A.bla; // Make A.__proto__ fast again.
boundA.bla; // Make boundA.__proto__ fast again.
a.gaga;
return a instanceof boundA;
};
%PrepareFunctionForOptimization(foo);
assertTrue(foo());
assertTrue(foo());
%OptimizeFunctionOnNextCall(foo);
assertTrue(foo());
})(); })();
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