Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(187)

Side by Side Diff: src/compiler/js-inlining.cc

Issue 2216353002: [turbofan] Also inline into try blocks. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@p5-base
Patch Set: Depend on changelist 2245263003 which consists of only the tests. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/js-inlining.h ('k') | test/cctest/test-heap-profiler.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 const 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
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 (subcall_count > 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 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
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
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
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 hasIfException = false;
480 for (Node* use : subnode->uses()) {
481 if (use->opcode() == IrOpcode::kIfException) {
482 hasIfException = true;
Jarin 2016/08/17 11:20:55 break; ?
bgeron 2016/08/18 17:57:25 Done.
483 }
484 }
485 if (!hasIfException) {
486 DCHECK_EQ(2, subnode->op()->ControlOutputCount());
487 uncaught_subcalls.push_back(subnode);
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
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 exception_target, 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
OLDNEW
« no previous file with comments | « src/compiler/js-inlining.h ('k') | test/cctest/test-heap-profiler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698