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.h" | 7 #include "src/ast/ast.h" |
8 #include "src/compilation-info.h" | 8 #include "src/compilation-info.h" |
9 #include "src/compiler.h" | 9 #include "src/compiler.h" |
10 #include "src/compiler/all-nodes.h" | 10 #include "src/compiler/all-nodes.h" |
(...skipping 13 matching lines...) Expand all Loading... |
24 namespace internal { | 24 namespace internal { |
25 namespace compiler { | 25 namespace compiler { |
26 | 26 |
27 #define TRACE(...) \ | 27 #define TRACE(...) \ |
28 do { \ | 28 do { \ |
29 if (FLAG_trace_turbo_inlining) PrintF(__VA_ARGS__); \ | 29 if (FLAG_trace_turbo_inlining) PrintF(__VA_ARGS__); \ |
30 } while (false) | 30 } while (false) |
31 | 31 |
32 | 32 |
33 // Provides convenience accessors for the common layout of nodes having either | 33 // Provides convenience accessors for the common layout of nodes having either |
34 // the {JSCallFunction} or the {JSCallConstruct} operator. | 34 // the {JSCallFunction} or the {JSConstruct} operator. |
35 class JSCallAccessor { | 35 class JSCallAccessor { |
36 public: | 36 public: |
37 explicit JSCallAccessor(Node* call) : call_(call) { | 37 explicit JSCallAccessor(Node* call) : call_(call) { |
38 DCHECK(call->opcode() == IrOpcode::kJSCallFunction || | 38 DCHECK(call->opcode() == IrOpcode::kJSCallFunction || |
39 call->opcode() == IrOpcode::kJSCallConstruct); | 39 call->opcode() == IrOpcode::kJSConstruct); |
40 } | 40 } |
41 | 41 |
42 Node* target() { | 42 Node* target() { |
43 // Both, {JSCallFunction} and {JSCallConstruct}, have same layout here. | 43 // Both, {JSCallFunction} and {JSConstruct}, have same layout here. |
44 return call_->InputAt(0); | 44 return call_->InputAt(0); |
45 } | 45 } |
46 | 46 |
47 Node* receiver() { | 47 Node* receiver() { |
48 DCHECK_EQ(IrOpcode::kJSCallFunction, call_->opcode()); | 48 DCHECK_EQ(IrOpcode::kJSCallFunction, call_->opcode()); |
49 return call_->InputAt(1); | 49 return call_->InputAt(1); |
50 } | 50 } |
51 | 51 |
52 Node* new_target() { | 52 Node* new_target() { |
53 DCHECK_EQ(IrOpcode::kJSCallConstruct, call_->opcode()); | 53 DCHECK_EQ(IrOpcode::kJSConstruct, call_->opcode()); |
54 return call_->InputAt(formal_arguments() + 1); | 54 return call_->InputAt(formal_arguments() + 1); |
55 } | 55 } |
56 | 56 |
57 Node* frame_state() { | 57 Node* frame_state() { |
58 // Both, {JSCallFunction} and {JSCallConstruct}, have frame state. | 58 // Both, {JSCallFunction} and {JSConstruct}, have frame state. |
59 return NodeProperties::GetFrameStateInput(call_); | 59 return NodeProperties::GetFrameStateInput(call_); |
60 } | 60 } |
61 | 61 |
62 int formal_arguments() { | 62 int formal_arguments() { |
63 // Both, {JSCallFunction} and {JSCallConstruct}, have two extra inputs: | 63 // Both, {JSCallFunction} and {JSConstruct}, have two extra inputs: |
64 // - JSCallConstruct: Includes target function and new target. | 64 // - JSConstruct: Includes target function and new target. |
65 // - JSCallFunction: Includes target function and receiver. | 65 // - JSCallFunction: Includes target function and receiver. |
66 return call_->op()->ValueInputCount() - 2; | 66 return call_->op()->ValueInputCount() - 2; |
67 } | 67 } |
68 | 68 |
69 float frequency() const { | 69 float frequency() const { |
70 return (call_->opcode() == IrOpcode::kJSCallFunction) | 70 return (call_->opcode() == IrOpcode::kJSCallFunction) |
71 ? CallFunctionParametersOf(call_->op()).frequency() | 71 ? CallFunctionParametersOf(call_->op()).frequency() |
72 : CallConstructParametersOf(call_->op()).frequency(); | 72 : ConstructParametersOf(call_->op()).frequency(); |
73 } | 73 } |
74 | 74 |
75 private: | 75 private: |
76 Node* call_; | 76 Node* call_; |
77 }; | 77 }; |
78 | 78 |
79 Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, | 79 Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, |
80 Node* frame_state, Node* start, Node* end, | 80 Node* frame_state, Node* start, Node* end, |
81 Node* exception_target, | 81 Node* exception_target, |
82 const NodeVector& uncaught_subcalls) { | 82 const NodeVector& uncaught_subcalls) { |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
347 | 347 |
348 } // namespace | 348 } // namespace |
349 | 349 |
350 | 350 |
351 Reduction JSInliner::Reduce(Node* node) { | 351 Reduction JSInliner::Reduce(Node* node) { |
352 if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange(); | 352 if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange(); |
353 | 353 |
354 // This reducer can handle both normal function calls as well a constructor | 354 // This reducer can handle both normal function calls as well a constructor |
355 // calls whenever the target is a constant function object, as follows: | 355 // calls whenever the target is a constant function object, as follows: |
356 // - JSCallFunction(target:constant, receiver, args...) | 356 // - JSCallFunction(target:constant, receiver, args...) |
357 // - JSCallConstruct(target:constant, args..., new.target) | 357 // - JSConstruct(target:constant, args..., new.target) |
358 HeapObjectMatcher match(node->InputAt(0)); | 358 HeapObjectMatcher match(node->InputAt(0)); |
359 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange(); | 359 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange(); |
360 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value()); | 360 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value()); |
361 | 361 |
362 return ReduceJSCall(node, function); | 362 return ReduceJSCall(node, function); |
363 } | 363 } |
364 | 364 |
365 Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { | 365 Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { |
366 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); | 366 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); |
367 JSCallAccessor call(node); | 367 JSCallAccessor call(node); |
368 Handle<SharedFunctionInfo> shared_info(function->shared()); | 368 Handle<SharedFunctionInfo> shared_info(function->shared()); |
369 | 369 |
370 // Inlining is only supported in the bytecode pipeline. | 370 // Inlining is only supported in the bytecode pipeline. |
371 if (!info_->is_optimizing_from_bytecode()) { | 371 if (!info_->is_optimizing_from_bytecode()) { |
372 TRACE("Inlining %s into %s is not supported in the deprecated pipeline\n", | 372 TRACE("Inlining %s into %s is not supported in the deprecated pipeline\n", |
373 shared_info->DebugName()->ToCString().get(), | 373 shared_info->DebugName()->ToCString().get(), |
374 info_->shared_info()->DebugName()->ToCString().get()); | 374 info_->shared_info()->DebugName()->ToCString().get()); |
375 return NoChange(); | 375 return NoChange(); |
376 } | 376 } |
377 | 377 |
378 // Function must be inlineable. | 378 // Function must be inlineable. |
379 if (!shared_info->IsInlineable()) { | 379 if (!shared_info->IsInlineable()) { |
380 TRACE("Not inlining %s into %s because callee is not inlineable\n", | 380 TRACE("Not inlining %s into %s because callee is not inlineable\n", |
381 shared_info->DebugName()->ToCString().get(), | 381 shared_info->DebugName()->ToCString().get(), |
382 info_->shared_info()->DebugName()->ToCString().get()); | 382 info_->shared_info()->DebugName()->ToCString().get()); |
383 return NoChange(); | 383 return NoChange(); |
384 } | 384 } |
385 | 385 |
386 // Constructor must be constructable. | 386 // Constructor must be constructable. |
387 if (node->opcode() == IrOpcode::kJSCallConstruct && | 387 if (node->opcode() == IrOpcode::kJSConstruct && |
388 IsNonConstructible(shared_info)) { | 388 IsNonConstructible(shared_info)) { |
389 TRACE("Not inlining %s into %s because constructor is not constructable.\n", | 389 TRACE("Not inlining %s into %s because constructor is not constructable.\n", |
390 shared_info->DebugName()->ToCString().get(), | 390 shared_info->DebugName()->ToCString().get(), |
391 info_->shared_info()->DebugName()->ToCString().get()); | 391 info_->shared_info()->DebugName()->ToCString().get()); |
392 return NoChange(); | 392 return NoChange(); |
393 } | 393 } |
394 | 394 |
395 // Class constructors are callable, but [[Call]] will raise an exception. | 395 // Class constructors are callable, but [[Call]] will raise an exception. |
396 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ). | 396 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ). |
397 if (node->opcode() == IrOpcode::kJSCallFunction && | 397 if (node->opcode() == IrOpcode::kJSCallFunction && |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
543 if (!hasIfException) { | 543 if (!hasIfException) { |
544 DCHECK_EQ(2, subnode->op()->ControlOutputCount()); | 544 DCHECK_EQ(2, subnode->op()->ControlOutputCount()); |
545 uncaught_subcalls.push_back(subnode); | 545 uncaught_subcalls.push_back(subnode); |
546 } | 546 } |
547 } | 547 } |
548 } | 548 } |
549 | 549 |
550 Node* frame_state = call.frame_state(); | 550 Node* frame_state = call.frame_state(); |
551 Node* new_target = jsgraph()->UndefinedConstant(); | 551 Node* new_target = jsgraph()->UndefinedConstant(); |
552 | 552 |
553 // Inline {JSCallConstruct} requires some additional magic. | 553 // Inline {JSConstruct} requires some additional magic. |
554 if (node->opcode() == IrOpcode::kJSCallConstruct) { | 554 if (node->opcode() == IrOpcode::kJSConstruct) { |
555 // Insert nodes around the call that model the behavior required for a | 555 // Insert nodes around the call that model the behavior required for a |
556 // constructor dispatch (allocate implicit receiver and check return value). | 556 // constructor dispatch (allocate implicit receiver and check return value). |
557 // This models the behavior usually accomplished by our {JSConstructStub}. | 557 // This models the behavior usually accomplished by our {JSConstructStub}. |
558 // Note that the context has to be the callers context (input to call node). | 558 // Note that the context has to be the callers context (input to call node). |
559 Node* receiver = jsgraph()->TheHoleConstant(); // Implicit receiver. | 559 Node* receiver = jsgraph()->TheHoleConstant(); // Implicit receiver. |
560 if (NeedsImplicitReceiver(shared_info)) { | 560 if (NeedsImplicitReceiver(shared_info)) { |
561 Node* frame_state_before = NodeProperties::FindFrameStateBefore(node); | 561 Node* frame_state_before = NodeProperties::FindFrameStateBefore(node); |
562 Node* effect = NodeProperties::GetEffectInput(node); | 562 Node* effect = NodeProperties::GetEffectInput(node); |
563 Node* context = NodeProperties::GetContextInput(node); | 563 Node* context = NodeProperties::GetContextInput(node); |
564 Node* create = graph()->NewNode(javascript()->Create(), call.target(), | 564 Node* create = graph()->NewNode(javascript()->Create(), call.target(), |
565 call.new_target(), context, | 565 call.new_target(), context, |
566 frame_state_before, effect); | 566 frame_state_before, effect); |
567 NodeProperties::ReplaceEffectInput(node, create); | 567 NodeProperties::ReplaceEffectInput(node, create); |
568 // Insert a check of the return value to determine whether the return | 568 // Insert a check of the return value to determine whether the return |
569 // value or the implicit receiver should be selected as a result of the | 569 // value or the implicit receiver should be selected as a result of the |
570 // call. | 570 // call. |
571 Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), node); | 571 Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), node); |
572 Node* select = | 572 Node* select = |
573 graph()->NewNode(common()->Select(MachineRepresentation::kTagged), | 573 graph()->NewNode(common()->Select(MachineRepresentation::kTagged), |
574 check, node, create); | 574 check, node, create); |
575 NodeProperties::ReplaceUses(node, select, node, node, node); | 575 NodeProperties::ReplaceUses(node, select, node, node, node); |
576 // Fix-up inputs that have been mangled by the {ReplaceUses} call above. | 576 // Fix-up inputs that have been mangled by the {ReplaceUses} call above. |
577 NodeProperties::ReplaceValueInput(select, node, 1); // Fix-up input. | 577 NodeProperties::ReplaceValueInput(select, node, 1); // Fix-up input. |
578 NodeProperties::ReplaceValueInput(check, node, 0); // Fix-up input. | 578 NodeProperties::ReplaceValueInput(check, node, 0); // Fix-up input. |
579 receiver = create; // The implicit receiver. | 579 receiver = create; // The implicit receiver. |
580 } | 580 } |
581 | 581 |
582 // Swizzle the inputs of the {JSCallConstruct} node to look like inputs to a | 582 // Swizzle the inputs of the {JSConstruct} node to look like inputs to a |
583 // normal {JSCallFunction} node so that the rest of the inlining machinery | 583 // normal {JSCallFunction} node so that the rest of the inlining machinery |
584 // behaves as if we were dealing with a regular function invocation. | 584 // behaves as if we were dealing with a regular function invocation. |
585 new_target = call.new_target(); // Retrieve new target value input. | 585 new_target = call.new_target(); // Retrieve new target value input. |
586 node->RemoveInput(call.formal_arguments() + 1); // Drop new target. | 586 node->RemoveInput(call.formal_arguments() + 1); // Drop new target. |
587 node->InsertInput(graph()->zone(), 1, receiver); | 587 node->InsertInput(graph()->zone(), 1, receiver); |
588 | 588 |
589 // Insert a construct stub frame into the chain of frame states. This will | 589 // Insert a construct stub frame into the chain of frame states. This will |
590 // reconstruct the proper frame when deoptimizing within the constructor. | 590 // reconstruct the proper frame when deoptimizing within the constructor. |
591 frame_state = CreateArtificialFrameState( | 591 frame_state = CreateArtificialFrameState( |
592 node, frame_state, call.formal_arguments(), | 592 node, frame_state, call.formal_arguments(), |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
657 | 657 |
658 CommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); } | 658 CommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); } |
659 | 659 |
660 SimplifiedOperatorBuilder* JSInliner::simplified() const { | 660 SimplifiedOperatorBuilder* JSInliner::simplified() const { |
661 return jsgraph()->simplified(); | 661 return jsgraph()->simplified(); |
662 } | 662 } |
663 | 663 |
664 } // namespace compiler | 664 } // namespace compiler |
665 } // namespace internal | 665 } // namespace internal |
666 } // namespace v8 | 666 } // namespace v8 |
OLD | NEW |