Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(67)

Unified Diff: src/compiler/js-inlining.cc

Issue 1146393002: [turbofan] Fix UnifyReturn magic in the inliner. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/js-inlining.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « src/compiler/js-inlining.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698