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