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