| 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 |