| Index: src/compiler/js-typed-lowering.cc | 
| diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc | 
| index 62861b3c1c70cd3d82fa1a14a464e5d186ad684c..ed8f3b0dae4afa3f5db2af01cef9c10f2d79852d 100644 | 
| --- a/src/compiler/js-typed-lowering.cc | 
| +++ b/src/compiler/js-typed-lowering.cc | 
| @@ -1145,6 +1145,7 @@ Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) { | 
| if (NodeProperties::IsExceptionalCall(node)) return NoChange(); | 
|  | 
| JSBinopReduction r(this, node); | 
| +  Node* object = r.left(); | 
| Node* effect = r.effect(); | 
| Node* control = r.control(); | 
|  | 
| @@ -1175,134 +1176,121 @@ Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) { | 
| Node* prototype = | 
| jsgraph()->Constant(handle(initial_map->prototype(), isolate())); | 
|  | 
| -  Node* if_is_smi = nullptr; | 
| -  Node* e_is_smi = nullptr; | 
| -  // If the left hand side is an object, no smi check is needed. | 
| -  if (r.left_type()->Maybe(Type::TaggedSigned())) { | 
| -    Node* is_smi = graph()->NewNode(simplified()->ObjectIsSmi(), r.left()); | 
| -    Node* branch_is_smi = | 
| -        graph()->NewNode(common()->Branch(BranchHint::kFalse), is_smi, control); | 
| -    if_is_smi = graph()->NewNode(common()->IfTrue(), branch_is_smi); | 
| -    e_is_smi = effect; | 
| -    control = graph()->NewNode(common()->IfFalse(), branch_is_smi); | 
| -  } | 
| +  Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), object); | 
| +  Node* branch0 = | 
| +      graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); | 
|  | 
| -  Node* object_map = effect = | 
| -      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 
| -                       r.left(), effect, control); | 
| +  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); | 
| +  Node* etrue0 = effect; | 
| +  Node* vtrue0 = jsgraph()->FalseConstant(); | 
| + | 
| +  control = graph()->NewNode(common()->IfFalse(), branch0); | 
|  | 
| // Loop through the {object}s prototype chain looking for the {prototype}. | 
| Node* loop = control = graph()->NewNode(common()->Loop(2), control, control); | 
| - | 
| -  Node* loop_effect = effect = | 
| +  Node* eloop = effect = | 
| graph()->NewNode(common()->EffectPhi(2), effect, effect, loop); | 
| +  Node* vloop = object = graph()->NewNode( | 
| +      common()->Phi(MachineRepresentation::kTagged, 2), object, object, loop); | 
| +  // TODO(jarin): This is a very ugly hack to work-around the super-smart | 
| +  // implicit typing of the Phi, which goes completely nuts if the {object} | 
| +  // is for example a HeapConstant. | 
| +  NodeProperties::SetType(vloop, Type::NonInternal()); | 
| + | 
| +  // Load the {object} map and instance type. | 
| +  Node* object_map = effect = | 
| +      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), object, | 
| +                       effect, control); | 
| +  Node* object_instance_type = effect = graph()->NewNode( | 
| +      simplified()->LoadField(AccessBuilder::ForMapInstanceType()), object_map, | 
| +      effect, control); | 
| + | 
| +  // Check if the {object} is a special receiver, because for special | 
| +  // receivers, i.e. proxies or API objects that need access checks, | 
| +  // we have to use the %HasInPrototypeChain runtime function instead. | 
| +  Node* check1 = graph()->NewNode( | 
| +      simplified()->NumberLessThanOrEqual(), object_instance_type, | 
| +      jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE)); | 
| +  Node* branch1 = | 
| +      graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control); | 
|  | 
| -  Node* loop_object_map = | 
| -      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | 
| -                       object_map, r.left(), loop); | 
| - | 
| -  // Check if the lhs needs access checks. | 
| -  Node* map_bit_field = effect = | 
| -      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMapBitField()), | 
| -                       loop_object_map, loop_effect, control); | 
| -  int is_access_check_needed_bit = 1 << Map::kIsAccessCheckNeeded; | 
| -  Node* is_access_check_needed_num = | 
| -      graph()->NewNode(simplified()->NumberBitwiseAnd(), map_bit_field, | 
| -                       jsgraph()->Constant(is_access_check_needed_bit)); | 
| -  Node* is_access_check_needed = | 
| -      graph()->NewNode(simplified()->NumberEqual(), is_access_check_needed_num, | 
| -                       jsgraph()->Constant(is_access_check_needed_bit)); | 
| - | 
| -  Node* branch_is_access_check_needed = graph()->NewNode( | 
| -      common()->Branch(BranchHint::kFalse), is_access_check_needed, control); | 
| -  Node* if_is_access_check_needed = | 
| -      graph()->NewNode(common()->IfTrue(), branch_is_access_check_needed); | 
| -  Node* e_is_access_check_needed = effect; | 
| +  control = graph()->NewNode(common()->IfFalse(), branch1); | 
|  | 
| -  control = | 
| -      graph()->NewNode(common()->IfFalse(), branch_is_access_check_needed); | 
| - | 
| -  // Check if the lhs is a proxy. | 
| -  Node* map_instance_type = effect = graph()->NewNode( | 
| -      simplified()->LoadField(AccessBuilder::ForMapInstanceType()), | 
| -      loop_object_map, loop_effect, control); | 
| -  Node* is_proxy = | 
| -      graph()->NewNode(simplified()->NumberEqual(), map_instance_type, | 
| -                       jsgraph()->Constant(JS_PROXY_TYPE)); | 
| -  Node* branch_is_proxy = | 
| -      graph()->NewNode(common()->Branch(BranchHint::kFalse), is_proxy, control); | 
| -  Node* if_is_proxy = graph()->NewNode(common()->IfTrue(), branch_is_proxy); | 
| -  Node* e_is_proxy = effect; | 
| - | 
| -  control = graph()->NewNode(common()->Merge(2), if_is_access_check_needed, | 
| -                             if_is_proxy); | 
| -  effect = graph()->NewNode(common()->EffectPhi(2), e_is_access_check_needed, | 
| -                            e_is_proxy, control); | 
| - | 
| -  // If we need an access check or the object is a Proxy, make a runtime call | 
| -  // to finish the lowering. | 
| -  Node* runtimecall = graph()->NewNode( | 
| -      javascript()->CallRuntime(Runtime::kHasInPrototypeChain), r.left(), | 
| -      prototype, context, frame_state, effect, control); | 
| - | 
| -  Node* runtimecall_control = | 
| -      graph()->NewNode(common()->IfSuccess(), runtimecall); | 
| - | 
| -  control = graph()->NewNode(common()->IfFalse(), branch_is_proxy); | 
| +  Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); | 
| +  Node* etrue1 = effect; | 
| +  Node* vtrue1; | 
| + | 
| +  // Check if the {object} is not a receiver at all. | 
| +  Node* check10 = | 
| +      graph()->NewNode(simplified()->NumberLessThan(), object_instance_type, | 
| +                       jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE)); | 
| +  Node* branch10 = | 
| +      graph()->NewNode(common()->Branch(BranchHint::kTrue), check10, if_true1); | 
| + | 
| +  // A primitive value cannot match the {prototype} we're looking for. | 
| +  if_true1 = graph()->NewNode(common()->IfTrue(), branch10); | 
| +  vtrue1 = jsgraph()->FalseConstant(); | 
| + | 
| +  Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch10); | 
| +  Node* efalse1 = etrue1; | 
| +  Node* vfalse1; | 
| +  { | 
| +    // Slow path, need to call the %HasInPrototypeChain runtime function. | 
| +    vfalse1 = efalse1 = graph()->NewNode( | 
| +        javascript()->CallRuntime(Runtime::kHasInPrototypeChain), object, | 
| +        prototype, context, frame_state, efalse1, if_false1); | 
| +    if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1); | 
| +  } | 
|  | 
| +  // Load the {object} prototype. | 
| Node* object_prototype = effect = graph()->NewNode( | 
| -      simplified()->LoadField(AccessBuilder::ForMapPrototype()), | 
| -      loop_object_map, loop_effect, control); | 
| - | 
| -  // If not, check if object prototype is the null prototype. | 
| -  Node* null_proto = | 
| -      graph()->NewNode(simplified()->ReferenceEqual(), object_prototype, | 
| -                       jsgraph()->NullConstant()); | 
| -  Node* branch_null_proto = graph()->NewNode( | 
| -      common()->Branch(BranchHint::kFalse), null_proto, control); | 
| -  Node* if_null_proto = graph()->NewNode(common()->IfTrue(), branch_null_proto); | 
| -  Node* e_null_proto = effect; | 
| - | 
| -  control = graph()->NewNode(common()->IfFalse(), branch_null_proto); | 
| - | 
| -  // Check if object prototype is equal to function prototype. | 
| -  Node* eq_proto = graph()->NewNode(simplified()->ReferenceEqual(), | 
| -                                    object_prototype, prototype); | 
| -  Node* branch_eq_proto = | 
| -      graph()->NewNode(common()->Branch(BranchHint::kFalse), eq_proto, control); | 
| -  Node* if_eq_proto = graph()->NewNode(common()->IfTrue(), branch_eq_proto); | 
| -  Node* e_eq_proto = effect; | 
| - | 
| -  control = graph()->NewNode(common()->IfFalse(), branch_eq_proto); | 
| - | 
| -  Node* load_object_map = effect = | 
| -      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 
| -                       object_prototype, effect, control); | 
| -  // Close the loop. | 
| -  loop_effect->ReplaceInput(1, effect); | 
| -  loop_object_map->ReplaceInput(1, load_object_map); | 
| -  loop->ReplaceInput(1, control); | 
| +      simplified()->LoadField(AccessBuilder::ForMapPrototype()), object_map, | 
| +      effect, control); | 
| + | 
| +  // Check if we reached the end of {object}s prototype chain. | 
| +  Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(), | 
| +                                  object_prototype, jsgraph()->NullConstant()); | 
| +  Node* branch2 = graph()->NewNode(common()->Branch(), check2, control); | 
|  | 
| -  control = graph()->NewNode(common()->Merge(3), runtimecall_control, | 
| -                             if_eq_proto, if_null_proto); | 
| -  effect = graph()->NewNode(common()->EffectPhi(3), runtimecall, e_eq_proto, | 
| -                            e_null_proto, control); | 
| +  Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); | 
| +  Node* etrue2 = effect; | 
| +  Node* vtrue2 = jsgraph()->FalseConstant(); | 
|  | 
| -  Node* result = graph()->NewNode( | 
| -      common()->Phi(MachineRepresentation::kTagged, 3), runtimecall, | 
| -      jsgraph()->TrueConstant(), jsgraph()->FalseConstant(), control); | 
| +  control = graph()->NewNode(common()->IfFalse(), branch2); | 
|  | 
| -  if (if_is_smi != nullptr) { | 
| -    DCHECK_NOT_NULL(e_is_smi); | 
| -    control = graph()->NewNode(common()->Merge(2), if_is_smi, control); | 
| -    effect = | 
| -        graph()->NewNode(common()->EffectPhi(2), e_is_smi, effect, control); | 
| -    result = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | 
| -                              jsgraph()->FalseConstant(), result, control); | 
| -  } | 
| +  // Check if we reached the {prototype}. | 
| +  Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(), | 
| +                                  object_prototype, prototype); | 
| +  Node* branch3 = graph()->NewNode(common()->Branch(), check3, control); | 
|  | 
| -  ReplaceWithValue(node, result, effect, control); | 
| -  return Changed(result); | 
| +  Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3); | 
| +  Node* etrue3 = effect; | 
| +  Node* vtrue3 = jsgraph()->TrueConstant(); | 
| + | 
| +  control = graph()->NewNode(common()->IfFalse(), branch3); | 
| + | 
| +  // Close the loop. | 
| +  vloop->ReplaceInput(1, object_prototype); | 
| +  eloop->ReplaceInput(1, effect); | 
| +  loop->ReplaceInput(1, control); | 
| + | 
| +  control = graph()->NewNode(common()->Merge(5), if_true0, if_true1, if_true2, | 
| +                             if_true3, if_false1); | 
| +  effect = graph()->NewNode(common()->EffectPhi(5), etrue0, etrue1, etrue2, | 
| +                            etrue3, efalse1, control); | 
| + | 
| +  // Morph the {node} into an appropriate Phi. | 
| +  ReplaceWithValue(node, node, effect, control); | 
| +  node->ReplaceInput(0, vtrue0); | 
| +  node->ReplaceInput(1, vtrue1); | 
| +  node->ReplaceInput(2, vtrue2); | 
| +  node->ReplaceInput(3, vtrue3); | 
| +  node->ReplaceInput(4, vfalse1); | 
| +  node->ReplaceInput(5, control); | 
| +  node->TrimInputCount(6); | 
| +  NodeProperties::ChangeOp(node, | 
| +                           common()->Phi(MachineRepresentation::kTagged, 5)); | 
| +  return Changed(node); | 
| } | 
|  | 
| Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) { | 
|  |