OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |