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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « src/compiler/js-inlining.h ('k') | src/compiler/pipeline.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/js-inlining.h" 5 #include "src/compiler/js-inlining.h"
6 6
7 #include "src/ast/ast-numbering.h" 7 #include "src/ast/ast-numbering.h"
8 #include "src/ast/ast.h" 8 #include "src/ast/ast.h"
9 #include "src/ast/scopes.h" 9 #include "src/ast/scopes.h"
10 #include "src/compiler.h" 10 #include "src/compiler.h"
11 #include "src/compiler/all-nodes.h"
12 #include "src/compiler/ast-graph-builder.h" 11 #include "src/compiler/ast-graph-builder.h"
13 #include "src/compiler/ast-loop-assignment-analyzer.h" 12 #include "src/compiler/ast-loop-assignment-analyzer.h"
14 #include "src/compiler/common-operator.h" 13 #include "src/compiler/common-operator.h"
15 #include "src/compiler/graph-reducer.h" 14 #include "src/compiler/graph-reducer.h"
16 #include "src/compiler/js-operator.h" 15 #include "src/compiler/js-operator.h"
17 #include "src/compiler/node-matchers.h" 16 #include "src/compiler/node-matchers.h"
18 #include "src/compiler/node-properties.h" 17 #include "src/compiler/node-properties.h"
19 #include "src/compiler/operator-properties.h" 18 #include "src/compiler/operator-properties.h"
20 #include "src/compiler/type-hint-analyzer.h" 19 #include "src/compiler/type-hint-analyzer.h"
21 #include "src/isolate-inl.h" 20 #include "src/isolate-inl.h"
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
70 // - JSCallConstruct: Includes target function and new target. 69 // - JSCallConstruct: Includes target function and new target.
71 // - JSCallFunction: Includes target function and receiver. 70 // - JSCallFunction: Includes target function and receiver.
72 return call_->op()->ValueInputCount() - 2; 71 return call_->op()->ValueInputCount() - 2;
73 } 72 }
74 73
75 private: 74 private:
76 Node* call_; 75 Node* call_;
77 }; 76 };
78 77
79 78
80 class CopyVisitor {
81 public:
82 CopyVisitor(Graph* source_graph, Graph* target_graph, Zone* temp_zone)
83 : sentinel_op_(IrOpcode::kDead, Operator::kNoProperties, "Sentinel", 0, 0,
84 0, 0, 0, 0),
85 sentinel_(target_graph->NewNode(&sentinel_op_)),
86 copies_(source_graph->NodeCount(), sentinel_, temp_zone),
87 source_graph_(source_graph),
88 target_graph_(target_graph),
89 temp_zone_(temp_zone) {}
90
91 Node* GetCopy(Node* orig) { return copies_[orig->id()]; }
92
93 void CopyGraph() {
94 NodeVector inputs(temp_zone_);
95 // TODO(bmeurer): AllNodes should be turned into something like
96 // Graph::CollectNodesReachableFromEnd() and the gray set stuff should be
97 // removed since it's only needed by the visualizer.
98 AllNodes all(temp_zone_, source_graph_);
99 // Copy all nodes reachable from end.
100 for (Node* orig : all.live) {
101 Node* copy = GetCopy(orig);
102 if (copy != sentinel_) {
103 // Mapping already exists.
104 continue;
105 }
106 // Copy the node.
107 inputs.clear();
108 for (Node* input : orig->inputs()) inputs.push_back(copies_[input->id()]);
109 copy = target_graph_->NewNode(orig->op(), orig->InputCount(),
110 inputs.empty() ? nullptr : &inputs[0]);
111 copies_[orig->id()] = copy;
112 }
113 // For missing inputs.
114 for (Node* orig : all.live) {
115 Node* copy = copies_[orig->id()];
116 for (int i = 0; i < copy->InputCount(); ++i) {
117 Node* input = copy->InputAt(i);
118 if (input == sentinel_) {
119 copy->ReplaceInput(i, GetCopy(orig->InputAt(i)));
120 }
121 }
122 }
123 }
124
125 const NodeVector& copies() const { return copies_; }
126
127 private:
128 Operator const sentinel_op_;
129 Node* const sentinel_;
130 NodeVector copies_;
131 Graph* const source_graph_;
132 Graph* const target_graph_;
133 Zone* const temp_zone_;
134 };
135
136
137 Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, 79 Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
138 Node* frame_state, Node* start, Node* end) { 80 Node* frame_state, Node* start, Node* end) {
139 // The scheduler is smart enough to place our code; we just ensure {control} 81 // The scheduler is smart enough to place our code; we just ensure {control}
140 // becomes the control input of the start of the inlinee, and {effect} becomes 82 // becomes the control input of the start of the inlinee, and {effect} becomes
141 // the effect input of the start of the inlinee. 83 // the effect input of the start of the inlinee.
142 Node* control = NodeProperties::GetControlInput(call); 84 Node* control = NodeProperties::GetControlInput(call);
143 Node* effect = NodeProperties::GetEffectInput(call); 85 Node* effect = NodeProperties::GetEffectInput(call);
144 86
145 int const inlinee_new_target_index = 87 int const inlinee_new_target_index =
146 static_cast<int>(start->op()->ValueOutputCount()) - 3; 88 static_cast<int>(start->op()->ValueOutputCount()) - 3;
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 info_->AddInlinedFunction(shared_info); 383 info_->AddInlinedFunction(shared_info);
442 384
443 // ---------------------------------------------------------------- 385 // ----------------------------------------------------------------
444 // After this point, we've made a decision to inline this function. 386 // After this point, we've made a decision to inline this function.
445 // We shall not bailout from inlining if we got here. 387 // We shall not bailout from inlining if we got here.
446 388
447 TRACE("Inlining %s into %s\n", 389 TRACE("Inlining %s into %s\n",
448 shared_info->DebugName()->ToCString().get(), 390 shared_info->DebugName()->ToCString().get(),
449 info_->shared_info()->DebugName()->ToCString().get()); 391 info_->shared_info()->DebugName()->ToCString().get());
450 392
451 // Run the loop assignment analyzer on the inlinee. 393 // Create the subgraph for the inlinee.
452 AstLoopAssignmentAnalyzer loop_assignment_analyzer(&zone, &info); 394 Node* start;
453 LoopAssignmentAnalysis* loop_assignment = loop_assignment_analyzer.Analyze(); 395 Node* end;
396 {
397 // Run the loop assignment analyzer on the inlinee.
398 AstLoopAssignmentAnalyzer loop_assignment_analyzer(&zone, &info);
399 LoopAssignmentAnalysis* loop_assignment =
400 loop_assignment_analyzer.Analyze();
454 401
455 // Run the type hint analyzer on the inlinee. 402 // Run the type hint analyzer on the inlinee.
456 TypeHintAnalyzer type_hint_analyzer(&zone); 403 TypeHintAnalyzer type_hint_analyzer(&zone);
457 TypeHintAnalysis* type_hint_analysis = 404 TypeHintAnalysis* type_hint_analysis =
458 type_hint_analyzer.Analyze(handle(shared_info->code(), info.isolate())); 405 type_hint_analyzer.Analyze(handle(shared_info->code(), info.isolate()));
459 406
460 // TODO(mstarzinger): We could use the temporary zone for the graph because 407 // Run the AstGraphBuilder to create the subgraph.
461 // nodes are copied. This however leads to Zone-Types being allocated in the 408 Graph::SubgraphScope scope(graph());
462 // wrong zone and makes the engine explode at high speeds. Explosion bad! 409 AstGraphBuilder graph_builder(&zone, &info, jsgraph(), loop_assignment,
463 Graph graph(jsgraph_->zone()); 410 type_hint_analysis);
464 JSGraph jsgraph(info.isolate(), &graph, jsgraph_->common(), 411 graph_builder.CreateGraph(false);
465 jsgraph_->javascript(), jsgraph_->simplified(),
466 jsgraph_->machine());
467 AstGraphBuilder graph_builder(local_zone_, &info, &jsgraph, loop_assignment,
468 type_hint_analysis);
469 graph_builder.CreateGraph(false);
470 412
471 CopyVisitor visitor(&graph, jsgraph_->graph(), &zone); 413 // Extract the inlinee start/end nodes.
472 visitor.CopyGraph(); 414 start = graph()->start();
415 end = graph()->end();
416 }
473 417
474 Node* start = visitor.GetCopy(graph.start());
475 Node* end = visitor.GetCopy(graph.end());
476 Node* frame_state = call.frame_state_after(); 418 Node* frame_state = call.frame_state_after();
477 Node* new_target = jsgraph_->UndefinedConstant(); 419 Node* new_target = jsgraph_->UndefinedConstant();
478 420
479 // Insert nodes around the call that model the behavior required for a 421 // Inline {JSCallConstruct} requires some additional magic.
480 // constructor dispatch (allocate implicit receiver and check return value). 422 if (node->opcode() == IrOpcode::kJSCallConstruct) {
481 // This models the behavior usually accomplished by our {JSConstructStub}. 423 // Insert nodes around the call that model the behavior required for a
482 // Note that the context has to be the callers context (input to call node). 424 // constructor dispatch (allocate implicit receiver and check return value).
483 Node* receiver = jsgraph_->UndefinedConstant(); // Implicit receiver. 425 // This models the behavior usually accomplished by our {JSConstructStub}.
484 if (node->opcode() == IrOpcode::kJSCallConstruct && 426 // Note that the context has to be the callers context (input to call node).
485 NeedsImplicitReceiver(shared_info)) { 427 Node* receiver = jsgraph_->UndefinedConstant(); // Implicit receiver.
486 Node* effect = NodeProperties::GetEffectInput(node); 428 if (NeedsImplicitReceiver(shared_info)) {
487 Node* context = NodeProperties::GetContextInput(node); 429 Node* effect = NodeProperties::GetEffectInput(node);
488 Node* create = jsgraph_->graph()->NewNode( 430 Node* context = NodeProperties::GetContextInput(node);
489 jsgraph_->javascript()->Create(), call.target(), call.new_target(), 431 Node* create = jsgraph_->graph()->NewNode(
490 context, call.frame_state_before(), effect); 432 jsgraph_->javascript()->Create(), call.target(), call.new_target(),
491 NodeProperties::ReplaceEffectInput(node, create); 433 context, call.frame_state_before(), effect);
492 // Insert a check of the return value to determine whether the return value 434 NodeProperties::ReplaceEffectInput(node, create);
493 // or the implicit receiver should be selected as a result of the call. 435 // Insert a check of the return value to determine whether the return
494 Node* check = jsgraph_->graph()->NewNode( 436 // value
495 jsgraph_->javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), 437 // or the implicit receiver should be selected as a result of the call.
496 node, context, node, start); 438 Node* check = jsgraph_->graph()->NewNode(
497 Node* select = jsgraph_->graph()->NewNode( 439 jsgraph_->javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1),
498 jsgraph_->common()->Select(MachineRepresentation::kTagged), check, node, 440 node, context, node, start);
499 create); 441 Node* select = jsgraph_->graph()->NewNode(
500 NodeProperties::ReplaceUses(node, select, check, node, node); 442 jsgraph_->common()->Select(MachineRepresentation::kTagged), check,
501 NodeProperties::ReplaceValueInput(select, node, 1); 443 node, create);
502 NodeProperties::ReplaceValueInput(check, node, 0); 444 NodeProperties::ReplaceUses(node, select, check, node, node);
503 NodeProperties::ReplaceEffectInput(check, node); 445 NodeProperties::ReplaceValueInput(select, node, 1);
504 receiver = create; // The implicit receiver. 446 NodeProperties::ReplaceValueInput(check, node, 0);
505 } 447 NodeProperties::ReplaceEffectInput(check, node);
448 receiver = create; // The implicit receiver.
449 }
506 450
507 // Swizzle the inputs of the {JSCallConstruct} node to look like inputs to a 451 // Swizzle the inputs of the {JSCallConstruct} node to look like inputs to a
508 // normal {JSCallFunction} node so that the rest of the inlining machinery 452 // normal {JSCallFunction} node so that the rest of the inlining machinery
509 // behaves as if we were dealing with a regular function invocation. 453 // behaves as if we were dealing with a regular function invocation.
510 if (node->opcode() == IrOpcode::kJSCallConstruct) {
511 new_target = call.new_target(); // Retrieve new target value input. 454 new_target = call.new_target(); // Retrieve new target value input.
512 node->RemoveInput(call.formal_arguments() + 1); // Drop new target. 455 node->RemoveInput(call.formal_arguments() + 1); // Drop new target.
513 node->InsertInput(jsgraph_->graph()->zone(), 1, receiver); 456 node->InsertInput(jsgraph_->graph()->zone(), 1, receiver);
457
514 // Insert a construct stub frame into the chain of frame states. This will 458 // Insert a construct stub frame into the chain of frame states. This will
515 // reconstruct the proper frame when deoptimizing within the constructor. 459 // reconstruct the proper frame when deoptimizing within the constructor.
516 frame_state = CreateArtificialFrameState( 460 frame_state = CreateArtificialFrameState(
517 node, frame_state, call.formal_arguments(), 461 node, frame_state, call.formal_arguments(),
518 FrameStateType::kConstructStub, info.shared_info()); 462 FrameStateType::kConstructStub, info.shared_info());
519 } 463 }
520 464
521 // The inlinee specializes to the context from the JSFunction object. 465 // The inlinee specializes to the context from the JSFunction object.
522 // TODO(turbofan): We might want to load the context from the JSFunction at 466 // TODO(turbofan): We might want to load the context from the JSFunction at
523 // runtime in case we only know the SharedFunctionInfo once we have dynamic 467 // runtime in case we only know the SharedFunctionInfo once we have dynamic
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
563 DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5); 507 DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5);
564 if (call.formal_arguments() != parameter_count) { 508 if (call.formal_arguments() != parameter_count) {
565 frame_state = CreateArtificialFrameState( 509 frame_state = CreateArtificialFrameState(
566 node, frame_state, call.formal_arguments(), 510 node, frame_state, call.formal_arguments(),
567 FrameStateType::kArgumentsAdaptor, shared_info); 511 FrameStateType::kArgumentsAdaptor, shared_info);
568 } 512 }
569 513
570 return InlineCall(node, new_target, context, frame_state, start, end); 514 return InlineCall(node, new_target, context, frame_state, start, end);
571 } 515 }
572 516
517 Graph* JSInliner::graph() const { return jsgraph()->graph(); }
518
573 } // namespace compiler 519 } // namespace compiler
574 } // namespace internal 520 } // namespace internal
575 } // namespace v8 521 } // namespace v8
OLDNEW
« 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