| 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/ic/ic.h" | 5 #include "src/ic/ic.h" |
| 6 | 6 |
| 7 #include <iostream> | 7 #include <iostream> |
| 8 | 8 |
| 9 #include "src/accessors.h" | 9 #include "src/accessors.h" |
| 10 #include "src/api-arguments-inl.h" | 10 #include "src/api-arguments-inl.h" |
| (...skipping 836 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 847 } | 847 } |
| 848 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub); | 848 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub); |
| 849 LoadFieldStub stub(isolate(), index); | 849 LoadFieldStub stub(isolate(), index); |
| 850 return stub.GetCode(); | 850 return stub.GetCode(); |
| 851 } | 851 } |
| 852 | 852 |
| 853 namespace { | 853 namespace { |
| 854 | 854 |
| 855 template <bool fill_array = true> | 855 template <bool fill_array = true> |
| 856 int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map, | 856 int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map, |
| 857 Handle<JSObject> holder, Handle<FixedArray> array, | 857 Handle<JSObject> holder, Handle<Name> name, |
| 858 Handle<Name> name, int first_index) { | 858 Handle<FixedArray> array, int first_index) { |
| 859 DCHECK(holder.is_null() || holder->HasFastProperties()); | 859 DCHECK(holder.is_null() || holder->HasFastProperties()); |
| 860 | 860 |
| 861 // The following kinds of receiver maps require custom handler compilation. | 861 // The following kinds of receiver maps require custom handler compilation. |
| 862 if (receiver_map->IsJSGlobalObjectMap()) { | 862 if (receiver_map->IsJSGlobalObjectMap()) { |
| 863 return -1; | 863 return -1; |
| 864 } | 864 } |
| 865 // We don't encode the requirement to check access rights because we already | 865 // We don't encode the requirement to check access rights because we already |
| 866 // passed the access check for current native context and the access | 866 // passed the access check for current native context and the access |
| 867 // can't be revoked. | 867 // can't be revoked. |
| 868 | 868 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 879 if (fill_array) { | 879 if (fill_array) { |
| 880 Handle<Context> native_context = isolate->native_context(); | 880 Handle<Context> native_context = isolate->native_context(); |
| 881 array->set(LoadHandler::kFirstPrototypeIndex + checks_count, | 881 array->set(LoadHandler::kFirstPrototypeIndex + checks_count, |
| 882 native_context->self_weak_cell()); | 882 native_context->self_weak_cell()); |
| 883 } | 883 } |
| 884 checks_count++; | 884 checks_count++; |
| 885 } | 885 } |
| 886 | 886 |
| 887 // Create/count entries for each global or dictionary prototype appeared in | 887 // Create/count entries for each global or dictionary prototype appeared in |
| 888 // the prototype chain contains from receiver till holder. | 888 // the prototype chain contains from receiver till holder. |
| 889 for (PrototypeIterator iter(receiver_map); !iter.IsAtEnd(); iter.Advance()) { | 889 PrototypeIterator::WhereToEnd end = name->IsPrivate() |
| 890 ? PrototypeIterator::END_AT_NON_HIDDEN |
| 891 : PrototypeIterator::END_AT_NULL; |
| 892 for (PrototypeIterator iter(receiver_map, end); !iter.IsAtEnd(); |
| 893 iter.Advance()) { |
| 890 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); | 894 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); |
| 891 if (holder.is_identical_to(current)) break; | 895 if (holder.is_identical_to(current)) break; |
| 892 Handle<Map> current_map(current->map(), isolate); | 896 Handle<Map> current_map(current->map(), isolate); |
| 893 | 897 |
| 894 if (current_map->IsJSGlobalObjectMap()) { | 898 if (current_map->IsJSGlobalObjectMap()) { |
| 895 if (fill_array) { | 899 if (fill_array) { |
| 896 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(current); | 900 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(current); |
| 897 Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell( | 901 Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell( |
| 898 global, name, PropertyCellType::kInvalidated); | 902 global, name, PropertyCellType::kInvalidated); |
| 899 DCHECK(cell->value()->IsTheHole(isolate)); | 903 DCHECK(cell->value()->IsTheHole(isolate)); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 917 return checks_count; | 921 return checks_count; |
| 918 } | 922 } |
| 919 | 923 |
| 920 // Returns 0 if the validity cell check is enough to ensure that the | 924 // Returns 0 if the validity cell check is enough to ensure that the |
| 921 // prototype chain from |receiver_map| till |holder| did not change. | 925 // prototype chain from |receiver_map| till |holder| did not change. |
| 922 // If the |holder| is an empty handle then the full prototype chain is | 926 // If the |holder| is an empty handle then the full prototype chain is |
| 923 // checked. | 927 // checked. |
| 924 // Returns -1 if the handler has to be compiled or the number of prototype | 928 // Returns -1 if the handler has to be compiled or the number of prototype |
| 925 // checks otherwise. | 929 // checks otherwise. |
| 926 int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map, | 930 int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map, |
| 927 Handle<JSObject> holder) { | 931 Handle<JSObject> holder, Handle<Name> name) { |
| 928 return InitPrototypeChecks<false>(isolate, receiver_map, holder, | 932 return InitPrototypeChecks<false>(isolate, receiver_map, holder, name, |
| 929 Handle<FixedArray>(), Handle<Name>(), 0); | 933 Handle<FixedArray>(), 0); |
| 930 } | 934 } |
| 931 | 935 |
| 932 } // namespace | 936 } // namespace |
| 933 | 937 |
| 934 Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map, | 938 Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map, |
| 935 Handle<JSObject> holder, | 939 Handle<JSObject> holder, |
| 936 Handle<Name> name, | 940 Handle<Name> name, |
| 937 Handle<Object> smi_handler) { | 941 Handle<Object> smi_handler) { |
| 938 int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder); | 942 int checks_count = |
| 943 GetPrototypeCheckCount(isolate(), receiver_map, holder, name); |
| 939 DCHECK_LE(0, checks_count); | 944 DCHECK_LE(0, checks_count); |
| 940 DCHECK(!receiver_map->IsJSGlobalObjectMap()); | 945 DCHECK(!receiver_map->IsJSGlobalObjectMap()); |
| 941 | 946 |
| 942 if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { | 947 if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { |
| 943 DCHECK(!receiver_map->is_dictionary_map()); | 948 DCHECK(!receiver_map->is_dictionary_map()); |
| 944 DCHECK_LE(1, checks_count); // For native context. | 949 DCHECK_LE(1, checks_count); // For native context. |
| 945 smi_handler = | 950 smi_handler = |
| 946 LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler); | 951 LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler); |
| 947 } else if (receiver_map->is_dictionary_map()) { | 952 } else if (receiver_map->is_dictionary_map()) { |
| 948 smi_handler = | 953 smi_handler = |
| 949 LoadHandler::EnableNegativeLookupOnReceiver(isolate(), smi_handler); | 954 LoadHandler::EnableNegativeLookupOnReceiver(isolate(), smi_handler); |
| 950 } | 955 } |
| 951 | 956 |
| 952 Handle<Cell> validity_cell = | 957 Handle<Cell> validity_cell = |
| 953 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); | 958 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); |
| 954 DCHECK(!validity_cell.is_null()); | 959 DCHECK(!validity_cell.is_null()); |
| 955 | 960 |
| 956 Handle<WeakCell> holder_cell = | 961 Handle<WeakCell> holder_cell = |
| 957 Map::GetOrCreatePrototypeWeakCell(holder, isolate()); | 962 Map::GetOrCreatePrototypeWeakCell(holder, isolate()); |
| 958 | 963 |
| 959 if (checks_count == 0) { | 964 if (checks_count == 0) { |
| 960 return isolate()->factory()->NewTuple3(holder_cell, smi_handler, | 965 return isolate()->factory()->NewTuple3(holder_cell, smi_handler, |
| 961 validity_cell); | 966 validity_cell); |
| 962 } | 967 } |
| 963 Handle<FixedArray> handler_array(isolate()->factory()->NewFixedArray( | 968 Handle<FixedArray> handler_array(isolate()->factory()->NewFixedArray( |
| 964 LoadHandler::kFirstPrototypeIndex + checks_count, TENURED)); | 969 LoadHandler::kFirstPrototypeIndex + checks_count, TENURED)); |
| 965 handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler); | 970 handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler); |
| 966 handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell); | 971 handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell); |
| 967 handler_array->set(LoadHandler::kHolderCellIndex, *holder_cell); | 972 handler_array->set(LoadHandler::kHolderCellIndex, *holder_cell); |
| 968 InitPrototypeChecks(isolate(), receiver_map, holder, handler_array, name, | 973 InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array, |
| 969 LoadHandler::kFirstPrototypeIndex); | 974 LoadHandler::kFirstPrototypeIndex); |
| 970 return handler_array; | 975 return handler_array; |
| 971 } | 976 } |
| 972 | 977 |
| 973 Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map, | 978 Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map, |
| 974 Handle<Name> name) { | 979 Handle<Name> name) { |
| 975 Handle<JSObject> holder; // null handle | 980 Handle<JSObject> holder; // null handle |
| 976 int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder); | 981 int checks_count = |
| 982 GetPrototypeCheckCount(isolate(), receiver_map, holder, name); |
| 977 DCHECK_LE(0, checks_count); | 983 DCHECK_LE(0, checks_count); |
| 978 DCHECK(!receiver_map->IsJSGlobalObjectMap()); | 984 DCHECK(!receiver_map->IsJSGlobalObjectMap()); |
| 979 | 985 |
| 980 Handle<Object> smi_handler = LoadHandler::LoadNonExistent( | 986 Handle<Object> smi_handler = LoadHandler::LoadNonExistent( |
| 981 isolate(), receiver_map->is_dictionary_map()); | 987 isolate(), receiver_map->is_dictionary_map()); |
| 982 | 988 |
| 983 if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { | 989 if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { |
| 984 DCHECK(!receiver_map->is_dictionary_map()); | 990 DCHECK(!receiver_map->is_dictionary_map()); |
| 985 DCHECK_LE(1, checks_count); // For native context. | 991 DCHECK_LE(1, checks_count); // For native context. |
| 986 smi_handler = | 992 smi_handler = |
| 987 LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler); | 993 LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler); |
| 988 } | 994 } |
| 989 | 995 |
| 990 Handle<Object> validity_cell = | 996 Handle<Object> validity_cell = |
| 991 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); | 997 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); |
| 992 if (validity_cell.is_null()) { | 998 if (validity_cell.is_null()) { |
| 993 // This must be a case when receiver's prototype is null. | |
| 994 DCHECK_EQ(*isolate()->factory()->null_value(), | |
| 995 receiver_map->GetPrototypeChainRootMap(isolate())->prototype()); | |
| 996 DCHECK_EQ(0, checks_count); | 999 DCHECK_EQ(0, checks_count); |
| 997 validity_cell = handle(Smi::FromInt(0), isolate()); | 1000 validity_cell = handle(Smi::FromInt(0), isolate()); |
| 998 } | 1001 } |
| 999 | 1002 |
| 1000 Factory* factory = isolate()->factory(); | 1003 Factory* factory = isolate()->factory(); |
| 1001 if (checks_count == 0) { | 1004 if (checks_count == 0) { |
| 1002 return factory->NewTuple3(factory->null_value(), smi_handler, | 1005 return factory->NewTuple3(factory->null_value(), smi_handler, |
| 1003 validity_cell); | 1006 validity_cell); |
| 1004 } | 1007 } |
| 1005 Handle<FixedArray> handler_array(factory->NewFixedArray( | 1008 Handle<FixedArray> handler_array(factory->NewFixedArray( |
| 1006 LoadHandler::kFirstPrototypeIndex + checks_count, TENURED)); | 1009 LoadHandler::kFirstPrototypeIndex + checks_count, TENURED)); |
| 1007 handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler); | 1010 handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler); |
| 1008 handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell); | 1011 handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell); |
| 1009 handler_array->set(LoadHandler::kHolderCellIndex, *factory->null_value()); | 1012 handler_array->set(LoadHandler::kHolderCellIndex, *factory->null_value()); |
| 1010 InitPrototypeChecks(isolate(), receiver_map, holder, handler_array, name, | 1013 InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array, |
| 1011 LoadHandler::kFirstPrototypeIndex); | 1014 LoadHandler::kFirstPrototypeIndex); |
| 1012 return handler_array; | 1015 return handler_array; |
| 1013 } | 1016 } |
| 1014 | 1017 |
| 1015 bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) { | 1018 bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) { |
| 1016 DCHECK(lookup->state() == LookupIterator::ACCESSOR); | 1019 DCHECK(lookup->state() == LookupIterator::ACCESSOR); |
| 1017 Isolate* isolate = lookup->isolate(); | 1020 Isolate* isolate = lookup->isolate(); |
| 1018 Handle<Object> accessors = lookup->GetAccessors(); | 1021 Handle<Object> accessors = lookup->GetAccessors(); |
| 1019 if (accessors->IsAccessorInfo()) { | 1022 if (accessors->IsAccessorInfo()) { |
| 1020 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); | 1023 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); |
| (...skipping 863 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1884 | 1887 |
| 1885 } else { | 1888 } else { |
| 1886 DCHECK_EQ(DATA, details.type()); | 1889 DCHECK_EQ(DATA, details.type()); |
| 1887 bool extend_storage = | 1890 bool extend_storage = |
| 1888 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0; | 1891 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0; |
| 1889 | 1892 |
| 1890 FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor); | 1893 FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor); |
| 1891 smi_handler = StoreHandler::TransitionToField( | 1894 smi_handler = StoreHandler::TransitionToField( |
| 1892 isolate(), descriptor, index, representation, extend_storage); | 1895 isolate(), descriptor, index, representation, extend_storage); |
| 1893 } | 1896 } |
| 1897 // |holder| is either a receiver if the property is non-existent or |
| 1898 // one of the prototypes. |
| 1899 DCHECK(!holder.is_null()); |
| 1900 bool is_nonexistent = holder->map() == transition->GetBackPointer(); |
| 1901 if (is_nonexistent) holder = Handle<JSObject>::null(); |
| 1894 | 1902 |
| 1895 int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder); | 1903 int checks_count = |
| 1904 GetPrototypeCheckCount(isolate(), receiver_map, holder, name); |
| 1896 DCHECK_LE(0, checks_count); | 1905 DCHECK_LE(0, checks_count); |
| 1897 DCHECK(!receiver_map->IsJSGlobalObjectMap()); | 1906 DCHECK(!receiver_map->IsJSGlobalObjectMap()); |
| 1898 | 1907 |
| 1899 Handle<Object> validity_cell = | 1908 Handle<Object> validity_cell = |
| 1900 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); | 1909 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); |
| 1901 if (validity_cell.is_null()) { | 1910 if (validity_cell.is_null()) { |
| 1902 // This must be a case when receiver's prototype is null. | |
| 1903 DCHECK_EQ(*isolate()->factory()->null_value(), | |
| 1904 receiver_map->GetPrototypeChainRootMap(isolate())->prototype()); | |
| 1905 DCHECK_EQ(0, checks_count); | 1911 DCHECK_EQ(0, checks_count); |
| 1906 validity_cell = handle(Smi::FromInt(0), isolate()); | 1912 validity_cell = handle(Smi::FromInt(0), isolate()); |
| 1907 } | 1913 } |
| 1908 | 1914 |
| 1909 Handle<WeakCell> transition_cell = Map::WeakCellForMap(transition); | 1915 Handle<WeakCell> transition_cell = Map::WeakCellForMap(transition); |
| 1910 | 1916 |
| 1911 Factory* factory = isolate()->factory(); | 1917 Factory* factory = isolate()->factory(); |
| 1912 if (checks_count == 0) { | 1918 if (checks_count == 0) { |
| 1913 return factory->NewTuple3(transition_cell, smi_handler, validity_cell); | 1919 return factory->NewTuple3(transition_cell, smi_handler, validity_cell); |
| 1914 } | 1920 } |
| 1915 Handle<FixedArray> handler_array(factory->NewFixedArray( | 1921 Handle<FixedArray> handler_array(factory->NewFixedArray( |
| 1916 StoreHandler::kFirstPrototypeIndex + checks_count, TENURED)); | 1922 StoreHandler::kFirstPrototypeIndex + checks_count, TENURED)); |
| 1917 handler_array->set(StoreHandler::kSmiHandlerIndex, *smi_handler); | 1923 handler_array->set(StoreHandler::kSmiHandlerIndex, *smi_handler); |
| 1918 handler_array->set(StoreHandler::kValidityCellIndex, *validity_cell); | 1924 handler_array->set(StoreHandler::kValidityCellIndex, *validity_cell); |
| 1919 handler_array->set(StoreHandler::kTransitionCellIndex, *transition_cell); | 1925 handler_array->set(StoreHandler::kTransitionCellIndex, *transition_cell); |
| 1920 InitPrototypeChecks(isolate(), receiver_map, holder, handler_array, name, | 1926 InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array, |
| 1921 StoreHandler::kFirstPrototypeIndex); | 1927 StoreHandler::kFirstPrototypeIndex); |
| 1922 return handler_array; | 1928 return handler_array; |
| 1923 } | 1929 } |
| 1924 | 1930 |
| 1925 static Handle<Code> PropertyCellStoreHandler( | 1931 static Handle<Code> PropertyCellStoreHandler( |
| 1926 Isolate* isolate, Handle<JSObject> receiver, Handle<JSGlobalObject> holder, | 1932 Isolate* isolate, Handle<JSObject> receiver, Handle<JSGlobalObject> holder, |
| 1927 Handle<Name> name, Handle<PropertyCell> cell, PropertyCellType type) { | 1933 Handle<Name> name, Handle<PropertyCell> cell, PropertyCellType type) { |
| 1928 auto constant_type = Nothing<PropertyCellConstantType>(); | 1934 auto constant_type = Nothing<PropertyCellConstantType>(); |
| 1929 if (type == PropertyCellType::kConstantType) { | 1935 if (type == PropertyCellType::kConstantType) { |
| 1930 constant_type = Just(cell->GetConstantType()); | 1936 constant_type = Just(cell->GetConstantType()); |
| (...skipping 1309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3240 DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); | 3246 DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); |
| 3241 it.Next(); | 3247 it.Next(); |
| 3242 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, | 3248 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, |
| 3243 Object::GetProperty(&it)); | 3249 Object::GetProperty(&it)); |
| 3244 } | 3250 } |
| 3245 | 3251 |
| 3246 return *result; | 3252 return *result; |
| 3247 } | 3253 } |
| 3248 } // namespace internal | 3254 } // namespace internal |
| 3249 } // namespace v8 | 3255 } // namespace v8 |
| OLD | NEW |