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