Index: src/compiler/js-inlining.cc |
diff --git a/src/compiler/js-inlining.cc b/src/compiler/js-inlining.cc |
index 359eea52f3df7aed19c2f5dc2f737ef6d3b35a3b..36abf8392070d0b583895ebddff97ed0fb5fda4c 100644 |
--- a/src/compiler/js-inlining.cc |
+++ b/src/compiler/js-inlining.cc |
@@ -59,100 +59,6 @@ class JSCallFunctionAccessor { |
}; |
-// A facade on a JSFunction's graph to facilitate inlining. It assumes |
-// that the function graph has only one return statement, and provides |
-// {UnifyReturn} to convert a function graph to that end. |
-struct Inlinee { |
- Inlinee(Node* start, Node* end) : start_(start), end_(end) {} |
- |
- // Returns the last regular control node, that is |
- // the last control node before the end node. |
- Node* end_block() { return NodeProperties::GetControlInput(unique_return()); } |
- |
- // Return the effect output of the graph, |
- // that is the effect input of the return statement of the inlinee. |
- Node* effect_output() { |
- return NodeProperties::GetEffectInput(unique_return()); |
- } |
- // Return the value output of the graph, |
- // that is the value input of the return statement of the inlinee. |
- Node* value_output() { |
- return NodeProperties::GetValueInput(unique_return(), 0); |
- } |
- // Return the control output of the graph, |
- // that is the control input of the return statement of the inlinee. |
- Node* control_output() { |
- return NodeProperties::GetControlInput(unique_return(), 0); |
- } |
- // Return the unique return statement of the graph. |
- Node* unique_return() { |
- Node* unique_return = NodeProperties::GetControlInput(end_); |
- DCHECK_EQ(IrOpcode::kReturn, unique_return->opcode()); |
- return unique_return; |
- } |
- |
- // Counts JSFunction, Receiver, arguments, context but not effect, control. |
- size_t total_parameters() { return start_->op()->ValueOutputCount(); } |
- |
- // Counts only formal parameters. |
- size_t formal_parameters() { |
- DCHECK_GE(total_parameters(), 3u); |
- return total_parameters() - 3; |
- } |
- |
- // Ensure that only a single return reaches the end node. |
- static void UnifyReturn(JSGraph* jsgraph); |
- |
- Node* start_; |
- Node* end_; |
-}; |
- |
- |
-void Inlinee::UnifyReturn(JSGraph* jsgraph) { |
- Graph* graph = jsgraph->graph(); |
- |
- Node* final_merge = NodeProperties::GetControlInput(graph->end(), 0); |
- if (final_merge->opcode() == IrOpcode::kReturn) { |
- // nothing to do |
- return; |
- } |
- DCHECK_EQ(IrOpcode::kMerge, final_merge->opcode()); |
- |
- int predecessors = final_merge->op()->ControlInputCount(); |
- |
- const Operator* op_phi = jsgraph->common()->Phi(kMachAnyTagged, predecessors); |
- const Operator* op_ephi = jsgraph->common()->EffectPhi(predecessors); |
- |
- NodeVector values(jsgraph->zone()); |
- NodeVector effects(jsgraph->zone()); |
- // Iterate over all control flow predecessors, |
- // which must be return statements. |
- for (Edge edge : final_merge->input_edges()) { |
- Node* input = edge.to(); |
- switch (input->opcode()) { |
- case IrOpcode::kReturn: |
- values.push_back(NodeProperties::GetValueInput(input, 0)); |
- effects.push_back(NodeProperties::GetEffectInput(input)); |
- edge.UpdateTo(NodeProperties::GetControlInput(input)); |
- input->NullAllInputs(); |
- break; |
- default: |
- UNREACHABLE(); |
- break; |
- } |
- } |
- values.push_back(final_merge); |
- effects.push_back(final_merge); |
- Node* phi = |
- graph->NewNode(op_phi, static_cast<int>(values.size()), &values.front()); |
- Node* ephi = graph->NewNode(op_ephi, static_cast<int>(effects.size()), |
- &effects.front()); |
- Node* new_return = |
- graph->NewNode(jsgraph->common()->Return(), phi, ephi, final_merge); |
- graph->end()->ReplaceInput(0, new_return); |
-} |
- |
- |
class CopyVisitor { |
public: |
CopyVisitor(Graph* source_graph, Graph* target_graph, Zone* temp_zone) |
@@ -210,7 +116,7 @@ class CopyVisitor { |
}; |
-Reduction JSInliner::InlineCall(Node* call, Inlinee& inlinee) { |
+Reduction JSInliner::InlineCall(Node* call, Node* start, Node* end) { |
// The scheduler is smart enough to place our code; we just ensure {control} |
// becomes the control input of the start of the inlinee, and {effect} becomes |
// the effect input of the start of the inlinee. |
@@ -218,12 +124,14 @@ Reduction JSInliner::InlineCall(Node* call, Inlinee& inlinee) { |
Node* effect = NodeProperties::GetEffectInput(call); |
// Context is last argument. |
- int inlinee_context_index = static_cast<int>(inlinee.total_parameters()) - 1; |
+ int const inlinee_context_index = |
+ static_cast<int>(start->op()->ValueOutputCount()) - 1; |
+ |
// {inliner_inputs} counts JSFunction, Receiver, arguments, but not |
// context, effect, control. |
int inliner_inputs = call->op()->ValueInputCount(); |
// Iterate over all uses of the start node. |
- for (Edge edge : inlinee.start_->use_edges()) { |
+ for (Edge edge : start->use_edges()) { |
Node* use = edge.from(); |
switch (use->opcode()) { |
case IrOpcode::kParameter: { |
@@ -257,10 +165,54 @@ Reduction JSInliner::InlineCall(Node* call, Inlinee& inlinee) { |
} |
} |
- ReplaceWithValue(call, inlinee.value_output(), inlinee.effect_output(), |
- inlinee.control_output()); |
+ // TODO(turbofan): This can be unified once End takes a variable number of |
+ // inputs. |
+ Node* value_output; |
+ Node* effect_output; |
+ Node* control_output; |
+ |
+ Node* final_merge = NodeProperties::GetControlInput(end); |
+ if (final_merge->opcode() == IrOpcode::kReturn) { |
+ value_output = NodeProperties::GetValueInput(final_merge, 0); |
+ effect_output = NodeProperties::GetEffectInput(final_merge, 0); |
+ control_output = NodeProperties::GetControlInput(final_merge, 0); |
+ } else { |
+ NodeVector values(local_zone_); |
+ NodeVector effects(local_zone_); |
+ NodeVector controls(local_zone_); |
+ DCHECK_EQ(IrOpcode::kMerge, final_merge->opcode()); |
+ for (Node* const input : final_merge->inputs()) { |
+ switch (input->opcode()) { |
+ case IrOpcode::kReturn: |
+ values.push_back(NodeProperties::GetValueInput(input, 0)); |
+ effects.push_back(NodeProperties::GetEffectInput(input)); |
+ controls.push_back(NodeProperties::GetControlInput(input)); |
+ break; |
+ default: |
+ // TODO(turbofan): Handle Throw, Terminate and Deoptimize here. |
+ UNREACHABLE(); |
+ break; |
+ } |
+ } |
+ DCHECK_NE(0u, values.size()); |
+ DCHECK_EQ(values.size(), effects.size()); |
+ DCHECK_EQ(values.size(), controls.size()); |
+ int const input_count = static_cast<int>(controls.size()); |
+ control_output = jsgraph_->graph()->NewNode( |
+ jsgraph_->common()->Merge(input_count), input_count, &controls.front()); |
+ values.push_back(control_output); |
+ effects.push_back(control_output); |
+ value_output = jsgraph_->graph()->NewNode( |
+ jsgraph_->common()->Phi(kMachAnyTagged, input_count), |
+ static_cast<int>(values.size()), &values.front()); |
+ effect_output = jsgraph_->graph()->NewNode( |
+ jsgraph_->common()->EffectPhi(input_count), |
+ static_cast<int>(effects.size()), &effects.front()); |
+ } |
+ |
+ ReplaceWithValue(call, value_output, effect_output, control_output); |
- return Replace(inlinee.value_output()); |
+ return Changed(value_output); |
} |
@@ -332,20 +284,21 @@ Reduction JSInliner::Reduce(Node* node) { |
GraphReducer graph_reducer(&graph, local_zone_); |
graph_reducer.AddReducer(&context_specializer); |
graph_reducer.ReduceGraph(); |
- Inlinee::UnifyReturn(&jsgraph); |
CopyVisitor visitor(&graph, jsgraph_->graph(), info.zone()); |
visitor.CopyGraph(); |
- Inlinee inlinee(visitor.GetCopy(graph.start()), visitor.GetCopy(graph.end())); |
+ Node* start = visitor.GetCopy(graph.start()); |
+ Node* end = visitor.GetCopy(graph.end()); |
Node* outer_frame_state = call.frame_state(); |
+ size_t const inlinee_formal_parameters = start->op()->ValueOutputCount() - 3; |
// Insert argument adaptor frame if required. |
- if (call.formal_arguments() != inlinee.formal_parameters()) { |
+ if (call.formal_arguments() != inlinee_formal_parameters) { |
// In strong mode, in case of too few arguments we need to throw a |
// TypeError so we must not inline this call. |
if (is_strong(info.language_mode()) && |
- call.formal_arguments() < inlinee.formal_parameters()) { |
+ call.formal_arguments() < inlinee_formal_parameters) { |
return NoChange(); |
} |
outer_frame_state = CreateArgumentsAdaptorFrameState(&call, info.zone()); |
@@ -363,7 +316,7 @@ Reduction JSInliner::Reduce(Node* node) { |
} |
} |
- return InlineCall(node, inlinee); |
+ return InlineCall(node, start, end); |
} |
} // namespace compiler |