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

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

Issue 2006353003: [turbofan] Avoid unnecessary copying of nodes during inlining. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Don't use one EmptyFrameState cross functions, that gets mutated during inlining. Created 4 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') | src/compiler/pipeline.cc » ('j') | 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 53ff3c9c1da9d3730e77fd1fe7caff34fc93990c..982d7a6e51f7d12570eb1f09517bb049b9e1b29c 100644
--- a/src/compiler/js-inlining.cc
+++ b/src/compiler/js-inlining.cc
@@ -8,7 +8,6 @@
#include "src/ast/ast.h"
#include "src/ast/scopes.h"
#include "src/compiler.h"
-#include "src/compiler/all-nodes.h"
#include "src/compiler/ast-graph-builder.h"
#include "src/compiler/ast-loop-assignment-analyzer.h"
#include "src/compiler/common-operator.h"
@@ -77,63 +76,6 @@ class JSCallAccessor {
};
-class CopyVisitor {
- public:
- CopyVisitor(Graph* source_graph, Graph* target_graph, Zone* temp_zone)
- : sentinel_op_(IrOpcode::kDead, Operator::kNoProperties, "Sentinel", 0, 0,
- 0, 0, 0, 0),
- sentinel_(target_graph->NewNode(&sentinel_op_)),
- copies_(source_graph->NodeCount(), sentinel_, temp_zone),
- source_graph_(source_graph),
- target_graph_(target_graph),
- temp_zone_(temp_zone) {}
-
- Node* GetCopy(Node* orig) { return copies_[orig->id()]; }
-
- void CopyGraph() {
- NodeVector inputs(temp_zone_);
- // TODO(bmeurer): AllNodes should be turned into something like
- // Graph::CollectNodesReachableFromEnd() and the gray set stuff should be
- // removed since it's only needed by the visualizer.
- AllNodes all(temp_zone_, source_graph_);
- // Copy all nodes reachable from end.
- for (Node* orig : all.live) {
- Node* copy = GetCopy(orig);
- if (copy != sentinel_) {
- // Mapping already exists.
- continue;
- }
- // Copy the node.
- inputs.clear();
- for (Node* input : orig->inputs()) inputs.push_back(copies_[input->id()]);
- copy = target_graph_->NewNode(orig->op(), orig->InputCount(),
- inputs.empty() ? nullptr : &inputs[0]);
- copies_[orig->id()] = copy;
- }
- // For missing inputs.
- for (Node* orig : all.live) {
- Node* copy = copies_[orig->id()];
- for (int i = 0; i < copy->InputCount(); ++i) {
- Node* input = copy->InputAt(i);
- if (input == sentinel_) {
- copy->ReplaceInput(i, GetCopy(orig->InputAt(i)));
- }
- }
- }
- }
-
- const NodeVector& copies() const { return copies_; }
-
- private:
- Operator const sentinel_op_;
- Node* const sentinel_;
- NodeVector copies_;
- Graph* const source_graph_;
- Graph* const target_graph_;
- Zone* const temp_zone_;
-};
-
-
Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
Node* frame_state, Node* start, Node* end) {
// The scheduler is smart enough to place our code; we just ensure {control}
@@ -448,69 +390,71 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
shared_info->DebugName()->ToCString().get(),
info_->shared_info()->DebugName()->ToCString().get());
- // Run the loop assignment analyzer on the inlinee.
- AstLoopAssignmentAnalyzer loop_assignment_analyzer(&zone, &info);
- LoopAssignmentAnalysis* loop_assignment = loop_assignment_analyzer.Analyze();
-
- // Run the type hint analyzer on the inlinee.
- TypeHintAnalyzer type_hint_analyzer(&zone);
- TypeHintAnalysis* type_hint_analysis =
- type_hint_analyzer.Analyze(handle(shared_info->code(), info.isolate()));
-
- // TODO(mstarzinger): We could use the temporary zone for the graph because
- // nodes are copied. This however leads to Zone-Types being allocated in the
- // wrong zone and makes the engine explode at high speeds. Explosion bad!
- Graph graph(jsgraph_->zone());
- JSGraph jsgraph(info.isolate(), &graph, jsgraph_->common(),
- jsgraph_->javascript(), jsgraph_->simplified(),
- jsgraph_->machine());
- AstGraphBuilder graph_builder(local_zone_, &info, &jsgraph, loop_assignment,
- type_hint_analysis);
- graph_builder.CreateGraph(false);
-
- CopyVisitor visitor(&graph, jsgraph_->graph(), &zone);
- visitor.CopyGraph();
-
- Node* start = visitor.GetCopy(graph.start());
- Node* end = visitor.GetCopy(graph.end());
+ // Create the subgraph for the inlinee.
+ Node* start;
+ Node* end;
+ {
+ // Run the loop assignment analyzer on the inlinee.
+ AstLoopAssignmentAnalyzer loop_assignment_analyzer(&zone, &info);
+ LoopAssignmentAnalysis* loop_assignment =
+ loop_assignment_analyzer.Analyze();
+
+ // Run the type hint analyzer on the inlinee.
+ TypeHintAnalyzer type_hint_analyzer(&zone);
+ TypeHintAnalysis* type_hint_analysis =
+ type_hint_analyzer.Analyze(handle(shared_info->code(), info.isolate()));
+
+ // Run the AstGraphBuilder to create the subgraph.
+ Graph::SubgraphScope scope(graph());
+ AstGraphBuilder graph_builder(&zone, &info, jsgraph(), loop_assignment,
+ type_hint_analysis);
+ graph_builder.CreateGraph(false);
+
+ // Extract the inlinee start/end nodes.
+ start = graph()->start();
+ end = graph()->end();
+ }
+
Node* frame_state = call.frame_state_after();
Node* new_target = jsgraph_->UndefinedConstant();
- // Insert nodes around the call that model the behavior required for a
- // constructor dispatch (allocate implicit receiver and check return value).
- // This models the behavior usually accomplished by our {JSConstructStub}.
- // Note that the context has to be the callers context (input to call node).
- Node* receiver = jsgraph_->UndefinedConstant(); // Implicit receiver.
- if (node->opcode() == IrOpcode::kJSCallConstruct &&
- NeedsImplicitReceiver(shared_info)) {
- Node* effect = NodeProperties::GetEffectInput(node);
- Node* context = NodeProperties::GetContextInput(node);
- Node* create = jsgraph_->graph()->NewNode(
- jsgraph_->javascript()->Create(), call.target(), call.new_target(),
- context, call.frame_state_before(), effect);
- NodeProperties::ReplaceEffectInput(node, create);
- // Insert a check of the return value to determine whether the return value
- // or the implicit receiver should be selected as a result of the call.
- Node* check = jsgraph_->graph()->NewNode(
- jsgraph_->javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1),
- node, context, node, start);
- Node* select = jsgraph_->graph()->NewNode(
- jsgraph_->common()->Select(MachineRepresentation::kTagged), check, node,
- create);
- NodeProperties::ReplaceUses(node, select, check, node, node);
- NodeProperties::ReplaceValueInput(select, node, 1);
- NodeProperties::ReplaceValueInput(check, node, 0);
- NodeProperties::ReplaceEffectInput(check, node);
- receiver = create; // The implicit receiver.
- }
-
- // Swizzle the inputs of the {JSCallConstruct} node to look like inputs to a
- // normal {JSCallFunction} node so that the rest of the inlining machinery
- // behaves as if we were dealing with a regular function invocation.
+ // Inline {JSCallConstruct} requires some additional magic.
if (node->opcode() == IrOpcode::kJSCallConstruct) {
+ // Insert nodes around the call that model the behavior required for a
+ // constructor dispatch (allocate implicit receiver and check return value).
+ // This models the behavior usually accomplished by our {JSConstructStub}.
+ // Note that the context has to be the callers context (input to call node).
+ Node* receiver = jsgraph_->UndefinedConstant(); // Implicit receiver.
+ if (NeedsImplicitReceiver(shared_info)) {
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* context = NodeProperties::GetContextInput(node);
+ Node* create = jsgraph_->graph()->NewNode(
+ jsgraph_->javascript()->Create(), call.target(), call.new_target(),
+ context, call.frame_state_before(), effect);
+ NodeProperties::ReplaceEffectInput(node, create);
+ // Insert a check of the return value to determine whether the return
+ // value
+ // or the implicit receiver should be selected as a result of the call.
+ Node* check = jsgraph_->graph()->NewNode(
+ jsgraph_->javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1),
+ node, context, node, start);
+ Node* select = jsgraph_->graph()->NewNode(
+ jsgraph_->common()->Select(MachineRepresentation::kTagged), check,
+ node, create);
+ NodeProperties::ReplaceUses(node, select, check, node, node);
+ NodeProperties::ReplaceValueInput(select, node, 1);
+ NodeProperties::ReplaceValueInput(check, node, 0);
+ NodeProperties::ReplaceEffectInput(check, node);
+ receiver = create; // The implicit receiver.
+ }
+
+ // Swizzle the inputs of the {JSCallConstruct} node to look like inputs to a
+ // normal {JSCallFunction} node so that the rest of the inlining machinery
+ // behaves as if we were dealing with a regular function invocation.
new_target = call.new_target(); // Retrieve new target value input.
node->RemoveInput(call.formal_arguments() + 1); // Drop new target.
node->InsertInput(jsgraph_->graph()->zone(), 1, receiver);
+
// Insert a construct stub frame into the chain of frame states. This will
// reconstruct the proper frame when deoptimizing within the constructor.
frame_state = CreateArtificialFrameState(
@@ -570,6 +514,8 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
return InlineCall(node, new_target, context, frame_state, start, end);
}
+Graph* JSInliner::graph() const { return jsgraph()->graph(); }
+
} // namespace compiler
} // namespace internal
} // namespace v8
« no previous file with comments | « src/compiler/js-inlining.h ('k') | src/compiler/pipeline.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698