| 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 |