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 |