| 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 <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "src/bailout-reason.h" | 9 #include "src/bailout-reason.h" |
| 10 #include "src/crankshaft/hydrogen.h" | 10 #include "src/crankshaft/hydrogen.h" |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 Isolate* isolate() { return info_->isolate(); } | 77 Isolate* isolate() { return info_->isolate(); } |
| 78 | 78 |
| 79 HLoadNamedField* BuildLoadNamedField(HValue* object, FieldIndex index); | 79 HLoadNamedField* BuildLoadNamedField(HValue* object, FieldIndex index); |
| 80 void BuildStoreNamedField(HValue* object, HValue* value, FieldIndex index, | 80 void BuildStoreNamedField(HValue* object, HValue* value, FieldIndex index, |
| 81 Representation representation, | 81 Representation representation, |
| 82 bool transition_to_field); | 82 bool transition_to_field); |
| 83 | 83 |
| 84 HValue* BuildPushElement(HValue* object, HValue* argc, | 84 HValue* BuildPushElement(HValue* object, HValue* argc, |
| 85 HValue* argument_elements, ElementsKind kind); | 85 HValue* argument_elements, ElementsKind kind); |
| 86 | 86 |
| 87 HValue* UnmappedCase(HValue* elements, HValue* key, HValue* value); | |
| 88 HValue* EmitKeyedSloppyArguments(HValue* receiver, HValue* key, | |
| 89 HValue* value); | |
| 90 | |
| 91 HValue* BuildToString(HValue* input, bool convert); | 87 HValue* BuildToString(HValue* input, bool convert); |
| 92 HValue* BuildToPrimitive(HValue* input, HValue* input_map); | 88 HValue* BuildToPrimitive(HValue* input, HValue* input_map); |
| 93 | 89 |
| 94 private: | 90 private: |
| 95 std::unique_ptr<HParameter* []> parameters_; | 91 std::unique_ptr<HParameter* []> parameters_; |
| 96 HValue* arguments_length_; | 92 HValue* arguments_length_; |
| 97 CompilationInfo* info_; | 93 CompilationInfo* info_; |
| 98 CodeStub* code_stub_; | 94 CodeStub* code_stub_; |
| 99 CodeStubDescriptor descriptor_; | 95 CodeStubDescriptor descriptor_; |
| 100 HContext* context_; | 96 HContext* context_; |
| (...skipping 797 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 898 HValue* descriptors = Add<HLoadNamedField>(map, nullptr, descriptors_access); | 894 HValue* descriptors = Add<HLoadNamedField>(map, nullptr, descriptors_access); |
| 899 HObjectAccess value_access = HObjectAccess::ForObservableJSObjectOffset( | 895 HObjectAccess value_access = HObjectAccess::ForObservableJSObjectOffset( |
| 900 DescriptorArray::GetValueOffset(casted_stub()->constant_index())); | 896 DescriptorArray::GetValueOffset(casted_stub()->constant_index())); |
| 901 return Add<HLoadNamedField>(descriptors, nullptr, value_access); | 897 return Add<HLoadNamedField>(descriptors, nullptr, value_access); |
| 902 } | 898 } |
| 903 | 899 |
| 904 | 900 |
| 905 Handle<Code> LoadConstantStub::GenerateCode() { return DoGenerateCode(this); } | 901 Handle<Code> LoadConstantStub::GenerateCode() { return DoGenerateCode(this); } |
| 906 | 902 |
| 907 | 903 |
| 908 HValue* CodeStubGraphBuilderBase::UnmappedCase(HValue* elements, HValue* key, | |
| 909 HValue* value) { | |
| 910 HValue* result = NULL; | |
| 911 HInstruction* backing_store = | |
| 912 Add<HLoadKeyed>(elements, graph()->GetConstant1(), nullptr, nullptr, | |
| 913 FAST_ELEMENTS, ALLOW_RETURN_HOLE); | |
| 914 Add<HCheckMaps>(backing_store, isolate()->factory()->fixed_array_map()); | |
| 915 HValue* backing_store_length = Add<HLoadNamedField>( | |
| 916 backing_store, nullptr, HObjectAccess::ForFixedArrayLength()); | |
| 917 IfBuilder in_unmapped_range(this); | |
| 918 in_unmapped_range.If<HCompareNumericAndBranch>(key, backing_store_length, | |
| 919 Token::LT); | |
| 920 in_unmapped_range.Then(); | |
| 921 { | |
| 922 if (value == NULL) { | |
| 923 result = Add<HLoadKeyed>(backing_store, key, nullptr, nullptr, | |
| 924 FAST_HOLEY_ELEMENTS, NEVER_RETURN_HOLE); | |
| 925 } else { | |
| 926 Add<HStoreKeyed>(backing_store, key, value, nullptr, FAST_HOLEY_ELEMENTS); | |
| 927 } | |
| 928 } | |
| 929 in_unmapped_range.ElseDeopt(DeoptimizeReason::kOutsideOfRange); | |
| 930 in_unmapped_range.End(); | |
| 931 return result; | |
| 932 } | |
| 933 | |
| 934 | |
| 935 HValue* CodeStubGraphBuilderBase::EmitKeyedSloppyArguments(HValue* receiver, | |
| 936 HValue* key, | |
| 937 HValue* value) { | |
| 938 // Mapped arguments are actual arguments. Unmapped arguments are values added | |
| 939 // to the arguments object after it was created for the call. Mapped arguments | |
| 940 // are stored in the context at indexes given by elements[key + 2]. Unmapped | |
| 941 // arguments are stored as regular indexed properties in the arguments array, | |
| 942 // held at elements[1]. See NewSloppyArguments() in runtime.cc for a detailed | |
| 943 // look at argument object construction. | |
| 944 // | |
| 945 // The sloppy arguments elements array has a special format: | |
| 946 // | |
| 947 // 0: context | |
| 948 // 1: unmapped arguments array | |
| 949 // 2: mapped_index0, | |
| 950 // 3: mapped_index1, | |
| 951 // ... | |
| 952 // | |
| 953 // length is 2 + min(number_of_actual_arguments, number_of_formal_arguments). | |
| 954 // If key + 2 >= elements.length then attempt to look in the unmapped | |
| 955 // arguments array (given by elements[1]) and return the value at key, missing | |
| 956 // to the runtime if the unmapped arguments array is not a fixed array or if | |
| 957 // key >= unmapped_arguments_array.length. | |
| 958 // | |
| 959 // Otherwise, t = elements[key + 2]. If t is the hole, then look up the value | |
| 960 // in the unmapped arguments array, as described above. Otherwise, t is a Smi | |
| 961 // index into the context array given at elements[0]. Return the value at | |
| 962 // context[t]. | |
| 963 | |
| 964 bool is_load = value == NULL; | |
| 965 | |
| 966 key = AddUncasted<HForceRepresentation>(key, Representation::Smi()); | |
| 967 IfBuilder positive_smi(this); | |
| 968 positive_smi.If<HCompareNumericAndBranch>(key, graph()->GetConstant0(), | |
| 969 Token::LT); | |
| 970 positive_smi.ThenDeopt(DeoptimizeReason::kKeyIsNegative); | |
| 971 positive_smi.End(); | |
| 972 | |
| 973 HValue* constant_two = Add<HConstant>(2); | |
| 974 HValue* elements = AddLoadElements(receiver, nullptr); | |
| 975 HValue* elements_length = Add<HLoadNamedField>( | |
| 976 elements, nullptr, HObjectAccess::ForFixedArrayLength()); | |
| 977 HValue* adjusted_length = AddUncasted<HSub>(elements_length, constant_two); | |
| 978 IfBuilder in_range(this); | |
| 979 in_range.If<HCompareNumericAndBranch>(key, adjusted_length, Token::LT); | |
| 980 in_range.Then(); | |
| 981 { | |
| 982 HValue* index = AddUncasted<HAdd>(key, constant_two); | |
| 983 HInstruction* mapped_index = | |
| 984 Add<HLoadKeyed>(elements, index, nullptr, nullptr, FAST_HOLEY_ELEMENTS, | |
| 985 ALLOW_RETURN_HOLE); | |
| 986 | |
| 987 IfBuilder is_valid(this); | |
| 988 is_valid.IfNot<HCompareObjectEqAndBranch>(mapped_index, | |
| 989 graph()->GetConstantHole()); | |
| 990 is_valid.Then(); | |
| 991 { | |
| 992 // TODO(mvstanton): I'd like to assert from this point, that if the | |
| 993 // mapped_index is not the hole that it is indeed, a smi. An unnecessary | |
| 994 // smi check is being emitted. | |
| 995 HValue* the_context = Add<HLoadKeyed>(elements, graph()->GetConstant0(), | |
| 996 nullptr, nullptr, FAST_ELEMENTS); | |
| 997 STATIC_ASSERT(Context::kHeaderSize == FixedArray::kHeaderSize); | |
| 998 if (is_load) { | |
| 999 HValue* result = | |
| 1000 Add<HLoadKeyed>(the_context, mapped_index, nullptr, nullptr, | |
| 1001 FAST_ELEMENTS, ALLOW_RETURN_HOLE); | |
| 1002 environment()->Push(result); | |
| 1003 } else { | |
| 1004 DCHECK(value != NULL); | |
| 1005 Add<HStoreKeyed>(the_context, mapped_index, value, nullptr, | |
| 1006 FAST_ELEMENTS); | |
| 1007 environment()->Push(value); | |
| 1008 } | |
| 1009 } | |
| 1010 is_valid.Else(); | |
| 1011 { | |
| 1012 HValue* result = UnmappedCase(elements, key, value); | |
| 1013 environment()->Push(is_load ? result : value); | |
| 1014 } | |
| 1015 is_valid.End(); | |
| 1016 } | |
| 1017 in_range.Else(); | |
| 1018 { | |
| 1019 HValue* result = UnmappedCase(elements, key, value); | |
| 1020 environment()->Push(is_load ? result : value); | |
| 1021 } | |
| 1022 in_range.End(); | |
| 1023 | |
| 1024 return environment()->Pop(); | |
| 1025 } | |
| 1026 | |
| 1027 | |
| 1028 template <> | |
| 1029 HValue* CodeStubGraphBuilder<KeyedLoadSloppyArgumentsStub>::BuildCodeStub() { | |
| 1030 HValue* receiver = GetParameter(Descriptor::kReceiver); | |
| 1031 HValue* key = GetParameter(Descriptor::kName); | |
| 1032 | |
| 1033 return EmitKeyedSloppyArguments(receiver, key, NULL); | |
| 1034 } | |
| 1035 | |
| 1036 | |
| 1037 Handle<Code> KeyedLoadSloppyArgumentsStub::GenerateCode() { | |
| 1038 return DoGenerateCode(this); | |
| 1039 } | |
| 1040 | |
| 1041 | |
| 1042 template <> | |
| 1043 HValue* CodeStubGraphBuilder<KeyedStoreSloppyArgumentsStub>::BuildCodeStub() { | |
| 1044 HValue* receiver = GetParameter(Descriptor::kReceiver); | |
| 1045 HValue* key = GetParameter(Descriptor::kName); | |
| 1046 HValue* value = GetParameter(Descriptor::kValue); | |
| 1047 | |
| 1048 return EmitKeyedSloppyArguments(receiver, key, value); | |
| 1049 } | |
| 1050 | |
| 1051 | |
| 1052 Handle<Code> KeyedStoreSloppyArgumentsStub::GenerateCode() { | |
| 1053 return DoGenerateCode(this); | |
| 1054 } | |
| 1055 | |
| 1056 | |
| 1057 void CodeStubGraphBuilderBase::BuildStoreNamedField( | 904 void CodeStubGraphBuilderBase::BuildStoreNamedField( |
| 1058 HValue* object, HValue* value, FieldIndex index, | 905 HValue* object, HValue* value, FieldIndex index, |
| 1059 Representation representation, bool transition_to_field) { | 906 Representation representation, bool transition_to_field) { |
| 1060 DCHECK(!index.is_double() || representation.IsDouble()); | 907 DCHECK(!index.is_double() || representation.IsDouble()); |
| 1061 int offset = index.offset(); | 908 int offset = index.offset(); |
| 1062 HObjectAccess access = | 909 HObjectAccess access = |
| 1063 index.is_inobject() | 910 index.is_inobject() |
| 1064 ? HObjectAccess::ForObservableJSObjectOffset(offset, representation) | 911 ? HObjectAccess::ForObservableJSObjectOffset(offset, representation) |
| 1065 : HObjectAccess::ForBackingStoreOffset(offset, representation); | 912 : HObjectAccess::ForBackingStoreOffset(offset, representation); |
| 1066 | 913 |
| (...skipping 772 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1839 return Pop(); | 1686 return Pop(); |
| 1840 } | 1687 } |
| 1841 | 1688 |
| 1842 | 1689 |
| 1843 Handle<Code> KeyedLoadGenericStub::GenerateCode() { | 1690 Handle<Code> KeyedLoadGenericStub::GenerateCode() { |
| 1844 return DoGenerateCode(this); | 1691 return DoGenerateCode(this); |
| 1845 } | 1692 } |
| 1846 | 1693 |
| 1847 } // namespace internal | 1694 } // namespace internal |
| 1848 } // namespace v8 | 1695 } // namespace v8 |
| OLD | NEW |