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

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: Remove failing test that depends on changing Turbofan internals. Created 4 years, 3 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') | src/compiler/js-inlining-heuristic.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/simplified-operator.h" 20 #include "src/compiler/simplified-operator.h"
20 #include "src/compiler/type-hint-analyzer.h" 21 #include "src/compiler/type-hint-analyzer.h"
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 // Both, {JSCallFunction} and {JSCallConstruct}, have two extra inputs: 66 // Both, {JSCallFunction} and {JSCallConstruct}, have two extra inputs:
66 // - JSCallConstruct: Includes target function and new target. 67 // - JSCallConstruct: Includes target function and new target.
67 // - JSCallFunction: Includes target function and receiver. 68 // - JSCallFunction: Includes target function and receiver.
68 return call_->op()->ValueInputCount() - 2; 69 return call_->op()->ValueInputCount() - 2;
69 } 70 }
70 71
71 private: 72 private:
72 Node* call_; 73 Node* call_;
73 }; 74 };
74 75
75
76 Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, 76 Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
77 Node* frame_state, Node* start, Node* end) { 77 Node* frame_state, Node* start, Node* end,
78 Node* exception_target,
79 const NodeVector& uncaught_subcalls) {
78 // The scheduler is smart enough to place our code; we just ensure {control} 80 // The scheduler is smart enough to place our code; we just ensure {control}
79 // becomes the control input of the start of the inlinee, and {effect} becomes 81 // becomes the control input of the start of the inlinee, and {effect} becomes
80 // the effect input of the start of the inlinee. 82 // the effect input of the start of the inlinee.
81 Node* control = NodeProperties::GetControlInput(call); 83 Node* control = NodeProperties::GetControlInput(call);
82 Node* effect = NodeProperties::GetEffectInput(call); 84 Node* effect = NodeProperties::GetEffectInput(call);
83 85
84 int const inlinee_new_target_index = 86 int const inlinee_new_target_index =
85 static_cast<int>(start->op()->ValueOutputCount()) - 3; 87 static_cast<int>(start->op()->ValueOutputCount()) - 3;
86 int const inlinee_arity_index = 88 int const inlinee_arity_index =
87 static_cast<int>(start->op()->ValueOutputCount()) - 2; 89 static_cast<int>(start->op()->ValueOutputCount()) - 2;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 edge.UpdateTo(control); 126 edge.UpdateTo(control);
125 } else if (NodeProperties::IsFrameStateEdge(edge)) { 127 } else if (NodeProperties::IsFrameStateEdge(edge)) {
126 edge.UpdateTo(frame_state); 128 edge.UpdateTo(frame_state);
127 } else { 129 } else {
128 UNREACHABLE(); 130 UNREACHABLE();
129 } 131 }
130 break; 132 break;
131 } 133 }
132 } 134 }
133 135
136 if (exception_target != nullptr) {
137 // Link uncaught calls in the inlinee to {exception_target}
138 int subcall_count = static_cast<int>(uncaught_subcalls.size());
139 if (subcall_count > 0) {
140 TRACE(
141 "Inlinee contains %d calls without IfException; "
142 "linking to existing IfException\n",
143 subcall_count);
144 }
145 NodeVector on_exception_nodes(local_zone_);
146 for (Node* subcall : uncaught_subcalls) {
147 Node* on_exception =
148 graph()->NewNode(common()->IfException(), 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(exception_target, value_output, effect_output,
167 control_output);
168 } else {
169 ReplaceWithValue(exception_target, exception_target, exception_target,
170 jsgraph()->Dead());
171 }
172 }
173
134 NodeVector values(local_zone_); 174 NodeVector values(local_zone_);
135 NodeVector effects(local_zone_); 175 NodeVector effects(local_zone_);
136 NodeVector controls(local_zone_); 176 NodeVector controls(local_zone_);
137 for (Node* const input : end->inputs()) { 177 for (Node* const input : end->inputs()) {
138 switch (input->opcode()) { 178 switch (input->opcode()) {
139 case IrOpcode::kReturn: 179 case IrOpcode::kReturn:
140 values.push_back(NodeProperties::GetValueInput(input, 0)); 180 values.push_back(NodeProperties::GetValueInput(input, 0));
141 effects.push_back(NodeProperties::GetEffectInput(input)); 181 effects.push_back(NodeProperties::GetEffectInput(input));
142 controls.push_back(NodeProperties::GetControlInput(input)); 182 controls.push_back(NodeProperties::GetControlInput(input));
143 break; 183 break;
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 // calls whenever the target is a constant function object, as follows: 303 // calls whenever the target is a constant function object, as follows:
264 // - JSCallFunction(target:constant, receiver, args...) 304 // - JSCallFunction(target:constant, receiver, args...)
265 // - JSCallConstruct(target:constant, args..., new.target) 305 // - JSCallConstruct(target:constant, args..., new.target)
266 HeapObjectMatcher match(node->InputAt(0)); 306 HeapObjectMatcher match(node->InputAt(0));
267 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange(); 307 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange();
268 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value()); 308 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value());
269 309
270 return ReduceJSCall(node, function); 310 return ReduceJSCall(node, function);
271 } 311 }
272 312
273
274 Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { 313 Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
275 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); 314 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
276 JSCallAccessor call(node); 315 JSCallAccessor call(node);
277 Handle<SharedFunctionInfo> shared_info(function->shared()); 316 Handle<SharedFunctionInfo> shared_info(function->shared());
278 317
279 // Function must be inlineable. 318 // Function must be inlineable.
280 if (!shared_info->IsInlineable()) { 319 if (!shared_info->IsInlineable()) {
281 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",
282 shared_info->DebugName()->ToCString().get(), 321 shared_info->DebugName()->ToCString().get(),
283 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
337 Handle<SharedFunctionInfo> frame_shared_info; 376 Handle<SharedFunctionInfo> frame_shared_info;
338 if (frame_info.shared_info().ToHandle(&frame_shared_info) && 377 if (frame_info.shared_info().ToHandle(&frame_shared_info) &&
339 *frame_shared_info == *shared_info) { 378 *frame_shared_info == *shared_info) {
340 TRACE("Not inlining %s into %s because call is recursive\n", 379 TRACE("Not inlining %s into %s because call is recursive\n",
341 shared_info->DebugName()->ToCString().get(), 380 shared_info->DebugName()->ToCString().get(),
342 info_->shared_info()->DebugName()->ToCString().get()); 381 info_->shared_info()->DebugName()->ToCString().get());
343 return NoChange(); 382 return NoChange();
344 } 383 }
345 } 384 }
346 385
347 // TODO(turbofan): Inlining into a try-block is not yet supported. 386 // Find the IfException node, if any.
348 if (NodeProperties::IsExceptionalCall(node)) { 387 Node* exception_target = nullptr;
349 TRACE("Not inlining %s into %s because of surrounding try-block\n", 388 for (Edge edge : node->use_edges()) {
389 if (NodeProperties::IsControlEdge(edge) &&
390 edge.from()->opcode() == IrOpcode::kIfException) {
391 DCHECK_NULL(exception_target);
392 exception_target = edge.from();
393 }
394 }
395
396 NodeVector uncaught_subcalls(local_zone_);
397
398 if (exception_target != nullptr) {
399 if (!FLAG_inline_into_try) {
400 TRACE(
401 "Try block surrounds #%d:%s and --no-inline-into-try active, so not "
402 "inlining %s into %s.\n",
403 exception_target->id(), exception_target->op()->mnemonic(),
350 shared_info->DebugName()->ToCString().get(), 404 shared_info->DebugName()->ToCString().get(),
351 info_->shared_info()->DebugName()->ToCString().get()); 405 info_->shared_info()->DebugName()->ToCString().get());
352 return NoChange(); 406 return NoChange();
407 } else {
408 TRACE(
409 "Inlining %s into %s regardless of surrounding try-block to catcher "
410 "#%d:%s\n",
411 shared_info->DebugName()->ToCString().get(),
412 info_->shared_info()->DebugName()->ToCString().get(),
413 exception_target->id(), exception_target->op()->mnemonic());
414 }
353 } 415 }
354 416
355 Zone zone(info_->isolate()->allocator()); 417 Zone zone(info_->isolate()->allocator());
356 ParseInfo parse_info(&zone, function); 418 ParseInfo parse_info(&zone, function);
357 CompilationInfo info(&parse_info, function); 419 CompilationInfo info(&parse_info, function);
358 if (info_->is_deoptimization_enabled()) info.MarkAsDeoptimizationEnabled(); 420 if (info_->is_deoptimization_enabled()) info.MarkAsDeoptimizationEnabled();
359 if (info_->is_type_feedback_enabled()) info.MarkAsTypeFeedbackEnabled(); 421 if (info_->is_type_feedback_enabled()) info.MarkAsTypeFeedbackEnabled();
360 422
361 if (!Compiler::ParseAndAnalyze(info.parse_info())) { 423 if (!Compiler::ParseAndAnalyze(info.parse_info())) {
362 TRACE("Not inlining %s into %s because parsing failed\n", 424 TRACE("Not inlining %s into %s because parsing failed\n",
(...skipping 18 matching lines...) Expand all
381 info_->AddInlinedFunction(shared_info); 443 info_->AddInlinedFunction(shared_info);
382 444
383 // ---------------------------------------------------------------- 445 // ----------------------------------------------------------------
384 // After this point, we've made a decision to inline this function. 446 // After this point, we've made a decision to inline this function.
385 // We shall not bailout from inlining if we got here. 447 // We shall not bailout from inlining if we got here.
386 448
387 TRACE("Inlining %s into %s\n", 449 TRACE("Inlining %s into %s\n",
388 shared_info->DebugName()->ToCString().get(), 450 shared_info->DebugName()->ToCString().get(),
389 info_->shared_info()->DebugName()->ToCString().get()); 451 info_->shared_info()->DebugName()->ToCString().get());
390 452
391 // If function was lazily compiled, it's literals array may not yet be set up. 453 // If function was lazily compiled, its literals array may not yet be set up.
392 JSFunction::EnsureLiterals(function); 454 JSFunction::EnsureLiterals(function);
393 455
394 // Create the subgraph for the inlinee. 456 // Create the subgraph for the inlinee.
395 Node* start; 457 Node* start;
396 Node* end; 458 Node* end;
397 { 459 {
398 // Run the loop assignment analyzer on the inlinee. 460 // Run the loop assignment analyzer on the inlinee.
399 AstLoopAssignmentAnalyzer loop_assignment_analyzer(&zone, &info); 461 AstLoopAssignmentAnalyzer loop_assignment_analyzer(&zone, &info);
400 LoopAssignmentAnalysis* loop_assignment = 462 LoopAssignmentAnalysis* loop_assignment =
401 loop_assignment_analyzer.Analyze(); 463 loop_assignment_analyzer.Analyze();
402 464
403 // Run the type hint analyzer on the inlinee. 465 // Run the type hint analyzer on the inlinee.
404 TypeHintAnalyzer type_hint_analyzer(&zone); 466 TypeHintAnalyzer type_hint_analyzer(&zone);
405 TypeHintAnalysis* type_hint_analysis = 467 TypeHintAnalysis* type_hint_analysis =
406 type_hint_analyzer.Analyze(handle(shared_info->code(), info.isolate())); 468 type_hint_analyzer.Analyze(handle(shared_info->code(), info.isolate()));
407 469
408 // Run the AstGraphBuilder to create the subgraph. 470 // Run the AstGraphBuilder to create the subgraph.
409 Graph::SubgraphScope scope(graph()); 471 Graph::SubgraphScope scope(graph());
410 AstGraphBuilder graph_builder(&zone, &info, jsgraph(), loop_assignment, 472 AstGraphBuilder graph_builder(&zone, &info, jsgraph(), loop_assignment,
411 type_hint_analysis); 473 type_hint_analysis);
412 graph_builder.CreateGraph(false); 474 graph_builder.CreateGraph(false);
413 475
414 // Extract the inlinee start/end nodes. 476 // Extract the inlinee start/end nodes.
415 start = graph()->start(); 477 start = graph()->start();
416 end = graph()->end(); 478 end = graph()->end();
417 } 479 }
418 480
481 if (exception_target != nullptr) {
482 // Find all uncaught 'calls' in the inlinee.
483 AllNodes inlined_nodes(local_zone_, end, graph());
484 for (Node* subnode : inlined_nodes.reachable) {
485 // Every possibly throwing node with an IfSuccess should get an
486 // IfException.
487 if (subnode->op()->HasProperty(Operator::kNoThrow)) {
488 continue;
489 }
490 bool hasIfException = false;
491 for (Node* use : subnode->uses()) {
492 if (use->opcode() == IrOpcode::kIfException) {
493 hasIfException = true;
494 break;
495 }
496 }
497 if (!hasIfException) {
498 DCHECK_EQ(2, subnode->op()->ControlOutputCount());
499 uncaught_subcalls.push_back(subnode);
500 }
501 }
502 }
503
419 Node* frame_state = call.frame_state(); 504 Node* frame_state = call.frame_state();
420 Node* new_target = jsgraph()->UndefinedConstant(); 505 Node* new_target = jsgraph()->UndefinedConstant();
421 506
422 // Inline {JSCallConstruct} requires some additional magic. 507 // Inline {JSCallConstruct} requires some additional magic.
423 if (node->opcode() == IrOpcode::kJSCallConstruct) { 508 if (node->opcode() == IrOpcode::kJSCallConstruct) {
424 // Insert nodes around the call that model the behavior required for a 509 // Insert nodes around the call that model the behavior required for a
425 // constructor dispatch (allocate implicit receiver and check return value). 510 // constructor dispatch (allocate implicit receiver and check return value).
426 // This models the behavior usually accomplished by our {JSConstructStub}. 511 // This models the behavior usually accomplished by our {JSConstructStub}.
427 // Note that the context has to be the callers context (input to call node). 512 // Note that the context has to be the callers context (input to call node).
428 Node* receiver = jsgraph()->UndefinedConstant(); // Implicit receiver. 513 Node* receiver = jsgraph()->UndefinedConstant(); // Implicit receiver.
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 // arguments count and context) have to match the number of arguments passed 590 // arguments count and context) have to match the number of arguments passed
506 // to the call. 591 // to the call.
507 int parameter_count = info.literal()->parameter_count(); 592 int parameter_count = info.literal()->parameter_count();
508 DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5); 593 DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5);
509 if (call.formal_arguments() != parameter_count) { 594 if (call.formal_arguments() != parameter_count) {
510 frame_state = CreateArtificialFrameState( 595 frame_state = CreateArtificialFrameState(
511 node, frame_state, call.formal_arguments(), 596 node, frame_state, call.formal_arguments(),
512 FrameStateType::kArgumentsAdaptor, shared_info); 597 FrameStateType::kArgumentsAdaptor, shared_info);
513 } 598 }
514 599
515 return InlineCall(node, new_target, context, frame_state, start, end); 600 return InlineCall(node, new_target, context, frame_state, start, end,
601 exception_target, uncaught_subcalls);
516 } 602 }
517 603
518 Graph* JSInliner::graph() const { return jsgraph()->graph(); } 604 Graph* JSInliner::graph() const { return jsgraph()->graph(); }
519 605
520 JSOperatorBuilder* JSInliner::javascript() const { 606 JSOperatorBuilder* JSInliner::javascript() const {
521 return jsgraph()->javascript(); 607 return jsgraph()->javascript();
522 } 608 }
523 609
524 CommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); } 610 CommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); }
525 611
526 SimplifiedOperatorBuilder* JSInliner::simplified() const { 612 SimplifiedOperatorBuilder* JSInliner::simplified() const {
527 return jsgraph()->simplified(); 613 return jsgraph()->simplified();
528 } 614 }
529 615
530 } // namespace compiler 616 } // namespace compiler
531 } // namespace internal 617 } // namespace internal
532 } // namespace v8 618 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-inlining.h ('k') | src/compiler/js-inlining-heuristic.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698