Index: src/compiler/js-call-reducer.cc |
diff --git a/src/compiler/js-call-reducer.cc b/src/compiler/js-call-reducer.cc |
index 0ca8fff05367b393e3b641b0975edab9f4cddd15..0c890b1c4908ecd8dc0f61e4b95cee0e16df7b1b 100644 |
--- a/src/compiler/js-call-reducer.cc |
+++ b/src/compiler/js-call-reducer.cc |
@@ -104,18 +104,11 @@ Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) { |
if (edge.from() == node) continue; |
return NoChange(); |
} |
- // Get to the actual frame state from which to extract the arguments; |
- // we can only optimize this in case the {node} was already inlined into |
- // some other function (and same for the {arg_array}). |
- CreateArgumentsType type = CreateArgumentsTypeOf(arg_array->op()); |
+ // Check if the arguments can be handled in the fast case (i.e. we don't |
+ // have aliased sloppy arguments), and compute the {start_index} for |
+ // rest parameters. |
+ CreateArgumentsType const type = CreateArgumentsTypeOf(arg_array->op()); |
Node* frame_state = NodeProperties::GetFrameStateInput(arg_array); |
- Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput); |
- if (outer_state->opcode() != IrOpcode::kFrameState) return NoChange(); |
- FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state); |
- if (outer_info.type() == FrameStateType::kArgumentsAdaptor) { |
- // Need to take the parameters from the arguments adaptor. |
- frame_state = outer_state; |
- } |
FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); |
int start_index = 0; |
if (type == CreateArgumentsType::kMappedArguments) { |
@@ -128,11 +121,43 @@ Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) { |
if (!state_info.shared_info().ToHandle(&shared)) return NoChange(); |
start_index = shared->internal_formal_parameter_count(); |
} |
+ // Check if are applying to inlined arguments or to the arguments of |
+ // the outermost function. |
+ Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput); |
+ if (outer_state->opcode() != IrOpcode::kFrameState) { |
+ // TODO(jarin,bmeurer): Support the NewUnmappedArgumentsElement and |
+ // NewRestParameterElements in the EscapeAnalysis and Deoptimizer |
+ // instead, then we don't need this hack. |
+ if (type != CreateArgumentsType::kRestParameter) { |
+ // There are no other uses of the {arg_array} except in StateValues, |
+ // so we just replace {arg_array} with a marker for the Deoptimizer |
+ // that this refers to the arguments object. |
+ Node* arguments = graph()->NewNode(common()->ArgumentsObjectState()); |
+ ReplaceWithValue(arg_array, arguments); |
+ } |
+ |
+ // Reduce {node} to a JSCallForwardVarargs operation, which just |
+ // re-pushes the incoming arguments and calls the {target}. |
+ node->RemoveInput(0); // Function.prototype.apply |
+ node->RemoveInput(2); // arguments |
+ NodeProperties::ChangeOp(node, javascript()->CallForwardVarargs( |
+ start_index, p.tail_call_mode())); |
+ return Changed(node); |
+ } |
+ // Get to the actual frame state from which to extract the arguments; |
+ // we can only optimize this in case the {node} was already inlined into |
+ // some other function (and same for the {arg_array}). |
+ FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state); |
+ if (outer_info.type() == FrameStateType::kArgumentsAdaptor) { |
+ // Need to take the parameters from the arguments adaptor. |
+ frame_state = outer_state; |
+ } |
// Remove the argArray input from the {node}. |
node->RemoveInput(static_cast<int>(--arity)); |
- // Add the actual parameters to the {node}, skipping the receiver. |
+ // Add the actual parameters to the {node}, skipping the receiver, |
+ // starting from {start_index}. |
Node* const parameters = frame_state->InputAt(kFrameStateParametersInput); |
- for (int i = start_index + 1; i < state_info.parameter_count(); ++i) { |
+ for (int i = start_index + 1; i < parameters->InputCount(); ++i) { |
node->InsertInput(graph()->zone(), static_cast<int>(arity), |
parameters->InputAt(i)); |
++arity; |