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-native-context-specialization.h" | 5 #include "src/compiler/js-native-context-specialization.h" |
6 | 6 |
7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.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" |
11 #include "src/compiler/js-graph.h" | 11 #include "src/compiler/js-graph.h" |
12 #include "src/compiler/js-operator.h" | 12 #include "src/compiler/js-operator.h" |
13 #include "src/compiler/linkage.h" | 13 #include "src/compiler/linkage.h" |
14 #include "src/compiler/node-matchers.h" | 14 #include "src/compiler/node-matchers.h" |
15 #include "src/field-index-inl.h" | 15 #include "src/field-index-inl.h" |
| 16 #include "src/isolate-inl.h" |
16 #include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker! | 17 #include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker! |
17 #include "src/type-cache.h" | 18 #include "src/type-cache.h" |
18 #include "src/type-feedback-vector.h" | 19 #include "src/type-feedback-vector.h" |
19 | 20 |
20 namespace v8 { | 21 namespace v8 { |
21 namespace internal { | 22 namespace internal { |
22 namespace compiler { | 23 namespace compiler { |
23 | 24 |
24 JSNativeContextSpecialization::JSNativeContextSpecialization( | 25 JSNativeContextSpecialization::JSNativeContextSpecialization( |
25 Editor* editor, JSGraph* jsgraph, Flags flags, | 26 Editor* editor, JSGraph* jsgraph, Flags flags, |
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
489 DCHECK_LT(0, receiver_maps.length()); | 490 DCHECK_LT(0, receiver_maps.length()); |
490 | 491 |
491 // Try to lower the named access based on the {receiver_maps}. | 492 // Try to lower the named access based on the {receiver_maps}. |
492 return ReduceNamedAccess(node, value, receiver_maps, p.name(), | 493 return ReduceNamedAccess(node, value, receiver_maps, p.name(), |
493 AccessMode::kStore, p.language_mode()); | 494 AccessMode::kStore, p.language_mode()); |
494 } | 495 } |
495 | 496 |
496 | 497 |
497 Reduction JSNativeContextSpecialization::ReduceElementAccess( | 498 Reduction JSNativeContextSpecialization::ReduceElementAccess( |
498 Node* node, Node* index, Node* value, MapHandleList const& receiver_maps, | 499 Node* node, Node* index, Node* value, MapHandleList const& receiver_maps, |
499 AccessMode access_mode, LanguageMode language_mode) { | 500 AccessMode access_mode, LanguageMode language_mode, |
| 501 KeyedAccessStoreMode store_mode) { |
500 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || | 502 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || |
501 node->opcode() == IrOpcode::kJSStoreProperty); | 503 node->opcode() == IrOpcode::kJSStoreProperty); |
502 Node* receiver = NodeProperties::GetValueInput(node, 0); | 504 Node* receiver = NodeProperties::GetValueInput(node, 0); |
503 Node* context = NodeProperties::GetContextInput(node); | 505 Node* context = NodeProperties::GetContextInput(node); |
504 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); | 506 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
505 Node* effect = NodeProperties::GetEffectInput(node); | 507 Node* effect = NodeProperties::GetEffectInput(node); |
506 Node* control = NodeProperties::GetControlInput(node); | 508 Node* control = NodeProperties::GetControlInput(node); |
507 | 509 |
508 // Not much we can do if deoptimization support is disabled. | 510 // Not much we can do if deoptimization support is disabled. |
509 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | 511 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); |
510 | 512 |
| 513 // TODO(bmeurer): Add support for non-standard stores. |
| 514 if (store_mode != STANDARD_STORE) return NoChange(); |
| 515 |
511 // Compute element access infos for the receiver maps. | 516 // Compute element access infos for the receiver maps. |
512 ZoneVector<ElementAccessInfo> access_infos(zone()); | 517 ZoneVector<ElementAccessInfo> access_infos(zone()); |
513 if (!access_info_factory().ComputeElementAccessInfos( | 518 if (!access_info_factory().ComputeElementAccessInfos( |
514 receiver_maps, access_mode, &access_infos)) { | 519 receiver_maps, access_mode, &access_infos)) { |
515 return NoChange(); | 520 return NoChange(); |
516 } | 521 } |
517 | 522 |
518 // Nothing to do if we have no non-deprecated maps. | 523 // Nothing to do if we have no non-deprecated maps. |
519 if (access_infos.empty()) return NoChange(); | 524 if (access_infos.empty()) return NoChange(); |
520 | 525 |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
721 if (IsFastDoubleElementsKind(elements_kind)) { | 726 if (IsFastDoubleElementsKind(elements_kind)) { |
722 element_type = type_cache_.kFloat64; | 727 element_type = type_cache_.kFloat64; |
723 element_machine_type = kMachFloat64; | 728 element_machine_type = kMachFloat64; |
724 } else if (IsFastSmiElementsKind(elements_kind)) { | 729 } else if (IsFastSmiElementsKind(elements_kind)) { |
725 element_type = type_cache_.kSmi; | 730 element_type = type_cache_.kSmi; |
726 } | 731 } |
727 ElementAccess element_access = {kTaggedBase, FixedArray::kHeaderSize, | 732 ElementAccess element_access = {kTaggedBase, FixedArray::kHeaderSize, |
728 element_type, element_machine_type}; | 733 element_type, element_machine_type}; |
729 | 734 |
730 // Access the actual element. | 735 // Access the actual element. |
| 736 // TODO(bmeurer): Refactor this into separate methods or even a separate |
| 737 // class that deals with the elements access. |
731 if (access_mode == AccessMode::kLoad) { | 738 if (access_mode == AccessMode::kLoad) { |
| 739 // Compute the real element access type, which includes the hole in case |
| 740 // of holey backing stores. |
| 741 if (elements_kind == FAST_HOLEY_ELEMENTS || |
| 742 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { |
| 743 element_access.type = Type::Union( |
| 744 element_type, |
| 745 Type::Constant(factory()->the_hole_value(), graph()->zone()), |
| 746 graph()->zone()); |
| 747 } |
| 748 // Perform the actual backing store access. |
732 this_value = this_effect = graph()->NewNode( | 749 this_value = this_effect = graph()->NewNode( |
733 simplified()->LoadElement(element_access), this_elements, this_index, | 750 simplified()->LoadElement(element_access), this_elements, this_index, |
734 this_effect, this_control); | 751 this_effect, this_control); |
| 752 // Handle loading from holey backing stores correctly, by either mapping |
| 753 // the hole to undefined if possible, or deoptimizing otherwise. |
| 754 if (elements_kind == FAST_HOLEY_ELEMENTS || |
| 755 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { |
| 756 // Perform the hole check on the result. |
| 757 Node* check = |
| 758 graph()->NewNode(simplified()->ReferenceEqual(element_access.type), |
| 759 this_value, jsgraph()->TheHoleConstant()); |
| 760 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 761 check, this_control); |
| 762 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 763 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 764 // Check if we are allowed to turn the hole into undefined. |
| 765 Type* initial_holey_array_type = Type::Class( |
| 766 handle(isolate()->get_initial_js_array_map(FAST_HOLEY_ELEMENTS)), |
| 767 graph()->zone()); |
| 768 if (receiver_type->NowIs(initial_holey_array_type) && |
| 769 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { |
| 770 // Add a code dependency on the array protector cell. |
| 771 AssumePrototypesStable(receiver_type, |
| 772 isolate()->initial_object_prototype()); |
| 773 dependencies()->AssumePropertyCell(factory()->array_protector()); |
| 774 // Turn the hole into undefined. |
| 775 this_control = |
| 776 graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 777 this_value = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), |
| 778 jsgraph()->UndefinedConstant(), |
| 779 this_value, this_control); |
| 780 element_type = |
| 781 Type::Union(element_type, Type::Undefined(), graph()->zone()); |
| 782 } else { |
| 783 // Deoptimize in case of the hole. |
| 784 exit_controls.push_back(if_true); |
| 785 this_control = if_false; |
| 786 } |
| 787 // Rename the result to represent the actual type (not polluted by the |
| 788 // hole). |
| 789 this_value = graph()->NewNode(common()->Guard(element_type), this_value, |
| 790 this_control); |
| 791 } |
735 } else { | 792 } else { |
736 DCHECK_EQ(AccessMode::kStore, access_mode); | 793 DCHECK_EQ(AccessMode::kStore, access_mode); |
737 if (IsFastSmiElementsKind(elements_kind)) { | 794 if (IsFastSmiElementsKind(elements_kind)) { |
738 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), this_value); | 795 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), this_value); |
739 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), | 796 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
740 check, this_control); | 797 check, this_control); |
741 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch)); | 798 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch)); |
742 this_control = graph()->NewNode(common()->IfTrue(), branch); | 799 this_control = graph()->NewNode(common()->IfTrue(), branch); |
743 } else if (IsFastDoubleElementsKind(elements_kind)) { | 800 } else if (IsFastDoubleElementsKind(elements_kind)) { |
744 Node* check = | 801 Node* check = |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
802 effect = graph()->NewNode(common()->EffectPhi(control_count), | 859 effect = graph()->NewNode(common()->EffectPhi(control_count), |
803 control_count + 1, &effects.front()); | 860 control_count + 1, &effects.front()); |
804 } | 861 } |
805 ReplaceWithValue(node, value, effect, control); | 862 ReplaceWithValue(node, value, effect, control); |
806 return Replace(value); | 863 return Replace(value); |
807 } | 864 } |
808 | 865 |
809 | 866 |
810 Reduction JSNativeContextSpecialization::ReduceKeyedAccess( | 867 Reduction JSNativeContextSpecialization::ReduceKeyedAccess( |
811 Node* node, Node* index, Node* value, FeedbackNexus const& nexus, | 868 Node* node, Node* index, Node* value, FeedbackNexus const& nexus, |
812 AccessMode access_mode, LanguageMode language_mode) { | 869 AccessMode access_mode, LanguageMode language_mode, |
| 870 KeyedAccessStoreMode store_mode) { |
813 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || | 871 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || |
814 node->opcode() == IrOpcode::kJSStoreProperty); | 872 node->opcode() == IrOpcode::kJSStoreProperty); |
815 | 873 |
816 // Extract receiver maps from the {nexus}. | 874 // Extract receiver maps from the {nexus}. |
817 MapHandleList receiver_maps; | 875 MapHandleList receiver_maps; |
818 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange(); | 876 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange(); |
819 DCHECK_LT(0, receiver_maps.length()); | 877 DCHECK_LT(0, receiver_maps.length()); |
820 | 878 |
821 // Optimize access for constant {index}. | 879 // Optimize access for constant {index}. |
822 HeapObjectMatcher mindex(index); | 880 HeapObjectMatcher mindex(index); |
(...skipping 18 matching lines...) Expand all Loading... |
841 | 899 |
842 // Check if we have feedback for a named access. | 900 // Check if we have feedback for a named access. |
843 if (Name* name = nexus.FindFirstName()) { | 901 if (Name* name = nexus.FindFirstName()) { |
844 return ReduceNamedAccess(node, value, receiver_maps, | 902 return ReduceNamedAccess(node, value, receiver_maps, |
845 handle(name, isolate()), access_mode, | 903 handle(name, isolate()), access_mode, |
846 language_mode, index); | 904 language_mode, index); |
847 } | 905 } |
848 | 906 |
849 // Try to lower the element access based on the {receiver_maps}. | 907 // Try to lower the element access based on the {receiver_maps}. |
850 return ReduceElementAccess(node, index, value, receiver_maps, access_mode, | 908 return ReduceElementAccess(node, index, value, receiver_maps, access_mode, |
851 language_mode); | 909 language_mode, store_mode); |
852 } | 910 } |
853 | 911 |
854 | 912 |
855 Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) { | 913 Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) { |
856 DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode()); | 914 DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode()); |
857 PropertyAccess const& p = PropertyAccessOf(node->op()); | 915 PropertyAccess const& p = PropertyAccessOf(node->op()); |
858 Node* const index = NodeProperties::GetValueInput(node, 1); | 916 Node* const index = NodeProperties::GetValueInput(node, 1); |
859 Node* const value = jsgraph()->Dead(); | 917 Node* const value = jsgraph()->Dead(); |
860 | 918 |
861 // Extract receiver maps from the KEYED_LOAD_IC using the KeyedLoadICNexus. | 919 // Extract receiver maps from the KEYED_LOAD_IC using the KeyedLoadICNexus. |
862 if (!p.feedback().IsValid()) return NoChange(); | 920 if (!p.feedback().IsValid()) return NoChange(); |
863 KeyedLoadICNexus nexus(p.feedback().vector(), p.feedback().slot()); | 921 KeyedLoadICNexus nexus(p.feedback().vector(), p.feedback().slot()); |
864 | 922 |
865 // Try to lower the keyed access based on the {nexus}. | 923 // Try to lower the keyed access based on the {nexus}. |
866 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kLoad, | 924 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kLoad, |
867 p.language_mode()); | 925 p.language_mode(), STANDARD_STORE); |
868 } | 926 } |
869 | 927 |
870 | 928 |
871 Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) { | 929 Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) { |
872 DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode()); | 930 DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode()); |
873 PropertyAccess const& p = PropertyAccessOf(node->op()); | 931 PropertyAccess const& p = PropertyAccessOf(node->op()); |
874 Node* const index = NodeProperties::GetValueInput(node, 1); | 932 Node* const index = NodeProperties::GetValueInput(node, 1); |
875 Node* const value = NodeProperties::GetValueInput(node, 2); | 933 Node* const value = NodeProperties::GetValueInput(node, 2); |
876 | 934 |
877 // Extract receiver maps from the KEYED_STORE_IC using the KeyedStoreICNexus. | 935 // Extract receiver maps from the KEYED_STORE_IC using the KeyedStoreICNexus. |
878 if (!p.feedback().IsValid()) return NoChange(); | 936 if (!p.feedback().IsValid()) return NoChange(); |
879 KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot()); | 937 KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot()); |
880 | 938 |
| 939 // Extract the keyed access store mode from the KEYED_STORE_IC. |
| 940 KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode(); |
| 941 |
881 // Try to lower the keyed access based on the {nexus}. | 942 // Try to lower the keyed access based on the {nexus}. |
882 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore, | 943 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore, |
883 p.language_mode()); | 944 p.language_mode(), store_mode); |
884 } | 945 } |
885 | 946 |
886 | 947 |
887 void JSNativeContextSpecialization::AssumePrototypesStable( | 948 void JSNativeContextSpecialization::AssumePrototypesStable( |
888 Type* receiver_type, Handle<JSObject> holder) { | 949 Type* receiver_type, Handle<JSObject> holder) { |
889 // Determine actual holder and perform prototype chain checks. | 950 // Determine actual holder and perform prototype chain checks. |
890 for (auto i = receiver_type->Classes(); !i.Done(); i.Advance()) { | 951 for (auto i = receiver_type->Classes(); !i.Done(); i.Advance()) { |
891 Handle<Map> map = i.Current(); | 952 Handle<Map> map = i.Current(); |
892 // Perform the implicit ToObject for primitives here. | 953 // Perform the implicit ToObject for primitives here. |
893 // Implemented according to ES6 section 7.3.2 GetV (V, P). | 954 // Implemented according to ES6 section 7.3.2 GetV (V, P). |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
952 } | 1013 } |
953 | 1014 |
954 | 1015 |
955 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 1016 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
956 return jsgraph()->simplified(); | 1017 return jsgraph()->simplified(); |
957 } | 1018 } |
958 | 1019 |
959 } // namespace compiler | 1020 } // namespace compiler |
960 } // namespace internal | 1021 } // namespace internal |
961 } // namespace v8 | 1022 } // namespace v8 |
OLD | NEW |