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" | |
11 #include "src/compiler/ast-graph-builder.h" | 12 #include "src/compiler/ast-graph-builder.h" |
12 #include "src/compiler/ast-loop-assignment-analyzer.h" | 13 #include "src/compiler/ast-loop-assignment-analyzer.h" |
13 #include "src/compiler/common-operator.h" | 14 #include "src/compiler/common-operator.h" |
14 #include "src/compiler/graph-reducer.h" | 15 #include "src/compiler/graph-reducer.h" |
15 #include "src/compiler/js-operator.h" | 16 #include "src/compiler/js-operator.h" |
16 #include "src/compiler/node-matchers.h" | 17 #include "src/compiler/node-matchers.h" |
17 #include "src/compiler/node-properties.h" | 18 #include "src/compiler/node-properties.h" |
18 #include "src/compiler/operator-properties.h" | 19 #include "src/compiler/operator-properties.h" |
19 #include "src/compiler/type-hint-analyzer.h" | 20 #include "src/compiler/type-hint-analyzer.h" |
20 #include "src/isolate-inl.h" | 21 #include "src/isolate-inl.h" |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
64 // Both, {JSCallFunction} and {JSCallConstruct}, have two extra inputs: | 65 // Both, {JSCallFunction} and {JSCallConstruct}, have two extra inputs: |
65 // - JSCallConstruct: Includes target function and new target. | 66 // - JSCallConstruct: Includes target function and new target. |
66 // - JSCallFunction: Includes target function and receiver. | 67 // - JSCallFunction: Includes target function and receiver. |
67 return call_->op()->ValueInputCount() - 2; | 68 return call_->op()->ValueInputCount() - 2; |
68 } | 69 } |
69 | 70 |
70 private: | 71 private: |
71 Node* call_; | 72 Node* call_; |
72 }; | 73 }; |
73 | 74 |
74 | |
75 Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, | 75 Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, |
76 Node* frame_state, Node* start, Node* end) { | 76 Node* frame_state, Node* start, Node* end, |
77 Node* exceptionTarget, | |
78 NodeVector uncaught_subcalls) { | |
77 // The scheduler is smart enough to place our code; we just ensure {control} | 79 // The scheduler is smart enough to place our code; we just ensure {control} |
78 // becomes the control input of the start of the inlinee, and {effect} becomes | 80 // becomes the control input of the start of the inlinee, and {effect} becomes |
79 // the effect input of the start of the inlinee. | 81 // the effect input of the start of the inlinee. |
80 Node* control = NodeProperties::GetControlInput(call); | 82 Node* control = NodeProperties::GetControlInput(call); |
81 Node* effect = NodeProperties::GetEffectInput(call); | 83 Node* effect = NodeProperties::GetEffectInput(call); |
82 | 84 |
83 int const inlinee_new_target_index = | 85 int const inlinee_new_target_index = |
84 static_cast<int>(start->op()->ValueOutputCount()) - 3; | 86 static_cast<int>(start->op()->ValueOutputCount()) - 3; |
85 int const inlinee_arity_index = | 87 int const inlinee_arity_index = |
86 static_cast<int>(start->op()->ValueOutputCount()) - 2; | 88 static_cast<int>(start->op()->ValueOutputCount()) - 2; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
123 edge.UpdateTo(control); | 125 edge.UpdateTo(control); |
124 } else if (NodeProperties::IsFrameStateEdge(edge)) { | 126 } else if (NodeProperties::IsFrameStateEdge(edge)) { |
125 edge.UpdateTo(frame_state); | 127 edge.UpdateTo(frame_state); |
126 } else { | 128 } else { |
127 UNREACHABLE(); | 129 UNREACHABLE(); |
128 } | 130 } |
129 break; | 131 break; |
130 } | 132 } |
131 } | 133 } |
132 | 134 |
135 if (exceptionTarget != nullptr) { | |
136 // Link uncaught calls in the inlinee to {exceptionTarget} | |
137 int subcall_count = static_cast<int>(uncaught_subcalls.size()); | |
138 if (uncaught_subcalls.size() > 0) { | |
139 TRACE( | |
140 "Inlinee contains %d calls without IfException; " | |
141 "linking to existing IfException\n", | |
142 subcall_count); | |
143 } | |
144 NodeVector on_exception_nodes(local_zone_); | |
145 for (Node* subcall : uncaught_subcalls) { | |
146 const Operator* op = common()->IfException(); | |
Jarin
2016/08/05 14:04:48
Nit: no need for separate variable, just inline in
bgeron
2016/08/08 09:30:06
Done.
| |
147 | |
148 Node* on_exception = graph()->NewNode(op, subcall, subcall); | |
149 on_exception_nodes.push_back(on_exception); | |
150 } | |
151 | |
152 DCHECK_EQ(subcall_count, static_cast<int>(on_exception_nodes.size())); | |
153 if (subcall_count > 0) { | |
154 Node* control_output = | |
155 graph()->NewNode(common()->Merge(subcall_count), subcall_count, | |
156 &on_exception_nodes.front()); | |
157 NodeVector values_effects(local_zone_); | |
158 values_effects = on_exception_nodes; | |
159 values_effects.push_back(control_output); | |
160 Node* value_output = graph()->NewNode( | |
161 common()->Phi(MachineRepresentation::kTagged, subcall_count), | |
162 subcall_count + 1, &values_effects.front()); | |
163 Node* effect_output = | |
164 graph()->NewNode(common()->EffectPhi(subcall_count), | |
165 subcall_count + 1, &values_effects.front()); | |
166 ReplaceWithValue(exceptionTarget, value_output, effect_output, | |
167 control_output); | |
168 } else { | |
169 ReplaceWithValue(exceptionTarget, exceptionTarget, exceptionTarget, | |
170 jsgraph()->Dead()); | |
171 } | |
172 } | |
173 | |
133 NodeVector values(local_zone_); | 174 NodeVector values(local_zone_); |
134 NodeVector effects(local_zone_); | 175 NodeVector effects(local_zone_); |
135 NodeVector controls(local_zone_); | 176 NodeVector controls(local_zone_); |
136 for (Node* const input : end->inputs()) { | 177 for (Node* const input : end->inputs()) { |
137 switch (input->opcode()) { | 178 switch (input->opcode()) { |
138 case IrOpcode::kReturn: | 179 case IrOpcode::kReturn: |
139 values.push_back(NodeProperties::GetValueInput(input, 0)); | 180 values.push_back(NodeProperties::GetValueInput(input, 0)); |
140 effects.push_back(NodeProperties::GetEffectInput(input)); | 181 effects.push_back(NodeProperties::GetEffectInput(input)); |
141 controls.push_back(NodeProperties::GetControlInput(input)); | 182 controls.push_back(NodeProperties::GetControlInput(input)); |
142 break; | 183 break; |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
262 // calls whenever the target is a constant function object, as follows: | 303 // calls whenever the target is a constant function object, as follows: |
263 // - JSCallFunction(target:constant, receiver, args...) | 304 // - JSCallFunction(target:constant, receiver, args...) |
264 // - JSCallConstruct(target:constant, args..., new.target) | 305 // - JSCallConstruct(target:constant, args..., new.target) |
265 HeapObjectMatcher match(node->InputAt(0)); | 306 HeapObjectMatcher match(node->InputAt(0)); |
266 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange(); | 307 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange(); |
267 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value()); | 308 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value()); |
268 | 309 |
269 return ReduceJSCall(node, function); | 310 return ReduceJSCall(node, function); |
270 } | 311 } |
271 | 312 |
272 | |
273 Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { | 313 Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { |
274 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); | 314 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); |
275 JSCallAccessor call(node); | 315 JSCallAccessor call(node); |
276 Handle<SharedFunctionInfo> shared_info(function->shared()); | 316 Handle<SharedFunctionInfo> shared_info(function->shared()); |
277 | 317 |
278 // Function must be inlineable. | 318 // Function must be inlineable. |
279 if (!shared_info->IsInlineable()) { | 319 if (!shared_info->IsInlineable()) { |
280 TRACE("Not inlining %s into %s because callee is not inlineable\n", | 320 TRACE("Not inlining %s into %s because callee is not inlineable\n", |
281 shared_info->DebugName()->ToCString().get(), | 321 shared_info->DebugName()->ToCString().get(), |
282 info_->shared_info()->DebugName()->ToCString().get()); | 322 info_->shared_info()->DebugName()->ToCString().get()); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
336 Handle<SharedFunctionInfo> frame_shared_info; | 376 Handle<SharedFunctionInfo> frame_shared_info; |
337 if (frame_info.shared_info().ToHandle(&frame_shared_info) && | 377 if (frame_info.shared_info().ToHandle(&frame_shared_info) && |
338 *frame_shared_info == *shared_info) { | 378 *frame_shared_info == *shared_info) { |
339 TRACE("Not inlining %s into %s because call is recursive\n", | 379 TRACE("Not inlining %s into %s because call is recursive\n", |
340 shared_info->DebugName()->ToCString().get(), | 380 shared_info->DebugName()->ToCString().get(), |
341 info_->shared_info()->DebugName()->ToCString().get()); | 381 info_->shared_info()->DebugName()->ToCString().get()); |
342 return NoChange(); | 382 return NoChange(); |
343 } | 383 } |
344 } | 384 } |
345 | 385 |
346 // TODO(turbofan): Inlining into a try-block is not yet supported. | 386 // Find the IfException node, if any. |
347 if (NodeProperties::IsExceptionalCall(node)) { | 387 Node* exceptionTarget = nullptr; |
Jarin
2016/08/05 14:04:48
exceptionTarget -> exception_target
bgeron
2016/08/08 09:30:06
Done.
| |
348 TRACE("Not inlining %s into %s because of surrounding try-block\n", | 388 for (Edge edge : node->use_edges()) { |
349 shared_info->DebugName()->ToCString().get(), | 389 if (NodeProperties::IsControlEdge(edge) && |
350 info_->shared_info()->DebugName()->ToCString().get()); | 390 edge.from()->opcode() == IrOpcode::kIfException) { |
351 return NoChange(); | 391 DCHECK_NULL(exceptionTarget); |
392 exceptionTarget = edge.from(); | |
393 } | |
394 } | |
395 | |
396 NodeVector uncaught_subcalls(local_zone_); | |
397 | |
398 if (exceptionTarget != nullptr) { | |
399 TRACE( | |
400 "Inlining %s into %s regardless of surrounding try-block to catcher " | |
401 "#%d:%s\n", | |
402 shared_info->DebugName()->ToCString().get(), | |
403 info_->shared_info()->DebugName()->ToCString().get(), | |
404 exceptionTarget->id(), exceptionTarget->op()->mnemonic()); | |
352 } | 405 } |
353 | 406 |
354 Zone zone(info_->isolate()->allocator()); | 407 Zone zone(info_->isolate()->allocator()); |
355 ParseInfo parse_info(&zone, function); | 408 ParseInfo parse_info(&zone, function); |
356 CompilationInfo info(&parse_info, function); | 409 CompilationInfo info(&parse_info, function); |
357 if (info_->is_deoptimization_enabled()) info.MarkAsDeoptimizationEnabled(); | 410 if (info_->is_deoptimization_enabled()) info.MarkAsDeoptimizationEnabled(); |
358 if (info_->is_type_feedback_enabled()) info.MarkAsTypeFeedbackEnabled(); | 411 if (info_->is_type_feedback_enabled()) info.MarkAsTypeFeedbackEnabled(); |
359 | 412 |
360 if (!Compiler::ParseAndAnalyze(info.parse_info())) { | 413 if (!Compiler::ParseAndAnalyze(info.parse_info())) { |
361 TRACE("Not inlining %s into %s because parsing failed\n", | 414 TRACE("Not inlining %s into %s because parsing failed\n", |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
408 Graph::SubgraphScope scope(graph()); | 461 Graph::SubgraphScope scope(graph()); |
409 AstGraphBuilder graph_builder(&zone, &info, jsgraph(), loop_assignment, | 462 AstGraphBuilder graph_builder(&zone, &info, jsgraph(), loop_assignment, |
410 type_hint_analysis); | 463 type_hint_analysis); |
411 graph_builder.CreateGraph(false); | 464 graph_builder.CreateGraph(false); |
412 | 465 |
413 // Extract the inlinee start/end nodes. | 466 // Extract the inlinee start/end nodes. |
414 start = graph()->start(); | 467 start = graph()->start(); |
415 end = graph()->end(); | 468 end = graph()->end(); |
416 } | 469 } |
417 | 470 |
471 // Find all uncaught calls in the inlinee. | |
472 AllNodes inlined_nodes(local_zone_, end, graph()); | |
473 for (Node* subcall : inlined_nodes.live) { | |
474 if (subcall->opcode() == IrOpcode::kJSCallFunction || | |
475 subcall->opcode() == IrOpcode::kJSCallConstruct || | |
476 subcall->opcode() == IrOpcode::kJSCallRuntime) { | |
Jarin
2016/08/05 14:04:48
As discussed offline, you need a more general way:
bgeron
2016/08/08 09:30:06
Done.
| |
477 bool hasIfException = false; | |
478 for (Node* use : subcall->uses()) { | |
479 if (use->opcode() == IrOpcode::kIfException) { | |
480 hasIfException = true; | |
481 std::ostringstream s; | |
482 s << "found exception node #" << use->id(); | |
Jarin
2016/08/05 14:04:48
Remove the logging.
bgeron
2016/08/08 09:30:06
Done.
| |
483 break; | |
484 } | |
485 } | |
486 if (!hasIfException) { | |
487 uncaught_subcalls.push_back(subcall); | |
488 } | |
489 } | |
490 } | |
491 | |
418 Node* frame_state = call.frame_state(); | 492 Node* frame_state = call.frame_state(); |
419 Node* new_target = jsgraph()->UndefinedConstant(); | 493 Node* new_target = jsgraph()->UndefinedConstant(); |
420 | 494 |
421 // Inline {JSCallConstruct} requires some additional magic. | 495 // Inline {JSCallConstruct} requires some additional magic. |
422 if (node->opcode() == IrOpcode::kJSCallConstruct) { | 496 if (node->opcode() == IrOpcode::kJSCallConstruct) { |
423 // Insert nodes around the call that model the behavior required for a | 497 // Insert nodes around the call that model the behavior required for a |
424 // constructor dispatch (allocate implicit receiver and check return value). | 498 // constructor dispatch (allocate implicit receiver and check return value). |
425 // This models the behavior usually accomplished by our {JSConstructStub}. | 499 // This models the behavior usually accomplished by our {JSConstructStub}. |
426 // Note that the context has to be the callers context (input to call node). | 500 // Note that the context has to be the callers context (input to call node). |
427 Node* receiver = jsgraph()->UndefinedConstant(); // Implicit receiver. | 501 Node* receiver = jsgraph()->UndefinedConstant(); // Implicit receiver. |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
506 // arguments count and context) have to match the number of arguments passed | 580 // arguments count and context) have to match the number of arguments passed |
507 // to the call. | 581 // to the call. |
508 int parameter_count = info.literal()->parameter_count(); | 582 int parameter_count = info.literal()->parameter_count(); |
509 DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5); | 583 DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5); |
510 if (call.formal_arguments() != parameter_count) { | 584 if (call.formal_arguments() != parameter_count) { |
511 frame_state = CreateArtificialFrameState( | 585 frame_state = CreateArtificialFrameState( |
512 node, frame_state, call.formal_arguments(), | 586 node, frame_state, call.formal_arguments(), |
513 FrameStateType::kArgumentsAdaptor, shared_info); | 587 FrameStateType::kArgumentsAdaptor, shared_info); |
514 } | 588 } |
515 | 589 |
516 return InlineCall(node, new_target, context, frame_state, start, end); | 590 return InlineCall(node, new_target, context, frame_state, start, end, |
591 exceptionTarget, uncaught_subcalls); | |
517 } | 592 } |
518 | 593 |
519 Graph* JSInliner::graph() const { return jsgraph()->graph(); } | 594 Graph* JSInliner::graph() const { return jsgraph()->graph(); } |
520 | 595 |
521 JSOperatorBuilder* JSInliner::javascript() const { | 596 JSOperatorBuilder* JSInliner::javascript() const { |
522 return jsgraph()->javascript(); | 597 return jsgraph()->javascript(); |
523 } | 598 } |
524 | 599 |
525 CommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); } | 600 CommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); } |
526 | 601 |
527 } // namespace compiler | 602 } // namespace compiler |
528 } // namespace internal | 603 } // namespace internal |
529 } // namespace v8 | 604 } // namespace v8 |
OLD | NEW |