LCOV - code coverage report
Current view: top level - src/compiler - js-call-reducer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 722 746 96.8 %
Date: 2017-10-20 Functions: 36 43 83.7 %

          Line data    Source code
       1             : // Copyright 2015 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/compiler/js-call-reducer.h"
       6             : 
       7             : #include "src/api.h"
       8             : #include "src/code-factory.h"
       9             : #include "src/code-stubs.h"
      10             : #include "src/compilation-dependencies.h"
      11             : #include "src/compiler/access-builder.h"
      12             : #include "src/compiler/js-graph.h"
      13             : #include "src/compiler/linkage.h"
      14             : #include "src/compiler/node-matchers.h"
      15             : #include "src/compiler/simplified-operator.h"
      16             : #include "src/feedback-vector-inl.h"
      17             : #include "src/ic/call-optimization.h"
      18             : #include "src/objects-inl.h"
      19             : 
      20             : namespace v8 {
      21             : namespace internal {
      22             : namespace compiler {
      23             : 
      24             : namespace {
      25             : 
      26         776 : bool CanBePrimitive(Node* node) {
      27         776 :   switch (node->opcode()) {
      28             :     case IrOpcode::kJSCreate:
      29             :     case IrOpcode::kJSCreateArguments:
      30             :     case IrOpcode::kJSCreateArray:
      31             :     case IrOpcode::kJSCreateBoundFunction:
      32             :     case IrOpcode::kJSCreateClosure:
      33             :     case IrOpcode::kJSCreateEmptyLiteralArray:
      34             :     case IrOpcode::kJSCreateEmptyLiteralObject:
      35             :     case IrOpcode::kJSCreateIterResultObject:
      36             :     case IrOpcode::kJSCreateKeyValueArray:
      37             :     case IrOpcode::kJSCreateLiteralArray:
      38             :     case IrOpcode::kJSCreateLiteralObject:
      39             :     case IrOpcode::kJSCreateLiteralRegExp:
      40             :     case IrOpcode::kJSConstructForwardVarargs:
      41             :     case IrOpcode::kJSConstruct:
      42             :     case IrOpcode::kJSConstructWithArrayLike:
      43             :     case IrOpcode::kJSConstructWithSpread:
      44             :     case IrOpcode::kJSConvertReceiver:
      45             :     case IrOpcode::kJSGetSuperConstructor:
      46             :     case IrOpcode::kJSToObject:
      47             :       return false;
      48             :     case IrOpcode::kHeapConstant: {
      49             :       Handle<HeapObject> value = HeapObjectMatcher(node).Value();
      50             :       return value->IsPrimitive();
      51             :     }
      52             :     default:
      53         208 :       return true;
      54             :   }
      55             : }
      56             : 
      57         835 : bool CanBeNullOrUndefined(Node* node) {
      58         634 :   if (CanBePrimitive(node)) {
      59         201 :     switch (node->opcode()) {
      60             :       case IrOpcode::kToBoolean:
      61             :       case IrOpcode::kJSToInteger:
      62             :       case IrOpcode::kJSToLength:
      63             :       case IrOpcode::kJSToName:
      64             :       case IrOpcode::kJSToNumber:
      65             :       case IrOpcode::kJSToString:
      66             :         return false;
      67             :       case IrOpcode::kHeapConstant: {
      68             :         Handle<HeapObject> value = HeapObjectMatcher(node).Value();
      69             :         Isolate* const isolate = value->GetIsolate();
      70             :         return value->IsNullOrUndefined(isolate);
      71             :       }
      72             :       default:
      73         123 :         return true;
      74             :     }
      75             :   }
      76             :   return false;
      77             : }
      78             : 
      79             : }  // namespace
      80             : 
      81    30743550 : Reduction JSCallReducer::Reduce(Node* node) {
      82    30743550 :   switch (node->opcode()) {
      83             :     case IrOpcode::kJSConstruct:
      84       40442 :       return ReduceJSConstruct(node);
      85             :     case IrOpcode::kJSConstructWithArrayLike:
      86           7 :       return ReduceJSConstructWithArrayLike(node);
      87             :     case IrOpcode::kJSConstructWithSpread:
      88         590 :       return ReduceJSConstructWithSpread(node);
      89             :     case IrOpcode::kJSCall:
      90      654697 :       return ReduceJSCall(node);
      91             :     case IrOpcode::kJSCallWithArrayLike:
      92         162 :       return ReduceJSCallWithArrayLike(node);
      93             :     case IrOpcode::kJSCallWithSpread:
      94        1110 :       return ReduceJSCallWithSpread(node);
      95             :     default:
      96             :       break;
      97             :   }
      98             :   return NoChange();
      99             : }
     100             : 
     101      492665 : void JSCallReducer::Finalize() {
     102             :   // TODO(turbofan): This is not the best solution; ideally we would be able
     103             :   // to teach the GraphReducer about arbitrary dependencies between different
     104             :   // nodes, even if they don't show up in the use list of the other node.
     105             :   std::set<Node*> const waitlist = std::move(waitlist_);
     106      985415 :   for (Node* node : waitlist) {
     107          85 :     if (!node->IsDead()) {
     108          85 :       Reduction const reduction = Reduce(node);
     109          85 :       if (reduction.Changed()) {
     110             :         Node* replacement = reduction.replacement();
     111          48 :         if (replacement != node) {
     112           0 :           Replace(node, replacement);
     113             :         }
     114             :       }
     115             :     }
     116             :   }
     117      492666 : }
     118             : 
     119             : // ES6 section 22.1.1 The Array Constructor
     120         452 : Reduction JSCallReducer::ReduceArrayConstructor(Node* node) {
     121             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     122         226 :   Node* target = NodeProperties::GetValueInput(node, 0);
     123         452 :   CallParameters const& p = CallParametersOf(node->op());
     124             : 
     125             :   // Turn the {node} into a {JSCreateArray} call.
     126             :   DCHECK_LE(2u, p.arity());
     127             :   Handle<AllocationSite> site;
     128         226 :   size_t const arity = p.arity() - 2;
     129         226 :   NodeProperties::ReplaceValueInput(node, target, 0);
     130         226 :   NodeProperties::ReplaceValueInput(node, target, 1);
     131         226 :   NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
     132         226 :   return Changed(node);
     133             : }
     134             : 
     135             : // ES6 section 19.3.1.1 Boolean ( value )
     136          12 : Reduction JSCallReducer::ReduceBooleanConstructor(Node* node) {
     137             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     138          12 :   CallParameters const& p = CallParametersOf(node->op());
     139             : 
     140             :   // Replace the {node} with a proper {ToBoolean} operator.
     141             :   DCHECK_LE(2u, p.arity());
     142             :   Node* value = (p.arity() == 2) ? jsgraph()->UndefinedConstant()
     143          12 :                                  : NodeProperties::GetValueInput(node, 2);
     144          24 :   value = graph()->NewNode(simplified()->ToBoolean(ToBooleanHint::kAny), value);
     145          12 :   ReplaceWithValue(node, value);
     146          12 :   return Replace(value);
     147             : }
     148             : 
     149             : // ES6 section 20.1.1 The Number Constructor
     150         150 : Reduction JSCallReducer::ReduceNumberConstructor(Node* node) {
     151             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     152         149 :   CallParameters const& p = CallParametersOf(node->op());
     153             : 
     154             :   // Turn the {node} into a {JSToNumber} call.
     155             :   DCHECK_LE(2u, p.arity());
     156             :   Node* value = (p.arity() == 2) ? jsgraph()->ZeroConstant()
     157         150 :                                  : NodeProperties::GetValueInput(node, 2);
     158         149 :   NodeProperties::ReplaceValueInputs(node, value);
     159         149 :   NodeProperties::ChangeOp(node, javascript()->ToNumber());
     160         149 :   return Changed(node);
     161             : }
     162             : 
     163             : // ES section #sec-object-constructor
     164         168 : Reduction JSCallReducer::ReduceObjectConstructor(Node* node) {
     165             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     166         168 :   CallParameters const& p = CallParametersOf(node->op());
     167         168 :   if (p.arity() < 3) return NoChange();
     168             :   Node* value = (p.arity() >= 3) ? NodeProperties::GetValueInput(node, 2)
     169         142 :                                  : jsgraph()->UndefinedConstant();
     170             : 
     171             :   // We can fold away the Object(x) call if |x| is definitely not a primitive.
     172         142 :   if (CanBePrimitive(value)) {
     173         135 :     if (!CanBeNullOrUndefined(value)) {
     174             :       // Turn the {node} into a {JSToObject} call if we know that
     175             :       // the {value} cannot be null or undefined.
     176          50 :       NodeProperties::ReplaceValueInputs(node, value);
     177          50 :       NodeProperties::ChangeOp(node, javascript()->ToObject());
     178             :       return Changed(node);
     179             :     }
     180             :   } else {
     181           7 :     ReplaceWithValue(node, value);
     182             :     return Replace(node);
     183             :   }
     184             :   return NoChange();
     185             : }
     186             : 
     187             : // ES6 section 19.2.3.1 Function.prototype.apply ( thisArg, argArray )
     188         624 : Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
     189             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     190         506 :   CallParameters const& p = CallParametersOf(node->op());
     191             :   size_t arity = p.arity();
     192             :   DCHECK_LE(2u, arity);
     193             :   ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny;
     194         506 :   if (arity == 2) {
     195             :     // Neither thisArg nor argArray was provided.
     196             :     convert_mode = ConvertReceiverMode::kNullOrUndefined;
     197          14 :     node->ReplaceInput(0, node->InputAt(1));
     198          14 :     node->ReplaceInput(1, jsgraph()->UndefinedConstant());
     199         492 :   } else if (arity == 3) {
     200             :     // The argArray was not provided, just remove the {target}.
     201           7 :     node->RemoveInput(0);
     202           7 :     --arity;
     203             :   } else {
     204         485 :     Node* target = NodeProperties::GetValueInput(node, 1);
     205         485 :     Node* this_argument = NodeProperties::GetValueInput(node, 2);
     206         485 :     Node* arguments_list = NodeProperties::GetValueInput(node, 3);
     207         485 :     Node* context = NodeProperties::GetContextInput(node);
     208         485 :     Node* frame_state = NodeProperties::GetFrameStateInput(node);
     209         485 :     Node* effect = NodeProperties::GetEffectInput(node);
     210         485 :     Node* control = NodeProperties::GetControlInput(node);
     211             : 
     212             :     // If {arguments_list} cannot be null or undefined, we don't need
     213             :     // to expand this {node} to control-flow.
     214         485 :     if (!CanBeNullOrUndefined(arguments_list)) {
     215             :       // Massage the value inputs appropriately.
     216         433 :       node->ReplaceInput(0, target);
     217         433 :       node->ReplaceInput(1, this_argument);
     218         433 :       node->ReplaceInput(2, arguments_list);
     219         433 :       while (arity-- > 3) node->RemoveInput(3);
     220             : 
     221             :       // Morph the {node} to a {JSCallWithArrayLike}.
     222             :       NodeProperties::ChangeOp(node,
     223         433 :                                javascript()->CallWithArrayLike(p.frequency()));
     224         433 :       Reduction const reduction = ReduceJSCallWithArrayLike(node);
     225         433 :       return reduction.Changed() ? reduction : Changed(node);
     226             :     } else {
     227             :       // Check whether {arguments_list} is null.
     228             :       Node* check_null =
     229             :           graph()->NewNode(simplified()->ReferenceEqual(), arguments_list,
     230         104 :                            jsgraph()->NullConstant());
     231             :       control = graph()->NewNode(common()->Branch(BranchHint::kFalse),
     232          52 :                                  check_null, control);
     233          52 :       Node* if_null = graph()->NewNode(common()->IfTrue(), control);
     234          52 :       control = graph()->NewNode(common()->IfFalse(), control);
     235             : 
     236             :       // Check whether {arguments_list} is undefined.
     237             :       Node* check_undefined =
     238             :           graph()->NewNode(simplified()->ReferenceEqual(), arguments_list,
     239         104 :                            jsgraph()->UndefinedConstant());
     240             :       control = graph()->NewNode(common()->Branch(BranchHint::kFalse),
     241          52 :                                  check_undefined, control);
     242          52 :       Node* if_undefined = graph()->NewNode(common()->IfTrue(), control);
     243          52 :       control = graph()->NewNode(common()->IfFalse(), control);
     244             : 
     245             :       // Lower to {JSCallWithArrayLike} if {arguments_list} is neither null
     246             :       // nor undefined.
     247             :       Node* effect0 = effect;
     248             :       Node* control0 = control;
     249             :       Node* value0 = effect0 = control0 = graph()->NewNode(
     250             :           javascript()->CallWithArrayLike(p.frequency()), target, this_argument,
     251          52 :           arguments_list, context, frame_state, effect0, control0);
     252             : 
     253             :       // Lower to {JSCall} if {arguments_list} is either null or undefined.
     254             :       Node* effect1 = effect;
     255             :       Node* control1 =
     256          52 :           graph()->NewNode(common()->Merge(2), if_null, if_undefined);
     257             :       Node* value1 = effect1 = control1 =
     258             :           graph()->NewNode(javascript()->Call(2), target, this_argument,
     259         156 :                            context, frame_state, effect1, control1);
     260             : 
     261             :       // Rewire potential exception edges.
     262          52 :       Node* if_exception = nullptr;
     263          52 :       if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
     264             :         // Create appropriate {IfException} and {IfSuccess} nodes.
     265             :         Node* if_exception0 =
     266           7 :             graph()->NewNode(common()->IfException(), control0, effect0);
     267           7 :         control0 = graph()->NewNode(common()->IfSuccess(), control0);
     268             :         Node* if_exception1 =
     269           7 :             graph()->NewNode(common()->IfException(), control1, effect1);
     270           7 :         control1 = graph()->NewNode(common()->IfSuccess(), control1);
     271             : 
     272             :         // Join the exception edges.
     273             :         Node* merge =
     274           7 :             graph()->NewNode(common()->Merge(2), if_exception0, if_exception1);
     275             :         Node* ephi = graph()->NewNode(common()->EffectPhi(2), if_exception0,
     276           7 :                                       if_exception1, merge);
     277             :         Node* phi =
     278             :             graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
     279           7 :                              if_exception0, if_exception1, merge);
     280          59 :         ReplaceWithValue(if_exception, phi, ephi, merge);
     281             :       }
     282             : 
     283             :       // Join control paths.
     284          52 :       control = graph()->NewNode(common()->Merge(2), control0, control1);
     285             :       effect =
     286          52 :           graph()->NewNode(common()->EffectPhi(2), effect0, effect1, control);
     287             :       Node* value =
     288             :           graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
     289          52 :                            value0, value1, control);
     290             :       ReplaceWithValue(node, value, effect, control);
     291             :       return Replace(value);
     292             :     }
     293             :   }
     294             :   // Change {node} to the new {JSCall} operator.
     295             :   NodeProperties::ChangeOp(
     296             :       node,
     297          42 :       javascript()->Call(arity, p.frequency(), VectorSlotPair(), convert_mode));
     298             :   // Try to further reduce the JSCall {node}.
     299          21 :   Reduction const reduction = ReduceJSCall(node);
     300          21 :   return reduction.Changed() ? reduction : Changed(node);
     301             : }
     302             : 
     303             : // ES section #sec-function.prototype.bind
     304         282 : Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
     305             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     306             :   // Value inputs to the {node} are as follows:
     307             :   //
     308             :   //  - target, which is Function.prototype.bind JSFunction
     309             :   //  - receiver, which is the [[BoundTargetFunction]]
     310             :   //  - bound_this (optional), which is the [[BoundThis]]
     311             :   //  - and all the remaining value inouts are [[BoundArguments]]
     312          94 :   Node* receiver = NodeProperties::GetValueInput(node, 1);
     313          94 :   Node* bound_this = (node->op()->ValueInputCount() < 3)
     314             :                          ? jsgraph()->UndefinedConstant()
     315          94 :                          : NodeProperties::GetValueInput(node, 2);
     316          94 :   Node* context = NodeProperties::GetContextInput(node);
     317          94 :   Node* effect = NodeProperties::GetEffectInput(node);
     318          94 :   Node* control = NodeProperties::GetControlInput(node);
     319             : 
     320             :   // Ensure that the {receiver} is known to be a JSBoundFunction or
     321             :   // a JSFunction with the same [[Prototype]], and all maps we've
     322             :   // seen for the {receiver} so far indicate that {receiver} is
     323             :   // definitely a constructor or not a constructor.
     324             :   ZoneHandleSet<Map> receiver_maps;
     325             :   NodeProperties::InferReceiverMapsResult result =
     326          94 :       NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
     327          94 :   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
     328             :   DCHECK_NE(0, receiver_maps.size());
     329             :   bool const is_constructor = receiver_maps[0]->is_constructor();
     330             :   Handle<Object> const prototype(receiver_maps[0]->prototype(), isolate());
     331         188 :   for (Handle<Map> const receiver_map : receiver_maps) {
     332             :     // Check for consistency among the {receiver_maps}.
     333             :     STATIC_ASSERT(LAST_TYPE == LAST_FUNCTION_TYPE);
     334          94 :     if (receiver_map->prototype() != *prototype) return NoChange();
     335          94 :     if (receiver_map->is_constructor() != is_constructor) return NoChange();
     336          94 :     if (receiver_map->instance_type() < FIRST_FUNCTION_TYPE) return NoChange();
     337             : 
     338             :     // Disallow binding of slow-mode functions. We need to figure out
     339             :     // whether the length and name property are in the original state.
     340          94 :     if (receiver_map->is_dictionary_map()) return NoChange();
     341             : 
     342             :     // Check whether the length and name properties are still present
     343             :     // as AccessorInfo objects. In that case, their values can be
     344             :     // recomputed even if the actual value of the object changes.
     345             :     // This mirrors the checks done in builtins-function-gen.cc at
     346             :     // runtime otherwise.
     347             :     Handle<DescriptorArray> descriptors(receiver_map->instance_descriptors(),
     348             :                                         isolate());
     349          94 :     if (descriptors->length() < 2) return NoChange();
     350          94 :     if (descriptors->GetKey(JSFunction::kLengthDescriptorIndex) !=
     351          94 :         isolate()->heap()->length_string()) {
     352             :       return NoChange();
     353             :     }
     354          94 :     if (!descriptors->GetValue(JSFunction::kLengthDescriptorIndex)
     355             :              ->IsAccessorInfo()) {
     356             :       return NoChange();
     357             :     }
     358          94 :     if (descriptors->GetKey(JSFunction::kNameDescriptorIndex) !=
     359          94 :         isolate()->heap()->name_string()) {
     360             :       return NoChange();
     361             :     }
     362          94 :     if (!descriptors->GetValue(JSFunction::kNameDescriptorIndex)
     363             :              ->IsAccessorInfo()) {
     364             :       return NoChange();
     365             :     }
     366             :   }
     367             : 
     368             :   // Setup the map for the resulting JSBoundFunction with the
     369             :   // correct instance {prototype}.
     370             :   Handle<Map> map(
     371             :       is_constructor
     372             :           ? native_context()->bound_function_with_constructor_map()
     373             :           : native_context()->bound_function_without_constructor_map(),
     374          94 :       isolate());
     375          94 :   if (map->prototype() != *prototype) {
     376           0 :     map = Map::TransitionToPrototype(map, prototype);
     377             :   }
     378             : 
     379             :   // Make sure we can rely on the {receiver_maps}.
     380          94 :   if (result == NodeProperties::kUnreliableReceiverMaps) {
     381             :     effect = graph()->NewNode(
     382             :         simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps), receiver,
     383           0 :         effect, control);
     384             :   }
     385             : 
     386             :   // Replace the {node} with a JSCreateBoundFunction.
     387         282 :   int const arity = std::max(0, node->op()->ValueInputCount() - 3);
     388          94 :   int const input_count = 2 + arity + 3;
     389         188 :   Node** inputs = graph()->zone()->NewArray<Node*>(input_count);
     390          94 :   inputs[0] = receiver;
     391          94 :   inputs[1] = bound_this;
     392         161 :   for (int i = 0; i < arity; ++i) {
     393          67 :     inputs[2 + i] = NodeProperties::GetValueInput(node, 3 + i);
     394             :   }
     395          94 :   inputs[2 + arity + 0] = context;
     396          94 :   inputs[2 + arity + 1] = effect;
     397          94 :   inputs[2 + arity + 2] = control;
     398             :   Node* value = effect = graph()->NewNode(
     399         188 :       javascript()->CreateBoundFunction(arity, map), input_count, inputs);
     400          94 :   ReplaceWithValue(node, value, effect, control);
     401             :   return Replace(value);
     402             : }
     403             : 
     404             : // ES6 section 19.2.3.3 Function.prototype.call (thisArg, ...args)
     405        2277 : Reduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) {
     406             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     407        2254 :   CallParameters const& p = CallParametersOf(node->op());
     408             :   Handle<JSFunction> call = Handle<JSFunction>::cast(
     409        1127 :       HeapObjectMatcher(NodeProperties::GetValueInput(node, 0)).Value());
     410             :   // Change context of {node} to the Function.prototype.call context,
     411             :   // to ensure any exception is thrown in the correct context.
     412             :   NodeProperties::ReplaceContextInput(
     413        1127 :       node, jsgraph()->HeapConstant(handle(call->context(), isolate())));
     414             :   // Remove the target from {node} and use the receiver as target instead, and
     415             :   // the thisArg becomes the new target.  If thisArg was not provided, insert
     416             :   // undefined instead.
     417             :   size_t arity = p.arity();
     418             :   DCHECK_LE(2u, arity);
     419             :   ConvertReceiverMode convert_mode;
     420        1127 :   if (arity == 2) {
     421             :     // The thisArg was not provided, use undefined as receiver.
     422             :     convert_mode = ConvertReceiverMode::kNullOrUndefined;
     423          23 :     node->ReplaceInput(0, node->InputAt(1));
     424          23 :     node->ReplaceInput(1, jsgraph()->UndefinedConstant());
     425             :   } else {
     426             :     // Just remove the target, which is the first value input.
     427             :     convert_mode = ConvertReceiverMode::kAny;
     428        1104 :     node->RemoveInput(0);
     429        1104 :     --arity;
     430             :   }
     431             :   NodeProperties::ChangeOp(
     432             :       node,
     433        2254 :       javascript()->Call(arity, p.frequency(), VectorSlotPair(), convert_mode));
     434             :   // Try to further reduce the JSCall {node}.
     435        1127 :   Reduction const reduction = ReduceJSCall(node);
     436        1127 :   return reduction.Changed() ? reduction : Changed(node);
     437             : }
     438             : 
     439             : // ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] (V)
     440        3316 : Reduction JSCallReducer::ReduceFunctionPrototypeHasInstance(Node* node) {
     441             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     442        1658 :   Node* receiver = NodeProperties::GetValueInput(node, 1);
     443        1658 :   Node* object = (node->op()->ValueInputCount() >= 3)
     444             :                      ? NodeProperties::GetValueInput(node, 2)
     445        1658 :                      : jsgraph()->UndefinedConstant();
     446        1658 :   Node* context = NodeProperties::GetContextInput(node);
     447        1658 :   Node* frame_state = NodeProperties::GetFrameStateInput(node);
     448        1658 :   Node* effect = NodeProperties::GetEffectInput(node);
     449        1658 :   Node* control = NodeProperties::GetControlInput(node);
     450             : 
     451             :   // TODO(turbofan): If JSOrdinaryToInstance raises an exception, the
     452             :   // stack trace doesn't contain the @@hasInstance call; we have the
     453             :   // corresponding bug in the baseline case. Some massaging of the frame
     454             :   // state would be necessary here.
     455             : 
     456             :   // Morph this {node} into a JSOrdinaryHasInstance node.
     457        1658 :   node->ReplaceInput(0, receiver);
     458        1658 :   node->ReplaceInput(1, object);
     459        1658 :   node->ReplaceInput(2, context);
     460        1658 :   node->ReplaceInput(3, frame_state);
     461        1658 :   node->ReplaceInput(4, effect);
     462        1658 :   node->ReplaceInput(5, control);
     463        1658 :   node->TrimInputCount(6);
     464        1658 :   NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance());
     465        1658 :   return Changed(node);
     466             : }
     467             : 
     468         303 : Reduction JSCallReducer::ReduceObjectGetPrototype(Node* node, Node* object) {
     469         185 :   Node* effect = NodeProperties::GetEffectInput(node);
     470             : 
     471             :   // Try to determine the {object} map.
     472             :   ZoneHandleSet<Map> object_maps;
     473             :   NodeProperties::InferReceiverMapsResult result =
     474         185 :       NodeProperties::InferReceiverMaps(object, effect, &object_maps);
     475         185 :   if (result != NodeProperties::kNoReceiverMaps) {
     476             :     Handle<Map> candidate_map = object_maps[0];
     477             :     Handle<Object> candidate_prototype(candidate_map->prototype(), isolate());
     478             : 
     479             :     // Check if we can constant-fold the {candidate_prototype}.
     480         420 :     for (size_t i = 0; i < object_maps.size(); ++i) {
     481             :       Handle<Map> object_map = object_maps[i];
     482         216 :       if (object_map->IsSpecialReceiverMap() ||
     483         216 :           object_map->has_hidden_prototype() ||
     484             :           object_map->prototype() != *candidate_prototype) {
     485             :         // We exclude special receivers, like JSProxy or API objects that
     486             :         // might require access checks here; we also don't want to deal
     487             :         // with hidden prototypes at this point.
     488             :         return NoChange();
     489             :       }
     490             :       // The above check also excludes maps for primitive values, which is
     491             :       // important because we are not applying [[ToObject]] here as expected.
     492             :       DCHECK(!object_map->IsPrimitiveMap() && object_map->IsJSReceiverMap());
     493         130 :       if (result == NodeProperties::kUnreliableReceiverMaps &&
     494             :           !object_map->is_stable()) {
     495             :         return NoChange();
     496             :       }
     497             :     }
     498          90 :     if (result == NodeProperties::kUnreliableReceiverMaps) {
     499          84 :       for (size_t i = 0; i < object_maps.size(); ++i) {
     500          28 :         dependencies()->AssumeMapStable(object_maps[i]);
     501             :       }
     502             :     }
     503          90 :     Node* value = jsgraph()->Constant(candidate_prototype);
     504          90 :     ReplaceWithValue(node, value);
     505             :     return Replace(value);
     506             :   }
     507             : 
     508             :   return NoChange();
     509             : }
     510             : 
     511             : // ES6 section 19.1.2.11 Object.getPrototypeOf ( O )
     512          78 : Reduction JSCallReducer::ReduceObjectGetPrototypeOf(Node* node) {
     513             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     514          78 :   Node* object = (node->op()->ValueInputCount() >= 3)
     515             :                      ? NodeProperties::GetValueInput(node, 2)
     516          78 :                      : jsgraph()->UndefinedConstant();
     517          78 :   return ReduceObjectGetPrototype(node, object);
     518             : }
     519             : 
     520             : // ES6 section B.2.2.1.1 get Object.prototype.__proto__
     521          92 : Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) {
     522             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     523          92 :   Node* receiver = NodeProperties::GetValueInput(node, 1);
     524          92 :   return ReduceObjectGetPrototype(node, receiver);
     525             : }
     526             : 
     527             : // ES #sec-object.prototype.hasownproperty
     528         609 : Reduction JSCallReducer::ReduceObjectPrototypeHasOwnProperty(Node* node) {
     529             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     530         465 :   CallParameters const& params = CallParametersOf(node->op());
     531         465 :   int const argc = static_cast<int>(params.arity() - 2);
     532         465 :   Node* receiver = NodeProperties::GetValueInput(node, 1);
     533         465 :   Node* name = (argc >= 1) ? NodeProperties::GetValueInput(node, 2)
     534         473 :                            : jsgraph()->UndefinedConstant();
     535         465 :   Node* effect = NodeProperties::GetEffectInput(node);
     536         465 :   Node* control = NodeProperties::GetControlInput(node);
     537             : 
     538             :   // We can optimize a call to Object.prototype.hasOwnProperty if it's being
     539             :   // used inside a fast-mode for..in, so for code like this:
     540             :   //
     541             :   //   for (name in receiver) {
     542             :   //     if (receiver.hasOwnProperty(name)) {
     543             :   //        ...
     544             :   //     }
     545             :   //   }
     546             :   //
     547             :   // If the for..in is in fast-mode, we know that the {receiver} has {name}
     548             :   // as own property, otherwise the enumeration wouldn't include it. The graph
     549             :   // constructed by the BytecodeGraphBuilder in this case looks like this:
     550             : 
     551             :   // receiver
     552             :   //  ^    ^
     553             :   //  |    |
     554             :   //  |    +-+
     555             :   //  |      |
     556             :   //  |   JSToObject
     557             :   //  |      ^
     558             :   //  |      |
     559             :   //  |   JSForInNext
     560             :   //  |      ^
     561             :   //  +----+ |
     562             :   //       | |
     563             :   //  JSCall[hasOwnProperty]
     564             : 
     565             :   // We can constant-fold the {node} to True in this case, and insert
     566             :   // a (potentially redundant) map check to guard the fact that the
     567             :   // {receiver} map didn't change since the dominating JSForInNext. This
     568             :   // map check is only necessary when TurboFan cannot prove that there
     569             :   // is no observable side effect between the {JSForInNext} and the
     570             :   // {JSCall} to Object.prototype.hasOwnProperty.
     571             :   //
     572             :   // Also note that it's safe to look through the {JSToObject}, since the
     573             :   // Object.prototype.hasOwnProperty does an implicit ToObject anyway, and
     574             :   // these operations are not observable.
     575         465 :   if (name->opcode() == IrOpcode::kJSForInNext) {
     576         214 :     ForInMode const mode = ForInModeOf(name->op());
     577         214 :     if (mode != ForInMode::kGeneric) {
     578         428 :       Node* object = NodeProperties::GetValueInput(name, 0);
     579         214 :       Node* cache_type = NodeProperties::GetValueInput(name, 2);
     580         214 :       if (object->opcode() == IrOpcode::kJSToObject) {
     581         200 :         object = NodeProperties::GetValueInput(object, 0);
     582             :       }
     583         214 :       if (object == receiver) {
     584             :         // No need to repeat the map check if we can prove that there's no
     585             :         // observable side effect between {effect} and {name].
     586         136 :         if (!NodeProperties::NoObservableSideEffectBetween(effect, name)) {
     587             :           Node* receiver_map = effect =
     588             :               graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
     589           0 :                                receiver, effect, control);
     590             :           Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
     591           0 :                                          receiver_map, cache_type);
     592             :           effect = graph()->NewNode(
     593             :               simplified()->CheckIf(DeoptimizeReason::kNoReason), check, effect,
     594           0 :               control);
     595             :         }
     596         136 :         Node* value = jsgraph()->TrueConstant();
     597         136 :         ReplaceWithValue(node, value, effect, control);
     598             :         return Replace(value);
     599             :       }
     600             :     }
     601             :   }
     602             : 
     603             :   return NoChange();
     604             : }
     605             : 
     606             : // ES #sec-object.prototype.isprototypeof
     607         175 : Reduction JSCallReducer::ReduceObjectPrototypeIsPrototypeOf(Node* node) {
     608             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     609          63 :   Node* receiver = NodeProperties::GetValueInput(node, 1);
     610          63 :   Node* value = node->op()->ValueInputCount() > 2
     611             :                     ? NodeProperties::GetValueInput(node, 2)
     612          63 :                     : jsgraph()->UndefinedConstant();
     613          63 :   Node* effect = NodeProperties::GetEffectInput(node);
     614             : 
     615             :   // Ensure that the {receiver} is known to be a JSReceiver (so that
     616             :   // the ToObject step of Object.prototype.isPrototypeOf is a no-op).
     617             :   ZoneHandleSet<Map> receiver_maps;
     618             :   NodeProperties::InferReceiverMapsResult result =
     619          63 :       NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
     620          63 :   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
     621         147 :   for (size_t i = 0; i < receiver_maps.size(); ++i) {
     622          49 :     if (!receiver_maps[i]->IsJSReceiverMap()) return NoChange();
     623             :   }
     624             : 
     625             :   // We don't check whether {value} is a proper JSReceiver here explicitly,
     626             :   // and don't explicitly rule out Primitive {value}s, since all of them
     627             :   // have null as their prototype, so the prototype chain walk inside the
     628             :   // JSHasInPrototypeChain operator immediately aborts and yields false.
     629          49 :   NodeProperties::ReplaceValueInput(node, value, 0);
     630          49 :   NodeProperties::ReplaceValueInput(node, receiver, 1);
     631         196 :   for (int i = node->op()->ValueInputCount(); i-- > 2;) {
     632          49 :     node->RemoveInput(i);
     633             :   }
     634          49 :   NodeProperties::ChangeOp(node, javascript()->HasInPrototypeChain());
     635             :   return Changed(node);
     636             : }
     637             : 
     638             : // ES6 section 26.1.1 Reflect.apply ( target, thisArgument, argumentsList )
     639         241 : Reduction JSCallReducer::ReduceReflectApply(Node* node) {
     640             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     641         220 :   CallParameters const& p = CallParametersOf(node->op());
     642         220 :   int arity = static_cast<int>(p.arity() - 2);
     643             :   DCHECK_LE(0, arity);
     644             :   // Massage value inputs appropriately.
     645         220 :   node->RemoveInput(0);
     646         220 :   node->RemoveInput(0);
     647         461 :   while (arity < 3) {
     648          42 :     node->InsertInput(graph()->zone(), arity++, jsgraph()->UndefinedConstant());
     649             :   }
     650         227 :   while (arity-- > 3) {
     651           7 :     node->RemoveInput(arity);
     652             :   }
     653             :   NodeProperties::ChangeOp(node,
     654         220 :                            javascript()->CallWithArrayLike(p.frequency()));
     655         220 :   Reduction const reduction = ReduceJSCallWithArrayLike(node);
     656         220 :   return reduction.Changed() ? reduction : Changed(node);
     657             : }
     658             : 
     659             : // ES6 section 26.1.2 Reflect.construct ( target, argumentsList [, newTarget] )
     660         218 : Reduction JSCallReducer::ReduceReflectConstruct(Node* node) {
     661             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     662         211 :   CallParameters const& p = CallParametersOf(node->op());
     663         211 :   int arity = static_cast<int>(p.arity() - 2);
     664             :   DCHECK_LE(0, arity);
     665             :   // Massage value inputs appropriately.
     666         211 :   node->RemoveInput(0);
     667         211 :   node->RemoveInput(0);
     668         429 :   while (arity < 2) {
     669          14 :     node->InsertInput(graph()->zone(), arity++, jsgraph()->UndefinedConstant());
     670             :   }
     671         211 :   if (arity < 3) {
     672          72 :     node->InsertInput(graph()->zone(), arity++, node->InputAt(0));
     673             :   }
     674         218 :   while (arity-- > 3) {
     675           7 :     node->RemoveInput(arity);
     676             :   }
     677             :   NodeProperties::ChangeOp(node,
     678         211 :                            javascript()->ConstructWithArrayLike(p.frequency()));
     679         211 :   Reduction const reduction = ReduceJSConstructWithArrayLike(node);
     680         211 :   return reduction.Changed() ? reduction : Changed(node);
     681             : }
     682             : 
     683             : // ES6 section 26.1.7 Reflect.getPrototypeOf ( target )
     684          15 : Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) {
     685             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     686          15 :   Node* target = (node->op()->ValueInputCount() >= 3)
     687             :                      ? NodeProperties::GetValueInput(node, 2)
     688          15 :                      : jsgraph()->UndefinedConstant();
     689          15 :   return ReduceObjectGetPrototype(node, target);
     690             : }
     691             : 
     692             : // ES section #sec-reflect.has
     693         147 : Reduction JSCallReducer::ReduceReflectHas(Node* node) {
     694             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     695          35 :   CallParameters const& p = CallParametersOf(node->op());
     696          35 :   int arity = static_cast<int>(p.arity() - 2);
     697             :   DCHECK_LE(0, arity);
     698             :   Node* target = (arity >= 1) ? NodeProperties::GetValueInput(node, 2)
     699          49 :                               : jsgraph()->UndefinedConstant();
     700             :   Node* key = (arity >= 2) ? NodeProperties::GetValueInput(node, 3)
     701          63 :                            : jsgraph()->UndefinedConstant();
     702          35 :   Node* context = NodeProperties::GetContextInput(node);
     703          35 :   Node* frame_state = NodeProperties::GetFrameStateInput(node);
     704          35 :   Node* effect = NodeProperties::GetEffectInput(node);
     705          35 :   Node* control = NodeProperties::GetControlInput(node);
     706             : 
     707             :   // Check whether {target} is a JSReceiver.
     708          35 :   Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), target);
     709             :   Node* branch =
     710          35 :       graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
     711             : 
     712             :   // Throw an appropriate TypeError if the {target} is not a JSReceiver.
     713          35 :   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
     714             :   Node* efalse = effect;
     715             :   {
     716             :     if_false = efalse = graph()->NewNode(
     717             :         javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
     718             :         jsgraph()->Constant(MessageTemplate::kCalledOnNonObject),
     719             :         jsgraph()->HeapConstant(
     720             :             factory()->NewStringFromAsciiChecked("Reflect.has")),
     721         175 :         context, frame_state, efalse, if_false);
     722             :   }
     723             : 
     724             :   // Otherwise just use the existing {JSHasProperty} logic.
     725          35 :   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
     726             :   Node* etrue = effect;
     727             :   Node* vtrue;
     728             :   {
     729             :     vtrue = etrue = if_true =
     730             :         graph()->NewNode(javascript()->HasProperty(), key, target, context,
     731          35 :                          frame_state, etrue, if_true);
     732             :   }
     733             : 
     734             :   // Rewire potential exception edges.
     735          35 :   Node* on_exception = nullptr;
     736          35 :   if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
     737             :     // Create appropriate {IfException} and {IfSuccess} nodes.
     738          14 :     Node* extrue = graph()->NewNode(common()->IfException(), etrue, if_true);
     739          14 :     if_true = graph()->NewNode(common()->IfSuccess(), if_true);
     740          14 :     Node* exfalse = graph()->NewNode(common()->IfException(), efalse, if_false);
     741          14 :     if_false = graph()->NewNode(common()->IfSuccess(), if_false);
     742             : 
     743             :     // Join the exception edges.
     744          14 :     Node* merge = graph()->NewNode(common()->Merge(2), extrue, exfalse);
     745             :     Node* ephi =
     746          14 :         graph()->NewNode(common()->EffectPhi(2), extrue, exfalse, merge);
     747             :     Node* phi =
     748             :         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
     749          14 :                          extrue, exfalse, merge);
     750          49 :     ReplaceWithValue(on_exception, phi, ephi, merge);
     751             :   }
     752             : 
     753             :   // Connect the throwing path to end.
     754          35 :   if_false = graph()->NewNode(common()->Throw(), efalse, if_false);
     755          35 :   NodeProperties::MergeControlToEnd(graph(), common(), if_false);
     756             : 
     757             :   // Continue on the regular path.
     758             :   ReplaceWithValue(node, vtrue, etrue, if_true);
     759          35 :   return Changed(vtrue);
     760             : }
     761             : 
     762         470 : bool CanInlineArrayIteratingBuiltin(Handle<Map> receiver_map) {
     763             :   Isolate* const isolate = receiver_map->GetIsolate();
     764         470 :   if (!receiver_map->prototype()->IsJSArray()) return false;
     765             :   Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()),
     766             :                                      isolate);
     767         470 :   return receiver_map->instance_type() == JS_ARRAY_TYPE &&
     768         470 :          IsFastElementsKind(receiver_map->elements_kind()) &&
     769         470 :          (!receiver_map->is_prototype_map() || receiver_map->is_stable()) &&
     770        1404 :          isolate->IsFastArrayConstructorPrototypeChainIntact() &&
     771         934 :          isolate->IsAnyInitialArrayPrototype(receiver_prototype);
     772             : }
     773             : 
     774         267 : Reduction JSCallReducer::ReduceArrayForEach(Handle<JSFunction> function,
     775        3227 :                                             Node* node) {
     776         267 :   if (!FLAG_turbo_inline_array_builtins) return NoChange();
     777             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     778         267 :   Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
     779         267 :   Node* effect = NodeProperties::GetEffectInput(node);
     780         267 :   Node* control = NodeProperties::GetControlInput(node);
     781         267 :   Node* context = NodeProperties::GetContextInput(node);
     782         267 :   CallParameters const& p = CallParametersOf(node->op());
     783             : 
     784             :   // Try to determine the {receiver} map.
     785         267 :   Node* receiver = NodeProperties::GetValueInput(node, 1);
     786         267 :   Node* fncallback = node->op()->ValueInputCount() > 2
     787             :                          ? NodeProperties::GetValueInput(node, 2)
     788         267 :                          : jsgraph()->UndefinedConstant();
     789         267 :   Node* this_arg = node->op()->ValueInputCount() > 3
     790             :                        ? NodeProperties::GetValueInput(node, 3)
     791         534 :                        : jsgraph()->UndefinedConstant();
     792             :   ZoneHandleSet<Map> receiver_maps;
     793             :   NodeProperties::InferReceiverMapsResult result =
     794         267 :       NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
     795         267 :   if (result != NodeProperties::kReliableReceiverMaps) {
     796             :     return NoChange();
     797             :   }
     798         258 :   if (receiver_maps.size() == 0) return NoChange();
     799             : 
     800             :   ElementsKind kind = IsDoubleElementsKind(receiver_maps[0]->elements_kind())
     801             :                           ? PACKED_DOUBLE_ELEMENTS
     802         258 :                           : PACKED_ELEMENTS;
     803         533 :   for (Handle<Map> receiver_map : receiver_maps) {
     804             :     ElementsKind next_kind = receiver_map->elements_kind();
     805         297 :     if (!CanInlineArrayIteratingBuiltin(receiver_map)) {
     806             :       return NoChange();
     807             :     }
     808         873 :     if (!IsFastElementsKind(next_kind) ||
     809          24 :         (IsDoubleElementsKind(next_kind) && IsHoleyElementsKind(next_kind))) {
     810             :       return NoChange();
     811             :     }
     812         283 :     if (IsDoubleElementsKind(kind) != IsDoubleElementsKind(next_kind)) {
     813             :       return NoChange();
     814             :     }
     815         275 :     if (IsHoleyElementsKind(next_kind)) {
     816             :       kind = HOLEY_ELEMENTS;
     817             :     }
     818             :   }
     819             : 
     820             :   // Install code dependencies on the {receiver} prototype maps and the
     821             :   // global array protector cell.
     822             :   dependencies()->AssumePropertyCell(factory()->array_protector());
     823             : 
     824         236 :   Node* k = jsgraph()->ZeroConstant();
     825             : 
     826             :   Node* original_length = effect = graph()->NewNode(
     827             :       simplified()->LoadField(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS)),
     828         708 :       receiver, effect, control);
     829             : 
     830             :   std::vector<Node*> checkpoint_params(
     831         472 :       {receiver, fncallback, this_arg, k, original_length});
     832         472 :   const int stack_parameters = static_cast<int>(checkpoint_params.size());
     833             : 
     834             :   // Check whether the given callback function is callable. Note that this has
     835             :   // to happen outside the loop to make sure we also throw on empty arrays.
     836         236 :   Node* check = graph()->NewNode(simplified()->ObjectIsCallable(), fncallback);
     837             :   Node* check_branch =
     838         236 :       graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
     839         236 :   Node* check_fail = graph()->NewNode(common()->IfFalse(), check_branch);
     840             :   Node* check_frame_state = CreateJavaScriptBuiltinContinuationFrameState(
     841             :       jsgraph(), function, Builtins::kArrayForEachLoopLazyDeoptContinuation,
     842         236 :       node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
     843         236 :       outer_frame_state, ContinuationFrameStateMode::LAZY);
     844             :   Node* check_throw = check_fail = graph()->NewNode(
     845             :       javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
     846             :       jsgraph()->Constant(MessageTemplate::kCalledNonCallable), fncallback,
     847         472 :       context, check_frame_state, effect, check_fail);
     848         236 :   control = graph()->NewNode(common()->IfTrue(), check_branch);
     849             : 
     850             :   // Start the loop.
     851         236 :   Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
     852             :   Node* eloop = effect =
     853         236 :       graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
     854             :   Node* vloop = k = graph()->NewNode(
     855         236 :       common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop);
     856         236 :   checkpoint_params[3] = k;
     857             : 
     858             :   control = loop;
     859             :   effect = eloop;
     860             : 
     861             :   Node* continue_test =
     862         236 :       graph()->NewNode(simplified()->NumberLessThan(), k, original_length);
     863             :   Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
     864         236 :                                            continue_test, control);
     865             : 
     866         236 :   Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch);
     867         236 :   Node* if_false = graph()->NewNode(common()->IfFalse(), continue_branch);
     868             :   control = if_true;
     869             : 
     870             :   Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
     871             :       jsgraph(), function, Builtins::kArrayForEachLoopEagerDeoptContinuation,
     872         236 :       node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
     873         236 :       outer_frame_state, ContinuationFrameStateMode::EAGER);
     874             : 
     875             :   effect =
     876         236 :       graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
     877             : 
     878             :   // Make sure the map hasn't changed during the iteration
     879             :   effect = graph()->NewNode(
     880             :       simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps), receiver,
     881         472 :       effect, control);
     882             : 
     883             :   // Make sure that the access is still in bounds, since the callback could have
     884             :   // changed the array's size.
     885             :   Node* length = effect = graph()->NewNode(
     886             :       simplified()->LoadField(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS)),
     887         708 :       receiver, effect, control);
     888             :   k = effect =
     889         236 :       graph()->NewNode(simplified()->CheckBounds(), k, length, effect, control);
     890             : 
     891             :   // Reload the elements pointer before calling the callback, since the previous
     892             :   // callback might have resized the array causing the elements buffer to be
     893             :   // re-allocated.
     894             :   Node* elements = effect = graph()->NewNode(
     895             :       simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
     896         708 :       effect, control);
     897             : 
     898             :   Node* element = effect = graph()->NewNode(
     899             :       simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(kind)),
     900         708 :       elements, k, effect, control);
     901             : 
     902             :   Node* next_k =
     903         472 :       graph()->NewNode(simplified()->NumberAdd(), k, jsgraph()->Constant(1));
     904         236 :   checkpoint_params[3] = next_k;
     905             : 
     906             :   Node* hole_true = nullptr;
     907             :   Node* hole_false = nullptr;
     908             :   Node* effect_true = effect;
     909             : 
     910         236 :   if (IsHoleyElementsKind(kind)) {
     911             :     // Holey elements kind require a hole check and skipping of the element in
     912             :     // the case of a hole.
     913             :     Node* check = graph()->NewNode(simplified()->ReferenceEqual(), element,
     914          70 :                                    jsgraph()->TheHoleConstant());
     915             :     Node* branch =
     916          35 :         graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
     917          35 :     hole_true = graph()->NewNode(common()->IfTrue(), branch);
     918          35 :     hole_false = graph()->NewNode(common()->IfFalse(), branch);
     919             :     control = hole_false;
     920             : 
     921             :     // The contract is that we don't leak "the hole" into "user JavaScript",
     922             :     // so we must rename the {element} here to explicitly exclude "the hole"
     923             :     // from the type of {element}.
     924             :     element = graph()->NewNode(common()->TypeGuard(Type::NonInternal()),
     925          35 :                                element, control);
     926             :   }
     927             : 
     928             :   frame_state = CreateJavaScriptBuiltinContinuationFrameState(
     929             :       jsgraph(), function, Builtins::kArrayForEachLoopLazyDeoptContinuation,
     930         236 :       node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
     931         236 :       outer_frame_state, ContinuationFrameStateMode::LAZY);
     932             : 
     933             :   control = effect = graph()->NewNode(
     934             :       javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
     935         708 :       receiver, context, frame_state, effect, control);
     936             : 
     937             :   // Rewire potential exception edges.
     938         236 :   Node* on_exception = nullptr;
     939         236 :   if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
     940             :     // Create appropriate {IfException} and {IfSuccess} nodes.
     941             :     Node* if_exception0 =
     942          33 :         graph()->NewNode(common()->IfException(), check_throw, check_fail);
     943          33 :     check_fail = graph()->NewNode(common()->IfSuccess(), check_fail);
     944             :     Node* if_exception1 =
     945          33 :         graph()->NewNode(common()->IfException(), effect, control);
     946          33 :     control = graph()->NewNode(common()->IfSuccess(), control);
     947             : 
     948             :     // Join the exception edges.
     949             :     Node* merge =
     950          33 :         graph()->NewNode(common()->Merge(2), if_exception0, if_exception1);
     951             :     Node* ephi = graph()->NewNode(common()->EffectPhi(2), if_exception0,
     952          33 :                                   if_exception1, merge);
     953             :     Node* phi =
     954             :         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
     955          33 :                          if_exception0, if_exception1, merge);
     956         269 :     ReplaceWithValue(on_exception, phi, ephi, merge);
     957             :   }
     958             : 
     959         236 :   if (IsHoleyElementsKind(kind)) {
     960             :     Node* after_call_control = control;
     961             :     Node* after_call_effect = effect;
     962             :     control = hole_true;
     963             :     effect = effect_true;
     964             : 
     965          35 :     control = graph()->NewNode(common()->Merge(2), control, after_call_control);
     966             :     effect = graph()->NewNode(common()->EffectPhi(2), effect, after_call_effect,
     967          35 :                               control);
     968             :   }
     969             : 
     970             :   k = next_k;
     971             : 
     972         236 :   loop->ReplaceInput(1, control);
     973         236 :   vloop->ReplaceInput(1, k);
     974         236 :   eloop->ReplaceInput(1, effect);
     975             : 
     976             :   control = if_false;
     977             :   effect = eloop;
     978             : 
     979             :   // The above %ThrowTypeError runtime call is an unconditional throw, making
     980             :   // it impossible to return a successful completion in this case. We simply
     981             :   // connect the successful completion to the graph end.
     982             :   Node* terminate =
     983         236 :       graph()->NewNode(common()->Throw(), check_throw, check_fail);
     984         236 :   NodeProperties::MergeControlToEnd(graph(), common(), terminate);
     985             : 
     986         236 :   ReplaceWithValue(node, jsgraph()->UndefinedConstant(), effect, control);
     987         236 :   return Replace(jsgraph()->UndefinedConstant());
     988             : }
     989             : 
     990         184 : Reduction JSCallReducer::ReduceArrayMap(Handle<JSFunction> function,
     991        2120 :                                         Node* node) {
     992         184 :   if (!FLAG_turbo_inline_array_builtins) return NoChange();
     993             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
     994         184 :   Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
     995         184 :   Node* effect = NodeProperties::GetEffectInput(node);
     996         184 :   Node* control = NodeProperties::GetControlInput(node);
     997         184 :   Node* context = NodeProperties::GetContextInput(node);
     998         184 :   CallParameters const& p = CallParametersOf(node->op());
     999             : 
    1000             :   // Try to determine the {receiver} map.
    1001         184 :   Node* receiver = NodeProperties::GetValueInput(node, 1);
    1002         184 :   Node* fncallback = node->op()->ValueInputCount() > 2
    1003             :                          ? NodeProperties::GetValueInput(node, 2)
    1004         184 :                          : jsgraph()->UndefinedConstant();
    1005         184 :   Node* this_arg = node->op()->ValueInputCount() > 3
    1006             :                        ? NodeProperties::GetValueInput(node, 3)
    1007         368 :                        : jsgraph()->UndefinedConstant();
    1008             :   ZoneHandleSet<Map> receiver_maps;
    1009             :   NodeProperties::InferReceiverMapsResult result =
    1010         184 :       NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
    1011         184 :   if (result != NodeProperties::kReliableReceiverMaps) {
    1012             :     return NoChange();
    1013             :   }
    1014             : 
    1015             :   // Ensure that any changes to the Array species constructor cause deopt.
    1016         177 :   if (!isolate()->IsArraySpeciesLookupChainIntact()) return NoChange();
    1017             : 
    1018         177 :   if (receiver_maps.size() == 0) return NoChange();
    1019             : 
    1020             :   const ElementsKind kind = receiver_maps[0]->elements_kind();
    1021             : 
    1022             :   // TODO(danno): Handle holey elements kinds.
    1023         177 :   if (!IsFastPackedElementsKind(kind)) {
    1024             :     return NoChange();
    1025             :   }
    1026             : 
    1027         346 :   for (Handle<Map> receiver_map : receiver_maps) {
    1028         173 :     if (!CanInlineArrayIteratingBuiltin(receiver_map)) {
    1029             :       return NoChange();
    1030             :     }
    1031             :     // We can handle different maps, as long as their elements kind are the
    1032             :     // same.
    1033         173 :     if (receiver_map->elements_kind() != kind) {
    1034             :       return NoChange();
    1035             :     }
    1036             :   }
    1037             : 
    1038             :   dependencies()->AssumePropertyCell(factory()->species_protector());
    1039             : 
    1040             :   Handle<JSFunction> handle_constructor(
    1041             :       JSFunction::cast(
    1042             :           native_context()->GetInitialJSArrayMap(kind)->GetConstructor()),
    1043         173 :       isolate());
    1044         173 :   Node* array_constructor = jsgraph()->HeapConstant(handle_constructor);
    1045             : 
    1046             : 
    1047         173 :   Node* k = jsgraph()->ZeroConstant();
    1048             : 
    1049             :   // Make sure the map hasn't changed before we construct the output array.
    1050             :   effect = graph()->NewNode(
    1051             :       simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps), receiver,
    1052         346 :       effect, control);
    1053             : 
    1054             :   Node* original_length = effect = graph()->NewNode(
    1055             :       simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver,
    1056         519 :       effect, control);
    1057             : 
    1058             :   // This array should be HOLEY_SMI_ELEMENTS because of the non-zero length.
    1059             :   // Even though {JSCreateArray} is not marked as {kNoThrow}, we can elide the
    1060             :   // exceptional projections because it cannot throw with the given parameters.
    1061             :   Node* a = control = effect = graph()->NewNode(
    1062             :       javascript()->CreateArray(1, Handle<AllocationSite>::null()),
    1063             :       array_constructor, array_constructor, original_length, context,
    1064         173 :       outer_frame_state, effect, control);
    1065             : 
    1066             :   std::vector<Node*> checkpoint_params(
    1067         346 :       {receiver, fncallback, this_arg, a, k, original_length});
    1068         346 :   const int stack_parameters = static_cast<int>(checkpoint_params.size());
    1069             : 
    1070             :   // Check whether the given callback function is callable. Note that this has
    1071             :   // to happen outside the loop to make sure we also throw on empty arrays.
    1072         173 :   Node* check = graph()->NewNode(simplified()->ObjectIsCallable(), fncallback);
    1073             :   Node* check_branch =
    1074         173 :       graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
    1075         173 :   Node* check_fail = graph()->NewNode(common()->IfFalse(), check_branch);
    1076             :   Node* check_frame_state = CreateJavaScriptBuiltinContinuationFrameState(
    1077             :       jsgraph(), function, Builtins::kArrayMapLoopLazyDeoptContinuation,
    1078         173 :       node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
    1079         173 :       outer_frame_state, ContinuationFrameStateMode::LAZY);
    1080             :   Node* check_throw = check_fail = graph()->NewNode(
    1081             :       javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
    1082             :       jsgraph()->Constant(MessageTemplate::kCalledNonCallable), fncallback,
    1083         346 :       context, check_frame_state, effect, check_fail);
    1084         173 :   control = graph()->NewNode(common()->IfTrue(), check_branch);
    1085             : 
    1086             :   // Start the loop.
    1087         173 :   Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
    1088             :   Node* eloop = effect =
    1089         173 :       graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
    1090             :   Node* vloop = k = graph()->NewNode(
    1091         173 :       common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop);
    1092         173 :   checkpoint_params[4] = k;
    1093             : 
    1094             :   control = loop;
    1095             :   effect = eloop;
    1096             : 
    1097             :   Node* continue_test =
    1098         173 :       graph()->NewNode(simplified()->NumberLessThan(), k, original_length);
    1099             :   Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
    1100         173 :                                            continue_test, control);
    1101             : 
    1102         173 :   Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch);
    1103         173 :   Node* if_false = graph()->NewNode(common()->IfFalse(), continue_branch);
    1104             :   control = if_true;
    1105             : 
    1106             :   Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState(
    1107             :       jsgraph(), function, Builtins::kArrayMapLoopEagerDeoptContinuation,
    1108         173 :       node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
    1109         173 :       outer_frame_state, ContinuationFrameStateMode::EAGER);
    1110             : 
    1111             :   effect =
    1112         173 :       graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
    1113             : 
    1114             :   // Make sure the map hasn't changed during the iteration
    1115             :   effect = graph()->NewNode(
    1116             :       simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps), receiver,
    1117         346 :       effect, control);
    1118             : 
    1119             :   // Make sure that the access is still in bounds, since the callback could have
    1120             :   // changed the array's size.
    1121             :   Node* length = effect = graph()->NewNode(
    1122             :       simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver,
    1123         519 :       effect, control);
    1124             :   k = effect =
    1125         173 :       graph()->NewNode(simplified()->CheckBounds(), k, length, effect, control);
    1126             : 
    1127             :   // Reload the elements pointer before calling the callback, since the previous
    1128             :   // callback might have resized the array causing the elements buffer to be
    1129             :   // re-allocated.
    1130             :   Node* elements = effect = graph()->NewNode(
    1131             :       simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
    1132         519 :       effect, control);
    1133             : 
    1134             :   Node* element = effect = graph()->NewNode(
    1135             :       simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(kind)),
    1136         519 :       elements, k, effect, control);
    1137             : 
    1138             :   Node* next_k =
    1139         346 :       graph()->NewNode(simplified()->NumberAdd(), k, jsgraph()->OneConstant());
    1140             : 
    1141             :   // This frame state is dealt with by hand in
    1142             :   // ArrayMapLoopLazyDeoptContinuation.
    1143             :   frame_state = CreateJavaScriptBuiltinContinuationFrameState(
    1144             :       jsgraph(), function, Builtins::kArrayMapLoopLazyDeoptContinuation,
    1145         173 :       node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
    1146         173 :       outer_frame_state, ContinuationFrameStateMode::LAZY);
    1147             : 
    1148             :   Node* callback_value = control = effect = graph()->NewNode(
    1149             :       javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
    1150         519 :       receiver, context, frame_state, effect, control);
    1151             : 
    1152             :   // Rewire potential exception edges.
    1153         173 :   Node* on_exception = nullptr;
    1154         173 :   if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
    1155             :     // Create appropriate {IfException} and {IfSuccess} nodes.
    1156             :     Node* if_exception0 =
    1157          30 :         graph()->NewNode(common()->IfException(), check_throw, check_fail);
    1158          30 :     check_fail = graph()->NewNode(common()->IfSuccess(), check_fail);
    1159             :     Node* if_exception1 =
    1160          30 :         graph()->NewNode(common()->IfException(), effect, control);
    1161          30 :     control = graph()->NewNode(common()->IfSuccess(), control);
    1162             : 
    1163             :     // Join the exception edges.
    1164             :     Node* merge =
    1165          30 :         graph()->NewNode(common()->Merge(2), if_exception0, if_exception1);
    1166             :     Node* ephi = graph()->NewNode(common()->EffectPhi(2), if_exception0,
    1167          30 :                                   if_exception1, merge);
    1168             :     Node* phi =
    1169             :         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
    1170          30 :                          if_exception0, if_exception1, merge);
    1171         203 :     ReplaceWithValue(on_exception, phi, ephi, merge);
    1172             :   }
    1173             : 
    1174             :   Handle<Map> double_map(Map::cast(
    1175             :       native_context()->get(Context::ArrayMapIndex(HOLEY_DOUBLE_ELEMENTS))));
    1176             :   Handle<Map> fast_map(
    1177             :       Map::cast(native_context()->get(Context::ArrayMapIndex(HOLEY_ELEMENTS))));
    1178             :   effect = graph()->NewNode(
    1179             :       simplified()->TransitionAndStoreElement(double_map, fast_map), a, k,
    1180         173 :       callback_value, effect, control);
    1181             : 
    1182             :   k = next_k;
    1183             : 
    1184         173 :   loop->ReplaceInput(1, control);
    1185         173 :   vloop->ReplaceInput(1, k);
    1186         173 :   eloop->ReplaceInput(1, effect);
    1187             : 
    1188             :   control = if_false;
    1189             :   effect = eloop;
    1190             : 
    1191             :   // The above %ThrowTypeError runtime call is an unconditional throw, making
    1192             :   // it impossible to return a successful completion in this case. We simply
    1193             :   // connect the successful completion to the graph end.
    1194             :   Node* terminate =
    1195         173 :       graph()->NewNode(common()->Throw(), check_throw, check_fail);
    1196         173 :   NodeProperties::MergeControlToEnd(graph(), common(), terminate);
    1197             : 
    1198             :   ReplaceWithValue(node, a, effect, control);
    1199             :   return Replace(a);
    1200             : }
    1201             : 
    1202       11196 : Reduction JSCallReducer::ReduceCallApiFunction(
    1203       63563 :     Node* node, Handle<FunctionTemplateInfo> function_template_info) {
    1204             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
    1205       11196 :   CallParameters const& p = CallParametersOf(node->op());
    1206       11196 :   int const argc = static_cast<int>(p.arity()) - 2;
    1207             :   Node* receiver = (p.convert_mode() == ConvertReceiverMode::kNullOrUndefined)
    1208       29128 :                        ? jsgraph()->HeapConstant(global_proxy())
    1209       22392 :                        : NodeProperties::GetValueInput(node, 1);
    1210       11196 :   Node* effect = NodeProperties::GetEffectInput(node);
    1211             : 
    1212             :   // CallApiCallbackStub expects the target in a register, so we count it out,
    1213             :   // and counts the receiver as an implicit argument, so we count the receiver
    1214             :   // out too.
    1215       11196 :   if (argc > CallApiCallbackStub::kArgMax) return NoChange();
    1216             : 
    1217             :   // Infer the {receiver} maps, and check if we can inline the API function
    1218             :   // callback based on those.
    1219             :   ZoneHandleSet<Map> receiver_maps;
    1220             :   NodeProperties::InferReceiverMapsResult result =
    1221       11194 :       NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
    1222       11194 :   if (result == NodeProperties::kNoReceiverMaps) return NoChange();
    1223       33132 :   for (size_t i = 0; i < receiver_maps.size(); ++i) {
    1224             :     Handle<Map> receiver_map = receiver_maps[i];
    1225       33132 :     if (!receiver_map->IsJSObjectMap() ||
    1226           0 :         (!function_template_info->accept_any_receiver() &&
    1227             :          receiver_map->is_access_check_needed())) {
    1228             :       return NoChange();
    1229             :     }
    1230             :     // In case of unreliable {receiver} information, the {receiver_maps}
    1231             :     // must all be stable in order to consume the information.
    1232       11044 :     if (result == NodeProperties::kUnreliableReceiverMaps) {
    1233       10426 :       if (!receiver_map->is_stable()) return NoChange();
    1234             :     }
    1235             :   }
    1236             : 
    1237             :   // See if we can constant-fold the compatible receiver checks.
    1238       11044 :   CallOptimization call_optimization(function_template_info);
    1239       11044 :   if (!call_optimization.is_simple_api_call()) return NoChange();
    1240             :   CallOptimization::HolderLookup lookup;
    1241             :   Handle<JSObject> api_holder =
    1242       11042 :       call_optimization.LookupHolderOfExpectedType(receiver_maps[0], &lookup);
    1243       11042 :   if (lookup == CallOptimization::kHolderNotFound) return NoChange();
    1244       10991 :   for (size_t i = 1; i < receiver_maps.size(); ++i) {
    1245             :     CallOptimization::HolderLookup lookupi;
    1246             :     Handle<JSObject> holder = call_optimization.LookupHolderOfExpectedType(
    1247           0 :         receiver_maps[i], &lookupi);
    1248           0 :     if (lookup != lookupi) return NoChange();
    1249           0 :     if (!api_holder.is_identical_to(holder)) return NoChange();
    1250             :   }
    1251             : 
    1252             :   // Install stability dependencies for unreliable {receiver_maps}.
    1253       10991 :   if (result == NodeProperties::kUnreliableReceiverMaps) {
    1254       31263 :     for (size_t i = 0; i < receiver_maps.size(); ++i) {
    1255       10421 :       dependencies()->AssumeMapStable(receiver_maps[i]);
    1256             :     }
    1257             :   }
    1258             : 
    1259             :   // CallApiCallbackStub's register arguments: code, target, call data, holder,
    1260             :   // function address.
    1261             :   // TODO(turbofan): Consider introducing a JSCallApiCallback operator for
    1262             :   // this and lower it during JSGenericLowering, and unify this with the
    1263             :   // JSNativeContextSpecialization::InlineApiCall method a bit.
    1264             :   Handle<CallHandlerInfo> call_handler_info(
    1265             :       CallHandlerInfo::cast(function_template_info->call_code()), isolate());
    1266             :   Handle<Object> data(call_handler_info->data(), isolate());
    1267             :   CallApiCallbackStub stub(isolate(), argc, false);
    1268             :   CallInterfaceDescriptor cid = stub.GetCallInterfaceDescriptor();
    1269             :   CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
    1270             :       isolate(), graph()->zone(), cid,
    1271       10991 :       cid.GetStackParameterCount() + argc +
    1272             :           2 /* implicit receiver + accessor_holder */,
    1273             :       CallDescriptor::kNeedsFrameState, Operator::kNoProperties,
    1274       32973 :       MachineType::AnyTagged(), 1);
    1275             :   ApiFunction api_function(v8::ToCData<Address>(call_handler_info->callback()));
    1276       10991 :   Node* holder = lookup == CallOptimization::kHolderFound
    1277       10998 :                      ? jsgraph()->HeapConstant(api_holder)
    1278       21982 :                      : receiver;
    1279             :   ExternalReference function_reference(
    1280       10991 :       &api_function, ExternalReference::DIRECT_API_CALL, isolate());
    1281             :   node->InsertInput(graph()->zone(), 0,
    1282       32973 :                     jsgraph()->HeapConstant(stub.GetCode()));
    1283       21982 :   node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(data));
    1284       10991 :   node->InsertInput(graph()->zone(), 3, holder);
    1285             :   node->InsertInput(graph()->zone(), 4,
    1286       21982 :                     jsgraph()->ExternalConstant(function_reference));
    1287       10991 :   node->InsertInput(graph()->zone(), 5, holder /* as accessor_holder */);
    1288       10991 :   node->ReplaceInput(6, receiver);
    1289       10991 :   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
    1290             :   return Changed(node);
    1291             : }
    1292             : 
    1293             : namespace {
    1294             : 
    1295             : // Check whether elements aren't mutated; we play it extremely safe here by
    1296             : // explicitly checking that {node} is only used by {LoadField} or {LoadElement}.
    1297          39 : bool IsSafeArgumentsElements(Node* node) {
    1298         273 :   for (Edge const edge : node->use_edges()) {
    1299         117 :     if (!NodeProperties::IsValueEdge(edge)) continue;
    1300         195 :     if (edge.from()->opcode() != IrOpcode::kLoadField &&
    1301          39 :         edge.from()->opcode() != IrOpcode::kLoadElement) {
    1302           0 :       return false;
    1303             :     }
    1304             :   }
    1305             :   return true;
    1306             : }
    1307             : 
    1308             : }  // namespace
    1309             : 
    1310        2733 : Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
    1311             :     Node* node, int arity, CallFrequency const& frequency,
    1312        1595 :     VectorSlotPair const& feedback) {
    1313             :   DCHECK(node->opcode() == IrOpcode::kJSCallWithArrayLike ||
    1314             :          node->opcode() == IrOpcode::kJSCallWithSpread ||
    1315             :          node->opcode() == IrOpcode::kJSConstructWithArrayLike ||
    1316             :          node->opcode() == IrOpcode::kJSConstructWithSpread);
    1317             : 
    1318             :   // In case of a call/construct with spread, we need to
    1319             :   // ensure that it's safe to avoid the actual iteration.
    1320       11425 :   if ((node->opcode() == IrOpcode::kJSCallWithSpread ||
    1321        4433 :        node->opcode() == IrOpcode::kJSConstructWithSpread) &&
    1322        6133 :       !isolate()->initial_array_iterator_prototype_map()->is_stable()) {
    1323             :     return NoChange();
    1324             :   }
    1325             : 
    1326             :   // Check if {arguments_list} is an arguments object, and {node} is the only
    1327             :   // value user of {arguments_list} (except for value uses in frame states).
    1328        4062 :   Node* arguments_list = NodeProperties::GetValueInput(node, arity);
    1329        2725 :   if (arguments_list->opcode() != IrOpcode::kJSCreateArguments) {
    1330             :     return NoChange();
    1331             :   }
    1332       20671 :   for (Edge edge : arguments_list->use_edges()) {
    1333        9667 :     if (!NodeProperties::IsValueEdge(edge)) continue;
    1334        8316 :     Node* const user = edge.from();
    1335        8277 :     switch (user->opcode()) {
    1336             :       case IrOpcode::kCheckMaps:
    1337             :       case IrOpcode::kFrameState:
    1338             :       case IrOpcode::kStateValues:
    1339             :       case IrOpcode::kReferenceEqual:
    1340             :       case IrOpcode::kReturn:
    1341             :         // Ignore safe uses that definitely don't mess with the arguments.
    1342             :         continue;
    1343             :       case IrOpcode::kLoadField: {
    1344             :         DCHECK_EQ(arguments_list, user->InputAt(0));
    1345          93 :         FieldAccess const& access = FieldAccessOf(user->op());
    1346          93 :         if (access.offset == JSArray::kLengthOffset) {
    1347             :           // Ignore uses for arguments#length.
    1348             :           STATIC_ASSERT(JSArray::kLengthOffset ==
    1349             :                         JSArgumentsObject::kLengthOffset);
    1350             :           continue;
    1351          39 :         } else if (access.offset == JSObject::kElementsOffset) {
    1352             :           // Ignore safe uses for arguments#elements.
    1353          39 :           if (IsSafeArgumentsElements(user)) continue;
    1354             :         }
    1355             :         break;
    1356             :       }
    1357             :       case IrOpcode::kJSCallWithArrayLike:
    1358             :         // Ignore uses as argumentsList input to calls with array like.
    1359         533 :         if (user->InputAt(2) == arguments_list) continue;
    1360             :         break;
    1361             :       case IrOpcode::kJSConstructWithArrayLike:
    1362             :         // Ignore uses as argumentsList input to calls with array like.
    1363         157 :         if (user->InputAt(1) == arguments_list) continue;
    1364             :         break;
    1365             :       case IrOpcode::kJSCallWithSpread: {
    1366             :         // Ignore uses as spread input to calls with spread.
    1367         407 :         CallParameters p = CallParametersOf(user->op());
    1368         407 :         int const arity = static_cast<int>(p.arity() - 1);
    1369         407 :         if (user->InputAt(arity) == arguments_list) continue;
    1370             :         break;
    1371             :       }
    1372             :       case IrOpcode::kJSConstructWithSpread: {
    1373             :         // Ignore uses as spread input to construct with spread.
    1374         539 :         ConstructParameters p = ConstructParametersOf(user->op());
    1375         539 :         int const arity = static_cast<int>(p.arity() - 2);
    1376         539 :         if (user->InputAt(arity) == arguments_list) continue;
    1377             :         break;
    1378             :       }
    1379             :       default:
    1380             :         break;
    1381             :     }
    1382             :     // We cannot currently reduce the {node} to something better than what
    1383             :     // it already is, but we might be able to do something about the {node}
    1384             :     // later, so put it on the waitlist and try again during finalization.
    1385             :     waitlist_.insert(node);
    1386         122 :     return NoChange();
    1387             :   }
    1388             : 
    1389             :   // Get to the actual frame state from which to extract the arguments;
    1390             :   // we can only optimize this in case the {node} was already inlined into
    1391             :   // some other function (and same for the {arguments_list}).
    1392        1337 :   CreateArgumentsType const type = CreateArgumentsTypeOf(arguments_list->op());
    1393        1337 :   Node* frame_state = NodeProperties::GetFrameStateInput(arguments_list);
    1394        1337 :   FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
    1395             :   int start_index = 0;
    1396             :   // Determine the formal parameter count;
    1397             :   Handle<SharedFunctionInfo> shared;
    1398        1337 :   if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
    1399             :   int formal_parameter_count = shared->internal_formal_parameter_count();
    1400        1337 :   if (type == CreateArgumentsType::kMappedArguments) {
    1401             :     // Mapped arguments (sloppy mode) that are aliased can only be handled
    1402             :     // here if there's no side-effect between the {node} and the {arg_array}.
    1403             :     // TODO(turbofan): Further relax this constraint.
    1404         391 :     if (formal_parameter_count != 0) {
    1405          66 :       Node* effect = NodeProperties::GetEffectInput(node);
    1406          66 :       if (!NodeProperties::NoObservableSideEffectBetween(effect,
    1407          66 :                                                          arguments_list)) {
    1408             :         return NoChange();
    1409             :       }
    1410             :     }
    1411         946 :   } else if (type == CreateArgumentsType::kRestParameter) {
    1412             :     start_index = formal_parameter_count;
    1413             : 
    1414             :     // For spread calls/constructs with rest parameters we need to ensure that
    1415             :     // the array iterator protector is intact, which guards that the rest
    1416             :     // parameter iteration is not observable.
    1417        1406 :     if (node->opcode() == IrOpcode::kJSCallWithSpread ||
    1418             :         node->opcode() == IrOpcode::kJSConstructWithSpread) {
    1419         625 :       if (!isolate()->IsArrayIteratorLookupChainIntact()) return NoChange();
    1420             :       dependencies()->AssumePropertyCell(factory()->array_iterator_protector());
    1421             :     }
    1422             :   }
    1423             : 
    1424             :   // For call/construct with spread, we need to also install a code
    1425             :   // dependency on the initial %ArrayIteratorPrototype% map here to
    1426             :   // ensure that no one messes with the next method.
    1427        2600 :   if (node->opcode() == IrOpcode::kJSCallWithSpread ||
    1428             :       node->opcode() == IrOpcode::kJSConstructWithSpread) {
    1429             :     dependencies()->AssumeMapStable(
    1430        1486 :         isolate()->initial_array_iterator_prototype_map());
    1431             :   }
    1432             : 
    1433             :   // Remove the {arguments_list} input from the {node}.
    1434        1300 :   node->RemoveInput(arity--);
    1435             :   // Check if are spreading to inlined arguments or to the arguments of
    1436             :   // the outermost function.
    1437        1300 :   Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
    1438        1300 :   if (outer_state->opcode() != IrOpcode::kFrameState) {
    1439             :     Operator const* op =
    1440        1426 :         (node->opcode() == IrOpcode::kJSCallWithArrayLike ||
    1441             :          node->opcode() == IrOpcode::kJSCallWithSpread)
    1442         384 :             ? javascript()->CallForwardVarargs(arity + 1, start_index)
    1443        1674 :             : javascript()->ConstructForwardVarargs(arity + 2, start_index);
    1444         837 :     NodeProperties::ChangeOp(node, op);
    1445         837 :     return Changed(node);
    1446             :   }
    1447             :   // Get to the actual frame state from which to extract the arguments;
    1448             :   // we can only optimize this in case the {node} was already inlined into
    1449             :   // some other function (and same for the {arg_array}).
    1450         463 :   FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state);
    1451         463 :   if (outer_info.type() == FrameStateType::kArgumentsAdaptor) {
    1452             :     // Need to take the parameters from the arguments adaptor.
    1453             :     frame_state = outer_state;
    1454             :   }
    1455             :   // Add the actual parameters to the {node}, skipping the receiver.
    1456             :   Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
    1457        2056 :   for (int i = start_index + 1; i < parameters->InputCount(); ++i) {
    1458             :     node->InsertInput(graph()->zone(), static_cast<int>(++arity),
    1459        1130 :                       parameters->InputAt(i));
    1460             :   }
    1461             : 
    1462         926 :   if (node->opcode() == IrOpcode::kJSCallWithArrayLike ||
    1463             :       node->opcode() == IrOpcode::kJSCallWithSpread) {
    1464             :     NodeProperties::ChangeOp(
    1465         452 :         node, javascript()->Call(arity + 1, frequency, feedback));
    1466         226 :     Reduction const reduction = ReduceJSCall(node);
    1467         226 :     return reduction.Changed() ? reduction : Changed(node);
    1468             :   } else {
    1469             :     NodeProperties::ChangeOp(
    1470         474 :         node, javascript()->Construct(arity + 2, frequency, feedback));
    1471         237 :     Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
    1472         237 :     Node* frame_state = NodeProperties::GetFrameStateInput(node);
    1473         237 :     Node* context = NodeProperties::GetContextInput(node);
    1474         237 :     Node* effect = NodeProperties::GetEffectInput(node);
    1475         237 :     Node* control = NodeProperties::GetControlInput(node);
    1476             : 
    1477             :     // Check whether the given new target value is a constructor function. The
    1478             :     // replacement {JSConstruct} operator only checks the passed target value
    1479             :     // but relies on the new target value to be implicitly valid.
    1480             :     Node* check =
    1481         237 :         graph()->NewNode(simplified()->ObjectIsConstructor(), new_target);
    1482             :     Node* check_branch =
    1483         237 :         graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
    1484         237 :     Node* check_fail = graph()->NewNode(common()->IfFalse(), check_branch);
    1485             :     Node* check_throw = check_fail =
    1486             :         graph()->NewNode(javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
    1487             :                          jsgraph()->Constant(MessageTemplate::kNotConstructor),
    1488         474 :                          new_target, context, frame_state, effect, check_fail);
    1489         237 :     control = graph()->NewNode(common()->IfTrue(), check_branch);
    1490         237 :     NodeProperties::ReplaceControlInput(node, control);
    1491             : 
    1492             :     // Rewire potential exception edges.
    1493         237 :     Node* on_exception = nullptr;
    1494         237 :     if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
    1495             :       // Create appropriate {IfException}  and {IfSuccess} nodes.
    1496             :       Node* if_exception =
    1497           8 :           graph()->NewNode(common()->IfException(), check_throw, check_fail);
    1498           8 :       check_fail = graph()->NewNode(common()->IfSuccess(), check_fail);
    1499             : 
    1500             :       // Join the exception edges.
    1501             :       Node* merge =
    1502          16 :           graph()->NewNode(common()->Merge(2), if_exception, on_exception);
    1503             :       Node* ephi = graph()->NewNode(common()->EffectPhi(2), if_exception,
    1504          16 :                                     on_exception, merge);
    1505             :       Node* phi =
    1506             :           graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
    1507          16 :                            if_exception, on_exception, merge);
    1508           8 :       ReplaceWithValue(on_exception, phi, ephi, merge);
    1509           8 :       merge->ReplaceInput(1, on_exception);
    1510           8 :       ephi->ReplaceInput(1, on_exception);
    1511           8 :       phi->ReplaceInput(1, on_exception);
    1512             :     }
    1513             : 
    1514             :     // The above %ThrowTypeError runtime call is an unconditional throw, making
    1515             :     // it impossible to return a successful completion in this case. We simply
    1516             :     // connect the successful completion to the graph end.
    1517             :     Node* terminate =
    1518         237 :         graph()->NewNode(common()->Throw(), check_throw, check_fail);
    1519         237 :     NodeProperties::MergeControlToEnd(graph(), common(), terminate);
    1520             : 
    1521         237 :     Reduction const reduction = ReduceJSConstruct(node);
    1522         237 :     return reduction.Changed() ? reduction : Changed(node);
    1523             :   }
    1524             : }
    1525             : 
    1526             : namespace {
    1527             : 
    1528       26277 : bool ShouldUseCallICFeedback(Node* node) {
    1529             :   HeapObjectMatcher m(node);
    1530       26277 :   if (m.HasValue() || m.IsJSCreateClosure()) {
    1531             :     // Don't use CallIC feedback when we know the function
    1532             :     // being called, i.e. either know the closure itself or
    1533             :     // at least the SharedFunctionInfo.
    1534             :     return false;
    1535       25376 :   } else if (m.IsPhi()) {
    1536             :     // Protect against endless loops here.
    1537         754 :     Node* control = NodeProperties::GetControlInput(node);
    1538         754 :     if (control->opcode() == IrOpcode::kLoop) return false;
    1539             :     // Check if {node} is a Phi of nodes which shouldn't
    1540             :     // use CallIC feedback (not looking through loops).
    1541         754 :     int const value_input_count = m.node()->op()->ValueInputCount();
    1542        1467 :     for (int n = 0; n < value_input_count; ++n) {
    1543        1464 :       if (ShouldUseCallICFeedback(node->InputAt(n))) return true;
    1544             :     }
    1545             :     return false;
    1546             :   }
    1547             :   return true;
    1548             : }
    1549             : 
    1550             : }  // namespace
    1551             : 
    1552      705445 : Reduction JSCallReducer::ReduceJSCall(Node* node) {
    1553             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
    1554     1361475 :   CallParameters const& p = CallParametersOf(node->op());
    1555      680753 :   Node* target = NodeProperties::GetValueInput(node, 0);
    1556      680739 :   Node* control = NodeProperties::GetControlInput(node);
    1557      680740 :   Node* effect = NodeProperties::GetEffectInput(node);
    1558             :   size_t arity = p.arity();
    1559             :   DCHECK_LE(2u, arity);
    1560             : 
    1561             :   // Try to specialize JSCall {node}s with constant {target}s.
    1562             :   HeapObjectMatcher m(target);
    1563      680738 :   if (m.HasValue()) {
    1564      355248 :     if (m.Value()->IsJSFunction()) {
    1565             :       Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
    1566             :       Handle<SharedFunctionInfo> shared(function->shared(), isolate());
    1567             : 
    1568             :       // Raise a TypeError if the {target} is a "classConstructor".
    1569      355143 :       if (IsClassConstructor(shared->kind())) {
    1570          32 :         NodeProperties::ReplaceValueInputs(node, target);
    1571             :         NodeProperties::ChangeOp(
    1572             :             node, javascript()->CallRuntime(
    1573          32 :                       Runtime::kThrowConstructorNonCallableError, 1));
    1574             :         return Changed(node);
    1575             :       }
    1576             : 
    1577             :       // Don't inline cross native context.
    1578      355111 :       if (function->native_context() != *native_context()) return NoChange();
    1579             : 
    1580             :       // Check for known builtin functions.
    1581      355083 :       switch (shared->code()->builtin_index()) {
    1582             :         case Builtins::kArrayConstructor:
    1583         226 :           return ReduceArrayConstructor(node);
    1584             :         case Builtins::kBooleanConstructor:
    1585          12 :           return ReduceBooleanConstructor(node);
    1586             :         case Builtins::kFunctionPrototypeApply:
    1587         506 :           return ReduceFunctionPrototypeApply(node);
    1588             :         case Builtins::kFastFunctionPrototypeBind:
    1589          94 :           return ReduceFunctionPrototypeBind(node);
    1590             :         case Builtins::kFunctionPrototypeCall:
    1591        1127 :           return ReduceFunctionPrototypeCall(node);
    1592             :         case Builtins::kFunctionPrototypeHasInstance:
    1593        1658 :           return ReduceFunctionPrototypeHasInstance(node);
    1594             :         case Builtins::kNumberConstructor:
    1595         149 :           return ReduceNumberConstructor(node);
    1596             :         case Builtins::kObjectConstructor:
    1597         168 :           return ReduceObjectConstructor(node);
    1598             :         case Builtins::kObjectGetPrototypeOf:
    1599          78 :           return ReduceObjectGetPrototypeOf(node);
    1600             :         case Builtins::kObjectPrototypeGetProto:
    1601          92 :           return ReduceObjectPrototypeGetProto(node);
    1602             :         case Builtins::kObjectPrototypeHasOwnProperty:
    1603         465 :           return ReduceObjectPrototypeHasOwnProperty(node);
    1604             :         case Builtins::kObjectPrototypeIsPrototypeOf:
    1605          63 :           return ReduceObjectPrototypeIsPrototypeOf(node);
    1606             :         case Builtins::kReflectApply:
    1607         220 :           return ReduceReflectApply(node);
    1608             :         case Builtins::kReflectConstruct:
    1609         211 :           return ReduceReflectConstruct(node);
    1610             :         case Builtins::kReflectGetPrototypeOf:
    1611          15 :           return ReduceReflectGetPrototypeOf(node);
    1612             :         case Builtins::kReflectHas:
    1613          35 :           return ReduceReflectHas(node);
    1614             :         case Builtins::kArrayForEach:
    1615         267 :           return ReduceArrayForEach(function, node);
    1616             :         case Builtins::kArrayMap:
    1617         184 :           return ReduceArrayMap(function, node);
    1618             :         case Builtins::kReturnReceiver:
    1619          54 :           return ReduceReturnReceiver(node);
    1620             :         default:
    1621             :           break;
    1622             :       }
    1623             : 
    1624      349459 :       if (!FLAG_runtime_stats && shared->IsApiFunction()) {
    1625             :         Handle<FunctionTemplateInfo> function_template_info(
    1626             :             FunctionTemplateInfo::cast(shared->function_data()), isolate());
    1627       11196 :         return ReduceCallApiFunction(node, function_template_info);
    1628             :       }
    1629         105 :     } else if (m.Value()->IsJSBoundFunction()) {
    1630             :       Handle<JSBoundFunction> function =
    1631             :           Handle<JSBoundFunction>::cast(m.Value());
    1632             :       Handle<JSReceiver> bound_target_function(
    1633             :           function->bound_target_function(), isolate());
    1634             :       Handle<Object> bound_this(function->bound_this(), isolate());
    1635             :       Handle<FixedArray> bound_arguments(function->bound_arguments(),
    1636             :                                          isolate());
    1637             :       ConvertReceiverMode const convert_mode =
    1638             :           (bound_this->IsNullOrUndefined(isolate()))
    1639             :               ? ConvertReceiverMode::kNullOrUndefined
    1640          32 :               : ConvertReceiverMode::kNotNullOrUndefined;
    1641             :       // Patch {node} to use [[BoundTargetFunction]] and [[BoundThis]].
    1642             :       NodeProperties::ReplaceValueInput(
    1643          32 :           node, jsgraph()->Constant(bound_target_function), 0);
    1644             :       NodeProperties::ReplaceValueInput(node, jsgraph()->Constant(bound_this),
    1645          32 :                                         1);
    1646             :       // Insert the [[BoundArguments]] for {node}.
    1647         108 :       for (int i = 0; i < bound_arguments->length(); ++i) {
    1648             :         node->InsertInput(
    1649             :             graph()->zone(), i + 2,
    1650          44 :             jsgraph()->Constant(handle(bound_arguments->get(i), isolate())));
    1651          22 :         arity++;
    1652             :       }
    1653             :       NodeProperties::ChangeOp(
    1654             :           node, javascript()->Call(arity, p.frequency(), VectorSlotPair(),
    1655          64 :                                    convert_mode));
    1656             :       // Try to further reduce the JSCall {node}.
    1657          32 :       Reduction const reduction = ReduceJSCall(node);
    1658          32 :       return reduction.Changed() ? reduction : Changed(node);
    1659             :     }
    1660             : 
    1661             :     // Don't mess with other {node}s that have a constant {target}.
    1662             :     // TODO(bmeurer): Also support proxies here.
    1663             :     return NoChange();
    1664             :   }
    1665             : 
    1666             :   // If {target} is the result of a JSCreateBoundFunction operation,
    1667             :   // we can just fold the construction and call the bound target
    1668             :   // function directly instead.
    1669      325490 :   if (target->opcode() == IrOpcode::kJSCreateBoundFunction) {
    1670          14 :     Node* bound_target_function = NodeProperties::GetValueInput(target, 0);
    1671          14 :     Node* bound_this = NodeProperties::GetValueInput(target, 1);
    1672             :     int const bound_arguments_length =
    1673          14 :         static_cast<int>(CreateBoundFunctionParametersOf(target->op()).arity());
    1674             : 
    1675             :     // Patch the {node} to use [[BoundTargetFunction]] and [[BoundThis]].
    1676          14 :     NodeProperties::ReplaceValueInput(node, bound_target_function, 0);
    1677          14 :     NodeProperties::ReplaceValueInput(node, bound_this, 1);
    1678             : 
    1679             :     // Insert the [[BoundArguments]] for {node}.
    1680          28 :     for (int i = 0; i < bound_arguments_length; ++i) {
    1681          14 :       Node* value = NodeProperties::GetValueInput(target, 2 + i);
    1682          14 :       node->InsertInput(graph()->zone(), 2 + i, value);
    1683          14 :       arity++;
    1684             :     }
    1685             : 
    1686             :     // Update the JSCall operator on {node}.
    1687             :     ConvertReceiverMode const convert_mode =
    1688          14 :         CanBeNullOrUndefined(bound_this)
    1689             :             ? ConvertReceiverMode::kAny
    1690          14 :             : ConvertReceiverMode::kNotNullOrUndefined;
    1691             :     NodeProperties::ChangeOp(
    1692             :         node, javascript()->Call(arity, p.frequency(), VectorSlotPair(),
    1693          28 :                                  convert_mode));
    1694             : 
    1695             :     // Try to further reduce the JSCall {node}.
    1696          14 :     Reduction const reduction = ReduceJSCall(node);
    1697          14 :     return reduction.Changed() ? reduction : Changed(node);
    1698             :   }
    1699             : 
    1700             :   // Extract feedback from the {node} using the CallICNexus.
    1701      325476 :   if (!p.feedback().IsValid()) return NoChange();
    1702             :   CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
    1703      315599 :   if (nexus.IsUninitialized()) {
    1704      284194 :     if (flags() & kBailoutOnUninitialized) {
    1705             :       // Introduce a SOFT deopt if the call {node} wasn't executed so far.
    1706             :       return ReduceSoftDeoptimize(
    1707           0 :           node, DeoptimizeReason::kInsufficientTypeFeedbackForCall);
    1708             :     }
    1709             :     return NoChange();
    1710             :   }
    1711             : 
    1712       31405 :   Handle<Object> feedback(nexus.GetFeedback(), isolate());
    1713       31405 :   if (feedback->IsWeakCell()) {
    1714             :     // Check if we want to use CallIC feedback here.
    1715       24813 :     if (!ShouldUseCallICFeedback(target)) return NoChange();
    1716             : 
    1717             :     Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
    1718       24622 :     if (cell->value()->IsCallable()) {
    1719             :       Node* target_function =
    1720       24622 :           jsgraph()->Constant(handle(cell->value(), isolate()));
    1721             : 
    1722             :       // Check that the {target} is still the {target_function}.
    1723             :       Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
    1724       24622 :                                      target_function);
    1725             :       effect =
    1726             :           graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kNoReason),
    1727       24622 :                            check, effect, control);
    1728             : 
    1729             :       // Specialize the JSCall node to the {target_function}.
    1730       24622 :       NodeProperties::ReplaceValueInput(node, target_function, 0);
    1731       24622 :       NodeProperties::ReplaceEffectInput(node, effect);
    1732             : 
    1733             :       // Try to further reduce the JSCall {node}.
    1734       24622 :       Reduction const reduction = ReduceJSCall(node);
    1735       24622 :       return reduction.Changed() ? reduction : Changed(node);
    1736             :     }
    1737             :   }
    1738             :   return NoChange();
    1739             : }
    1740             : 
    1741         815 : Reduction JSCallReducer::ReduceJSCallWithArrayLike(Node* node) {
    1742             :   DCHECK_EQ(IrOpcode::kJSCallWithArrayLike, node->opcode());
    1743         815 :   CallFrequency frequency = CallFrequencyOf(node->op());
    1744         815 :   VectorSlotPair feedback;
    1745             :   return ReduceCallOrConstructWithArrayLikeOrSpread(node, 2, frequency,
    1746         815 :                                                     feedback);
    1747             : }
    1748             : 
    1749        1110 : Reduction JSCallReducer::ReduceJSCallWithSpread(Node* node) {
    1750             :   DCHECK_EQ(IrOpcode::kJSCallWithSpread, node->opcode());
    1751        1110 :   CallParameters const& p = CallParametersOf(node->op());
    1752             :   DCHECK_LE(3u, p.arity());
    1753        1110 :   int arity = static_cast<int>(p.arity() - 1);
    1754        1110 :   CallFrequency frequency = p.frequency();
    1755        1110 :   VectorSlotPair feedback = p.feedback();
    1756             :   return ReduceCallOrConstructWithArrayLikeOrSpread(node, arity, frequency,
    1757        1110 :                                                     feedback);
    1758             : }
    1759             : 
    1760       47705 : Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
    1761             :   DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
    1762       43934 :   ConstructParameters const& p = ConstructParametersOf(node->op());
    1763             :   DCHECK_LE(2u, p.arity());
    1764       43934 :   int const arity = static_cast<int>(p.arity() - 2);
    1765       43934 :   Node* target = NodeProperties::GetValueInput(node, 0);
    1766       43934 :   Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
    1767       43934 :   Node* effect = NodeProperties::GetEffectInput(node);
    1768       43934 :   Node* control = NodeProperties::GetControlInput(node);
    1769             : 
    1770             :   // Extract feedback from the {node} using the CallICNexus.
    1771       43934 :   if (p.feedback().IsValid()) {
    1772             :     CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
    1773       43902 :     if (nexus.IsUninitialized()) {
    1774       24707 :       if (flags() & kBailoutOnUninitialized) {
    1775             :         // Introduce a SOFT deopt if the construct {node} wasn't executed so
    1776             :         // far.
    1777             :         return ReduceSoftDeoptimize(
    1778           0 :             node, DeoptimizeReason::kInsufficientTypeFeedbackForConstruct);
    1779             :       }
    1780             :       return NoChange();
    1781             :     }
    1782             : 
    1783       19195 :     Handle<Object> feedback(nexus.GetFeedback(), isolate());
    1784       19195 :     if (feedback->IsAllocationSite()) {
    1785             :       // The feedback is an AllocationSite, which means we have called the
    1786             :       // Array function and collected transition (and pretenuring) feedback
    1787             :       // for the resulting arrays.  This has to be kept in sync with the
    1788             :       // implementation in Ignition.
    1789         516 :       Handle<AllocationSite> site = Handle<AllocationSite>::cast(feedback);
    1790             : 
    1791             :       // Retrieve the Array function from the {node}.
    1792             :       Node* array_function = jsgraph()->HeapConstant(
    1793         516 :           handle(native_context()->array_function(), isolate()));
    1794             : 
    1795             :       // Check that the {target} is still the {array_function}.
    1796             :       Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
    1797         516 :                                      array_function);
    1798             :       effect =
    1799             :           graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kNoReason),
    1800         516 :                            check, effect, control);
    1801             : 
    1802             :       // Turn the {node} into a {JSCreateArray} call.
    1803         516 :       NodeProperties::ReplaceEffectInput(node, effect);
    1804        1092 :       for (int i = arity; i > 0; --i) {
    1805             :         NodeProperties::ReplaceValueInput(
    1806         576 :             node, NodeProperties::GetValueInput(node, i), i + 1);
    1807             :       }
    1808         516 :       NodeProperties::ReplaceValueInput(node, array_function, 1);
    1809        1032 :       NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
    1810             :       return Changed(node);
    1811       32146 :     } else if (feedback->IsWeakCell() &&
    1812             :                !HeapObjectMatcher(new_target).HasValue()) {
    1813             :       Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
    1814        3255 :       if (cell->value()->IsConstructor()) {
    1815             :         Node* new_target_feedback =
    1816        3255 :             jsgraph()->Constant(handle(cell->value(), isolate()));
    1817             : 
    1818             :         // Check that the {new_target} is still the {new_target_feedback}.
    1819             :         Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
    1820        3255 :                                        new_target, new_target_feedback);
    1821             :         effect =
    1822             :             graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kNoReason),
    1823        3255 :                              check, effect, control);
    1824             : 
    1825             :         // Specialize the JSConstruct node to the {new_target_feedback}.
    1826        3255 :         NodeProperties::ReplaceValueInput(node, new_target_feedback, arity + 1);
    1827        3255 :         NodeProperties::ReplaceEffectInput(node, effect);
    1828        3255 :         if (target == new_target) {
    1829        3199 :           NodeProperties::ReplaceValueInput(node, new_target_feedback, 0);
    1830             :         }
    1831             : 
    1832             :         // Try to further reduce the JSConstruct {node}.
    1833        3255 :         Reduction const reduction = ReduceJSConstruct(node);
    1834        3255 :         return reduction.Changed() ? reduction : Changed(node);
    1835             :       }
    1836             :     }
    1837             :   }
    1838             : 
    1839             :   // Try to specialize JSConstruct {node}s with constant {target}s.
    1840             :   HeapObjectMatcher m(target);
    1841       15456 :   if (m.HasValue()) {
    1842       15247 :     if (m.Value()->IsJSFunction()) {
    1843             :       Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
    1844             : 
    1845             :       // Raise a TypeError if the {target} is not a constructor.
    1846       13943 :       if (!function->IsConstructor()) {
    1847           8 :         NodeProperties::ReplaceValueInputs(node, target);
    1848             :         NodeProperties::ChangeOp(
    1849             :             node, javascript()->CallRuntime(
    1850           8 :                       Runtime::kThrowConstructedNonConstructable));
    1851             :         return Changed(node);
    1852             :       }
    1853             : 
    1854             :       // Don't inline cross native context.
    1855       13935 :       if (function->native_context() != *native_context()) return NoChange();
    1856             : 
    1857             :       // Check for the ArrayConstructor.
    1858       13935 :       if (*function == function->native_context()->array_function()) {
    1859             :         // TODO(bmeurer): Deal with Array subclasses here.
    1860             :         Handle<AllocationSite> site;
    1861             :         // Turn the {node} into a {JSCreateArray} call.
    1862         448 :         for (int i = arity; i > 0; --i) {
    1863             :           NodeProperties::ReplaceValueInput(
    1864         210 :               node, NodeProperties::GetValueInput(node, i), i + 1);
    1865             :         }
    1866         238 :         NodeProperties::ReplaceValueInput(node, new_target, 1);
    1867         476 :         NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
    1868             :         return Changed(node);
    1869             :       }
    1870             : 
    1871             :       // Check for the ObjectConstructor.
    1872       13697 :       if (*function == function->native_context()->object_function()) {
    1873             :         // If no value is passed, we can immediately lower to a simple
    1874             :         // JSCreate and don't need to do any massaging of the {node}.
    1875         144 :         if (arity == 0) {
    1876         129 :           NodeProperties::ChangeOp(node, javascript()->Create());
    1877             :           return Changed(node);
    1878             :         }
    1879             : 
    1880             :         // Otherwise we can only lower to JSCreate if we know that
    1881             :         // the value parameter is ignored, which is only the case if
    1882             :         // the {new_target} and {target} are definitely not identical.
    1883             :         HeapObjectMatcher mnew_target(new_target);
    1884          30 :         if (mnew_target.HasValue() && *mnew_target.Value() != *function) {
    1885             :           // Drop the value inputs.
    1886          21 :           for (int i = arity; i > 0; --i) node->RemoveInput(i);
    1887           7 :           NodeProperties::ChangeOp(node, javascript()->Create());
    1888             :           return Changed(node);
    1889             :         }
    1890             :       }
    1891             :     }
    1892             : 
    1893             :     // TODO(bmeurer): Also support optimizing bound functions and proxies here.
    1894             :   }
    1895             : 
    1896             :   return NoChange();
    1897             : }
    1898             : 
    1899         218 : Reduction JSCallReducer::ReduceJSConstructWithArrayLike(Node* node) {
    1900             :   DCHECK_EQ(IrOpcode::kJSConstructWithArrayLike, node->opcode());
    1901         218 :   CallFrequency frequency = CallFrequencyOf(node->op());
    1902         218 :   VectorSlotPair feedback;
    1903             :   return ReduceCallOrConstructWithArrayLikeOrSpread(node, 1, frequency,
    1904         218 :                                                     feedback);
    1905             : }
    1906             : 
    1907         590 : Reduction JSCallReducer::ReduceJSConstructWithSpread(Node* node) {
    1908             :   DCHECK_EQ(IrOpcode::kJSConstructWithSpread, node->opcode());
    1909         590 :   ConstructParameters const& p = ConstructParametersOf(node->op());
    1910             :   DCHECK_LE(3u, p.arity());
    1911         590 :   int arity = static_cast<int>(p.arity() - 2);
    1912         590 :   CallFrequency frequency = p.frequency();
    1913         590 :   VectorSlotPair feedback = p.feedback();
    1914             :   return ReduceCallOrConstructWithArrayLikeOrSpread(node, arity, frequency,
    1915         590 :                                                     feedback);
    1916             : }
    1917             : 
    1918          54 : Reduction JSCallReducer::ReduceReturnReceiver(Node* node) {
    1919             :   DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
    1920          54 :   Node* receiver = NodeProperties::GetValueInput(node, 1);
    1921          54 :   ReplaceWithValue(node, receiver);
    1922          54 :   return Replace(receiver);
    1923             : }
    1924             : 
    1925           0 : Reduction JSCallReducer::ReduceSoftDeoptimize(Node* node,
    1926             :                                               DeoptimizeReason reason) {
    1927           0 :   Node* effect = NodeProperties::GetEffectInput(node);
    1928           0 :   Node* control = NodeProperties::GetControlInput(node);
    1929           0 :   Node* frame_state = NodeProperties::FindFrameStateBefore(node);
    1930             :   Node* deoptimize =
    1931             :       graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kSoft, reason),
    1932           0 :                        frame_state, effect, control);
    1933             :   // TODO(bmeurer): This should be on the AdvancedReducer somehow.
    1934           0 :   NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
    1935           0 :   Revisit(graph()->end());
    1936           0 :   node->TrimInputCount(0);
    1937           0 :   NodeProperties::ChangeOp(node, common()->Dead());
    1938           0 :   return Changed(node);
    1939             : }
    1940             : 
    1941      137063 : Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
    1942             : 
    1943      514982 : Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
    1944             : 
    1945           0 : Factory* JSCallReducer::factory() const { return isolate()->factory(); }
    1946             : 
    1947        8966 : Handle<JSGlobalProxy> JSCallReducer::global_proxy() const {
    1948        8966 :   return handle(JSGlobalProxy::cast(native_context()->global_proxy()),
    1949        8966 :                 isolate());
    1950             : }
    1951             : 
    1952       18617 : CommonOperatorBuilder* JSCallReducer::common() const {
    1953       18617 :   return jsgraph()->common();
    1954             : }
    1955             : 
    1956        7916 : JSOperatorBuilder* JSCallReducer::javascript() const {
    1957        7916 :   return jsgraph()->javascript();
    1958             : }
    1959             : 
    1960       61236 : SimplifiedOperatorBuilder* JSCallReducer::simplified() const {
    1961       61236 :   return jsgraph()->simplified();
    1962             : }
    1963             : 
    1964             : }  // namespace compiler
    1965             : }  // namespace internal
    1966             : }  // namespace v8

Generated by: LCOV version 1.10