js-call-reducer.cc revision c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7a
1014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Copyright 2015 the V8 project authors. All rights reserved.
2014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// found in the LICENSE file.
4014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
5014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/compiler/js-call-reducer.h"
6014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
7014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/compiler/js-graph.h"
8014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/compiler/node-matchers.h"
9f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#include "src/compiler/simplified-operator.h"
10014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/objects-inl.h"
11014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/type-feedback-vector-inl.h"
12014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
13014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochnamespace v8 {
14014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochnamespace internal {
15014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochnamespace compiler {
16014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
17014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochReduction JSCallReducer::Reduce(Node* node) {
18014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  switch (node->opcode()) {
19014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    case IrOpcode::kJSCallConstruct:
20014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      return ReduceJSCallConstruct(node);
21014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    case IrOpcode::kJSCallFunction:
22014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      return ReduceJSCallFunction(node);
23014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    default:
24014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      break;
25014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
26014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return NoChange();
27014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
28014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
29014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
30014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// ES6 section 22.1.1 The Array Constructor
31014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochReduction JSCallReducer::ReduceArrayConstructor(Node* node) {
32014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
33014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Node* target = NodeProperties::GetValueInput(node, 0);
34014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
35014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
36014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Check if we have an allocation site from the CallIC.
37014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Handle<AllocationSite> site;
38014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (p.feedback().IsValid()) {
39014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
40014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Handle<Object> feedback(nexus.GetFeedback(), isolate());
41014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (feedback->IsAllocationSite()) {
42014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      site = Handle<AllocationSite>::cast(feedback);
43014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
44014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
45014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
46014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Turn the {node} into a {JSCreateArray} call.
47014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK_LE(2u, p.arity());
48014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  size_t const arity = p.arity() - 2;
49014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  NodeProperties::ReplaceValueInput(node, target, 0);
50014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  NodeProperties::ReplaceValueInput(node, target, 1);
51014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // TODO(bmeurer): We might need to propagate the tail call mode to
52014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // the JSCreateArray operator, because an Array call in tail call
53014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // position must always properly consume the parent stack frame.
54014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
55014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return Changed(node);
56014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
57014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
58014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
59014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// ES6 section 20.1.1 The Number Constructor
60014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochReduction JSCallReducer::ReduceNumberConstructor(Node* node) {
61014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
62014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
63014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
64014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Turn the {node} into a {JSToNumber} call.
65014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK_LE(2u, p.arity());
66014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Node* value = (p.arity() == 2) ? jsgraph()->ZeroConstant()
67014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                 : NodeProperties::GetValueInput(node, 2);
68014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  NodeProperties::ReplaceValueInputs(node, value);
69014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  NodeProperties::ChangeOp(node, javascript()->ToNumber());
70014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return Changed(node);
71014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
72014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
73014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
74014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// ES6 section 19.2.3.1 Function.prototype.apply ( thisArg, argArray )
75014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochReduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
76014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
77014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Node* target = NodeProperties::GetValueInput(node, 0);
78014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
79014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Handle<JSFunction> apply =
80014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Handle<JSFunction>::cast(HeapObjectMatcher(target).Value());
81014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  size_t arity = p.arity();
82014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK_LE(2u, arity);
83014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny;
84014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (arity == 2) {
85014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Neither thisArg nor argArray was provided.
86014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    convert_mode = ConvertReceiverMode::kNullOrUndefined;
87014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    node->ReplaceInput(0, node->InputAt(1));
88014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    node->ReplaceInput(1, jsgraph()->UndefinedConstant());
89014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  } else if (arity == 3) {
90014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // The argArray was not provided, just remove the {target}.
91014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    node->RemoveInput(0);
92014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    --arity;
93014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  } else if (arity == 4) {
94014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Check if argArray is an arguments object, and {node} is the only value
95014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // user of argArray (except for value uses in frame states).
96014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Node* arg_array = NodeProperties::GetValueInput(node, 3);
97014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (arg_array->opcode() != IrOpcode::kJSCreateArguments) return NoChange();
98014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    for (Edge edge : arg_array->use_edges()) {
99014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (edge.from()->opcode() == IrOpcode::kStateValues) continue;
100014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (!NodeProperties::IsValueEdge(edge)) continue;
101014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (edge.from() == node) continue;
102014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      return NoChange();
103014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
104014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Get to the actual frame state from which to extract the arguments;
105014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // we can only optimize this in case the {node} was already inlined into
106014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // some other function (and same for the {arg_array}).
107109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    CreateArgumentsType type = CreateArgumentsTypeOf(arg_array->op());
108f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    Node* frame_state = NodeProperties::GetFrameStateInput(arg_array);
109014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
110014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (outer_state->opcode() != IrOpcode::kFrameState) return NoChange();
111014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state);
112014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (outer_info.type() == FrameStateType::kArgumentsAdaptor) {
113014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Need to take the parameters from the arguments adaptor.
114014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      frame_state = outer_state;
115014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
116014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
117109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    int start_index = 0;
118109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    if (type == CreateArgumentsType::kMappedArguments) {
119014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Mapped arguments (sloppy mode) cannot be handled if they are aliased.
120014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Handle<SharedFunctionInfo> shared;
121014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
122014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (shared->internal_formal_parameter_count() != 0) return NoChange();
123109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    } else if (type == CreateArgumentsType::kRestParameter) {
124109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      Handle<SharedFunctionInfo> shared;
125109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
126109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      start_index = shared->internal_formal_parameter_count();
127014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
128014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Remove the argArray input from the {node}.
129014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    node->RemoveInput(static_cast<int>(--arity));
130014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Add the actual parameters to the {node}, skipping the receiver.
131014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
132109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch    for (int i = start_index + 1; i < state_info.parameter_count(); ++i) {
133014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      node->InsertInput(graph()->zone(), static_cast<int>(arity),
134014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                        parameters->InputAt(i));
135014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      ++arity;
136014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
137014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Drop the {target} from the {node}.
138014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    node->RemoveInput(0);
139014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    --arity;
140014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  } else {
141014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return NoChange();
142014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
143014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Change {node} to the new {JSCallFunction} operator.
144014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  NodeProperties::ChangeOp(
145f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch      node, javascript()->CallFunction(arity, p.frequency(), VectorSlotPair(),
146014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                       convert_mode, p.tail_call_mode()));
147014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Change context of {node} to the Function.prototype.apply context,
148014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // to ensure any exception is thrown in the correct context.
149014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  NodeProperties::ReplaceContextInput(
150014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      node, jsgraph()->HeapConstant(handle(apply->context(), isolate())));
151014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Try to further reduce the JSCallFunction {node}.
152014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Reduction const reduction = ReduceJSCallFunction(node);
153014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return reduction.Changed() ? reduction : Changed(node);
154014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
155014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
156014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
157014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// ES6 section 19.2.3.3 Function.prototype.call (thisArg, ...args)
158014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochReduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) {
159014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
160014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
161014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Handle<JSFunction> call = Handle<JSFunction>::cast(
162014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      HeapObjectMatcher(NodeProperties::GetValueInput(node, 0)).Value());
163014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Change context of {node} to the Function.prototype.call context,
164014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // to ensure any exception is thrown in the correct context.
165014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  NodeProperties::ReplaceContextInput(
166014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      node, jsgraph()->HeapConstant(handle(call->context(), isolate())));
167014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Remove the target from {node} and use the receiver as target instead, and
168014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // the thisArg becomes the new target.  If thisArg was not provided, insert
169014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // undefined instead.
170014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  size_t arity = p.arity();
171014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK_LE(2u, arity);
172014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ConvertReceiverMode convert_mode;
173014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (arity == 2) {
174014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // The thisArg was not provided, use undefined as receiver.
175014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    convert_mode = ConvertReceiverMode::kNullOrUndefined;
176014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    node->ReplaceInput(0, node->InputAt(1));
177014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    node->ReplaceInput(1, jsgraph()->UndefinedConstant());
178014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  } else {
179014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Just remove the target, which is the first value input.
180014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    convert_mode = ConvertReceiverMode::kAny;
181014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    node->RemoveInput(0);
182014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    --arity;
183014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
184014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  NodeProperties::ChangeOp(
185f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch      node, javascript()->CallFunction(arity, p.frequency(), VectorSlotPair(),
186014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                       convert_mode, p.tail_call_mode()));
187014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Try to further reduce the JSCallFunction {node}.
188014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Reduction const reduction = ReduceJSCallFunction(node);
189014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return reduction.Changed() ? reduction : Changed(node);
190014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
191014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
192c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochnamespace {
193c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
194c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch// TODO(turbofan): Shall we move this to the NodeProperties? Or some (untyped)
195c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch// alias analyzer?
196c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochbool IsSame(Node* a, Node* b) {
197c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  if (a == b) {
198c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    return true;
199c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  } else if (a->opcode() == IrOpcode::kCheckHeapObject) {
200c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    return IsSame(a->InputAt(0), b);
201c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  } else if (b->opcode() == IrOpcode::kCheckHeapObject) {
202c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    return IsSame(a, b->InputAt(0));
203c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  }
204c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  return false;
205c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch}
206c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
207c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch// TODO(turbofan): Share with similar functionality in JSInliningHeuristic
208c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch// and JSNativeContextSpecialization, i.e. move to NodeProperties helper?!
209c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen MurdochMaybeHandle<Map> InferReceiverMap(Node* node) {
210c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  Node* receiver = NodeProperties::GetValueInput(node, 1);
211c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  Node* effect = NodeProperties::GetEffectInput(node);
212c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // Check if the {node} is dominated by a CheckMaps with a single map
213c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // for the {receiver}, and if so use that map for the lowering below.
214c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  for (Node* dominator = effect;;) {
215c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    if (dominator->opcode() == IrOpcode::kCheckMaps &&
216c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        IsSame(dominator->InputAt(0), receiver)) {
217c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      if (dominator->op()->ValueInputCount() == 2) {
218c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        HeapObjectMatcher m(dominator->InputAt(1));
219c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        if (m.HasValue()) return Handle<Map>::cast(m.Value());
220c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      }
221c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      return MaybeHandle<Map>();
222c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    }
223c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    if (dominator->op()->EffectInputCount() != 1) {
224c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      // Didn't find any appropriate CheckMaps node.
225c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      return MaybeHandle<Map>();
226c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    }
227c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    dominator = NodeProperties::GetEffectInput(dominator);
228c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  }
229c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch}
230c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
231c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch}  // namespace
232c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
233c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch// ES6 section B.2.2.1.1 get Object.prototype.__proto__
234c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen MurdochReduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) {
235c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
236c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
237c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  // Try to determine the {receiver} map.
238c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  Handle<Map> receiver_map;
239c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  if (InferReceiverMap(node).ToHandle(&receiver_map)) {
240c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    // Check if we can constant-fold the {receiver} map.
241c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    if (!receiver_map->IsJSProxyMap() &&
242c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        !receiver_map->has_hidden_prototype() &&
243c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        !receiver_map->is_access_check_needed()) {
244c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      Handle<Object> receiver_prototype(receiver_map->prototype(), isolate());
245c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      Node* value = jsgraph()->Constant(receiver_prototype);
246c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      ReplaceWithValue(node, value);
247c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      return Replace(value);
248c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    }
249c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  }
250c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch
251c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  return NoChange();
252c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch}
253014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
254014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochReduction JSCallReducer::ReduceJSCallFunction(Node* node) {
255014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
256014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
257014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Node* target = NodeProperties::GetValueInput(node, 0);
258014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Node* control = NodeProperties::GetControlInput(node);
259014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Node* effect = NodeProperties::GetEffectInput(node);
260014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
261014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Try to specialize JSCallFunction {node}s with constant {target}s.
262014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  HeapObjectMatcher m(target);
263014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (m.HasValue()) {
264014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (m.Value()->IsJSFunction()) {
265014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
266014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Handle<SharedFunctionInfo> shared(function->shared(), isolate());
267014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
268014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Raise a TypeError if the {target} is a "classConstructor".
269014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (IsClassConstructor(shared->kind())) {
270014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        NodeProperties::ReplaceValueInputs(node, target);
271014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        NodeProperties::ChangeOp(
272014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch            node, javascript()->CallRuntime(
273014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                      Runtime::kThrowConstructorNonCallableError, 1));
274014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        return Changed(node);
275014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
276014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
277014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Check for known builtin functions.
278c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch      switch (shared->code()->builtin_index()) {
279c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        case Builtins::kFunctionPrototypeApply:
280c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch          return ReduceFunctionPrototypeApply(node);
281c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        case Builtins::kFunctionPrototypeCall:
282c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch          return ReduceFunctionPrototypeCall(node);
283c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        case Builtins::kNumberConstructor:
284c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch          return ReduceNumberConstructor(node);
285c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        case Builtins::kObjectPrototypeGetProto:
286c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch          return ReduceObjectPrototypeGetProto(node);
287c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        default:
288c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch          break;
289014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
290014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
291014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Check for the Array constructor.
292014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (*function == function->native_context()->array_function()) {
293014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        return ReduceArrayConstructor(node);
294014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
295014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    } else if (m.Value()->IsJSBoundFunction()) {
296014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Handle<JSBoundFunction> function =
297014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          Handle<JSBoundFunction>::cast(m.Value());
298014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Handle<JSReceiver> bound_target_function(
299014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          function->bound_target_function(), isolate());
300014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Handle<Object> bound_this(function->bound_this(), isolate());
301014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Handle<FixedArray> bound_arguments(function->bound_arguments(),
302014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                         isolate());
303014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
304014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      ConvertReceiverMode const convert_mode =
30513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch          (bound_this->IsNull(isolate()) || bound_this->IsUndefined(isolate()))
306014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch              ? ConvertReceiverMode::kNullOrUndefined
307014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch              : ConvertReceiverMode::kNotNullOrUndefined;
308014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      size_t arity = p.arity();
309014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      DCHECK_LE(2u, arity);
310014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Patch {node} to use [[BoundTargetFunction]] and [[BoundThis]].
311014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      NodeProperties::ReplaceValueInput(
312014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          node, jsgraph()->Constant(bound_target_function), 0);
313014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      NodeProperties::ReplaceValueInput(node, jsgraph()->Constant(bound_this),
314014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                        1);
315014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Insert the [[BoundArguments]] for {node}.
316014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      for (int i = 0; i < bound_arguments->length(); ++i) {
317014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        node->InsertInput(
318014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch            graph()->zone(), i + 2,
319014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch            jsgraph()->Constant(handle(bound_arguments->get(i), isolate())));
320014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        arity++;
321014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
322109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      NodeProperties::ChangeOp(node, javascript()->CallFunction(
323f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch                                         arity, p.frequency(), VectorSlotPair(),
324109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch                                         convert_mode, p.tail_call_mode()));
325014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Try to further reduce the JSCallFunction {node}.
326014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Reduction const reduction = ReduceJSCallFunction(node);
327014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      return reduction.Changed() ? reduction : Changed(node);
328014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
329014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
330014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Don't mess with other {node}s that have a constant {target}.
331014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // TODO(bmeurer): Also support proxies here.
332014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return NoChange();
333014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
334014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
335014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Not much we can do if deoptimization support is disabled.
336014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!(flags() & kDeoptimizationEnabled)) return NoChange();
337014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
338014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Extract feedback from the {node} using the CallICNexus.
339014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!p.feedback().IsValid()) return NoChange();
340014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
341f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  if (nexus.IsUninitialized() && (flags() & kBailoutOnUninitialized)) {
342f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    Node* frame_state = NodeProperties::FindFrameStateBefore(node);
343f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    Node* deoptimize = graph()->NewNode(
344f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch        common()->Deoptimize(
345f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch            DeoptimizeKind::kSoft,
346f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch            DeoptimizeReason::kInsufficientTypeFeedbackForCall),
347f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch        frame_state, effect, control);
348f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    // TODO(bmeurer): This should be on the AdvancedReducer somehow.
349f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
350f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    Revisit(graph()->end());
351f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    node->TrimInputCount(0);
352f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    NodeProperties::ChangeOp(node, common()->Dead());
353f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch    return Changed(node);
354f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  }
355014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Handle<Object> feedback(nexus.GetFeedback(), isolate());
356014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (feedback->IsAllocationSite()) {
357014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Retrieve the Array function from the {node}.
358c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    Node* array_function = jsgraph()->HeapConstant(
359c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        handle(native_context()->array_function(), isolate()));
360014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
361014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Check that the {target} is still the {array_function}.
362f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
363f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                   array_function);
364f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
365014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
366014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Turn the {node} into a {JSCreateArray} call.
367014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    NodeProperties::ReplaceValueInput(node, array_function, 0);
368014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    NodeProperties::ReplaceEffectInput(node, effect);
369014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return ReduceArrayConstructor(node);
370014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  } else if (feedback->IsWeakCell()) {
371014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
372014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (cell->value()->IsJSFunction()) {
373014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Node* target_function =
374014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          jsgraph()->Constant(handle(cell->value(), isolate()));
375014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
376014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Check that the {target} is still the {target_function}.
377f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
378f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                     target_function);
379f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      effect =
380f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          graph()->NewNode(simplified()->CheckIf(), check, effect, control);
381014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
382014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Specialize the JSCallFunction node to the {target_function}.
383014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      NodeProperties::ReplaceValueInput(node, target_function, 0);
38413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      NodeProperties::ReplaceEffectInput(node, effect);
385014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
386014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Try to further reduce the JSCallFunction {node}.
387014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Reduction const reduction = ReduceJSCallFunction(node);
388014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      return reduction.Changed() ? reduction : Changed(node);
389014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
390014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
391014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return NoChange();
392014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
393014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
394014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
395014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochReduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
396014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode());
397014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  CallConstructParameters const& p = CallConstructParametersOf(node->op());
398014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK_LE(2u, p.arity());
399014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  int const arity = static_cast<int>(p.arity() - 2);
400014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Node* target = NodeProperties::GetValueInput(node, 0);
401014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
402014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Node* effect = NodeProperties::GetEffectInput(node);
403014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Node* control = NodeProperties::GetControlInput(node);
404014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
405014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Try to specialize JSCallConstruct {node}s with constant {target}s.
406014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  HeapObjectMatcher m(target);
407014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (m.HasValue()) {
408014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (m.Value()->IsJSFunction()) {
409014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
410014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
411014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Raise a TypeError if the {target} is not a constructor.
412014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (!function->IsConstructor()) {
413014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        NodeProperties::ReplaceValueInputs(node, target);
414014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        NodeProperties::ChangeOp(
415109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch            node, javascript()->CallRuntime(Runtime::kThrowCalledNonCallable));
416014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        return Changed(node);
417014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
418014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
419014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Check for the ArrayConstructor.
420014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (*function == function->native_context()->array_function()) {
421014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        // Check if we have an allocation site.
422014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        Handle<AllocationSite> site;
423014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        if (p.feedback().IsValid()) {
424f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch          CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
425f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch          Handle<Object> feedback(nexus.GetFeedback(), isolate());
426014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          if (feedback->IsAllocationSite()) {
427014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch            site = Handle<AllocationSite>::cast(feedback);
428014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          }
429014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        }
430014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
431014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        // Turn the {node} into a {JSCreateArray} call.
432014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        for (int i = arity; i > 0; --i) {
433014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          NodeProperties::ReplaceValueInput(
434014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch              node, NodeProperties::GetValueInput(node, i), i + 1);
435014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        }
436014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        NodeProperties::ReplaceValueInput(node, new_target, 1);
437014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
438014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        return Changed(node);
439014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
440014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
441014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
442014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Don't mess with other {node}s that have a constant {target}.
443014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // TODO(bmeurer): Also support optimizing bound functions and proxies here.
444014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return NoChange();
445014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
446014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
447014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Not much we can do if deoptimization support is disabled.
448014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!(flags() & kDeoptimizationEnabled)) return NoChange();
449014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
450014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!p.feedback().IsValid()) return NoChange();
451f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
452f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch  Handle<Object> feedback(nexus.GetFeedback(), isolate());
453014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (feedback->IsAllocationSite()) {
454014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // The feedback is an AllocationSite, which means we have called the
455014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Array function and collected transition (and pretenuring) feedback
456014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // for the resulting arrays.  This has to be kept in sync with the
457014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // implementation of the CallConstructStub.
458014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Handle<AllocationSite> site = Handle<AllocationSite>::cast(feedback);
459014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
460014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Retrieve the Array function from the {node}.
461c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch    Node* array_function = jsgraph()->HeapConstant(
462c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch        handle(native_context()->array_function(), isolate()));
463014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
464014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Check that the {target} is still the {array_function}.
465f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
466f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                   array_function);
467f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
468014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
469014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // Turn the {node} into a {JSCreateArray} call.
470014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    NodeProperties::ReplaceEffectInput(node, effect);
471014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    for (int i = arity; i > 0; --i) {
472014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      NodeProperties::ReplaceValueInput(
473014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          node, NodeProperties::GetValueInput(node, i), i + 1);
474014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
475014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    NodeProperties::ReplaceValueInput(node, new_target, 1);
476014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
477014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return Changed(node);
478014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  } else if (feedback->IsWeakCell()) {
479014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
480014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (cell->value()->IsJSFunction()) {
481014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Node* target_function =
482014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          jsgraph()->Constant(handle(cell->value(), isolate()));
483014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
484014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Check that the {target} is still the {target_function}.
485f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
486f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                     target_function);
487f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      effect =
488f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          graph()->NewNode(simplified()->CheckIf(), check, effect, control);
489014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
490014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Specialize the JSCallConstruct node to the {target_function}.
491014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      NodeProperties::ReplaceValueInput(node, target_function, 0);
492014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      NodeProperties::ReplaceEffectInput(node, effect);
493014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (target == new_target) {
494014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        NodeProperties::ReplaceValueInput(node, target_function, arity + 1);
495014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      }
496014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
497014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      // Try to further reduce the JSCallConstruct {node}.
498014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      Reduction const reduction = ReduceJSCallConstruct(node);
499014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      return reduction.Changed() ? reduction : Changed(node);
500014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
501014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
502014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
503014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return NoChange();
504014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
505014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
506014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochGraph* JSCallReducer::graph() const { return jsgraph()->graph(); }
507014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
508014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochIsolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
509014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
510014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochCommonOperatorBuilder* JSCallReducer::common() const {
511014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return jsgraph()->common();
512014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
513014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
514014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochJSOperatorBuilder* JSCallReducer::javascript() const {
515014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return jsgraph()->javascript();
516014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
517014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
518f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen MurdochSimplifiedOperatorBuilder* JSCallReducer::simplified() const {
519f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  return jsgraph()->simplified();
520f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch}
521f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
522014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace compiler
523014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace internal
524014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace v8
525