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

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: Don't inspect control outputs if the operator is NoThrow 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
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 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
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
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 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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698