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.h" | 7 #include "src/ast.h" |
8 #include "src/ast-numbering.h" | 8 #include "src/ast-numbering.h" |
9 #include "src/compiler.h" | 9 #include "src/compiler.h" |
10 #include "src/compiler/all-nodes.h" | 10 #include "src/compiler/all-nodes.h" |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 private: | 126 private: |
127 Operator const sentinel_op_; | 127 Operator const sentinel_op_; |
128 Node* const sentinel_; | 128 Node* const sentinel_; |
129 NodeVector copies_; | 129 NodeVector copies_; |
130 Graph* const source_graph_; | 130 Graph* const source_graph_; |
131 Graph* const target_graph_; | 131 Graph* const target_graph_; |
132 Zone* const temp_zone_; | 132 Zone* const temp_zone_; |
133 }; | 133 }; |
134 | 134 |
135 | 135 |
136 Reduction JSInliner::InlineCall(Node* call, Node* context, Node* frame_state, | 136 Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, |
137 Node* start, Node* end) { | 137 Node* frame_state, Node* start, Node* end) { |
138 // The scheduler is smart enough to place our code; we just ensure {control} | 138 // The scheduler is smart enough to place our code; we just ensure {control} |
139 // becomes the control input of the start of the inlinee, and {effect} becomes | 139 // becomes the control input of the start of the inlinee, and {effect} becomes |
140 // the effect input of the start of the inlinee. | 140 // the effect input of the start of the inlinee. |
141 Node* control = NodeProperties::GetControlInput(call); | 141 Node* control = NodeProperties::GetControlInput(call); |
142 Node* effect = NodeProperties::GetEffectInput(call); | 142 Node* effect = NodeProperties::GetEffectInput(call); |
143 | 143 |
| 144 int const inlinee_new_target_index = |
| 145 static_cast<int>(start->op()->ValueOutputCount()) - 3; |
144 int const inlinee_arity_index = | 146 int const inlinee_arity_index = |
145 static_cast<int>(start->op()->ValueOutputCount()) - 2; | 147 static_cast<int>(start->op()->ValueOutputCount()) - 2; |
146 // Context is last parameter. | |
147 int const inlinee_context_index = | 148 int const inlinee_context_index = |
148 static_cast<int>(start->op()->ValueOutputCount()) - 1; | 149 static_cast<int>(start->op()->ValueOutputCount()) - 1; |
149 | 150 |
150 // {inliner_inputs} counts JSFunction, Receiver, arguments, but not | 151 // {inliner_inputs} counts JSFunction, receiver, arguments, but not |
151 // context, effect, control. | 152 // new target value, argument count, context, effect or control. |
152 int inliner_inputs = call->op()->ValueInputCount(); | 153 int inliner_inputs = call->op()->ValueInputCount(); |
153 // Iterate over all uses of the start node. | 154 // Iterate over all uses of the start node. |
154 for (Edge edge : start->use_edges()) { | 155 for (Edge edge : start->use_edges()) { |
155 Node* use = edge.from(); | 156 Node* use = edge.from(); |
156 switch (use->opcode()) { | 157 switch (use->opcode()) { |
157 case IrOpcode::kParameter: { | 158 case IrOpcode::kParameter: { |
158 int index = 1 + ParameterIndexOf(use->op()); | 159 int index = 1 + ParameterIndexOf(use->op()); |
159 DCHECK_LE(index, inlinee_context_index); | 160 DCHECK_LE(index, inlinee_context_index); |
160 if (index < inliner_inputs && index < inlinee_arity_index) { | 161 if (index < inliner_inputs && index < inlinee_new_target_index) { |
161 // There is an input from the call, and the index is a value | 162 // There is an input from the call, and the index is a value |
162 // projection but not the context, so rewire the input. | 163 // projection but not the context, so rewire the input. |
163 Replace(use, call->InputAt(index)); | 164 Replace(use, call->InputAt(index)); |
| 165 } else if (index == inlinee_new_target_index) { |
| 166 // The projection is requesting the new target value. |
| 167 Replace(use, new_target); |
164 } else if (index == inlinee_arity_index) { | 168 } else if (index == inlinee_arity_index) { |
165 // The projection is requesting the number of arguments. | 169 // The projection is requesting the number of arguments. |
166 Replace(use, jsgraph_->Int32Constant(inliner_inputs - 2)); | 170 Replace(use, jsgraph_->Int32Constant(inliner_inputs - 2)); |
167 } else if (index == inlinee_context_index) { | 171 } else if (index == inlinee_context_index) { |
168 // The projection is requesting the inlinee function context. | 172 // The projection is requesting the inlinee function context. |
169 Replace(use, context); | 173 Replace(use, context); |
170 } else { | 174 } else { |
171 // Call has fewer arguments than required, fill with undefined. | 175 // Call has fewer arguments than required, fill with undefined. |
172 Replace(use, jsgraph_->UndefinedConstant()); | 176 Replace(use, jsgraph_->UndefinedConstant()); |
173 } | 177 } |
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
402 jsgraph_->machine()); | 406 jsgraph_->machine()); |
403 AstGraphBuilder graph_builder(local_zone_, &info, &jsgraph); | 407 AstGraphBuilder graph_builder(local_zone_, &info, &jsgraph); |
404 graph_builder.CreateGraph(false); | 408 graph_builder.CreateGraph(false); |
405 | 409 |
406 CopyVisitor visitor(&graph, jsgraph_->graph(), &zone); | 410 CopyVisitor visitor(&graph, jsgraph_->graph(), &zone); |
407 visitor.CopyGraph(); | 411 visitor.CopyGraph(); |
408 | 412 |
409 Node* start = visitor.GetCopy(graph.start()); | 413 Node* start = visitor.GetCopy(graph.start()); |
410 Node* end = visitor.GetCopy(graph.end()); | 414 Node* end = visitor.GetCopy(graph.end()); |
411 Node* frame_state = call.frame_state_after(); | 415 Node* frame_state = call.frame_state_after(); |
| 416 Node* new_target = jsgraph_->UndefinedConstant(); |
412 | 417 |
413 // Insert nodes around the call that model the behavior required for a | 418 // Insert nodes around the call that model the behavior required for a |
414 // constructor dispatch and turn the constructor call into a regular call. | 419 // constructor dispatch and turn the constructor call into a regular call. |
415 // This models the behavior usually accomplished by our {JSConstructStub}. | 420 // This models the behavior usually accomplished by our {JSConstructStub}. |
416 // Note that the context has to be the callers context (input to call node). | 421 // Note that the context has to be the callers context (input to call node). |
417 if (node->opcode() == IrOpcode::kJSCallConstruct) { | 422 if (node->opcode() == IrOpcode::kJSCallConstruct) { |
418 Node* effect = NodeProperties::GetEffectInput(node); | 423 Node* effect = NodeProperties::GetEffectInput(node); |
419 Node* context = NodeProperties::GetContextInput(node); | 424 Node* context = NodeProperties::GetContextInput(node); |
420 Node* create = jsgraph_->graph()->NewNode(jsgraph_->javascript()->Create(), | 425 Node* create = jsgraph_->graph()->NewNode(jsgraph_->javascript()->Create(), |
421 call.target(), call.new_target(), | 426 call.target(), call.new_target(), |
422 context, frame_state, effect); | 427 context, frame_state, effect); |
423 NodeProperties::ReplaceEffectInput(node, create); | 428 NodeProperties::ReplaceEffectInput(node, create); |
424 // TODO(4544): For now Runtime_GetNewTarget depends on the actual target to | 429 // TODO(4544): For now Runtime_GetNewTarget depends on the actual target to |
425 // coincide with the new target. Fix this! | 430 // coincide with the new target. Fix this! |
426 CHECK_EQ(call.target(), call.new_target()); | 431 CHECK_EQ(call.target(), call.new_target()); |
427 // TODO(4544): For derived constructors we should not allocate an implicit | 432 // TODO(4544): For derived constructors we should not allocate an implicit |
428 // receiver and also the return value should not be checked afterwards. | 433 // receiver and also the return value should not be checked afterwards. |
429 CHECK(!IsClassConstructor(function->shared()->kind())); | 434 CHECK(!IsClassConstructor(function->shared()->kind())); |
430 // Swizzle the inputs of the {JSCallConstruct} node to look like inputs to | 435 // Swizzle the inputs of the {JSCallConstruct} node to look like inputs to |
431 // any {JSCallFunction} node so that the rest of the inlining machinery | 436 // any {JSCallFunction} node so that the rest of the inlining machinery |
432 // behaves as if we were dealing with a regular function invocation. | 437 // behaves as if we were dealing with a regular function invocation. |
433 node->RemoveInput(call.formal_arguments() + 1); // Drop new.target. | 438 new_target = call.new_target(); // Retrieve new target value input. |
| 439 node->RemoveInput(call.formal_arguments() + 1); // Drop new target. |
434 node->InsertInput(jsgraph_->graph()->zone(), 1, create); | 440 node->InsertInput(jsgraph_->graph()->zone(), 1, create); |
435 // Insert a check of the return value to determine whether the return value | 441 // Insert a check of the return value to determine whether the return value |
436 // or the implicit receiver should be selected as a result of the call. | 442 // or the implicit receiver should be selected as a result of the call. |
437 Node* check = jsgraph_->graph()->NewNode( | 443 Node* check = jsgraph_->graph()->NewNode( |
438 jsgraph_->javascript()->CallRuntime(Runtime::kInlineIsSpecObject, 1), | 444 jsgraph_->javascript()->CallRuntime(Runtime::kInlineIsSpecObject, 1), |
439 node, context, node, start); | 445 node, context, node, start); |
440 Node* select = jsgraph_->graph()->NewNode( | 446 Node* select = jsgraph_->graph()->NewNode( |
441 jsgraph_->common()->Select(kMachAnyTagged), check, node, create); | 447 jsgraph_->common()->Select(kMachAnyTagged), check, node, create); |
442 NodeProperties::ReplaceUses(node, select, check, node, node); | 448 NodeProperties::ReplaceUses(node, select, check, node, node); |
443 NodeProperties::ReplaceValueInput(select, node, 1); | 449 NodeProperties::ReplaceValueInput(select, node, 1); |
(...skipping 23 matching lines...) Expand all Loading... |
467 const CallFunctionParameters& p = CallFunctionParametersOf(node->op()); | 473 const CallFunctionParameters& p = CallFunctionParametersOf(node->op()); |
468 Node* effect = NodeProperties::GetEffectInput(node); | 474 Node* effect = NodeProperties::GetEffectInput(node); |
469 Node* convert = jsgraph_->graph()->NewNode( | 475 Node* convert = jsgraph_->graph()->NewNode( |
470 jsgraph_->javascript()->ConvertReceiver(p.convert_mode()), | 476 jsgraph_->javascript()->ConvertReceiver(p.convert_mode()), |
471 call.receiver(), context, call.frame_state_before(), effect, start); | 477 call.receiver(), context, call.frame_state_before(), effect, start); |
472 NodeProperties::ReplaceValueInput(node, convert, 1); | 478 NodeProperties::ReplaceValueInput(node, convert, 1); |
473 NodeProperties::ReplaceEffectInput(node, convert); | 479 NodeProperties::ReplaceEffectInput(node, convert); |
474 } | 480 } |
475 | 481 |
476 // Insert argument adaptor frame if required. The callees formal parameter | 482 // Insert argument adaptor frame if required. The callees formal parameter |
477 // count (i.e. value outputs of start node minus target, receiver, num args | 483 // count (i.e. value outputs of start node minus target, receiver, new target, |
478 // and context) have to match the number of arguments passed to the call. | 484 // arguments count and context) have to match the number of arguments passed |
479 DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 4); | 485 // to the call. |
| 486 DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5); |
480 if (call.formal_arguments() != parameter_count) { | 487 if (call.formal_arguments() != parameter_count) { |
481 frame_state = CreateArtificialFrameState( | 488 frame_state = CreateArtificialFrameState( |
482 node, frame_state, call.formal_arguments(), | 489 node, frame_state, call.formal_arguments(), |
483 FrameStateType::kArgumentsAdaptor, info.shared_info()); | 490 FrameStateType::kArgumentsAdaptor, info.shared_info()); |
484 } | 491 } |
485 | 492 |
486 return InlineCall(node, context, frame_state, start, end); | 493 return InlineCall(node, new_target, context, frame_state, start, end); |
487 } | 494 } |
488 | 495 |
489 } // namespace compiler | 496 } // namespace compiler |
490 } // namespace internal | 497 } // namespace internal |
491 } // namespace v8 | 498 } // namespace v8 |
OLD | NEW |