OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/code-stubs.h" | 5 #include "src/code-stubs.h" |
6 | 6 |
7 #include "src/bailout-reason.h" | 7 #include "src/bailout-reason.h" |
8 #include "src/crankshaft/hydrogen.h" | 8 #include "src/crankshaft/hydrogen.h" |
9 #include "src/crankshaft/lithium.h" | 9 #include "src/crankshaft/lithium.h" |
10 #include "src/field-index.h" | 10 #include "src/field-index.h" |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 CompilationInfo* info() { return info_; } | 71 CompilationInfo* info() { return info_; } |
72 CodeStub* stub() { return code_stub_; } | 72 CodeStub* stub() { return code_stub_; } |
73 HContext* context() { return context_; } | 73 HContext* context() { return context_; } |
74 Isolate* isolate() { return info_->isolate(); } | 74 Isolate* isolate() { return info_->isolate(); } |
75 | 75 |
76 HLoadNamedField* BuildLoadNamedField(HValue* object, FieldIndex index); | 76 HLoadNamedField* BuildLoadNamedField(HValue* object, FieldIndex index); |
77 void BuildStoreNamedField(HValue* object, HValue* value, FieldIndex index, | 77 void BuildStoreNamedField(HValue* object, HValue* value, FieldIndex index, |
78 Representation representation, | 78 Representation representation, |
79 bool transition_to_field); | 79 bool transition_to_field); |
80 | 80 |
| 81 HValue* BuildPushElement(HValue* object, HValue* value, ElementsKind kind); |
| 82 |
81 enum ArgumentClass { | 83 enum ArgumentClass { |
82 NONE, | 84 NONE, |
83 SINGLE, | 85 SINGLE, |
84 MULTIPLE | 86 MULTIPLE |
85 }; | 87 }; |
86 | 88 |
87 HValue* UnmappedCase(HValue* elements, HValue* key, HValue* value); | 89 HValue* UnmappedCase(HValue* elements, HValue* key, HValue* value); |
88 HValue* EmitKeyedSloppyArguments(HValue* receiver, HValue* key, | 90 HValue* EmitKeyedSloppyArguments(HValue* receiver, HValue* key, |
89 HValue* value); | 91 HValue* value); |
90 | 92 |
(...skipping 682 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
773 HObjectAccess::ForContextSlot(slot_index), | 775 HObjectAccess::ForContextSlot(slot_index), |
774 GetParameter(2), STORE_TO_INITIALIZED_ENTRY); | 776 GetParameter(2), STORE_TO_INITIALIZED_ENTRY); |
775 return GetParameter(2); | 777 return GetParameter(2); |
776 } | 778 } |
777 | 779 |
778 | 780 |
779 Handle<Code> StoreScriptContextFieldStub::GenerateCode() { | 781 Handle<Code> StoreScriptContextFieldStub::GenerateCode() { |
780 return DoGenerateCode(this); | 782 return DoGenerateCode(this); |
781 } | 783 } |
782 | 784 |
| 785 HValue* CodeStubGraphBuilderBase::BuildPushElement(HValue* object, |
| 786 HValue* value, |
| 787 ElementsKind kind) { |
| 788 HValue* length = Add<HLoadNamedField>(object, nullptr, |
| 789 HObjectAccess::ForArrayLength(kind)); |
| 790 HValue* key = length; |
| 791 HValue* elements = Add<HLoadNamedField>(object, nullptr, |
| 792 HObjectAccess::ForElementsPointer()); |
| 793 elements = BuildCheckForCapacityGrow(object, elements, kind, length, key, |
| 794 true, STORE); |
| 795 AddElementAccess(elements, key, value, object, nullptr, kind, STORE); |
| 796 return key; |
| 797 } |
| 798 |
| 799 template <> |
| 800 HValue* CodeStubGraphBuilder<FastArrayPushStub>::BuildCodeStub() { |
| 801 // TODO(verwaest): Fix deoptimizer messages. |
| 802 HValue* argc = GetArgumentsLength(); |
| 803 IfBuilder arg_check(this); |
| 804 arg_check.If<HCompareNumericAndBranch>(argc, graph()->GetConstant1(), |
| 805 Token::NE); |
| 806 arg_check.ThenDeopt(Deoptimizer::kFastArrayPushFailed); |
| 807 arg_check.End(); |
| 808 |
| 809 HInstruction* argument_elements = Add<HArgumentsElements>(false, false); |
| 810 HInstruction* object = Add<HAccessArgumentsAt>(argument_elements, argc, |
| 811 graph()->GetConstantMinus1()); |
| 812 HInstruction* value = |
| 813 Add<HAccessArgumentsAt>(argument_elements, argc, graph()->GetConstant0()); |
| 814 |
| 815 BuildCheckHeapObject(object); |
| 816 HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap()); |
| 817 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_JS_ARRAY); |
| 818 |
| 819 // Disallow pushing onto prototypes. It might be the JSArray prototype. |
| 820 // Disallow pushing onto non-extensible objects. |
| 821 { |
| 822 HValue* bit_field2 = |
| 823 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2()); |
| 824 HValue* mask = |
| 825 Add<HConstant>(static_cast<int>(Map::IsPrototypeMapBits::kMask) | |
| 826 (1 << Map::kIsExtensible)); |
| 827 HValue* bits = AddUncasted<HBitwise>(Token::BIT_AND, bit_field2, mask); |
| 828 IfBuilder check(this); |
| 829 check.If<HCompareNumericAndBranch>( |
| 830 bits, Add<HConstant>(1 << Map::kIsExtensible), Token::NE); |
| 831 check.ThenDeopt(Deoptimizer::kFastArrayPushFailed); |
| 832 check.End(); |
| 833 } |
| 834 |
| 835 // Disallow pushing onto observed objects. |
| 836 { |
| 837 HValue* bit_field = |
| 838 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField()); |
| 839 HValue* mask = Add<HConstant>(1 << Map::kIsObserved); |
| 840 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field, mask); |
| 841 IfBuilder check(this); |
| 842 check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); |
| 843 check.ThenDeopt(Deoptimizer::kFastArrayPushFailed); |
| 844 check.End(); |
| 845 } |
| 846 |
| 847 // Disallow pushing onto arrays in dictionary named property mode. We need to |
| 848 // figure out whether the length property is still writable. |
| 849 { |
| 850 HValue* bit_field3 = |
| 851 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3()); |
| 852 HValue* mask = Add<HConstant>(static_cast<int>(Map::DictionaryMap::kMask)); |
| 853 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field3, mask); |
| 854 IfBuilder check(this); |
| 855 check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); |
| 856 check.ThenDeopt(Deoptimizer::kFastArrayPushFailed); |
| 857 check.End(); |
| 858 } |
| 859 |
| 860 // Check whether the length property is writable. The length property is the |
| 861 // only default named property on arrays. It's nonconfigurable, hence is |
| 862 // guaranteed to stay the first property. |
| 863 { |
| 864 HValue* descriptors = |
| 865 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapDescriptors()); |
| 866 HValue* details = Add<HLoadKeyed>( |
| 867 descriptors, Add<HConstant>(DescriptorArray::ToDetailsIndex(0)), |
| 868 nullptr, nullptr, FAST_SMI_ELEMENTS); |
| 869 HValue* mask = |
| 870 Add<HConstant>(READ_ONLY << PropertyDetails::AttributesField::kShift); |
| 871 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, details, mask); |
| 872 IfBuilder readonly(this); |
| 873 readonly.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); |
| 874 readonly.ThenDeopt(Deoptimizer::kFastArrayPushFailed); |
| 875 readonly.End(); |
| 876 } |
| 877 |
| 878 HValue* null = Add<HLoadRoot>(Heap::kNullValueRootIndex); |
| 879 HValue* empty = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex); |
| 880 environment()->Push(map); |
| 881 LoopBuilder check_prototypes(this); |
| 882 check_prototypes.BeginBody(1); |
| 883 { |
| 884 HValue* parent_map = environment()->Pop(); |
| 885 HValue* prototype = Add<HLoadNamedField>(parent_map, nullptr, |
| 886 HObjectAccess::ForPrototype()); |
| 887 |
| 888 IfBuilder is_null(this); |
| 889 is_null.If<HCompareObjectEqAndBranch>(prototype, null); |
| 890 is_null.Then(); |
| 891 check_prototypes.Break(); |
| 892 is_null.End(); |
| 893 |
| 894 HValue* prototype_map = |
| 895 Add<HLoadNamedField>(prototype, nullptr, HObjectAccess::ForMap()); |
| 896 HValue* instance_type = Add<HLoadNamedField>( |
| 897 prototype_map, nullptr, HObjectAccess::ForMapInstanceType()); |
| 898 IfBuilder check_instance_type(this); |
| 899 check_instance_type.If<HCompareNumericAndBranch>( |
| 900 instance_type, Add<HConstant>(LAST_CUSTOM_ELEMENTS_RECEIVER), |
| 901 Token::LTE); |
| 902 check_instance_type.ThenDeopt(Deoptimizer::kFastArrayPushFailed); |
| 903 check_instance_type.End(); |
| 904 |
| 905 HValue* elements = Add<HLoadNamedField>( |
| 906 prototype, nullptr, HObjectAccess::ForElementsPointer()); |
| 907 IfBuilder no_elements(this); |
| 908 no_elements.IfNot<HCompareObjectEqAndBranch>(elements, empty); |
| 909 no_elements.ThenDeopt(Deoptimizer::kFastArrayPushFailed); |
| 910 no_elements.End(); |
| 911 |
| 912 environment()->Push(prototype_map); |
| 913 } |
| 914 check_prototypes.EndBody(); |
| 915 |
| 916 HValue* bit_field2 = |
| 917 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2()); |
| 918 HValue* kind = BuildDecodeField<Map::ElementsKindBits>(bit_field2); |
| 919 |
| 920 // Below we only check the upper bound of the relevant ranges to include both |
| 921 // holey and non-holey versions. We check them in order smi, object, double |
| 922 // since smi < object < double. |
| 923 STATIC_ASSERT(FAST_SMI_ELEMENTS < FAST_HOLEY_SMI_ELEMENTS); |
| 924 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS < FAST_HOLEY_ELEMENTS); |
| 925 STATIC_ASSERT(FAST_ELEMENTS < FAST_HOLEY_ELEMENTS); |
| 926 STATIC_ASSERT(FAST_HOLEY_ELEMENTS < FAST_HOLEY_DOUBLE_ELEMENTS); |
| 927 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FAST_HOLEY_DOUBLE_ELEMENTS); |
| 928 IfBuilder has_smi_elements(this); |
| 929 has_smi_elements.If<HCompareNumericAndBranch>( |
| 930 kind, Add<HConstant>(FAST_HOLEY_SMI_ELEMENTS), Token::LTE); |
| 931 has_smi_elements.Then(); |
| 932 { |
| 933 HValue* smi_value = |
| 934 AddUncasted<HForceRepresentation>(value, Representation::Smi()); |
| 935 HValue* key = BuildPushElement(object, smi_value, FAST_HOLEY_SMI_ELEMENTS); |
| 936 environment()->Push(key); |
| 937 } |
| 938 has_smi_elements.Else(); |
| 939 { |
| 940 IfBuilder has_object_elements(this); |
| 941 has_object_elements.If<HCompareNumericAndBranch>( |
| 942 kind, Add<HConstant>(FAST_HOLEY_ELEMENTS), Token::LTE); |
| 943 has_object_elements.Then(); |
| 944 { |
| 945 HValue* key = BuildPushElement(object, value, FAST_HOLEY_ELEMENTS); |
| 946 environment()->Push(key); |
| 947 } |
| 948 has_object_elements.Else(); |
| 949 { |
| 950 IfBuilder has_double_elements(this); |
| 951 has_double_elements.If<HCompareNumericAndBranch>( |
| 952 kind, Add<HConstant>(FAST_HOLEY_DOUBLE_ELEMENTS), Token::LTE); |
| 953 has_double_elements.Then(); |
| 954 { |
| 955 HValue* double_value = |
| 956 AddUncasted<HForceRepresentation>(value, Representation::Double()); |
| 957 HValue* key = |
| 958 BuildPushElement(object, double_value, FAST_HOLEY_DOUBLE_ELEMENTS); |
| 959 environment()->Push(key); |
| 960 } |
| 961 has_double_elements.ElseDeopt(Deoptimizer::kFastArrayPushFailed); |
| 962 has_double_elements.End(); |
| 963 } |
| 964 has_object_elements.End(); |
| 965 } |
| 966 has_smi_elements.End(); |
| 967 |
| 968 HValue* key = environment()->Pop(); |
| 969 return AddUncasted<HAdd>(key, graph()->GetConstant1()); |
| 970 } |
| 971 |
| 972 Handle<Code> FastArrayPushStub::GenerateCode() { return DoGenerateCode(this); } |
783 | 973 |
784 template <> | 974 template <> |
785 HValue* CodeStubGraphBuilder<GrowArrayElementsStub>::BuildCodeStub() { | 975 HValue* CodeStubGraphBuilder<GrowArrayElementsStub>::BuildCodeStub() { |
786 ElementsKind kind = casted_stub()->elements_kind(); | 976 ElementsKind kind = casted_stub()->elements_kind(); |
787 if (IsFastDoubleElementsKind(kind)) { | 977 if (IsFastDoubleElementsKind(kind)) { |
788 info()->MarkAsSavesCallerDoubles(); | 978 info()->MarkAsSavesCallerDoubles(); |
789 } | 979 } |
790 | 980 |
791 HValue* object = GetParameter(GrowArrayElementsDescriptor::kObjectIndex); | 981 HValue* object = GetParameter(GrowArrayElementsDescriptor::kObjectIndex); |
792 HValue* key = GetParameter(GrowArrayElementsDescriptor::kKeyIndex); | 982 HValue* key = GetParameter(GrowArrayElementsDescriptor::kKeyIndex); |
(...skipping 1570 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2363 return Pop(); | 2553 return Pop(); |
2364 } | 2554 } |
2365 | 2555 |
2366 | 2556 |
2367 Handle<Code> KeyedLoadGenericStub::GenerateCode() { | 2557 Handle<Code> KeyedLoadGenericStub::GenerateCode() { |
2368 return DoGenerateCode(this); | 2558 return DoGenerateCode(this); |
2369 } | 2559 } |
2370 | 2560 |
2371 } // namespace internal | 2561 } // namespace internal |
2372 } // namespace v8 | 2562 } // namespace v8 |
OLD | NEW |