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* exception_target, | |
78 NodeVector uncaught_subcalls) { | |
Jarin
2016/08/10 12:02:52
You should pass the uncought_subcalls as a pointer
bgeron
2016/08/10 14:37:26
Agree, done.
| |
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 (exception_target != nullptr) { | |
136 // Link uncaught calls in the inlinee to {exception_target} | |
137 int subcall_count = static_cast<int>(uncaught_subcalls.size()); | |
138 if (uncaught_subcalls.size() > 0) { | |
Jarin
2016/08/10 12:02:52
Nit: why don't you use subcall_count that you defi
bgeron
2016/08/10 14:37:26
Done.
| |
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 Node* on_exception = | |
147 graph()->NewNode(common()->IfException(), subcall, subcall); | |
148 on_exception_nodes.push_back(on_exception); | |
149 } | |
150 | |
151 DCHECK_EQ(subcall_count, static_cast<int>(on_exception_nodes.size())); | |
152 if (subcall_count > 0) { | |
153 Node* control_output = | |
154 graph()->NewNode(common()->Merge(subcall_count), subcall_count, | |
155 &on_exception_nodes.front()); | |
156 NodeVector values_effects(local_zone_); | |
157 values_effects = on_exception_nodes; | |
158 values_effects.push_back(control_output); | |
159 Node* value_output = graph()->NewNode( | |
160 common()->Phi(MachineRepresentation::kTagged, subcall_count), | |
161 subcall_count + 1, &values_effects.front()); | |
162 Node* effect_output = | |
163 graph()->NewNode(common()->EffectPhi(subcall_count), | |
164 subcall_count + 1, &values_effects.front()); | |
165 ReplaceWithValue(exception_target, value_output, effect_output, | |
166 control_output); | |
167 } else { | |
168 ReplaceWithValue(exception_target, exception_target, exception_target, | |
169 jsgraph()->Dead()); | |
170 } | |
171 } | |
172 | |
133 NodeVector values(local_zone_); | 173 NodeVector values(local_zone_); |
134 NodeVector effects(local_zone_); | 174 NodeVector effects(local_zone_); |
135 NodeVector controls(local_zone_); | 175 NodeVector controls(local_zone_); |
136 for (Node* const input : end->inputs()) { | 176 for (Node* const input : end->inputs()) { |
137 switch (input->opcode()) { | 177 switch (input->opcode()) { |
138 case IrOpcode::kReturn: | 178 case IrOpcode::kReturn: |
139 values.push_back(NodeProperties::GetValueInput(input, 0)); | 179 values.push_back(NodeProperties::GetValueInput(input, 0)); |
140 effects.push_back(NodeProperties::GetEffectInput(input)); | 180 effects.push_back(NodeProperties::GetEffectInput(input)); |
141 controls.push_back(NodeProperties::GetControlInput(input)); | 181 controls.push_back(NodeProperties::GetControlInput(input)); |
142 break; | 182 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: | 302 // calls whenever the target is a constant function object, as follows: |
263 // - JSCallFunction(target:constant, receiver, args...) | 303 // - JSCallFunction(target:constant, receiver, args...) |
264 // - JSCallConstruct(target:constant, args..., new.target) | 304 // - JSCallConstruct(target:constant, args..., new.target) |
265 HeapObjectMatcher match(node->InputAt(0)); | 305 HeapObjectMatcher match(node->InputAt(0)); |
266 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange(); | 306 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange(); |
267 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value()); | 307 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value()); |
268 | 308 |
269 return ReduceJSCall(node, function); | 309 return ReduceJSCall(node, function); |
270 } | 310 } |
271 | 311 |
272 | |
273 Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { | 312 Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { |
274 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); | 313 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); |
275 JSCallAccessor call(node); | 314 JSCallAccessor call(node); |
276 Handle<SharedFunctionInfo> shared_info(function->shared()); | 315 Handle<SharedFunctionInfo> shared_info(function->shared()); |
277 | 316 |
278 // Function must be inlineable. | 317 // Function must be inlineable. |
279 if (!shared_info->IsInlineable()) { | 318 if (!shared_info->IsInlineable()) { |
280 TRACE("Not inlining %s into %s because callee is not inlineable\n", | 319 TRACE("Not inlining %s into %s because callee is not inlineable\n", |
281 shared_info->DebugName()->ToCString().get(), | 320 shared_info->DebugName()->ToCString().get(), |
282 info_->shared_info()->DebugName()->ToCString().get()); | 321 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; | 375 Handle<SharedFunctionInfo> frame_shared_info; |
337 if (frame_info.shared_info().ToHandle(&frame_shared_info) && | 376 if (frame_info.shared_info().ToHandle(&frame_shared_info) && |
338 *frame_shared_info == *shared_info) { | 377 *frame_shared_info == *shared_info) { |
339 TRACE("Not inlining %s into %s because call is recursive\n", | 378 TRACE("Not inlining %s into %s because call is recursive\n", |
340 shared_info->DebugName()->ToCString().get(), | 379 shared_info->DebugName()->ToCString().get(), |
341 info_->shared_info()->DebugName()->ToCString().get()); | 380 info_->shared_info()->DebugName()->ToCString().get()); |
342 return NoChange(); | 381 return NoChange(); |
343 } | 382 } |
344 } | 383 } |
345 | 384 |
346 // TODO(turbofan): Inlining into a try-block is not yet supported. | 385 // Find the IfException node, if any. |
347 if (NodeProperties::IsExceptionalCall(node)) { | 386 Node* exception_target = nullptr; |
348 TRACE("Not inlining %s into %s because of surrounding try-block\n", | 387 for (Edge edge : node->use_edges()) { |
349 shared_info->DebugName()->ToCString().get(), | 388 if (NodeProperties::IsControlEdge(edge) && |
350 info_->shared_info()->DebugName()->ToCString().get()); | 389 edge.from()->opcode() == IrOpcode::kIfException) { |
351 return NoChange(); | 390 DCHECK_NULL(exception_target); |
391 exception_target = edge.from(); | |
392 } | |
393 } | |
394 | |
395 NodeVector uncaught_subcalls(local_zone_); | |
396 | |
397 if (exception_target != nullptr) { | |
398 TRACE( | |
399 "Inlining %s into %s regardless of surrounding try-block to catcher " | |
400 "#%d:%s\n", | |
401 shared_info->DebugName()->ToCString().get(), | |
402 info_->shared_info()->DebugName()->ToCString().get(), | |
403 exception_target->id(), exception_target->op()->mnemonic()); | |
352 } | 404 } |
353 | 405 |
354 Zone zone(info_->isolate()->allocator()); | 406 Zone zone(info_->isolate()->allocator()); |
355 ParseInfo parse_info(&zone, function); | 407 ParseInfo parse_info(&zone, function); |
356 CompilationInfo info(&parse_info, function); | 408 CompilationInfo info(&parse_info, function); |
357 if (info_->is_deoptimization_enabled()) info.MarkAsDeoptimizationEnabled(); | 409 if (info_->is_deoptimization_enabled()) info.MarkAsDeoptimizationEnabled(); |
358 if (info_->is_type_feedback_enabled()) info.MarkAsTypeFeedbackEnabled(); | 410 if (info_->is_type_feedback_enabled()) info.MarkAsTypeFeedbackEnabled(); |
359 | 411 |
360 if (!Compiler::ParseAndAnalyze(info.parse_info())) { | 412 if (!Compiler::ParseAndAnalyze(info.parse_info())) { |
361 TRACE("Not inlining %s into %s because parsing failed\n", | 413 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()); | 460 Graph::SubgraphScope scope(graph()); |
409 AstGraphBuilder graph_builder(&zone, &info, jsgraph(), loop_assignment, | 461 AstGraphBuilder graph_builder(&zone, &info, jsgraph(), loop_assignment, |
410 type_hint_analysis); | 462 type_hint_analysis); |
411 graph_builder.CreateGraph(false); | 463 graph_builder.CreateGraph(false); |
412 | 464 |
413 // Extract the inlinee start/end nodes. | 465 // Extract the inlinee start/end nodes. |
414 start = graph()->start(); | 466 start = graph()->start(); |
415 end = graph()->end(); | 467 end = graph()->end(); |
416 } | 468 } |
417 | 469 |
470 if (exception_target != nullptr) { | |
471 // Find all uncaught 'calls' in the inlinee. | |
472 AllNodes inlined_nodes(local_zone_, end, graph()); | |
473 for (Node* subnode : inlined_nodes.live) { | |
474 // Every possibly throwing node with an IfSuccess should get an | |
475 // IfException. | |
476 if (subnode->op()->HasProperty(Operator::kNoThrow)) { | |
477 continue; | |
478 } | |
479 bool hasIfSuccess = false; | |
480 bool hasIfException = false; | |
481 for (Node* use : subnode->uses()) { | |
482 if (use->opcode() == IrOpcode::kIfSuccess) { | |
Jarin
2016/08/10 12:02:52
I assume this won't be needed once every no-no-thr
bgeron
2016/08/10 14:37:26
Hm, I fixed some things to make them saner, but cu
Jarin
2016/08/11 09:54:23
Actually, if Throw does not have IfSuccess, this c
bgeron
2016/08/11 18:55:55
Removed that condition.
To make this work, I had
| |
483 hasIfSuccess = true; | |
484 } else if (use->opcode() == IrOpcode::kIfException) { | |
485 hasIfException = true; | |
486 } | |
487 } | |
488 if (hasIfSuccess && !hasIfException) { | |
489 DCHECK_EQ(2, subnode->op()->ControlOutputCount()); | |
490 uncaught_subcalls.push_back(subnode); | |
491 } | |
492 } | |
493 } | |
494 | |
418 Node* frame_state = call.frame_state(); | 495 Node* frame_state = call.frame_state(); |
419 Node* new_target = jsgraph()->UndefinedConstant(); | 496 Node* new_target = jsgraph()->UndefinedConstant(); |
420 | 497 |
421 // Inline {JSCallConstruct} requires some additional magic. | 498 // Inline {JSCallConstruct} requires some additional magic. |
422 if (node->opcode() == IrOpcode::kJSCallConstruct) { | 499 if (node->opcode() == IrOpcode::kJSCallConstruct) { |
423 // Insert nodes around the call that model the behavior required for a | 500 // Insert nodes around the call that model the behavior required for a |
424 // constructor dispatch (allocate implicit receiver and check return value). | 501 // constructor dispatch (allocate implicit receiver and check return value). |
425 // This models the behavior usually accomplished by our {JSConstructStub}. | 502 // This models the behavior usually accomplished by our {JSConstructStub}. |
426 // Note that the context has to be the callers context (input to call node). | 503 // Note that the context has to be the callers context (input to call node). |
427 Node* receiver = jsgraph()->UndefinedConstant(); // Implicit receiver. | 504 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 | 583 // arguments count and context) have to match the number of arguments passed |
507 // to the call. | 584 // to the call. |
508 int parameter_count = info.literal()->parameter_count(); | 585 int parameter_count = info.literal()->parameter_count(); |
509 DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5); | 586 DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5); |
510 if (call.formal_arguments() != parameter_count) { | 587 if (call.formal_arguments() != parameter_count) { |
511 frame_state = CreateArtificialFrameState( | 588 frame_state = CreateArtificialFrameState( |
512 node, frame_state, call.formal_arguments(), | 589 node, frame_state, call.formal_arguments(), |
513 FrameStateType::kArgumentsAdaptor, shared_info); | 590 FrameStateType::kArgumentsAdaptor, shared_info); |
514 } | 591 } |
515 | 592 |
516 return InlineCall(node, new_target, context, frame_state, start, end); | 593 return InlineCall(node, new_target, context, frame_state, start, end, |
594 exception_target, uncaught_subcalls); | |
517 } | 595 } |
518 | 596 |
519 Graph* JSInliner::graph() const { return jsgraph()->graph(); } | 597 Graph* JSInliner::graph() const { return jsgraph()->graph(); } |
520 | 598 |
521 JSOperatorBuilder* JSInliner::javascript() const { | 599 JSOperatorBuilder* JSInliner::javascript() const { |
522 return jsgraph()->javascript(); | 600 return jsgraph()->javascript(); |
523 } | 601 } |
524 | 602 |
525 CommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); } | 603 CommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); } |
526 | 604 |
527 } // namespace compiler | 605 } // namespace compiler |
528 } // namespace internal | 606 } // namespace internal |
529 } // namespace v8 | 607 } // namespace v8 |
OLD | NEW |