OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |