Index: src/compiler/js-native-context-specialization.cc |
diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc |
index 48421c9b442b4bc6d8399fa4341707c4dc1a9b2b..742660ffb271b83393c44e1b55c17b4b12863505 100644 |
--- a/src/compiler/js-native-context-specialization.cc |
+++ b/src/compiler/js-native-context-specialization.cc |
@@ -76,6 +76,8 @@ Reduction JSNativeContextSpecialization::Reduce(Node* node) { |
return ReduceJSGetSuperConstructor(node); |
case IrOpcode::kJSInstanceOf: |
return ReduceJSInstanceOf(node); |
+ case IrOpcode::kJSHasInPrototypeChain: |
+ return ReduceJSHasInPrototypeChain(node); |
case IrOpcode::kJSOrdinaryHasInstance: |
return ReduceJSOrdinaryHasInstance(node); |
case IrOpcode::kJSLoadContext: |
@@ -257,6 +259,80 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) { |
return NoChange(); |
} |
+JSNativeContextSpecialization::InferHasInPrototypeChainResult |
+JSNativeContextSpecialization::InferHasInPrototypeChain( |
+ Node* receiver, Node* effect, Handle<HeapObject> prototype) { |
+ ZoneHandleSet<Map> receiver_maps; |
+ NodeProperties::InferReceiverMapsResult result = |
+ NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps); |
+ if (result == NodeProperties::kNoReceiverMaps) return kMayBeInPrototypeChain; |
+ |
+ // Check if either all or none of the {receiver_maps} have the given |
+ // {prototype} in their prototype chain. |
+ bool all = true; |
+ bool none = true; |
+ for (size_t i = 0; i < receiver_maps.size(); ++i) { |
+ Handle<Map> receiver_map = receiver_maps[i]; |
+ if (receiver_map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) { |
+ return kMayBeInPrototypeChain; |
+ } |
+ if (result == NodeProperties::kUnreliableReceiverMaps) { |
+ // In case of an unreliable {result} we need to ensure that all |
+ // {receiver_maps} are stable, because otherwise we cannot trust |
+ // the {receiver_maps} information, since arbitrary side-effects |
+ // may have happened. |
+ if (!receiver_map->is_stable()) { |
+ return kMayBeInPrototypeChain; |
+ } |
+ } |
+ for (PrototypeIterator j(receiver_map);; j.Advance()) { |
+ if (j.IsAtEnd()) { |
+ all = false; |
+ break; |
+ } |
+ Handle<HeapObject> const current = |
+ PrototypeIterator::GetCurrent<HeapObject>(j); |
+ if (current.is_identical_to(prototype)) { |
+ none = false; |
+ break; |
+ } |
+ if (!current->map()->is_stable() || |
+ current->map()->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) { |
+ return kMayBeInPrototypeChain; |
+ } |
+ } |
+ } |
+ DCHECK_IMPLIES(all, !none); |
+ DCHECK_IMPLIES(none, !all); |
+ |
+ if (all) return kIsInPrototypeChain; |
+ if (none) return kIsNotInPrototypeChain; |
+ return kMayBeInPrototypeChain; |
+} |
+ |
+Reduction JSNativeContextSpecialization::ReduceJSHasInPrototypeChain( |
+ Node* node) { |
+ DCHECK_EQ(IrOpcode::kJSHasInPrototypeChain, node->opcode()); |
+ Node* value = NodeProperties::GetValueInput(node, 0); |
+ Node* prototype = NodeProperties::GetValueInput(node, 1); |
+ Node* effect = NodeProperties::GetEffectInput(node); |
+ |
+ // Check if we can constant-fold the prototype chain walk |
+ // for the given {value} and the {prototype}. |
+ HeapObjectMatcher m(prototype); |
+ if (m.HasValue()) { |
+ InferHasInPrototypeChainResult result = |
+ InferHasInPrototypeChain(value, effect, m.Value()); |
+ if (result != kMayBeInPrototypeChain) { |
+ Node* value = jsgraph()->BooleanConstant(result == kIsInPrototypeChain); |
+ ReplaceWithValue(node, value); |
+ return Replace(value); |
+ } |
+ } |
+ |
+ return NoChange(); |
+} |
+ |
Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance( |
Node* node) { |
DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode()); |
@@ -302,7 +378,8 @@ Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance( |
NodeProperties::ReplaceValueInput(node, object, 0); |
NodeProperties::ReplaceValueInput(node, prototype, 1); |
NodeProperties::ChangeOp(node, javascript()->HasInPrototypeChain()); |
- return Changed(node); |
+ Reduction const reduction = ReduceJSHasInPrototypeChain(node); |
+ return reduction.Changed() ? reduction : Changed(node); |
} |
} |