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

Side by Side Diff: src/compiler/js-call-reducer.cc

Issue 2956233002: [turbofan] Further optimize spread/apply with arguments/rest parameters. (Closed)
Patch Set: Fix nit. Created 3 years, 5 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-call-reducer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 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-call-reducer.h" 5 #include "src/compiler/js-call-reducer.h"
6 6
7 #include "src/code-factory.h" 7 #include "src/code-factory.h"
8 #include "src/code-stubs.h" 8 #include "src/code-stubs.h"
9 #include "src/compilation-dependencies.h" 9 #include "src/compilation-dependencies.h"
10 #include "src/compiler/access-builder.h" 10 #include "src/compiler/access-builder.h"
(...skipping 22 matching lines...) Expand all
33 case IrOpcode::kJSCallWithArrayLike: 33 case IrOpcode::kJSCallWithArrayLike:
34 return ReduceJSCallWithArrayLike(node); 34 return ReduceJSCallWithArrayLike(node);
35 case IrOpcode::kJSCallWithSpread: 35 case IrOpcode::kJSCallWithSpread:
36 return ReduceJSCallWithSpread(node); 36 return ReduceJSCallWithSpread(node);
37 default: 37 default:
38 break; 38 break;
39 } 39 }
40 return NoChange(); 40 return NoChange();
41 } 41 }
42 42
43 void JSCallReducer::Finalize() {
44 // TODO(turbofan): This is not the best solution; ideally we would be able
45 // to teach the GraphReducer about arbitrary dependencies between different
46 // nodes, even if they don't show up in the use list of the other node.
47 std::set<Node*> const waitlist = std::move(waitlist_);
48 for (Node* node : waitlist) {
49 if (!node->IsDead()) {
50 Reduction const reduction = Reduce(node);
51 if (reduction.Changed()) {
52 Node* replacement = reduction.replacement();
53 if (replacement != node) {
54 Replace(node, replacement);
55 }
56 }
57 }
58 }
59 }
43 60
44 // ES6 section 22.1.1 The Array Constructor 61 // ES6 section 22.1.1 The Array Constructor
45 Reduction JSCallReducer::ReduceArrayConstructor(Node* node) { 62 Reduction JSCallReducer::ReduceArrayConstructor(Node* node) {
46 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); 63 DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
47 Node* target = NodeProperties::GetValueInput(node, 0); 64 Node* target = NodeProperties::GetValueInput(node, 0);
48 CallParameters const& p = CallParametersOf(node->op()); 65 CallParameters const& p = CallParametersOf(node->op());
49 66
50 // Check if we have an allocation site from the CallIC. 67 // Check if we have an allocation site from the CallIC.
51 Handle<AllocationSite> site; 68 Handle<AllocationSite> site;
52 if (p.feedback().IsValid()) { 69 if (p.feedback().IsValid()) {
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after
679 jsgraph()->HeapConstant(stub.GetCode())); 696 jsgraph()->HeapConstant(stub.GetCode()));
680 node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(data)); 697 node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(data));
681 node->InsertInput(graph()->zone(), 3, holder); 698 node->InsertInput(graph()->zone(), 3, holder);
682 node->InsertInput(graph()->zone(), 4, 699 node->InsertInput(graph()->zone(), 4,
683 jsgraph()->ExternalConstant(function_reference)); 700 jsgraph()->ExternalConstant(function_reference));
684 node->ReplaceInput(5, receiver); 701 node->ReplaceInput(5, receiver);
685 NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); 702 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
686 return Changed(node); 703 return Changed(node);
687 } 704 }
688 705
706 namespace {
707
708 // Check whether elements aren't mutated; we play it extremely safe here by
709 // explicitly checking that {node} is only used by {LoadField} or {LoadElement}.
710 bool IsSafeArgumentsElements(Node* node) {
711 for (Edge const edge : node->use_edges()) {
712 if (!NodeProperties::IsValueEdge(edge)) continue;
713 if (edge.from()->opcode() != IrOpcode::kLoadField &&
714 edge.from()->opcode() != IrOpcode::kLoadElement) {
715 return false;
716 }
717 }
718 return true;
719 }
720
721 } // namespace
722
689 Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread( 723 Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
690 Node* node, int arity, CallFrequency const& frequency) { 724 Node* node, int arity, CallFrequency const& frequency) {
691 DCHECK(node->opcode() == IrOpcode::kJSCallWithArrayLike || 725 DCHECK(node->opcode() == IrOpcode::kJSCallWithArrayLike ||
692 node->opcode() == IrOpcode::kJSCallWithSpread || 726 node->opcode() == IrOpcode::kJSCallWithSpread ||
693 node->opcode() == IrOpcode::kJSConstructWithArrayLike || 727 node->opcode() == IrOpcode::kJSConstructWithArrayLike ||
694 node->opcode() == IrOpcode::kJSConstructWithSpread); 728 node->opcode() == IrOpcode::kJSConstructWithSpread);
695 729
696 // In case of a call/construct with spread, we need to 730 // In case of a call/construct with spread, we need to
697 // ensure that it's safe to avoid the actual iteration. 731 // ensure that it's safe to avoid the actual iteration.
698 if ((node->opcode() == IrOpcode::kJSCallWithSpread || 732 if ((node->opcode() == IrOpcode::kJSCallWithSpread ||
699 node->opcode() == IrOpcode::kJSConstructWithSpread) && 733 node->opcode() == IrOpcode::kJSConstructWithSpread) &&
700 !isolate()->initial_array_iterator_prototype_map()->is_stable()) { 734 !isolate()->initial_array_iterator_prototype_map()->is_stable()) {
701 return NoChange(); 735 return NoChange();
702 } 736 }
703 737
704 // Check if {arguments_list} is an arguments object, and {node} is the only 738 // Check if {arguments_list} is an arguments object, and {node} is the only
705 // value user of {arguments_list} (except for value uses in frame states). 739 // value user of {arguments_list} (except for value uses in frame states).
706 Node* arguments_list = NodeProperties::GetValueInput(node, arity); 740 Node* arguments_list = NodeProperties::GetValueInput(node, arity);
707 if (arguments_list->opcode() != IrOpcode::kJSCreateArguments) 741 if (arguments_list->opcode() != IrOpcode::kJSCreateArguments) {
708 return NoChange(); 742 return NoChange();
743 }
709 for (Edge edge : arguments_list->use_edges()) { 744 for (Edge edge : arguments_list->use_edges()) {
745 if (!NodeProperties::IsValueEdge(edge)) continue;
710 Node* const user = edge.from(); 746 Node* const user = edge.from();
711 if (user == node) continue; 747 switch (user->opcode()) {
712 // Ignore uses as frame state's locals or parameters. 748 case IrOpcode::kCheckMaps:
713 if (user->opcode() == IrOpcode::kStateValues) continue; 749 case IrOpcode::kFrameState:
714 // Ignore uses as frame state's accumulator. 750 case IrOpcode::kStateValues:
715 if (user->opcode() == IrOpcode::kFrameState && 751 case IrOpcode::kReferenceEqual:
716 user->InputAt(2) == arguments_list) { 752 case IrOpcode::kReturn:
717 continue; 753 // Ignore safe uses that definitely don't mess with the arguments.
754 continue;
755 case IrOpcode::kLoadField: {
756 DCHECK_EQ(arguments_list, user->InputAt(0));
757 FieldAccess const& access = FieldAccessOf(user->op());
758 if (access.offset == JSArray::kLengthOffset) {
759 // Ignore uses for arguments#length.
760 STATIC_ASSERT(JSArray::kLengthOffset ==
761 JSArgumentsObject::kLengthOffset);
762 continue;
763 } else if (access.offset == JSObject::kElementsOffset) {
764 // Ignore safe uses for arguments#elements.
765 if (IsSafeArgumentsElements(user)) continue;
766 }
767 break;
768 }
769 case IrOpcode::kJSCallWithArrayLike:
770 // Ignore uses as argumentsList input to calls with array like.
771 if (user->InputAt(2) == arguments_list) continue;
772 break;
773 case IrOpcode::kJSConstructWithArrayLike:
774 // Ignore uses as argumentsList input to calls with array like.
775 if (user->InputAt(1) == arguments_list) continue;
776 break;
777 case IrOpcode::kJSCallWithSpread: {
778 // Ignore uses as spread input to calls with spread.
779 SpreadWithArityParameter p = SpreadWithArityParameterOf(user->op());
780 int const arity = static_cast<int>(p.arity() - 1);
781 if (user->InputAt(arity) == arguments_list) continue;
782 break;
783 }
784 case IrOpcode::kJSConstructWithSpread: {
785 // Ignore uses as spread input to construct with spread.
786 SpreadWithArityParameter p = SpreadWithArityParameterOf(user->op());
787 int const arity = static_cast<int>(p.arity() - 2);
788 if (user->InputAt(arity) == arguments_list) continue;
789 break;
790 }
791 default:
792 break;
718 } 793 }
719 if (!NodeProperties::IsValueEdge(edge)) continue; 794 // We cannot currently reduce the {node} to something better than what
795 // it already is, but we might be able to do something about the {node}
796 // later, so put it on the waitlist and try again during finalization.
797 waitlist_.insert(node);
720 return NoChange(); 798 return NoChange();
721 } 799 }
722 800
723 // Get to the actual frame state from which to extract the arguments; 801 // Get to the actual frame state from which to extract the arguments;
724 // we can only optimize this in case the {node} was already inlined into 802 // we can only optimize this in case the {node} was already inlined into
725 // some other function (and same for the {arguments_list}). 803 // some other function (and same for the {arguments_list}).
726 CreateArgumentsType const type = CreateArgumentsTypeOf(arguments_list->op()); 804 CreateArgumentsType const type = CreateArgumentsTypeOf(arguments_list->op());
727 Node* frame_state = NodeProperties::GetFrameStateInput(arguments_list); 805 Node* frame_state = NodeProperties::GetFrameStateInput(arguments_list);
728 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state); 806 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
729 int start_index = 0; 807 int start_index = 0;
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after
1186 return jsgraph()->javascript(); 1264 return jsgraph()->javascript();
1187 } 1265 }
1188 1266
1189 SimplifiedOperatorBuilder* JSCallReducer::simplified() const { 1267 SimplifiedOperatorBuilder* JSCallReducer::simplified() const {
1190 return jsgraph()->simplified(); 1268 return jsgraph()->simplified();
1191 } 1269 }
1192 1270
1193 } // namespace compiler 1271 } // namespace compiler
1194 } // namespace internal 1272 } // namespace internal
1195 } // namespace v8 1273 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-call-reducer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698